Agent 如何管理上下文窗口?
简化版
Agent 不能把每轮思考、完整工具响应和全部历史一直追加到 Prompt。应把上下文分为稳定指令、当前任务状态、近期轨迹和按需证据:稳定指令固定保留,任务状态结构化维护,旧轨迹压缩成带来源的摘要,大工具结果存到外部并只注入引用或相关片段。每轮装配前精确计数,给输出留预算;被压缩的关键信息必须能按 ID 回取。
详细版
Agent 上下文比普通聊天多了计划、工具 Schema、工具观察、中间产物和错误轨迹,膨胀更快。治理时要区分“状态”和“记录”:当前目标、约束、已完成节点属于状态,必须准确;历史推理和旧工具输出属于记录,可以摘要或外置。
[稳定区] system + policy
[状态区] goal + constraints + plan + completed/blocked
[工作区] recent actions + latest observations
[证据区] 按当前步骤检索出的片段
[预留区] next action / final answer
每轮由上下文装配器按优先级打包,而不是让模型自己复制历史。超限时先移除无关工具定义与重复观察,再压缩已完成阶段,保留未解决错误和当前步骤证据。评测要覆盖长轨迹中的约束保持、引用回溯、工具选择准确率、压缩后任务成功率与成本延迟。
完整版教学
一、Agent 为什么比聊天更容易爆窗
聊天主要累积用户和助手消息,Agent 还会积累工具定义、计划、每次调用参数、原始返回、重试错误和中间文件。一个网页抓取工具可能一次返回 20 KB;连续调用十次,即使模型只说了几句话,上下文也会迅速膨胀。
长上下文不仅会触碰硬上限,还会提高 prefill 延迟,让重要约束被大量旧观察稀释。真正的问题不是“装不下”才处理,而是从设计之初控制每类信息的生命周期。
记忆钩子:状态回答“现在必须知道什么”,日志回答“以前发生过什么”;Agent 每轮需要状态,不一定需要整本日志。
二、把上下文分成不同保真等级
系统安全规则、用户当前目标和不可违反的约束属于高保真区,不能由自由摘要替代。已完成步骤的细节可以压缩,但要保留产物 ID 和验证结果。原始工具响应通常外置,只注入当前决策相关的字段。
| 信息 | 保留方式 | 淘汰条件 |
|---|---|---|
| 系统与权限规则 | 原文或受控模板 | 本次请求不淘汰 |
| 目标与硬约束 | 结构化状态 | 用户明确修改 |
| 当前步骤证据 | 原文相关片段 | 步骤完成且已归档 |
| 已完成轨迹 | 摘要 + 产物引用 | 任务结束 |
| 调试日志 | 外部 Trace | 不进入正常 Prompt |
这种分区避免一个统一的“截掉最旧消息”策略误删仍然有效的约束。
三、结构化状态优于反复摘要
若只让模型总结历史,“预算不超过 500 元”可能在多次摘要后变成“预算约 500 元”,语义已经变化。目标、数值约束、实体 ID、计划状态和待确认项应放进有 Schema 的状态对象,并由控制器更新。
{
"goal": "预订周五上海到北京的高铁",
"constraints": {"depart_after": "14:00", "max_price": 500},
"completed": ["search_trains"],
"pending": ["user_select_train"]
}
模型可以提出状态更新候选,但写入前要做类型、范围和权限校验。这样压缩对话时,不会把任务骨架一起压没。
四、工具结果采用“外置 + 投影”
数据库查询的 1000 行、网页全文和编译日志不应永久放进上下文。工具层把原始结果存入对象存储或任务附件,返回 artifact_id、摘要、关键字段和可分页引用;上下文装配器根据下一步需要选择投影。
例如原始日志有 50,000 token,而定位错误只需最后 200 行和首个异常栈,投影后可能仅 1,500 token,减少 97%。如果模型需要上文,可用 artifact ID 再请求局部范围,而不是重新执行工具。
投影必须保留证据定位,如页码、行号、记录主键和内容哈希。否则摘要一旦出错,后续无法回到真值核对。
五、轨迹压缩要按阶段做
每轮都总结全部历史会额外花费模型调用,并产生逐次失真。更合适的是在子任务完成、上下文达到水位或阶段切换时压缩:保留目标、关键决策、产物、失败原因和未完成项,删除可重建的过程性表达。
搜索阶段 18 条消息
-> 阶段摘要:查过哪些源、选中哪些证据、哪些问题未解决
-> 原始轨迹保存在 trace://task/123/search
摘要应带版本和覆盖范围。若后续发现结论矛盾,可以展开对应轨迹重新核查,而不是继续在错误摘要上推理。
六、每轮动态装配而非固定拼接
当前执行“查询价格”时,需要价格工具 Schema 和商品 ID,不需要发布工具及三轮前的排版讨论。装配器可先根据当前计划节点选择工具,再检索与该节点相关的记忆和证据,最后按预算排序装箱。
假设窗口 16K,输出预留 2K,安全余量 500,系统与状态占 3K,那么工作区和证据区共有 16000-2000-500-3000=10500 token。若候选证据超限,应按任务相关性与不可替代性裁剪,而不是平均砍半。
动态装配还要防止不可信工具文本进入系统区。网页中的“忽略之前指令”只能作为数据片段,不能改变权限和工具策略。
七、压缩失败有可观测信号
压缩后 Agent 重复调用已经成功的工具,说明完成状态丢失;违反用户早期约束,说明状态抽取有误;引用不存在的 artifact,说明索引生命周期失配。这些都应成为自动评测用例。
可记录每轮各分区 token、压缩次数、召回的 artifact、重复动作率、约束违反率和最终任务成功率。只看平均 token 下降会鼓励过度压缩;质量必须与成本一起比较。
在 200 条长任务上,若压缩使平均输入减少 40%,但成功率从 88% 降到 80%,通常不可接受。应定位是哪个状态字段或证据类型被删,而不是简单扩大摘要。
八、不同失败采用不同降级
接近窗口上限时,可以删除未使用工具、压缩旧阶段、分离子任务,或换长窗口模型。若仍无法容纳不可丢内容,应明确停止并要求缩小任务,而不能静默截断。
摘要服务失败时可以回退到最近检查点和结构化状态;artifact 存储不可用时,不应假装已经读取证据;输出空间不足时应缩短响应计划,而不是侵占安全指令。
设计降级顺序的原则是先牺牲便利与细节,再牺牲覆盖范围,绝不牺牲权限边界和任务硬约束。
九、常见误区与追问
- 误区:模型窗口足够长就无需管理。 工具轨迹会持续增长,长输入仍有成本、延迟和注意力稀释问题。
- 误区:保留最近 N 条消息最简单可靠。 消息长度差异大,早期硬约束可能仍然有效。
- 误区:把所有工具结果总结一次即可。 摘要有损,原始结果必须外置并可按引用回取。
- 误区:思考轨迹越完整,Agent 越聪明。 大量过程文本会制造噪声,任务状态和证据更重要。
- 误区:压缩率越高越好。 应以任务成功率、约束保持率和成本的联合指标评价。
- 追问:哪些信息绝不能摘要? 安全规则、权限、精确数值约束和当前未解决条件应原文或结构化保存。
- 追问:何时触发轨迹压缩? 阶段完成、达到 token 水位或切换子任务时,而不是机械地每轮执行。
- 追问:怎样验证摘要没有遗漏? 用结构化必填字段、来源引用和长任务回归集检查,并允许展开原始 artifact。
十、加强记忆
Agent 上下文管理记住“分区、状态、外置、装配”:安全规则和硬约束高保真保留,目标与进度写成结构化状态,大型工具结果外置并留下可回取引用,旧轨迹按阶段压缩;每轮只为当前节点动态装配相关工具与证据。优化目标不是单纯减少 token,而是在任务成功、约束保持和可追溯的前提下,降低成本与延迟。