07 · 长跑的上下文
单轮对话里上下文窗口是个"聊久了会忘"的问题。在 Agent 里它变成一个结构性问题:每转一圈,工具返回的东西就往桌上堆一层。跑到二十圈,你的目标已经被埋在最底下了。
一圈往桌上放多少东西
数一遍:
text
每一圈进上下文的:
· 它的思考("我打算搜索……")
· 它发出的工具调用(工具名 + 参数)
· 工具返回的结果 ← 大头,可能几千字十圈就是十份工具返回。如果每份两千字,光工具返回就是两万字——而你的目标只有三百字,还在最上面。
于是就有了 Agent 最典型的三种"跑着跑着变傻":
| 现象 | 原因 |
|---|---|
| 忘了目标,开始做别的 | 目标被挤到边上或挤出去了 |
| 重复做已经做过的事 | 早期的工具返回被挤掉,它不记得查过了 |
| 早期的约束失效(开始碰不该碰的) | 约束和目标写在一起,一起被挤掉了 |
四个办法
一、把目标和约束放进"每轮都在"的位置
最便宜的一招。
关键约束不要只写在第一条消息里——写进系统提示,那是每一轮都会重新发的。
text
系统提示(每轮都在):
- 当前任务目标:【一句话】
- 完成标准:【清单】
- 硬约束:不要写 ./data/;对外动作必须先请求确认;
连续三次同样的尝试无果就换路这一招几乎零成本,但能解决大半问题。
二、让工具返回瘦下来
03 章那条"返回要精简",在长跑里是硬需求:
text
❌ 读网页 → 返回整页 HTML(一万字)
✅ 读网页 → 返回:标题 + 正文纯文本,截断到 2000 字 + URL再进一步:让工具返回"摘要 + 存到文件":
text
返回:已保存到 ./output/page-03.txt(全文 12000 字)
摘要:这是 A 家的定价页,包含 5 个套餐,
起步价 $29/月,按席位计费。全文落到文件里,上下文里只留一句摘要。 需要细节时它可以再去读那个文件——这就是渐进式披露在 Agent 里的用法。
三、外置的"工作笔记"
给 Agent 一个专门的文件当草稿本,要求它每完成一项就写进去:
text
每查完一家,把结果追加写入 ./output/notes.md,格式:
## A 家
- 套餐:…
- 价格:…
- 未获得:计费单位(官网未公开,已查 pricing 和 docs 两页)
写完之后,你的上下文里不需要保留这家的原始网页内容。好处有三个:上下文压力降下来;你随时能打开这个文件看进度;跑挂了重来时,已完成的部分还在。
四、压缩:能用就用,但知道它的代价
有些工具会在上下文快满时自动做一次摘要,把前面的历史压成一段。这能续命,但要清楚代价:
压缩必然丢细节
被压掉的是"当时的原文",留下的是"它对当时的总结"。如果某个细节在压缩时被判断为不重要,它就永远消失了——而它的重要性可能要到第 25 圈才显现。
所以:重要的东西别指望留在上下文里,落到文件里去。(上面第三招)
拆子任务:更彻底的办法
当一个任务实在太长,最干净的做法不是压缩,是拆成几个独立的运行:
text
❌ 一个 Agent 跑 40 圈把三家都查完
✅ 主流程(这是一条 Workflow):
for 每一家:
起一个新的 Agent 运行,目标只有"查清这一家"
它跑完,产出写进 notes.md
最后:汇总 notes.md好处很实在:
注意这里发生了什么
外层是一条 Workflow,内层每一步是一个 Agent。
这就是上一篇那句"Agent 是流水线里的一个节点"的实际长相。 你会发现真正好用的 Agent 系统,多半长这样——而不是一个跑八十圈的巨型 Agent。
一个判断信号
跑完之后,看它用了多少圈。
- 5 圈以内:很好,可能这活本来就该是 Workflow。
- 5~15 圈:正常范围。
- 20 圈以上:警惕。多半是目标太大、或者工具返回太胖、或者它在绕圈。
- 接近你设的上限:几乎肯定有问题,去看轨迹。
圈数是最便宜的健康指标,每次都值得瞄一眼。