章节导航 第 15 章 / 共 23 章
从 Claude Code 学到的 Agent 设计范式
Harness >> Model 的核心论点、Context Engineering 方法论、工具设计的 7 条原则——可复用到自己 Agent 产品的模式清单
15.1 Harness 比 Model 更重要
这是 Claude Code 给出的最核心启示。51 万行代码中,与模型交互的 API 调用代码可能不到 1000 行。剩下的 50 万行都是 Harness——工具系统、权限系统、System Prompt 构建、上下文管理、多代理编排、UI 和基础设施。
真正决定 Claude Code 能力上限的不是 Claude 模型有多强,而是 Harness 有多精细。这个判断的详细数据佐证和行动建议见第 18 章教训一。
Harness 的核心价值在于”Agent(谁)与 Skill(怎么做)的分离”。Agent 定义文件承载角色、原则、协议;Skill 承载具体执行方式。这一设计使系统可以灵活替换底层模型而不影响上层业务逻辑——51 万行 Harness 是可迁移的资产,而模型是可替换的组件。
补充证据:规模之外的”构成”
“51 万行”给的是规模,更有说服力的是构成。Dive into Claude Code: The Design Space of Today's and Future AI Agent Systems(arXiv:2604.14228v2,2026-07-02)对 v2.1.88 源码的拆解给出的比例是:约 1.6% 是 AI 决策逻辑,其余 98.4% 是运行基础设施。同一研究把结构归纳为 7 层安全防护、9 步 turn 管线、5 层压缩、54 个工具、27 个 hook 事件、4 种扩展机制、7 种权限模式,并抽象为 5 Values → 13 Principles。论文对语料规模的描述是”约 1,884 个文件、约 512K 行 TypeScript”(此前流传的”~1,900 个文件”说法可据此收敛为 1,884)。
⚠️ 但这个比例不是”可测量的事实”,引用时必须带上它自身的限定。论文原文写的是 “Community analysis of the extracted source estimates that only about 1.6%…”——即来自社区分析的估算,不是作者团队的实测。更要紧的是,该论文自设了证据分层,而这一条属于最弱的 Tier C(reconstructed):论文对 Tier C 的定义是”由社区分析、与其他 Agent 的结构比对、或从代码模式推断得出的主张,均以对冲措辞陈述”。
上述原文的措辞(“estimates”、“An estimated”)正是论文 Tier C 政策所要求的对冲语。因此正确的读法是:这个比例指出了一个方向性事实(决策层极薄、工程层极厚),但不构成可精确的量化结论。把它当成”1.6% 这个数字已被测量确认”来引用,会超出来源自身的证据强度。论文对架构的定性判断(” overwhelmingly deterministic infrastructure … with the LLM invoked as a stateless completion endpoint”)则比这个比例稳健得多。
但”Harness 决定产品”不只是说 Harness 比 Model 重要——更准确地说,Harness 和 Model 是协同优化的。 Addy Osmani 指出:“Today’s agent products are post-trained with harnesses in the loop. The model gets specifically better at the actions the harness designers think it should be good at.” Opus 4.7 装进 Claude Code 的 Harness 里,比装进自己手搓的 while 循环里好用一大截,部分原因正是共训(co-training)造成的——Anthropic 在后训练时把 Harness 和模型一起优化,让模型专门适配 Harness 期望的行为。
这形成了一个正反馈循环:Harness 设计 → 训练数据设计 → 模型适配 Harness → 改进 Harness → 改进训练数据……业界共识也在收敛于此——OpenAI 2026 年发布 Harness Engineering 博文,Martin Fowler 网站凝练出 Agent = Model + Harness 公式,shareAI-lab 发布 learn-claude-code 12 节渐进课程(从 while 循环到多 Agent 团队),都确认了这一判断。
竞品侧的独立证据:OpenAI 的 Codex 实验
同类现象不只出现在 Anthropic 一侧,这一点很关键——它说明 Harness 优先不是某家公司的路线选择,而是行业级现象。OpenAI 官方工程博文《Harness engineering: leveraging Codex in an agent-first world》(2026-02-11)报告了一次极端实验:3 名工程师、5 个月、约 100 万行代码、约 1,500 个已合并 PR,人均 3.5 PR/天,且全程零手写代码。规模之外有两点值得注意:团队扩大到 7 人后人均产出不降反升(与传统软件工程的 Brooks 法则相反);瓶颈从”代码产出”转移到了人类 QA 的注意力容量。
博文给出的一条反面经验与本书 15.2 直接互补:“one giant AGENTS.md fails”。他们最初把所有约定塞进单个巨型 AGENTS.md,失败方式有四种——上下文是稀缺资源(大指令文件挤掉了任务本身)、“当所有事都重要时就没有真正重要的”、庞大的手册会立刻变成过时规则的坟场、单一大文件无法机械化校验(覆盖率/更新状态/归属/交叉链接)。修正做法是把 AGENTS.md 压到约 100 行,只作目录索引,细节放进结构化的 docs/ 并视其为系统的唯一事实来源。
这个”约 100 行”与 15.2 的 150 指令预算是同一约束的两个观测面:前者从工程实践反推,后者从模型遵从度实验正推,结论量级相当。本书前文讲”怎么组织上下文”,这条讲”不该怎么组织”——把 AGENTS.md 当百科全书是最常见的失败姿势。
适用边界(2026-10-01 更新):AGENTS.md 支持此前有 provider 限定,v2.1.281(2026-09-23)起改为也覆盖 Amazon Bedrock、Google Vertex AI、Microsoft Foundry、LLM 网关,以及遥测关闭的会话。读者若按更早的资料以为「Bedrock / Foundry / 自建网关上用不了 AGENTS.md」,该限制已不存在。
博文另有一条方法论值得单列:“对 Agent 来说,运行时不在上下文里的东西,实际上就不存在”(储存在 Google Docs、聊天记录或某个人脑子里的知识,系统够不着)。这解释了为什么他们的结论是把知识版本化进仓库,而不是写得更详细。
15.2 Context Engineering 的七个实践
从 prompts.ts 中提炼的七个实践(详细分析见第 6 章和第 18 章教训二):
| # | 实践 | 关键实现 |
|---|---|---|
| 1 | 静态/动态分离 | SYSTEM_PROMPT_DYNAMIC_BOUNDARY 标记 |
| 2 | 环境感知注入 | OS、Shell、CWD、Git 状态动态写入 |
| 3 | 条件加载 | 50+ 个 Feature Flag 控制提示片段 |
| 4 | 工具描述即指令 | description 影响模型选择行为 |
| 5 | 角色定义 | 能力边界 + 行为规范 + 输出格式 |
| 6 | 动态记忆加载 | CLAUDE.md / memory.md 会话时注入 |
| 7 | 预算感知 | 信息量与 token 效率平衡 |
150 指令预算约束:HumanLayer 2026 年初内部研究显示,LLM 指令遵从度在约 150 条行为指令处显著退化。Claude Code 自身的系统提示已消耗约 50 条预算,留给 CLAUDE.md 的只有约 100 条。超过此阈值后,模型不是均匀降低所有指令的遵从度,而是选择性忽略最新添加的指令、与预训练强先验冲突的指令、以及深埋在长文档底部的指令。这解释了为什么社区趋向 3-Layer Agent Harness 架构(CLAUDE.md → Skills → Agents)——每一层承载不同类型的指令,避免单层膨胀。SAP 社区进一步提出”disallowedTools 不是权限而是架构保证——让捏造不可能,不只不鼓励”。
提示腐化与体检:/doctor prompt-audit
上面的七个实践与 150 指令预算回答的是写多少、怎么写。还缺一环:写完会坏,坏了怎么查。
这件事现在有了一等入口。v2.1.283(2026-09-25)新增 /doctor prompt-audit(别名 /checkup prompt-audit),审计 CLAUDE.md 文件、skills、agents、commands 中为旧模型写的提示模式。同一版本改进了报告排序:陈旧路径、陈旧命令、互相矛盾的指令文件排在最前,并保留 Claude Code 自身文档化的 thinking 关键词,不作为陈旧项误报。
⚠️ 沿革要写准。底层 audit 能力早于本轮——本书第 18 章已把它与
claude plugin eval并列收录,写作「上一版已收录的prompt-audit子命令(扫描旧模型冗余提示)」。v2.1.283 的新增量是「一等入口 + 报告排序」,不是「这个功能从无到有」。 把它写成「Anthropic 新增了提示审计功能」是错的。
这一条对本章的意义不止于多一个命令。15.1 的论点是 Model 是可替换组件、Harness 是可迁移资产;若 Model 可替换,那么写给 Model 看的提示就必然有保质期——为上一代模型写的措辞,在新模型上可能不再是最佳提示,甚至是有害提示。「提示会腐化」是「Harness 比 Model 更重要」的直接推论,而官方把它产品化,等于承认了这个推论。
「互相矛盾的指令文件」被单列为一类尤其值得注意。本节上文 one giant AGENTS.md fails 给出的修正做法是把 AGENTS.md 压到约 100 行、细节拆进 docs/——拆分的代价就是文件之间会互相打架,而这条代价此前只能靠人肉 review 承担。现在它是检测器的一个独立类别,且排在报告最前。OpenAI 博文指出的「单一大文件无法机械化校验」这个缺陷,在 Claude Code 这一侧正被逐个类别补上。
15.3 工具设计的七条原则
从 Claude Code 的 50+ 工具中,可以总结出工具设计的七条原则:
| 原则 | 说明 | 例子 |
|---|---|---|
| 1. Schema 即契约 | 用 Zod 做运行时验证,不信任模型的输出 | 所有工具都有 inputSchema |
| 2. 行为标记驱动调度 | 声明式标记(并发安全/只读/破坏性)让编排层做决策 | isConcurrencySafe |
| 3. Fail-Closed 默认 | 不确定的标记选择更安全的默认值 | isReadOnly: false |
| 4. 精确 > 通用 | FileEdit(精确替换)和 FileWrite(完整覆写)分离 | 不同权限粒度 |
| 5. 描述引导选择 | 告诉模型”何时用这个”比”这个能做什么”更有用 | Grep vs FileRead 的选择指导 |
| 6. 延迟加载节省上下文 | 不常用工具按需加载 | shouldDefer + ToolSearch |
| 7. 工具池排序影响缓存 | 稳定的工具顺序提升 Prompt Caching 命中率 | assembleToolPool 排序 |
原则 3 在 2026-11 又向前推了一格:fail-closed 从「检查器的默认值」扩展到「交互本身的默认值」。 v2.1.319 新增 permissions.denyInsteadOfPrompting 设置:等待权限提示的工具调用被直接拒绝、回合继续,作用于终端会话、子代理与 teammates。此前无人值守场景的权限悬空是「挂起等人」,现在多了一种「没人能回答时,取消问题而不是挂起」的选项。它与 v2.1.309 的「bypass 模式下危险 rm/rmdir 直接拒绝并给改写提示(Desktop 应用与 VS Code)」同族——两条合起来是「无人值守 ≠ 放行」的产品化表达:兜底行为的方向从「等待授权」转向「拒绝并继续」,让无人在场的回合也能走完而不是死锁。
反向向量:分发物可以给自己发许可证。上表七条默认的前提是「工具被授权后才能用」——授权发生在用户或管理员一侧。v2.1.284 与 v2.1.282 的两条修复指出还有相反方向:来自 marketplace、claude.ai、npm 的插件(v2.1.284),以及 repository / user / --add-dir 的 skills、commands 与 skills-directory 插件 manifest(v2.1.282),曾通过 allowed-tools 自我预授权自己的工具。在托管 allowManagedPermissionRulesOnly 下,修复后只有来自 Anthropic 官方源、或被 managed settings 背书的源的插件保留该预授权。第三条路径随后也被纳入同一收紧逻辑:v2.1.305 起,Claude Desktop 按路径挂载的插件在 allowManagedPermissionRulesOnly 托管策略下同样不再保留 allowed-tools 预授权——三条路径(市场分发、仓库/用户目录、Desktop 路径挂载)至此全部进入来源分级(详述见第 11/12 章,此处只更新枚举)。
扩展点的能力会从「能不能」扩展到「以什么参数」。 上面这条反向向量讲的是分发物能决定”自己能不能用某个工具”。v2.1.300 把它推进了编排层:agent.spawn mod hook 对 workflow agent 此前只能拒绝;现在可以改写它的 prompt 与 model。
这个可改写清单还在变长:v2.1.318 起 mod 的 $.model.fork 还能指定 effort——一个快速旁路任务可以不管会话当前用什么档位、以 low 跑,且结果会回报实际所用的 effort。「参数被授权后才能改」的清单从 prompt/model 两项扩到三项,方向未变:改写粒度越细,“这个 agent 是谁、以什么强度干活”的定义权就越分散。
这一步的语义变化比看起来大。此前第三方对一个即将被派生的 agent 只有一个权力——否决;现在多了一个——重定义。当一个 mod 能改写子代理的提示词与模型时,“这个 agent 说了什么、跑在什么模型上”就不再由编排者单独决定。上表七条原则里”工具被授权后才能用”的前提,在这里变成了”参数被授权后才能改”。
对自研产品是一条可直接落地的判据:只要开放了 spawn 级别的扩展点,就要同时设计”参数是否允许被改写”这一层权限。 只做”能不能 spawn”的门禁而放开参数,等于把门禁建在了错误的位置——因为改写 prompt 与改写”这个 agent 是谁”是同一件事。
(同版本还新增了 prompt.change mod hook,在 prompt 框文本发生非键入变化时触发:历史回溯、clear、undo、插件填充。它与 agent.spawn 一起说明 mod hook 这一层正在从”审批”向”改写”扩张。)
这条对自研 Agent 产品的提醒是结构性的:只要允许第三方分发「带工具声明的封装物」,你就默认引入了一条绕过授权方的通道。它不是 bug 而是设计——allowed-tools 本来就是为了让 skill 声明它需要的工具;问题只出在「谁有权替用户批准」。判据是:分发物的来源分级,必须与管理侧的授权策略打通,否则「官方源」与「随便谁的源」在用户眼里长得一样。
15.3.1 12 个 Harness 设计模式
社区从 Claude Code 源码中提炼出 12 个可复用的 Agentic Harness 设计模式(by Bilgin Ibryam,Kubernetes Patterns 作者),分四类:
记忆与上下文(2 个)
| 模式 | 描述 |
|---|---|
| 持久化指令文件 | CLAUDE.md / CLAUDE_TOML 定义项目级指令,session 启动时自动注入 |
| 上下文压缩与恢复 | 长会话时自动压缩历史,保留关键信息,支持恢复 |
工作流与编排(4 个)
| 模式 | 描述 |
|---|---|
| 工具适配器层 | 统一封装不同工具的调用接口,隐藏底层差异 |
| 无头批处理 | 后台批量执行任务,不阻塞交互界面 |
| 两阶段确认 | 破坏性操作分”预览意图”和”确认执行”两步 |
| 状态机驱动 | Agent 行为用状态机建模,避免混乱 |
工具与权限(4 个)
| 模式 | 描述 |
|---|---|
| 最小权限范围 | 工具只申请完成任务所需的最小权限集 |
| 行为标记驱动调度 | 声明式标记(并发安全/只读/破坏性)让编排层做决策 |
| 延迟加载 | 不常用工具按需加载,减少冷启动开销 |
| Schema 即契约 | 用 Zod 做运行时验证,不信任模型输出 |
自动化(2 个)
| 模式 | 描述 |
|---|---|
| Pre/Post Hook 扩展点 | 用户在工具执行前后插入自定义逻辑 |
| 异步消息流 | 使用 AsyncGenerator 实现流式进度展示 |
编辑说明:12 个 Harness 模式基于 hubwiz.com 和 besthub.dev 文章补充(2026)。子 Agent 使用 Sonnet 模型筛选相关记忆、主动过滤刚使用过的工具文档——这是”用合适成本的模型做合适复杂度的事”的成本优化策略的具体实现。
从”设计模式”到”工程资产”:ant apply。上面 12 个模式长期停留在设计建议层面——可读、可借鉴,但不可版本控制、不可 Code Review、不可回滚。Anthropic 于 2026-09-03 随 CLI v1.30.0 引入 ant apply,把这件事推进了一步:agents、environments、skills、memory stores、deployments 五类资源可以声明为仓库中的文件,通过 ant apply 与 API 侧资源保持同步。
它的工作流与 Terraform 同构:写声明文件 → ant apply 打印计划 → 人工确认 → 生成并提交 claude-lock.json 锁文件(记录每个文件创建的资源 ID、组织、工作区,以及本地/远端两侧的 hash)。后续运行据此更新同一批资源而非重复创建,也能发现”文件被改过”或”资源在仓库之外被改过”。CI 用法是默认分支合并后跑 ant apply --yes .,PR 上跑 ant apply --dry-run . 让评审者看计划。
三条值得读者注意的边界:资源之间用相对路径互相引用(不必硬编码 ID),改一个被引用者会在同一次运行里更新所有引用者;ant apply 无法接管在 Console 里或用 ant beta:agents create 创建的资源;删除文件不会删除远端资源,需要 --prune(多数资源为归档,skills 为删除)。
⚠️ 提案原文称
ant apply管理「agents / skills / memory / deployments」四类,实际官方为五类,遗漏了 environments。已按官方docs.anthropic.com的 apply 文档更正。对本章的意义:
ant apply是”Agent Config as Code”落地的官方信号——本节所述模式从此可以进 Git、过 Code Review、随提交回滚,从设计建议变成工程资产。
15.3.2 Anthropic 官方五大多代理协调模式
Anthropic 于 2026 年 4 月发布官方多代理协调模式指南,提出五种模式:
| 模式 | 描述 | 对应 Harness 模式 |
|---|---|---|
| Generator-Verifier Pairs | 一个生成、一个验证的配对模式 | 对抗性验证(15.5) |
| Parallelization | 多个代理并行执行独立子任务 | 无头批处理 |
| Orchestration | 中心协调器分配和汇总任务 | 状态机驱动 |
| Routing | 根据输入特征路由到专业代理 | 工具适配器层 |
| Specialization with Feedback Loops | 专业代理 + 反馈闭环持续改进 | Pre/Post Hook 扩展点 |
关键指导原则:“从识别系统最可能的失败模式开始选择模式”——如果你的系统最怕幻觉,选 Generator-Verifier;最怕延迟,选 Parallelization;最怕不一致,选 Orchestration。
Generator-Verifier 的生产级实现:Dynamic Workflows。Opus 4.8 引入的 Dynamic Workflows(2026-05-28)是 Generator-Verifier Pairs 模式的生产级落地。核心机制不再是单个 Verification Agent 的单次检查,而是持续的 Generator-Validator 循环——一组 Agent 生成代码,另一组 Agent 对抗性验证,反复迭代直到答案收敛,类似 GAN 的”生成器-判别器”对抗训练。关键创新:(1) 中间结果存储在 JS 编排脚本的变量中而非对话上下文中,避免上下文膨胀;(2) 支持断点恢复,长时间运行的 workflow 中断后可从断点继续;(3) 杀手锏不是”并行 Agent”而是”对抗收敛”——每个生成结果都经过对抗性验证。
Bun 移植案例:Bun 创始人 Jarred Sumner(2025 年 12 月被 Anthropic 收购后成为 Anthropic 员工)用 Dynamic Workflows 将 Bun 从 Zig 移植到 Rust——6 天、96 万行代码、99.8% 测试通过,含约 1.3-1.4 万个 unsafe 块。每个 .zig 文件有 2 个 reviewer Agent,数百个 Agent 并行工作。
Claude Code 的纵深防御体系:确定性规则匹配(快速)→ AI 分类器(智能)→ 用户确认(兜底),加上 Fail-Closed 默认值和熔断机制。详细架构见第 7 章,可执行建议见第 18 章教训三。
15.5 多代理的实践经验
四条核心经验:代理是权限边界(最小必要权限)、模型选择是成本优化(不是所有代理都需要最强模型)、对抗性验证(“敌意挑错”而非”友好检查”)、协调器 vs 直接调用(复杂度匹配)。详见第 8 章和第 18 章教训五。
Conductor vs Swarm:行业架构收敛趋势
2026 年多代理架构正收敛为两极:
| 维度 | Conductor(集中式) | Swarm(去中心化) |
|---|---|---|
| 协调方式 | 中心协调器分配和汇总 | 代理对等通信,自主协作 |
| 故障隔离 | 协调器单点风险 | 无单点故障 |
| 复杂度 | 简单可控 | 灵活但难调试 |
| 典型案例 | Claude Code Agent Teams(Team Lead) | Cognition Managed Devins |
LangChain 提出四模式分类(Subagents、Skills、Handoffs、Routers),与 Anthropic 五大模式互补。行业实际趋势:Cognition 从”反多代理”转向 Managed Devins(Conductor 模式),Anthropic 走 decoupled brain/hands 路线——两者都趋向 Orchestrator + Isolated Subagents 模式,在集中协调和自主执行之间找平衡。
Dynamic Workflows:脚本驱动动态编排
Opus 4.8 引入的 Dynamic Workflows 代表了第三种架构模式——既不同于静态编排的 Conductor,也不同于去中心化的 Swarm:
- JS 编排脚本驱动:Claude 动态编写 JavaScript 编排脚本,在单个会话中运行数十到数百个并行 sub-agent,每个 sub-agent 独立执行子任务。不是 Agent 自主决策如何协作,而是由 AI 生成的脚本决定编排逻辑
- Generator-Validator 循环:一组 Agent 生成代码,另一组 Agent 对抗性验证,反复迭代直到答案收敛(类似 GAN)
- 断点恢复:长时间运行的 workflow 中断后可从断点继续
- 变量级中间结果:中间结果存储在脚本变量而非对话上下文中,避免上下文膨胀
四模式对比:
| 维度 | Single-agent looped | Supervisor-workers | Dynamic Workflows | Peer-to-peer Swarm |
|---|---|---|---|---|
| 编排方式 | 单代理循环执行 | 中心协调器分配 | 脚本驱动动态编排 | 去中心化对等通信 |
| 决策主体 | 单一模型 | 协调器 | AI 编写的 JS 脚本 | 各代理自主 |
| 中间状态 | 对话上下文 | 协调器汇总 | 脚本变量 | 共享消息 |
| Token 开销 | 基线 | +285% | 中等(变量不占上下文) | +58% |
| 适用场景 | 简单任务 | 标准生产部署 | 大规模代码工程 | 去中心化协作 |
| 生产部署占比 | ~10% | ~70% | 新兴 | ~20% |
Token 开销数据来自 DecodetheFuture 统计:独立多代理额外 token 开销约 58%,集中式约 285%。Orchestrator-Worker 占 70% 生产部署。
Dynamic Workflows GA:六大编排模式分类(2026-06-08)
Dynamic Workflows 于 2026-06-08 从 research preview 升级为 GA,扩展到 Pro 计划($20/月)。GA 版本的核心架构变化是”编排计划外置”——Claude 编写 JavaScript 编排脚本,由独立运行时在后台执行,模型上下文仅接收最终综合答案,使得长达数天的自主运行在架构上成为可能。GA 后明确了 6 种编排模式,每种有清晰的适用场景:
| 模式 | 描述 | 典型场景 |
|---|---|---|
| Classify-and-act | 按任务类型路由(switchboard) | 多类型工单分流 |
| Fan-out-and-synthesize | 并行 Agent → barrier 合并(map/reduce) | 大规模代码移植、批量文件操作 |
| Adversarial verification | 独立 Agent 攻击每个结果 | 代码审查、安全审计 |
| Generate-and-filter | 广撒网 → 只保留幸存者 | 头脑风暴、方案筛选 |
| Tournament | Agent 竞争 + 成对评判 | 设计决策、命名 |
| Loop-until-done | 持续生成直到满足停止条件 | bug 修复、测试驱动补全 |
使用方式:通过”ultracode”关键词或 /effort ultracode 触发。Pro 计划默认关闭(需 /config 手动启用),Max/Team 默认开启。v2.1.202(7/6)新增 workflow-size 引导配置(small/medium/large),最多支持 1,000 并行子 Agent(16 并发硬上限)。
官方自家的模板已把默认值切了过去(v2.1.309)。 /claude-api 技能生成的 Managed Agents 子代理团队,默认编排从 coordinator 改为 multiagent_20261001 且 dynamic workflows 默认开启。这为四模式对比表里 Supervisor-workers「~70% 生产部署」提供了一个方向性数据点:70% 是第三方统计的存量,官方自家模板代表增量方向——至少在 Anthropic 托管 Agent 的官方路径上,新部署的默认已经是脚本驱动编排。
成本警告:并行 Agent 不共享 token,成本线性增长。复杂 workflow 24 小时可达 $400-600。子 Agent 应使用 Sonnet 等轻量模型做初步筛选,仅在必要时使用旗舰模型。
另一个分类轴:按架构关注点,而不是按决策主体。 上面这张四模式对比与 Conductor ↔ Swarm 两极,都是按决策主体分类的(单一模型 / 协调器 / AI 编写的 JS 脚本 / 各代理自主)。还存在一个与之正交的轴——按协调 / 状态 / 控制三个架构关注点分类。
arXiv:2605.20173(A Methodology for Selecting and Composing Runtime Architecture Patterns for Production LLM Agents,2026-05-19)给出六种运行时模式:① 层级委托、② 分散-聚集加 Saga、③ 事件驱动序列、④ 共享状态机、⑤ 监督者加门控、⑥ 人在回路。论文的出发点是一个值得本书采用的命名——随机-确定边界(stochastic-deterministic boundary, SDB):一个由 proposer、verifier、commit step 与 reject signal 构成的四方契约,规定”LLM 的输出如何变成系统动作”。论文主张 SDB 才是生产级 agent 运行时的承重原语,六种模式只是把 SDB 以不同方式组合起来。
其中三条是本章完全没有覆盖的维度:
- ② 的 Saga 补偿:扇出到对称节点,每个节点记录补偿动作以支持回滚。本章的 Dynamic Workflows 有”断点恢复”,但没有”回滚”——这两件事在长事务里是互补的,不是替代的。
- ③ 的重放发散(replay divergence):事件日志本身是确定性的,但读日志的 LLM 消费者不是——模型版本或提示词修订后,同一输入事件重放可能产生不同的下游事件。这是本章”确定性规则 vs AI 判断”这一张力在状态层的版本,且它意味着”把日志当真值源”这一常见做法在 agent 场景下并不成立。
- ④ 的共享状态机 + CAS:以持久化的版本行作为真值源,工作者通过 CAS(compare-and-swap) 提议变更。这给出了一条本章没有的并发控制手段——本章的多agent 协调靠的是消息与合并,而不是乐观并发。
⚠️ 本条此前提案列为”低置信度、编号未锁定、不得进正文”;本轮经 arXiv 检索锁定编号并回源摘要,六种模式的命名与”重放发散”均已在摘要中逐字确认。但正文表格未回源,六种模式的编号顺序按摘要所列,不作进一步断言。
Dynamic Workflows 的失败模式与硬约束
上面四段讲的都是能力参数——GA 时间、编排模式、规模上限、成本。对一本讲设计模式的书,缺了另一半:它会怎么失败。
一条会静默生效的硬约束(已获官方确认)。workflow 文件必须以 export const meta 作为第一条语句,且 meta 必须是纯字面量对象,包含 name 与 description。若其中含有任何非字面量的东西——变量、函数调用、或展开运算符(spread)——Claude Code 会把 /<name> 从 / 自动补全中移除。
注意这里的失败形态:不是报错,而是静默消失。读者写了一个带变量的
meta,不会看到任何错误信息,只会发现自己的 workflow 在补全列表里找不到了。这比报错难排查得多。另一条相关约束:
phases若在meta中列出,每一项的标题必须与传给phase()的标题逐字一致;用了phase()标题却没有对应条目,会单独成组显示。
三条已知失败模式(社区来源)。Dynamic Workflows 的设计者之一 Thariq Shihipar(Anthropic)与 Sid Bidasaria 归纳了三类:
- agentic laziness——Agent 倾向走最短路径,跳过必要步骤
- self-preferential bias——Agent 评审自身产出时系统性高估
- goal drift——长流程中目标逐渐偏离初始意图
📌 来源强度:以上三条在官方 workflows 文档中零命中(已 grep 核验),目前只能作为实践者经验而非官方结论来读。它们的价值在于提示一个方向——本节”Adversarial verification”模式存在的理由,正是为了对抗第 1 与第 2 条;而”断点恢复”与阶段化结构则是对抗第 3 条的手段。换句话说,这些失败模式不是孤立经验,而是与前述六大编排模式互为因果的:后者是前者的对策。
三条官方失败模式(changelog 一手,2026-10-01 补)。上面三条来自社区,来源强度已在批注中标明。下面三条性质不同——它们逐条出现在官方 changelog 里,且都不是上面三类能覆盖的:
| 版本 | 失败模式 | 为什么危险 |
|---|---|---|
| v2.1.285 | workflow 脚本中被晚 await、或完全不 await 的失败 agent() / parallel() / pipeline() 调用,被当作 unhandled promise rejection | 可能直接结束一个后台会话。这是编排层的生命周期陷阱:错误没在它该出现的地方被处理,而是浮到最外层把整个会话带走 |
| v2.1.283 | 在 model fallback 期间启动的 dynamic workflow,每个 agent 都跑在 fallback model 上,而不是重试配置的模型 | 静默错误。用户看到的是「跑完了」,不是「跑错了模型」——整条 workflow 的模型选择被一次降级悄悄污染,且事后从结果上几乎看不出来 |
| v2.1.285 | disableWorkflows 开启时,Code Review 的 PR 评审与 /ultrareview 仍然运行 | 组织策略的逃逸口。除非运行评审的那台机器由它自己的管理员设置了该键(MDM 或 managed-settings 文件),否则管理员以为关掉的编排能力仍在跑 |
| v2.1.305 / 318 | resume 路径不读 journal:已完成 agent 被重新执行而非从 run 的 journal 取回结果(305 修 pipeline()/parallel();318 再修 usage limit 之后 resume 的同型问题) | 断点恢复的第二条故障面。15.3.2 的卖点是「断点恢复 + 变量级中间结果」,而 journal 的写入与读取是两条独立故障面:写入面(容器重启后 journal 缺失,v2.1.265 才把 resume 从全部重跑改为明确报错)与读取面(journal 在场而 resume 不读,305/318 两修)——「有 journal」不等于「resume 一定从 journal 恢复」,重跑意味着成本翻倍且结果可能不一致 |
第四行值得按本书的「第二次发生」规律升格:同一故障形态(resume 后已完成 agent 被重跑)在 15 天内修了两次,第二次的触发面更具体(usage limit 之后 resume)。它与第一行(unhandled rejection)共同构成 resume 场景的完整性清单:一条管执行路径的异常上浮,一条管恢复路径的结果取回——编排系统的断点恢复承诺,要在执行与恢复两条路径上都成立才算数。
第二条是这里最该被记住的一条。它把两个此前分离的主题连了起来:模型降级与编排。前面讲过模型可用性降级(第 14 章 14.4),那里的影响是「换了个模型」;一旦进入 workflow,影响面变成「整条流水线上几十上百个 agent 全换了模型」,且没有任何一条报错。第三条则说明「策略键」与「策略实际覆盖的执行位置」是两件事——disableWorkflows 管的是这台机器上的 workflow,而 Code Review 的评审可能跑在另一台机器上。
中间结果存在变量里,那么变量能装多深? Dynamic Workflows 的一个关键设计是”中间结果存储在编排脚本的变量中而非上下文里”。这条路走到边界时是这样的:
- v2.1.296 之前:workflow 脚本交回的结果、agent options 等值,嵌套超过约 20,000 层时被静默截断(还会写出巨大的 task output 文件);
- v2.1.299 起:改为显式拒绝并报出上限(官方原文:“refuse values they hand back that nest deeper than 28,000 levels, with an error naming the limit (workflow scripts allowed 100,000)”)。
⚠️ 两个数字的适用对象官方措辞有歧义——同一句里既有 28,000 又有 100,000,从句式看是”基线 28,000、workflow 脚本放宽到 100,000”,但本书不据此换算,按官方原句并列记录。
真正值得记的不是数字,而是失败形态的变更顺序:先静默截断,后显式拒绝。对一个把中间结果存在变量里的设计,静默截断比报错危险得多——它与上文”meta 违规是静默消失”是同一型:错误不在它发生的地方显形,而是在下游某个不相关的位置以数据缺失的形式出现。
workflow 是一种可迁移的执行物。 v2.1.300 起,后台会话恢复所携带的 workflow 改为走 Workflow 工具的审批,而不是直接运行 handoff 文件。这一条的含义比措辞更重:workflow 会离开创建它的会话,因此恢复时必须重新过一次审批——否则一个 handoff 文件就成了绕过审批的通道。对自研产品是一条直接的判据:凡是能被序列化、跨会话携带的执行物,都要在复活点重新做一次授权,而不是在序列化时做一次。
三条之外:跨主体边界的失败
上面三组失败模式(社区三条、官方三条)有一个共同前提:一个编排者、一个共享工作区、一个委托人。本章 15.3.2 的对抗性验证、Generator-Verifier Pairs 也都建立在这个前提上。A2-Failures(arXiv:2610.19342,v1 2026-10-14,Why Do Agent Teams Fail Across Boundaries?)问的正是:把这三个假设全部移除之后会怎样——每个 agent 有自己看不见的环境、信息与权限,利益关系可以是合作、混合动机或对抗(如买方的个人 agent 与企业的卖方 agent 谈判)。
研究覆盖 2,500+ 次已记录的 A2A 运行,来自不同 harness 与模型,横跨 488 个场景、8 个领域族(legal / CRM / security / commerce 等),产出 20 种失败模式、四大类:(i) 发现与委派、(ii) groundedness 与记录一致性、(iii) 验证、(iv) 行为与忠诚。运行日志已公开(HuggingFace: a2a-salesforce/a2-failures),读者可自行复核。
三条跨所有 harness、模型与场景成立的发现,逐条与本章对撞:
其一:发现与交互由任务的措辞驱动,而不是由可用 peer 的实际情况驱动。 agents 去匹配 prompt 里提到的 peer 名字,而不是主动搜索有哪些 peer 可用。这对 15.3.2 的 Routing 模式(“根据输入特征路由到专业代理”)是一条反向提醒:路由的输入是措辞,不是能力目录——措辞里没提到某个 peer,它就等于不存在。一个在注册表里可用、能力也匹配的 agent,仅仅因为任务描述里没点名,就永远不会参与。
其二:没有任何 agent 会主动核实 peer 的事实性断言,因此一个 A2A 系统继承其最不可靠参与者的可靠性,除非由协议或机制来执行这个检查。这是本章 self-preferential bias 的跨主体版本:本章写的是”评审自身产出时系统性高估”,论文说的是更基本的一件事——peer 之间根本不互验。这一条给 Adversarial verification 补上了此前缺失的理据:它存在的理由不只是”自己会高估自己”,还包括”peer 之间不会互查”。 推论对自研产品是硬的:在跨主体场景里,验证必须由机制承担,不能指望任何一个参与方自愿执行。
其三:聚合结果分只给完成任务的那一个 agent 记功,对底层的协调、验证与行为失败完全失明——所以 A2A 系统必须按 agent 逐个评分,对着各自的委托人目标评。这一条指向本章完全没写的一环:多代理系统该怎么打分。15.5 讲了怎么拆、怎么协调、怎么验证,但评估口径一直是缺的;而按这条发现,聚合分不仅不够,还会系统性地奖励”掩盖了协调失败的那次成功”。
子 agent 的权限继承
15.3.2 的五大协调模式与本节前面讲的多是怎么拆、怎么协调。还有一个切面此前没有:拆出去的 agent 继承什么样的权限边界。v2.1.285 三条给出了答案:
- fork subagent 现在运行在父会话的权限模式下,且不能退出 plan mode。此前 fork subagents 不保留会话的 plan mode 或
dontAskmode——意味着一次 fork 就可能把一个「只读规划」会话变成「有个子 agent 在真改文件」。修复之后,plan mode 从「一个会话状态」变成「一个向下继承的约束」。 claude -p配CLAUDE_CODE_FORK_SUBAGENT=1时,子 agent 自己的 Agent 调用改为前台运行,使子 agent 能拿到 child 的结果。claude -p --permission-prompt-tool下,后台 subagent 的权限请求改为走 prompt tool,不再被自动拒绝。
第一条的抽象价值高于它的修复价值:权限边界若不显式声明继承规则,默认的继承行为就是「不继承」。而「不继承」在多代理系统里几乎总是错的——它意味着权限只约束发起者,不约束被发起者。
fork subagent 的默认值在 17 个 release 后又变了一次(v2.1.302)。 本节按 v2.1.285 写的”配 CLAUDE_CODE_FORK_SUBAGENT=1 时……”已经过期:fork subagents 现在默认开启,范围从终端扩到 claude -p、Agent SDK、桌面应用与 VS Code 四个宿主;CLAUDE_CODE_FORK_SUBAGENT=0 关闭;claude mcp serve 永不提供。
同版本还有一条更值得记住,因为它推翻了”前后台是一个开关”的心智模型:前后台的默认值按”层”分叉,且方向相反——
| 层 | 默认 | 说明 |
|---|---|---|
| 主会话派生的子代理 | 恒后台 | 桌面与 VS Code 也改为如此,不再由 Claude 选择 |
| 子代理自己再派生的 Agent 调用 | 前台(claude -p / Agent SDK / 桌面 / VS Code) | 与上一层方向相反 |
默认行为不是一个值,而是一棵树。 同一个”子代理”概念,在主会话层与子代理层拿到的默认值方向相反。这一条与上一段的”权限边界必须显式声明继承规则”是同一主题的两个维度:继承的不只是权限,还有执行形态;而两者都会分叉。
⚠️ 本轮排除一条二手来源。 agentpatterns.ai 的 multi-agent topology 页称 “Claude Code’s agent team architecture enforces a topology constraint: sub-agents cannot spawn sub-agents”。这条与 v2.1.302 官方条目直接冲突——官方写明”a subagent’s own Agent calls … now run in the foreground by default”,即子代理可以再发起 Agent 调用。照抄二手来源会让本章写进一条与产品现状相反的约束。凡二手来源描述产品能力边界,必须与 changelog 对撞后才可写。
子 agent 何时该停。v2.1.285 改进:auto mode 下的 subagent 交回报告后立刻结束运行,不再多跑那些「到不了任何人手里」的额外轮次(同版本还修掉了 background subagent 在每次报告后再发一条多余回复的问题)。这既是成本修正也是语义修正——「报告已交回」才是终止条件,「还有话说」不是。
这个终止条件要连修两次才成立,第二次的注脚更有信息量。 v2.1.299 又修了一次:后台子代理在 auto mode 下有时把最终报告发两次——一次作为结果、一次作为消息。
两次修复的形态不同:第一次是”多说一句”(9-29),第二次是”重复投递最终报告”(10-14),后者更严重,因为接收方会看到同一份结果出现两遍。合起来给出一条现实约束:“交回即停”必须在结果通道与消息通道上都成立,只堵一条不够。 一个在语义上完全清晰的终止条件(报告交回就该停),在工程上要修两次才真正成立——这正说明”终止”在多代理系统里不是一个布尔量,而是每条出向通道上各有一个。
15.6 可复用的模式清单
如果你正在构建自己的 AI Agent 产品,以下是从 Claude Code 中可以直接复用的模式:
| 模式 | 适用场景 | 参考章节 |
|---|---|---|
| AsyncGenerator 消息流 | 需要流式展示进度的 Agent | 第 4 章 |
| 工具的并发/串行分批 | 多工具调用编排 | 第 4-5 章 |
| 静态/动态 Prompt 分离 | 使用 Prompt Caching | 第 6 章 |
| 六层权限规则 + AI 审批 | 企业级安全需求 | 第 7 章 |
| 双阶段 AI 分类器 | 自动模式的安全保障 | 第 7 章 |
| 专业代理 + 权限白名单 | 多代理系统 | 第 8 章 |
| 对抗性验证代理 | 代码质量保障 | 第 8 章 |
| 三层记忆作用域 | 跨会话知识管理 | 第 9 章 |
| 上下文压缩 + 恢复 | 长会话支持 | 第 9 章 |
| Pre/Post Hook 扩展点 | 用户自定义扩展 | 第 11 章 |
| 构建时 Feature Flag 消除 | 安全的灰度发布 | 第 13 章 |
| 多云模型标识符映射 | 企业级多云部署 | 第 14 章 |
| 会话级 web search/subagent 上限 | 防止失控循环 | 新增(v2.1.212) |
| 后台子 Agent 默认 + 完成通知 | 长时间并行任务 | 第 8 章 |
| /fork 后台会话复制 | 实验性分支探索 | 第 4 章 |
| subagent tool 列表逐字节稳定 | 恢复会话后仍要命中 Prompt Caching | 第 9 章(v2.1.280) |
提示腐化体检(/doctor prompt-audit) | 指令文件随模型换代而失效 | 15.2(v2.1.283) |
| 子代理独立资源域 | 一个跑偏的子代理不应与主会话争抢同一份预算 | 15.6(v2.1.295 / 2.1.296 / 2.1.312 / 2.1.316 / 2.1.317) |
成本告警产品化(/usage 四类告警) | 让预算感知变成可观测项而非设计原则 | 15.6(v2.1.299) |
无人值守 fail-closed(permissions.denyInsteadOfPrompting) | 等待权限提示的调用直接拒绝、回合继续——没人能回答时取消问题而非挂起 | 15.3(v2.1.319) |
子代理是独立的资源域,不是主会话的等比缩小版。 v2.1.295–2.1.317 给出五个可以按子代理单独设的旋钮:
| 旋钮 | 版本 | 作用 |
|---|---|---|
| 预加载技能上限 | v2.1.295 | 子代理从 skills 字段最多预加载 32 个技能,每个一次;带 Skill 工具的仍可调用其余 |
CLAUDE_CODE_WORKFLOW_SUBAGENT_MODEL | v2.1.296 | 让每个 workflow agent 跑在同一个模型上,其他子代理不受影响 |
autoCompactWindow | v2.1.296 引入,v2.1.312 订正语义 | 子代理可声明不晚于 CLAUDE_CODE_AUTO_COMPACT_WINDOW 所设窗口的更小压缩窗口——只能调低、不能调高。订正前的 14 个已发布版本里(2.1.296–2.1.311,其中 297/298 未发布),该 frontmatter 值对环境变量路径完全无效 |
CLAUDE_CODE_SUBAGENT_EFFORT | v2.1.316 | 无其他指定时子代理的 effort 兜底档位,不再继承会话档位 |
| 按模型的 effort 记忆 | v2.1.317 | 与主会话不同模型的 subagents/teammates,改用该模型自己保存的档位或其默认值,而非会话的档位 |
autoCompactWindow 那行是一次必须留痕的订正。 本书此前写「可声明比主会话更早的压缩窗口」——按 v2.1.312 的官方措辞,正确的语义是「只能调低、不能调高环境变量所设的窗口」,且从 2.1.296 引入到 2.1.311 的 14 个已发布版本里,这个 frontmatter 值对环境变量路径根本不生效。这不只是增量,是对既有事实的订正:读者若在 2.1.296–2.1.312 之间配过这个旋钮并发现没反应,那不是配置错误,是它当时真的没有作用。
effort 的配置面已经分裂成三层,其中「跟模型走」一条最有意思。 会话层(/effort)之下,现在还有模型层(v2.1.317:档位跟着模型走而不是跟会话走)与逐任务层(v2.1.318:mod fork 可指定)。「档位跟模型走」与本节 fork 段落已记的「默认行为是一棵树」同构——资源默认值也在分叉:换一个模型的子代理,带走的不是会话的档位,而是那个模型自己的记忆。对自研产品的含义:凡是有「按实体记忆」维度的资源(模型、代理、通道),都要回答「新实体的默认值从哪来」这个问题,答案不会自动是「跟当前会话」。
三条合起来说明一件事:子代理的技能预算、模型选择、压缩窗口都不必跟着主会话走。 对自研 Agent 产品的可操作结论是硬的一句:把”资源配额”设计成 per-agent 而不是 per-session,否则一个跑偏的子代理会与主会话争抢同一份预算,而且你没有任何手段单独掐掉它。
成本告警从设计原则变成了产品内的可观测项。 v2.1.299 起 /usage 新增四类告警:max effort、workflows、always-on context、large tool results。这四条恰好覆盖本章讨论过的四类成本源——effort 档位、workflow 并行、常驻上下文、工具输出体积。
把它与上一行并列看,本章现在有两个”官方把某条设计原则做成一个命令”的例子(/doctor prompt-audit 提示腐化体检、/usage 成本告警)。可以抽成一条对读者有用的启发:凡是本章写下的原则,都值得去看官方有没有把它做成一个命令。 有,说明这条原则已经过了”重要到值得单独观测”的门槛;没有,说明它还只是本书的归纳。
这条启发本身也在演进:做成命令之后,下一个问题是命令能不能修复。 v2.1.305 起 /usage 的每条告警都带一行点名来源的修复建议,按 f 即可应用,同一套修复还出现在 VS Code 与 /doctor 里。观测项变成修复项,说明官方已把这条原则从「值得观测」升格为「值得自动化」——「能不能一键修」比「有没有命令」是更硬的成熟度判据:前者意味着失败模式已被完全定型(知道怎么修才敢自动化),后者只意味着它被承认存在。读者用这条判据去扫自己产品里的告警体系,能很快分出哪些告警只是噪音、哪些已经是可以托管的闭环。
subagent 的 tool 列表必须逐字节稳定。v2.1.280 修的一条 bug 值得提炼成模式:恢复的 fork subagent 若重建 tool 列表、而不是重发它首次使用的那个列表,会破坏该 agent 的 prompt caching。它把上表「静态/动态 Prompt 分离」这一行从会话级推进到 subagent 级:缓存命中的前提不只是「提示前缀不变」,还包括「工具定义序列不变」。与第 18 章教训七同源——凡是靠前缀匹配省钱的设计,「重建一个等价但字节不同的东西」就是最隐蔽的破财方式。
缓存感知正在从提示词层下沉到调度层与内存层。 「tool 列表逐字节稳定」管的是提示词层;2026-10 以来的三条改动说明编排器已把 prompt cache 的生命周期当作调度决策的输入:① 后台子代理的 shell 命令 3 分钟后统一转后台(所有 provider 上),以免 prompt cache 在命令运行期间过期(v2.1.318);② Bedrock / Vertex / Foundry 或遥测关闭时,冷缓存下的子代理进度摘要最多可等 5 分钟待其响应(v2.1.318);③ 长回合跑大量子代理时(headless 与 SDK 会话),父会话不再把每个子代理的工具结果囤到回合结束(v2.1.314)。三条分别落在「何时转后台」「等多久」「内存里留多久」——缓存已从「写提示词时要考虑的约束」变成「编排器排程时要读的参数」。「凡是靠前缀匹配省钱的设计」这条教训的适用面,正在变宽。
一次 24 小时内的命名空间往返(脚注)。v2.1.282(09-24)保留
anthropic-skills与claude-ai两个命名空间:该命名空间下的 skill 文件夹 / command 文件 / workflow command 不再加载,以此命名的 MCP server 不列出 skill 与 prompt,并把Skill(anthropic-skills:*)与Skill(claude-ai:*)的 allow 规则收紧为「只覆盖从 claude.ai 同步来的 skill」。⚠️ v2.1.283 只回滚了
claude-ai这一个。官方 v2.1.283 的原文是 “Reverted the 2.1.282 reservation of theclaude-ainame”,同版本对anthropic-skills做的是另一件事——把Skill(anthropic-skills:<name>)的 deny 规则扩展到 Claude Desktop 以插件形式投递的场合,并让Skill(skill:<name>)的 deny 匹配 skill 的别名与显示名。anthropic-skills的保留并未撤销。这次往返的净效果不是零:24 小时内回滚了一个命名空间,另一个留了下来并被加固。它仍可作为第 18 章教训八「Feature Flag 是产品演进的基础设施」的实证,但实证的是「能回滚一半」,不是「一键复原」。
15.7 最后的话
本章是一份模式清单——把 Claude Code 的设计决策提炼为可迁移到你自己产品的模式。每个模式都附带了参考章节,方便你回到源头深入理解。
如果你想要更聚焦、更可执行的行动建议(每条都有”明天就能做什么”),请看第 18 章的十个教训。那一章不是本章的重复,而是从不同角度切入——本章回答”Claude Code 里有哪些可复用的模式”,第 18 章回答”你构建 AI 产品时最应该先改变的十个认知”。
系统性解剖到此完成。接下来的专题研究会持续追加新章节,深入探讨社区发现的有趣设计点。