首页
All Posts

Claude Code 工程化实战(二):上下文工程:Memory、Sub-Agents、Skills 与 Workflow

这张图把上下文工程画成信息分拣中心:噪声进入暂存区,长期事实进入 Memory,操作手册进入 Skills,复杂探索交给 Sub-Agents,固定流程沉淀为 Workflow。上下文工程的核心不是把信息塞满,而是让每类信息去它该...

上下文工程信息分拣中心

这张图把上下文工程画成信息分拣中心:噪声进入暂存区,长期事实进入 Memory,操作手册进入 Skills,复杂探索交给 Sub-Agents,固定流程沉淀为 Workflow。上下文工程的核心不是把信息塞满,而是让每类信息去它该去的位置。

一、上下文不是仓库的压缩包

很多人第一次让 Agent 处理复杂问题时,会本能地提供更多信息:把需求、报错、代码片段、日志、历史讨论都贴进去。短期看,这似乎能减少误解;长期看,反而会让 Agent 更难做判断。

原因很简单:大模型处理上下文时,不会天然区分哪些是长期事实、哪些是临时线索、哪些是用户猜测、哪些是已经验证的结论。你把所有信息混在一起,它就可能把一次性日志当成长期规则,把旧方案当成当前约束,把没有验证的猜测当成事实。

上下文工程要做的事情,是把信息分类、路由、压缩和淘汰。它更像一套信息分拣系统:不同类型的材料进入不同的容器,临时线索、长期事实、操作手册和执行流程不能混在一起。Agent 的主对话也不应该承担全部信息管理,它应该只保留目标、关键决策和当前证据。

二、Memory:只保存会影响未来决策的事实

Memory 的价值在于跨任务复用。它应该回答“下一次 Agent 进入这个项目时,哪些信息会改变它的行动方式?”

有效 Memory 通常有三类。

第一类是项目事实。比如技术栈、启动命令、测试命令、关键目录、服务端口、生成文件位置。这些信息稳定存在,能减少 Agent 的初始探索成本。

第二类是工程约束。比如“数据库迁移必须兼容旧版本”“不要直接修改生成代码”“支付模块必须补审计日志”“发布前必须跑某个脚本”。这类信息不只是背景,它会直接影响 Agent 是否能改、怎么改、改完如何验证。

第三类是已验证路径。比如“登录态问题优先检查 session service,再看 OAuth callback”“账单差异先比较标准模板结构,再比较数据行”。这类路径来自经验沉淀,能把下一次排查从盲目搜索变成有方向的定位。

Memory 最怕两种污染。第一种是把临时状态写成长期事实,例如“当前分支测试失败”或“今天某个服务连不上”。第二种是把未验证猜测写进去,例如“可能是缓存导致”。一旦污染进入 Memory,Agent 未来会带着错误偏见行动。

更好的写法是短、硬、可执行:

  • 使用 npm run build 验证前端构建,失败日志优先看 src/routessrc/components
  • 修改数据库迁移时必须检查向后兼容,不能只改最新 schema。
  • 支付回调只允许幂等写入,重复通知必须返回成功但不能重复扣款。

这些句子不会讲故事,却能改变 Agent 的决策。

三、Sub-Agents:让复杂探索不污染主线

Sub-Agents 的关键价值不是“多开几个模型”,而是隔离上下文与职责。主对话负责掌握目标和最终决策;子代理负责隔离上下文,处理某个局部任务。

适合交给 Sub-Agent 的任务一般有四类。

第一类是高噪声阅读。比如分析 800 行失败日志、比对多份配置、搜索全仓库 API 用法。让主对话直接吞下这些信息,会挤占上下文,也会干扰后续判断。子代理可以读完后只返回结论、证据位置和不确定点。

第二类是并行假设验证。比如线上支付超时,可能来自网关、数据库锁、队列积压、前端重试。可以让多个子代理分别探索不同方向,主对话再汇总证据。

第三类是跨领域检查。比如一个改动同时影响后端接口、前端页面、测试夹具和文档。让不同子代理按领域检查,可以降低单个上下文遗漏的风险。

第四类是重复执行的专门角色。比如“安全审查代理”“性能分析代理”“文档同步代理”“测试补全代理”。这些角色可以有固定提示、固定工具和固定输出格式。

Sub-Agent 的边界要清楚。它不应该随意扩大目标,也不应该直接做不可逆修改。更稳的模式是:子代理负责调查与建议,主对话负责决策与集成。这样既能利用并行能力,又不会让多个执行者同时改同一片代码。

四、Skills:把经验变成可加载的操作手册

Skills 与 Memory 的区别在于:Memory 存事实,Skills 存做法。Memory 会告诉 Agent“这个项目用什么命令测试”;Skill 会告诉 Agent“遇到某类任务时按什么步骤处理,读哪些文件,使用哪些工具,怎么验证结果”。

一个好 Skill 通常包括五部分。

第一,触发条件。明确什么时候该加载它,比如“处理支付回调、退款、对账问题时使用”。

第二,输入要求。告诉 Agent 开始前需要确认哪些信息,比如订单号、回调日志、环境、时间范围。

第三,操作步骤。不是空泛地说“仔细分析”,而是写出顺序:先查幂等键,再查网关响应,再看本地事务,再比对审计日志。

第四,验证方式。比如运行哪些测试、检查哪些日志、确认哪些边界条件。

第五,禁止事项。比如不能直接改生产数据,不能绕过签名校验,不能把密钥写入日志。

Skills 的加载应该按需发生。把所有 Skill 都塞进主上下文,会变成另一种噪声。更合理的方式是逐步披露:当任务确实涉及支付,再加载支付 Skill;当任务涉及文档生成,再加载文档 Skill。

这就像操作手册,不需要每次执行都把整本书读一遍。Agent 只需要当前任务相关的步骤。

五、Workflow:把稳定路径变成固定节奏

Workflow 适合处理步骤稳定、验证明确、经常重复的任务。它和 Skill 有重叠,但重点不同:Skill 更像“如何处理这一类问题”的知识包,Workflow 更像“每次必须按这个顺序跑”的流程。

比如修复一个后端接口 Bug,可以定义这样的 Workflow:

  1. 复现或定位失败证据。
  2. 阅读入口、服务、数据访问和测试。
  3. 提出根因假设,说明要验证什么。
  4. 做最小修改。
  5. 运行相关测试。
  6. 检查 diff 是否只包含必要变更。
  7. 输出变更说明、验证结果和风险。

Workflow 的好处是减少随机性。Agent 每次都可能想到不同路线,但团队不希望交付质量依赖“这次模型想到了什么”。固定流程能让基本动作成为默认值。

Workflow 也不能过度僵硬。遇到测试环境不可用、依赖下载失败、外部接口超时等情况时,它应该允许 Agent 记录阻塞并选择替代验证,而不是死等一个命令。

六、案例:一次线上支付超时如何组织上下文

设想一个问题:用户支付成功,但订单状态长时间停留在“待支付”。日志里有超时、重试、回调失败、队列积压等多种线索。

如果把所有日志直接丢给主 Agent,它可能会被噪声淹没。更好的上下文组织方式如下。

第一步,主对话只保留目标:确认支付成功但订单未更新的根因,要求不做生产写操作,只给修复方案和验证路径。

第二步,读取 Memory。Memory 提供稳定事实:支付回调必须幂等;订单状态更新在 payment-service;队列消费者失败会写入 payment_audit;本地复现用 PAYMENT_GATEWAY_MOCK=true

第三步,加载支付 Skill。Skill 告诉 Agent 先检查网关回调签名,再看幂等键,再看事务提交,再看异步队列,最后检查前端展示缓存。这样 Agent 不会被第一条超时日志带偏。

第四步,启动 Sub-Agents。一个子代理分析网关回调日志,一个子代理检查队列消费者,一个子代理阅读订单状态机代码,一个子代理看最近改动。每个子代理只返回结论、证据文件、关键日志行和不确定项。

第五步,主对话整合证据。假设发现网关回调成功、幂等键正常、队列消费失败,失败原因是新字段 paid_at 不能为空但迁移没有给历史订单默认值。主对话此时再读相关迁移和模型代码,避免基于二手结论直接修改。

第六步,执行最小修复。可能是补迁移、调整历史数据兼容、补测试,或者修改状态机对旧订单的处理。修改范围由证据决定,不由猜测决定。

第七步,按 Workflow 验证。运行支付回调测试、队列消费者测试、迁移测试;如果有本地模拟网关,再跑一次从回调到订单状态更新的完整路径。

这个案例里,Memory 提供长期事实,Skill 提供领域步骤,Sub-Agents 负责并行调查,Workflow 负责固定交付节奏。主对话没有被日志淹没,也没有丢失最终决策权。

七、上下文压缩:不是少给信息,而是给正确形态

上下文压缩不是把 1000 行日志压成 100 行摘要那么简单。真正有效的压缩要保留推理所需的结构。

一个好的日志摘要应该包含:

  • 时间范围与环境。
  • 失败请求或任务 ID。
  • 第一处异常,而不是最后一处连锁报错。
  • 与当前假设相关的关键字段。
  • 已排除的方向。
  • 仍然缺失的证据。

一个差的摘要只会写:“日志显示支付失败,可能是队列问题。”这句话看起来简洁,却没有任何可验证价值。

对代码阅读也是一样。子代理或工具返回摘要时,不应该只说“这里处理了登录”,而要说明入口函数、核心分支、外部依赖、错误处理和测试覆盖。上下文越结构化,主 Agent 越能做出稳定决策。

八、常见反模式

第一,把 Memory 当备忘录。任何临时发现都往里写,最后 Memory 变成旧日志仓库。

第二,把 Sub-Agent 当廉价并发。没有明确问题、没有输出格式、没有边界,最后得到四份互相矛盾的长摘要。

第三,把 Skills 写成口号。比如“你要认真分析、保证质量、不要出错”。这类话没有操作性,无法改变执行路径。

第四,把 Workflow 写成审批表。步骤太多、没有弹性,Agent 每次都在填空,反而降低效率。

第五,把主对话变成垃圾桶。所有搜索结果、所有命令输出、所有猜测都塞进来,导致后续判断越来越重。

九、落地清单

如果要为一个项目建立上下文工程,可以从四个小动作开始。

先写一份最小 Memory。只包括启动、测试、目录、禁区和高频排查路径。不要超过一屏。

再挑一个高频领域写 Skill。比如登录、支付、对账、文档发布、前端构建。Skill 要写步骤和验证,不写空话。

然后定义一个常用 Workflow。比如“修 Bug 的固定节奏”或“更新文档后的验证流程”。让 Agent 每次都能按同样标准交付。

最后为高噪声任务引入 Sub-Agent。先从只读调查开始,要求返回结构化结论,确认效果后再扩大使用范围。

上下文工程的目标不是让 Agent 知道一切,而是让它在正确时间知道正确的事。信息管理里最好的路由不是把内容塞得最多,而是把材料放到最容易被正确使用的位置。对 Agent 也是一样:信息只有被放到合适的位置,才会变成能力。