上下文窗口大了,Agent 反而更笨:一份手工管理的「预算表」
窗口从 8K 涨到 1M,很多 Agent 的效果却在下滑。本文把上下文当成稀缺预算来管:四类内容的价值密度测算、压缩与驱逐的决策顺序、以及一份可直接照抄的上下文预算表。
一个反直觉的现象:把模型的上下文窗口从 128K 拉到 1M,很多 Agent 的任务成功率没涨,反而跌了。原因不在模型,在我们的用法。窗口变大之后,团队开始”什么都塞进去”——完整对话历史、全量工具返回、几十份文档原文。结果是信噪比崩塌:关键指令被淹没,模型开始忽略中间段落(lost in the middle),成本还翻了五倍。
把上下文当成一份有限的预算,问题就变得可解了。
先给每类内容算”价值密度”
不要凭感觉决定放什么。对每一类候选内容,估两个数:它对当前这一步决策有多大帮助(0-3 分),以及它占多少 token。价值除以 token,就是密度。
一份实测下来的排序(针对客服 / 运营类 Agent):
| 内容类型 | 价值 | 典型 token | 处理方式 |
|---|---|---|---|
| 系统指令与硬约束 | 3 | 500-1.5K | 永久驻留,不可驱逐 |
| 当前任务目标与验收标准 | 3 | 200-500 | 永久驻留 |
| 最近 3 轮工具调用结果 | 2-3 | 1-8K | 保留,成功后折叠成摘要 |
| 检索到的文档片段 | 2 | 4-20K | 按分数截断,宁少勿滥 |
| 完整对话历史 | 1 | 5-50K | 只留摘要 + 最近 3 轮原文 |
| 全部工具定义 | 1 | 3-15K | 按需加载,别一次全给 |
| 中间思考过程 | 0-1 | 变化大 | 单步结束即丢弃 |
表格里最容易被违反的是最后两条。工具定义一次全量下发,是新手最常见的浪费:50 个工具的 schema 能吃掉 10K token,而单步真正会用到的通常不超过 3 个。
压缩的顺序:先折叠,再摘要,最后才丢
很多团队一遇到超限就直接截断最老的消息,这会丢掉任务最初的目标,Agent 于是开始”目标漂移”。正确的顺序是三级:
- 折叠:把一次成功的工具调用压缩成”动作 + 结论 + 关键 ID”,去掉原始 JSON。一次搜索结果 6K token,折叠后通常 200 token 以内,信息损失很小。
- 摘要:把更早的多轮对话写成结构化摘要,只保留已确认的事实、已排除的假设、未完成的子任务三项。让模型自己写摘要比外部规则更准,但要用固定模板,否则摘要会越来越长。
- 驱逐:以上都不够时才删,且从”与当前子任务无关”的内容开始,而不是从时间最老的开始。
一个具体规则:任何一次工具调用返回后,立即判断它是否已经在后续步骤中被消费。已消费的,降级为一行结论。
一份可以直接照抄的预算表
给每一步设一个硬上限,超了就强制走压缩流程:
总预算:32K(即使模型支持 200K,也主动限制)
├─ 系统指令 ≤ 1.5K 固定
├─ 任务目标+验收标准 ≤ 500 固定
├─ 工具定义 ≤ 3K 只加载当前步骤所需
├─ 检索上下文 ≤ 8K 最多 5 个片段
├─ 历史摘要 ≤ 2K 结构化三段式
├─ 最近原文 ≤ 6K 最近 3 轮
└─ 余量(安全垫) ≥ 11K 给工具返回和思考用
安全垫这一项常被砍掉,然后系统在复杂步骤上反复崩。留出 1/3 的余量,是让 Agent 有空间”边做边想”的前提。
长任务里的两个实操细节
第一,把”当前进度”外化为文件,而不是留在上下文里。 长任务每完成一个子目标,就往一个 progress.md 里写一行:完成了什么、产出在哪里、下一步是什么。上下文被压缩后,从文件里重新读回来——这比指望模型记住更可靠,也让中断恢复成为可能。
第二,子任务隔离。 需要读 20 份文档做汇总时,不要把它们都塞进主对话。开一个子 Agent,只回传 300 字的结论。主 Agent 的上下文只增长 300 token,而不是 20 份文档。
判断预算是否真的在起作用
两个监控信号:每步 token 的 P90 和任务完成率随步数衰减的斜率。如果 P90 持续贴着上限、完成率在第 8 步之后断崖下跌,说明预算太紧或压缩策略在丢关键信息;反过来,如果 P90 只有预算的三成,说明你在浪费窗口,该给的检索上下文没给够。
窗口大小是模型的参数,信噪比是你自己的责任。把这份表贴进团队文档,比订阅一个更大的模型便宜得多,也有效得多。