Context Engineering:为什么 Agent 会越聊越笨

用 Agent 做短任务时,它常常让人产生一种错觉:只要把聊天记录留得足够长,它就会越来越了解项目。

真正做过几轮迭代后,体验通常恰好相反。

它会带着已经被推翻的架构继续推理;明明上一轮刚确认的风险边界,几轮之后又被忽略;工具调用和日志越堆越多,最后连当前到底在修什么都开始模糊。

这不是因为 Agent “失忆”了,而是因为我们把上下文当成了一个越大越好的仓库。

我更愿意把 Context Engineering 理解为:在每一次推理前,主动决定什么信息值得占用 Agent 此刻有限的注意力。

它不是给模型塞更多资料,而是不断做选择、压缩、更新、淘汰和恢复。

一、聊天记录不是项目状态

下面是一种很危险、也很常见的工作方式:

历史聊天记录
+ 整个代码仓库
+ 全部设计文档
+ 大量工具定义
+ 所有日志和中间结果
→ 一次性提供给 Agent

看起来信息很完整,实际却把三种性质不同的东西混在了一起:

  • 已确认的事实;
  • 仍待验证的假设;
  • 已经失效的历史过程。

Agent 在这里的难题不是“缺少知识”,而是“在噪声和冲突里找不到此刻最重要的事实”。

因此,长任务不能只依赖聊天记录。聊天记录适合回看过程;项目状态应该被压缩成一个能被下一次会话直接接手的持久化产物。

一个合格的状态文件,至少要让新 Agent 很快回答五个问题:

  1. 最终目标是什么?
  2. 当前完成到哪里?
  3. 哪些决定已经有证据,不应轻易推翻?
  4. 哪些验证已经通过或失败?
  5. 下一步最小、最合理的动作是什么?

如果这五个问题只能靠翻几千行聊天记录回答,项目就还没有真正拥有可恢复状态。

二、上下文不是一个整体,而是五层信息

为了避免“所有东西都叫上下文”,我会先把它们拆成五层。

层级 它解决的问题 典型内容 管理方式
稳定规则 默认怎样工作 安全边界、代码约定、审批规则 短、稳定、长期保留
当前任务状态 这次到底在做什么 目标、进度、假设、下一步 高频更新,始终保持最新
检索知识 现场需要了解什么 相关代码、文档、ADR、历史 issue 按需加载,不全量灌入
工具上下文 现在能做什么 少量候选工具、参数、返回结构 只暴露相关工具
执行反馈 下一步该怎样调整 测试、日志、trace、失败结果 优先保留能改变决策的证据

这张表不是为了增加目录,而是为了让信息有不同的生命周期。

上下文路由:从全部信息中选择此刻真正相关的内容

例如,“生产环境发布必须先确认”是稳定规则;“当前正在排查评论接口 429”是任务状态;一份过期的 Nginx 日志可能只是执行反馈,确认根因后不该永久留在主要上下文中。

当它们被当成同一类信息时,旧结论就会和新决定争夺注意力。

三、三个最实用的 Context Engineering 动作

1. 先写状态,再开始下一轮工作

长任务不怕中断,怕的是中断后只能重新猜。

对跨会话、跨天或可能交给另一个 Agent 的任务,我建议维护一个很短的 progress.md。它不是工作日报,更不是把思考过程全部复制进去。

# Objective

为评论接口增加限流,并保持现有评论读取行为不变。

## Current status

- 状态:in progress
- 当前工作单元:验证 Nginx 限流是否只作用于写入请求。

## Completed

- 已确认评论服务由反向代理路径 `/api/comment/` 暴露。
- 已添加每 IP 限流规则;配置语法检查通过。

## Decisions

- 写入接口返回 429,而不是静默丢弃:便于客户端和日志定位。

## Validation

- `nginx -t`:通过。
- 读取、提交评论、异常方法请求:待分别验证。

## Open questions / risks

- 需要确认限流不会影响正常评论表单的预检请求。

## Next action

1. 用 GET、POST、OPTIONS 分别测试代理路径。
2. 记录状态码与访问日志,再决定是否发布。

## Recovery notes

- 不要重复修改限流参数;先完成方法与路径验证。

这个例子没有记录每一次命令,也没有把完整配置贴进去。它只保留了下一轮决策真正需要的事实、证据和未决项。

2. 让文档按需展开,而不是让根规则无限长

AGENTS.md、README 或项目级说明很容易越写越大。最后它看似什么都有,实际上没有人能快速分辨哪条和当前任务有关。

更稳的结构是渐进式披露:

AGENTS.md
├── 项目是什么、入口在哪里、全局边界是什么
├── docs/architecture.md # 架构任务再读
├── docs/decisions/ # 需要理解历史决策时再读
├── docs/agent/progress.md # 接手长期任务时再读
└── skills/release/ # 发布任务才加载

根入口只负责让 Agent 不走错门:项目目标、标准命令、禁止事项和文档地图。细节应该放到需要它的目录或 Skill 中。

这和人进入陌生项目的过程很像。没有人会在写一个表单时先读完整部署史;Agent 也不应该被迫这么做。

3. 主动标记过期信息,而不是默默追加新结论

项目在演进时,最容易伤害 Agent 判断的不是“没有文档”,而是同时存在两份看起来都合理、但已经互相矛盾的文档。

因此每当架构、部署或流程发生变化,除了写下新事实,还应该注明旧事实已经失效。

## Recently superseded

- 旧结论:博客完全由 GitHub Pages 托管。
- 当前事实:静态站仍可构建,但评论、订阅等服务由自有服务器承载。
- 证据:`deploy/docker-compose.yml`、生产部署文档。

这段信息的价值很高:它不只告诉 Agent 现在是什么,还告诉它不要再沿用哪个旧模型

四、一个完整例子:同一件事,为什么第二次会做得更好

假设你让 Agent “把博客的技术文章发布流程整理一下”。

第一次,它看了几份文档,写出了一套流程。但它没有区分草稿和发布,没有记录敏感信息边界,也不知道构建成功后是否还需要人工确认。

如果你只是继续在聊天里纠正它,下一次换会话,这些教训又会消失。

更好的做法是把被验证的结论归位:

发现 应放的位置 原因
文章源码目录 项目记忆 / AGENTS.md 是稳定入口事实
草稿不允许直接发布 协作规则 会影响默认行为
发布前必须通过敏感信息扫描 发布 Skill / 脚本 可被机器验证
本次文章缺少封面 当前任务状态 只影响当前工作单元
某次构建报错的完整日志 任务记录 只有定位时才需要

下次 Agent 接手时,它不必“记住上一次聊天”。它只要读取对应的稳定规则、当前状态和发布 Skill,就能在较小的上下文里做出更好的决定。

这也是为什么我不把“记忆更多”视为目标。真正有用的是:信息该留下时能留下,该退出时也能退出。

五、常见反模式

反模式一:把所有聊天历史都保留给下一轮

历史中可能有正确的过程,也可能有过期假设、错误尝试和临时情绪。保留全部,并不等于恢复得更准确。

替代做法:每个工作单元结束时写一段状态摘要,并把验证结果和决策放到可追溯的位置。

反模式二:用很长的系统提示代替项目文档

系统提示适合稳定、少量、跨任务的规则;它不适合承载频繁变化的部署事实、当前进度和完整历史。

替代做法:稳定原则放在根规则;变化事实放在项目记忆或状态文件;具体流程放入按需加载的 Skill。

反模式三:摘要只写“做了什么”

“已修改三个文件,完成限流”无法让下一位协作者判断是否应该继续、回滚还是验证。

替代做法:每条状态都尽量附带“为什么这样做、证据是什么、下一步是什么”。

六、可以直接复制的状态恢复模板

如果你正在做任何会跨越多轮的任务,可以从下面的最小版本开始:

# Objective

[最终要完成什么。]

## Current status

- 状态:[not started / in progress / blocked / complete]
- 当前工作单元:[本轮只处理什么。]

## Completed

- [已完成事项与证据。]

## Decisions

- [决定]:原因;关联文件、ADR 或验证命令。

## Validation

- `[command]`:通过 / 失败;结果摘要。

## Open questions / risks

- [未决问题、风险和假设。]

## Next action

1. [最具体的下一步。]

## Recovery notes

- 不要重复:[已被证明无效的尝试。]

写完后做一次五分钟检查:一个完全不了解任务的人,能否只读这份文件就知道下一步要做什么、为什么还不能宣布完成?如果不能,它就还只是记录,而不是恢复点。

七、从今天开始的推荐做法

  1. 给每个超过半小时、可能中断的 Agent 任务创建一个状态文件。
  2. 把根规则控制在“入口、边界、命令、文档地图”四类内容内。
  3. 每次项目形态发生变化时,写新事实,也标记被淘汰的旧结论。
  4. 不要用“聊天记录很长”作为长期协作可靠的证据。

下一篇会继续讨论一个自然的问题:当某种工作已经反复发生时,我们不该每次都临时拼 Prompt。它应该被做成一个可复用、可验证、能持续迭代的 Skill。

AI 实现摘要

  • 要解决的问题:减少长会话和长期任务中的上下文噪声、过期结论与交接丢失,使 Agent 能从持久化状态恢复工作。
  • 适用版本与前置条件:适用于支持读取项目文档的 AI Agent;建议项目具备版本控制与可执行验证命令。
  • 输入、输出与验收标准:输入是跨轮或跨会话任务;输出为项目根规则、按需文档与 progress.md 等状态产物。新会话应能据此回答目标、进度、决策、验证和下一步。
  • 文件改动清单:可新增 docs/agent/progress.mddocs/agent/project-memory.md,并在根 AGENTS.md 增加文档地图;按项目实际路径调整。
  • 完整命令:无通用命令。使用项目已有的测试、构建和日志查询命令记录验证证据。
  • 测试步骤与预期结果:中断一个真实任务后,在新会话只提供状态文件和必要规则;预期 Agent 不重复已完成工作,并能提出与“Next action”一致的后续动作。
  • 常见错误、回滚方法与安全边界:状态文件不应写入密钥、个人数据或完整敏感日志。未经验证的猜测必须标注为假设,不要提升为长期事实或全局规则。