第 8 课 上下文工程:管理上下文窗口
管理上下文窗口就是管理注意力。
预计 18 分钟 · 系列:从 0 到 1 设计一个 Agent
本课要点
- 理解模型上下文窗口与 Agent 自己上下文预算的区别
- 看懂上下文如何组装,以及固定前缀、截断、压缩与检索的作用
- 决定这一轮到底应该让模型看到什么,并识别哪些信息不能忘
当我们向 ChatGPT、Codex、豆包、WorkBuddy 这些 AI 应用发出一句请求时,模型真正收到的内容,通常远远不止我们刚刚输入的这一句话。
它看到的内容可能包括:系统提示词、当前可以使用的工具、历史对话、历史工具调用结果、当前任务的状态,以及用户最新发出的一句话。这些信息放在一起,就组成了当前的上下文(Context)。
Agent 会基于这些上下文,判断自己现在应该做什么、调用什么工具、下一步怎么行动。
你可以把上下文想象成 Agent 此刻摆在桌面上的所有资料。桌面上的资料越多,不一定越好。如果当前任务需要的是一份合同,但桌子上同时堆着几十份历史对话、工具说明、旧任务记录和无关材料,Agent 就需要从一大堆信息里找到真正重要的东西。
管理上下文,本质上就是管理 Agent 的注意力。
1. 上下文窗口大小
模型自己的上下文窗口
模型一次能够看到的信息是有限的。这个限制通常被称为上下文窗口(Context Window)。你可以把它理解成模型的「工作台大小」。工作台再大,也不可能无限大。
模型需要同时处理上下文中的所有 Token。上下文越长,需要计算和保存的信息也越多,会影响显存、计算量和推理速度。不同模型支持的 Token 上限也不同,有的支持几十万 Token,有的可以达到百万 Token。
上下文窗口通常同时包含输入和输出。比如一个模型支持 128K Token,并不意味着你可以塞进去 128K Token 的资料,然后再让它继续输出大量内容。模型之前看到的内容,以及接下来准备生成的内容,都要占用这个窗口。
智能体自己的上下文窗口
用户的请求理论上可以不断延续,但模型的窗口有限。上下文越长,成本越高,响应可能越慢,输出质量也可能下降;当历史信息超出模型自身窗口后,还需要有办法保持对话的连续性。
所以很多 Agent 产品会设置自己的上下文窗口大小。设计 Agent 时,不光要知道模型窗口有多大,还需要考虑:这一轮到底应该让模型看到什么。
2. 智能体的上下文由什么组成?
智能体需要设置一个自己的上下文窗口大小,因为用户的请求理论上是无限的,但是:
1、模型自己的上下文是有限的,上下文越长,成本越高,响应可能越慢,输出的质量也会下降,同时还可能让模型被大量无关信息干扰
2、当历史信息大小超出模型自身上下文大小之后,需要有办法保持对话的连续性
智能体的上下文窗口容量不直接等于模型的上下文窗口。
比如一个 Agent 连续调用了 20 次工具,如果每一次工具返回的完整结果都一直留在上下文里,窗口很快就会变得非常拥挤。
尽量把固定不变的内容放在前面。
系统提示词、工具说明等内容,在很多轮请求里都不会发生变化。把固定内容放在前面,有助于利用提示词缓存(Prompt Caching),减少重复计算、降低成本并提升响应速度。
缓存是否命中,还需要满足具体模型与接口的缓存规则。
3. 智能体如何在有限窗口中处理无限上下文
上面已经提到,模型能够处理的上下文有限。而 Agent 在运行过程中会不断产生新的信息:用户继续聊天、Agent 调用工具、工具返回结果、任务继续执行……
如果什么都不处理,上下文一定会越来越长。所以不同的 AI 应用,会采用不同的上下文控制策略。
比如:
- 最多保留多少轮对话
- 上下文达到多少 Token 后开始压缩
常见的方法大概有下面几种:
3.1 硬截断
最简单粗暴的方法,就是直接丢掉一部分历史信息。
滑动窗口
永远只保留最近几轮对话。假设只保留最近 3 轮,第 4 轮进来以后,第 1 轮就会被挤出去。
(最近 3 轮)
(最近 3 轮)
固定轮次截断
比如最多允许 5 轮对话。达到限制以后,直接开启一个新的上下文,之前的信息全部清空。
真的会忘。实现简单、成本低。但如果前面的信息之后又变得重要,单靠当前上下文已经找不回来了。
3.2 压缩
内容太多以后,把历史信息总结一下。原来有 30,000 Token 的历史信息,可以提炼成 3,000 Token,再带着这份总结继续执行任务。
提炼总结
这有点像你开了一个很长的会议。会议进行到一半,桌面上的材料已经堆满了,于是有人把前半场的结论整理成一页会议纪要,接下来大家只拿着这页纪要继续讨论。
固定压缩
当前上下文使用量达到 90%,就进行一次压缩。
动态压缩
根据任务复杂度与信息类型,决定保留多少细节。
哪些信息可以忘,哪些信息绝对不能忘。
3.3 历史信息检索
不把所有历史信息一直放在上下文里,先存起来,需要的时候再找回来。
比如 Agent 之前和用户已经聊了几百轮。这些内容全部保存到外部存储中,当前上下文只保留最近的内容。当 Agent 发现“这个问题之前好像聊过”,它就去历史记录里搜索相关信息,再把搜索结果放回当前上下文。
从这个角度看,Agent 能够使用的历史信息几乎可以无限延长。忘掉也没关系,需要的时候再查。但历史检索解决了「存不下」的问题,却又带来了「能不能准确找回来」的问题。
检索出来的内容可能缺少当时的语境,检索结果本身也会占用新的上下文;实际系统还需要处理搜索耗时、召回质量与失败兜底。
4. 不同产品是怎么做的?
现实中的 Agent 产品,通常会组合使用上面几种方法,具体实现也会不断变化。
| 产品 | 上下文处理 | 阅读提示 |
|---|---|---|
| Codex | 自动压缩后继续执行 | 窗口与阈值依模型、配置而定 |
| Claude Code | 压缩历史,保留重要状态 | 200K / 1M 等,依模型与配置而定 |
Agent 每一步能看到什么、忘掉什么、压缩什么、什么时候重新找回来,都会直接影响它接下来的判断。