上下文管理
Agent 的表现由它此刻能看到的东西决定,上下文管理就是决定「放什么进去、什么时候丢掉」。
上下文为什么会退化
harness 每轮重发整段历史,窗口越满,单轮成本越高,延迟越长。更麻烦的是质量:长上下文里中段信息最容易被忽略,早期读过的文件内容也会和后来改动过的版本混在一起。
两个日常后果:
- 一次
cat整仓日志,代价在之后每轮重复支付 - 读到的文件版本可能已过期,先让它重读再讨论
| 症状 | 常见原因 |
|---|---|
| 反复读同一个文件 | 早期内容被挤出或被覆盖 |
| 结论与最新代码不符 | 上下文里留着旧版本 |
| 越到后面越笨 | 无关历史太多,注意力被稀释 |
| 突然变慢 | 历史过长,未触发压缩 |
三种主动控制
| 手段 | 做法 | 适用 |
|---|---|---|
| 清空 | 开新对话 | 换一个不相关的任务 |
| 回退 | rewind 到某条消息之前 | 方向错了,想撤销而非纠正 |
| 压缩 | 用摘要替换历史前缀 | 同一条长任务必须继续 |
三种手段的代价不同:
- 清空最便宜,代价是重新交代背景
rewind只删错误分支,保留有效的探索- 压缩由 harness 自动触发,部分工具可手动调用
压缩是有损的:摘要会丢掉具体的行号、命令输出和已经排除的方案。压缩后先让它复述当前状态和下一步,确认没跑偏再继续。
判断标准很朴素:如果解释「刚才那个方向为什么错」要花三句话以上,就回退或重开,别在错误前提上叠加修正。
AGENTS.md
多数 agent 支持 AGENTS.md,Claude Code 找 CLAUDE.md。启动时全文注入,所以它适合放跨会话不变的约定。
# 项目约定
- 改完代码跑 `mypy src/` 和 `pytest -q`
- 不要编辑 `migrations/` 下已有的迁移
- 第三方文档见 https://example.com/llms.txt
- 提交信息用 Conventional Commits写操作指令,不写背景故事。文件越长,留给任务的窗口越小;把「这个项目是什么」压缩成一两句就够。/init 能生成初稿,但它倾向于罗列目录结构,需要手工删。
常见错误是把它写成项目介绍。模型的窗口里不缺架构散文,缺的是可执行约定:用什么命令跑测试、哪些目录只读、提交前必跑什么。每条能落成命令的规则,比一段描述有用。
Skills 与 subagents
AGENTS.md 是常驻成本,skills 把这份成本改成按需:只有名字和一行描述常驻,模型判断需要时才打开正文。适合放「代码审查流程」「发布检查清单」这类不常触发但要求详细的规程。
subagents 解决的是另一个问题:子任务看到的中间过程不必回传给主对话。例如网页研究,子 agent 读完五个页面,只交回一段结论,主对话的窗口不被原文撑爆。
| 机制 | 加载时机 | 上下文成本 |
|---|---|---|
AGENTS.md | 每次启动 | 全文,长期占用 |
skills | 模型判断需要时 | 描述常驻,正文按需 |
subagents | 被调用时 | 独立窗口,只回结论 |
skill 的描述决定它会不会被加载。写清触发条件——「审查 TypeScript 改动时使用」「发布前检查版本号」——比写「代码质量助手」有效,因为模型只看得到描述那一行。
llms.txt
llms.txt 是给模型读的文档入口,通常放在域名根目录,比如 cursor.com/llms.txt、ai.pydantic.dev/llms.txt。内容是压缩过的 API 摘要和链接,比让 agent 抓 HTML 页面省很多 token。
对知识截止之后发布的库,这一步往往决定它能否用对 API。遇到不认识的依赖,先找 llms.txt 或官方 Markdown 文档,比让它凭印象编参数可靠。
llms.txt只是提案,缺失时退一步找 GitHub 仓库里的 Markdown 源文件- MCP server 的工具定义同样常驻窗口,装多了等于开局砍预算