长任务的上下文管理
摘要压缩、外置笔记、清理旧工具结果与子任务隔离。
一句话理解:长任务的上下文管理靠四种手段组合——把历史压缩成摘要、把关键信息写到上下文之外的笔记里、清理已用过的工具结果、把探索性子任务交给独立上下文去做。
一个逐笔核查 200 笔退款失败订单的批量任务,或一个要改动 30 个文件的重构任务,不可能在一个“干净”的上下文里跑完。每查一笔订单、每读一个文件,上下文就长一截。很快会遇到两个问题:一是窗口真的装不下了;二是还没装满,上下文腐化就已经让 Agent 越来越不可靠。
这一课讲清楚四种应对手段各自解决什么问题、会丢失什么,以及产品经理在方案里需要确定哪些规则。
四种手段总览
| 手段 | 做法 | 解决的问题 | 代价与风险 |
|---|---|---|---|
| 摘要压缩(Compaction) | 接近上限时,把较早的历史总结成一段摘要,替换原文 | 让任务可以持续跑下去 | 摘要会丢细节;需要额外一次模型调用 |
| 外置笔记(Note-taking) | Agent 把进度、结论、待办写进文件或存储,需要时再读回 | 关键信息不依赖上下文存活 | 笔记可能写错、写乱;需要读写工具 |
| 清理旧工具结果(Context editing) | 已经被消化过的工具返回原文被删除或替换为占位 | 工具结果是上下文里最大的“垃圾” | 之后若需要原文,只能重新调用 |
| 子任务隔离(Subagent) | 把探索性子任务交给拥有独立上下文的子 Agent,只取回精简结论 | 主上下文不被大量探索过程污染 | 成本增加;子 Agent 结论里的信息可能丢失 |
它们不是互斥的。一个设计良好的长任务 Agent 通常四种都用。
四种手段逐一拆解
摘要压缩:决定“留什么”比“怎么压”更重要
压缩的原理很简单:让模型把之前的过程总结一遍,用总结替换原文。难点在于 摘要里必须保留什么。Anthropic 的建议是调试压缩提示词时先追求召回(宁可多留),确认关键信息不丢之后,再逐步提高精炼度。
压缩前后,上下文的结构变化如下:
对 Agent 来说,摘要至少要保留下面这些内容:
## 任务目标
批量排查 9 月第二周退款失败的 200 笔订单,输出原因分布与处置建议。
## 用户确认过的约束
- 只看企业版客户;不直接修改订单状态;报告按原因分类
## 已执行的有副作用的动作(必须完整保留)
- 09-17 10:41 已为 ORD-1024、ORD-1031 创建人工退款工单(工单号 TK-5521、TK-5522)
- 尚未发送任何通知
## 关键发现与结论
- 已处理 37/200;原因 A:已开票但发票未作废(21 笔);原因 B:收款账户信息失效(12 笔);待定 4 笔
## 已排除的假设
- 不是支付通道故障(通道日志正常)
## 下一步
- 继续处理第 38 笔起;待定的 4 笔需要查发票状态
其中最容易被忽视、后果也最严重的,是 “已执行的有副作用的动作”。如果摘要里丢了“已为 ORD-1024 创建工单”,压缩后的 Agent 很可能再创建一次,或者再发一次通知。这类信息最好不要只靠模型总结,而应由 Harness 从执行日志中确定性地生成(参见 任务状态与 Checkpoint)。
平台能力方面,截至本课更新时:Claude API 提供了服务端压缩(beta),在输入 Token 达到设定阈值时自动生成摘要并替换之前的内容,默认阈值为 15 万输入 Token,可以调低但最低为 5 万;Claude Code 等产品也提供手动或自动的压缩命令。需要注意的是,压缩本身需要额外一次模型调用,会产生成本;而且压缩会改变上下文前缀,可能使提示缓存失效(参见 提示缓存)。
外置笔记:让关键信息活在上下文之外
压缩再好也会丢细节。更稳妥的做法是:Agent 边干边记,把需要长期保留的东西写到上下文之外,需要时再读回来。
常见形式:
- 进度文件:
progress.md记录已完成、进行中、待处理。 - Todo 列表:Coding Agent 常见,既是计划,也是持续提醒。
- 结论表:批量任务中每处理一项写一行,最终报告直接由表生成,而不是靠模型回忆。
- 记忆工具:例如 Claude API 提供的 memory tool,让模型在一个由你的应用管理的目录里读写文件;官方文档建议把它与上下文清理或压缩搭配使用,在内容被清理之前先把要保留的信息写下来。
外置笔记的设计要点是 结构固定、位置固定、写入时机固定。“每处理完一笔订单,在结论表追加一行”比“适时记录重要信息”可靠得多。
清理旧工具结果:最便宜的一刀
在大多数 Agent 里,工具结果是上下文中占比最大、过期最快的部分。一份 2000 Token 的订单 JSON,模型读完得出“发票尚未作废”之后,原文就基本没用了。
清理策略通常包括:
- 触发条件:上下文超过某个阈值时开始清理。
- 保留最近 N 次:最近几次工具结果保留原文,因为模型可能还在用。
- 例外名单:某些工具的结果永不清理,例如任务说明、用户上传的需求文档。
- 一次至少清理多少:清理会让提示缓存失效,零碎地清理不划算。
Claude API 的 context editing 功能就提供了这几类参数(目前为 beta),默认在输入超过 10 万 Token 时触发、保留最近 3 次工具调用。即使不用平台功能,自研 Harness 也可以按同样的思路实现。
子任务隔离:把“翻箱倒柜”关在另一个房间
有些子任务天然需要大量探索:读 3000 条支付流水找异常点、在代码仓库里搜出某个函数的全部调用方、对比 10 个历史版本的退款政策。如果在主上下文里做,这些过程材料会长期占据主 Agent 的注意力。
子 Agent 的做法是:主 Agent 发出一个边界清晰的子任务,子 Agent 在自己独立的上下文里完成探索,只把精简的结论返回。主上下文里多出来的,只是几行摘要。
代价是更多的 Token 和调用次数,以及子 Agent 返回的摘要可能遗漏主 Agent 需要的细节。什么时候值得拆,见 Subagent 与上下文隔离。
怎么组合:一张选择表
| 情况 | 优先使用 |
|---|---|
| 工具结果大、用完即弃 | 清理旧工具结果 |
| 批量处理、需要最终汇总 | 外置笔记(结论表) |
| 单个子任务需要大量阅读 | 子任务隔离 |
| 对话很长、无法预先拆分 | 摘要压缩 |
| 任务跨天、可能中断 | 外置笔记 + 任务状态持久化(参见 长时间运行的任务) |
常见误区
- “等窗口快满了再压缩。” 腐化在窗口满之前就开始了。阈值应该根据评测结果设定,而不是根据窗口上限。
- “摘要交给模型总结就行。” 有副作用的动作、用户确认过的约束、关键 ID,应该由程序从结构化日志中生成,而不是依赖模型回忆。
- “子 Agent 返回得越详细越好。” 子 Agent 返回全量内容,隔离就失去了意义。子任务要约定返回格式和长度。
产品经理检查清单
- 这个 Agent 的典型任务会跑多少步?上下文大约增长到多大?
- 压缩摘要必须保留哪些字段?有副作用的动作由谁记录?
- 哪些工具结果可以清理?哪些永远不能清理?
- 批量任务的中间结论写在哪里?最终报告是从结构化记录生成,还是靠模型回忆?
- 哪些子任务适合交给子 Agent?返回格式是否约定?
- 压缩或中断之后,用户能看到 Agent 的进度吗?
练习
设计一个“批量排查 200 笔退款失败订单”的长任务方案:
- 写出压缩摘要模板,至少包含目标、约束、有副作用的动作、已完成进度、已排除假设、下一步。
- 设计结论表的字段(订单号、原因分类、证据、处置建议、是否已创建工单……)。
- 标出哪一步适合交给子 Agent,写出给子 Agent 的任务描述和返回格式。
- 假设第 120 笔时任务中断,写出恢复时 Agent 需要读取的内容清单。
延伸阅读
- Anthropic Engineering:Effective context engineering for AI agents
- Claude 文档:Compaction
- Claude 文档:Context editing
- Claude 文档:Memory tool
下一步
压缩和清理是“事后减负”。下一课「渐进式披露」讲“事前节制”:工具说明、Skill 与文档如何按需加载,而不是一开始就全部塞入。