驯服概率系统:Claude Code 工程化交付框架实践

5 阅读20分钟

驯服概率系统:Claude Code 工程化交付框架实践

本文分享基于 Claude Code 的多 Agent 交付框架 /deliver。通过专职分工、JIT 上下文加载、Pre-tool Hooks 守护和经验沉淀闭环,将 AI 从「聪明助手」变成「可靠交付管道」。

AI Agent 写代码最不需要的能力,是"写代码"。

这个结论听起来很反直觉。我们花了大量时间评测模型的编码能力——HumanEval、SWE-bench、TerminalBench——但实际在生产项目中使用 Claude Code 之后,我发现代码生成只是交付链条中最容易被解决的环节。真正让人头疼的是上下文管理、架构约束遵守、跨服务影响评估,以及如何让 Agent 在第 50 次执行任务时不再犯第 1 次就犯过的错误。

过去几个月,我在一个海外催收系统(Java 微服务架构,Spring Boot + MyBatis-Plus,十几个独立服务)上搭建了一套完整的 AI 驱动交付管道——/deliver。它把"需求描述"到"代码提交"的全过程拆分为多个阶段,由 8 个专职 Agent 分工执行,主会话只做调度。这篇文章分享这套框架的设计思路、踩过的坑,以及我认为什么样的项目值得搭建这种系统。

问题:为什么你的 Claude Code 总在犯同样的错?

在搭建 /deliver 之前,我用 Claude Code 的方式和大多数人一样——打开终端,描述需求,让它去改。对于小任务,这种方式完全够用。但当需求涉及多个服务、需要遵守特定的分层约定、还要考虑国家差异化的 SPI 扩展时,问题开始集中爆发。

第一个问题是上下文丢失。 我的项目有一套严格的分层规范:Controller → Biz → Service → Manager → Dao,禁止跳层调用。Claude Code 在开始阶段会遵守,但随着对话变长、上下文被压缩,它开始"忘记"这些约束。一个 Controller 里直接注入了 Dao,代码能编译、能运行,但违反了架构规则。这不是偶发事件——根据我的观察,在长对话中 Claude 对 CLAUDE.md 规则的遵守率大约在 70% 左右,剩下 30% 的违规需要人工逐行审查才能发现。

第二个问题是重复犯错。 上次交付时踩过的坑(比如某个表的 JOIN 没有索引导致全表扫描),下次交付同类需求时又踩了一遍。Claude Code 没有"记忆"——每次会话都是全新的开始。经验只存在于开发者的脑子里,不存在于系统中。

第三个问题是"一个 Agent 干所有事"的可靠性衰减。 需求分析需要理解业务规则,方案设计需要了解服务架构,代码实施需要掌握编码规范,设计审查需要识别风险模式。把这些全部扔给一个 Agent,它的上下文窗口很快被撑满,输出质量肉眼可见地下降。研究数据也印证了这一点:Google Research 与 MIT 的联合研究发现多 Agent 在可并行化任务上提升 81%,但在顺序任务上性能退化高达 70%。问题的关键不在于"要不要多 Agent",而在于"用什么架构编排它们"。

这三个问题让我意识到:Claude Code 的瓶颈不是模型能力,而是工程化程度。 模型已经足够聪明,但我们没有给它足够好的工程约束和知识基础设施。

核心理念:三个设计原则

在动手搭建之前,我先确立了三个设计原则。这些原则不是理论推导,而是在反复踩坑后总结出来的。

检索优先,禁止猜测

所有 Agent 的决策必须基于实际代码和文档,禁止依赖 AI 的预训练知识。这意味着 Agent 在回答"这个表属于哪个服务"时,必须去查 table-registry.md,而不是根据表名猜测。每条规则、每个决策都要标注证据来源:[代码][文档][用户][规则],或者诚实地标注 [待确认]

为什么要做到这一步?因为预训练知识会过时。三个月前的服务架构和今天的可能已经不同,而模型不知道这一点。我在早期吃过这个亏——Claude 根据"经验"判断某个功能应该放在 Case 服务,但实际上半个月前的重构已经把这块逻辑迁移到了 Allot 服务。检索优先原则从根源上消除了这类问题。

文件即状态,Agent 间不通信

Agent 之间不通过内存传递信息,所有状态都写入文件。需求文档里用 <!-- deliver-state stage:方案设计 review_round:1 --> 标签记录当前阶段和审查轮次,审查意见写入独立的 review 文件,实施规格写入 exec-plans/。下一个 Agent 启动时,通过读文件获取上游的全部输出。

这个决策的直接好处是断点续做。一个需求做到方案设计阶段,用户关掉终端去开会,回来后输入 /deliver 尼日利亚催收列表,系统读取状态标签,直接从方案设计阶段继续——不需要重新描述需求,不需要重新分析。这在实际工作中非常实用,因为需求交付很少在一次会话中完成。

JIT 上下文加载

不一次性把所有知识灌入 Agent 的上下文窗口,而是按阶段按需加载。需求分析阶段只加载业务知识(knowledge/business/),方案设计阶段加载技术知识(knowledge/tech/),编码实施阶段加载经验模式(knowledge/patterns/)和实施规格(exec-plans/)。

为什么不全部加载?因为上下文窗口不是越满越好。一个被反复验证的发现是:指令超过一定长度后,Agent 对早期指令的遵守率开始下降。500 行的 CLAUDE.md 不会让 Claude 更聪明,只会让它更困惑。JIT 加载确保每个 Agent 在每个阶段只看到自己需要的信息,上下文保持精简,指令遵守率显著提高。

四层架构:各司其职

整个框架分为四层,每层有明确的职责边界。

graph TD
    User["用户输入 /deliver"] --> CMD["命令层<br>.claude/commands/"]
    CMD --> IR["intent-resolver<br>意图路由"]

    IR --> RA["requirement-analyst<br>需求分析"]
    IR --> DP["design-planner<br>方案设计"]
    IR --> CI["code-implementer<br>编码实施"]
    IR --> ED["experience-depositor<br>经验沉淀"]

    DP --> R1["review-arch"]
    DP --> R2["review-risk"]
    DP --> R3["review-impact"]

    RA & DP & CI & ED -->|"JIT 按需加载"| KNW["知识层<br>rules · business · tech · patterns"]
    CI -.->|"Edit/Write 自动触发"| GRD["守护层<br>Pre-tool Hooks"]

    style IR fill:#2196F3,color:#fff
    style R1 fill:#F44336,color:#fff
    style R2 fill:#F44336,color:#fff
    style R3 fill:#F44336,color:#fff
    style GRD fill:#FF9800,color:#fff

命令层:用户入口

用户通过 5 个斜杠命令与系统交互:

命令用途
/deliver需求交付主入口,自动路由到正确的阶段
/load-service扫描服务源码,生成技术总结
/load-flow分析业务流程,生成业务 + 技术流程文档
/load-api分析聚合接口的跨服务依赖
/optimize-flow手动触发经验沉淀

用户不需要知道底层有几个 Agent、该用哪个——/deliver 接受自然语言输入,由 intent-resolver 自动判断意图和阶段,路由到正确的 Agent。输入 /deliver 尼日利亚催收列表需要增加催收员搜索功能,系统判断这是新需求,启动 requirement-analyst;输入 /deliver 尼日利亚催收列表(不带额外描述),系统检查状态标签,从上次中断的阶段继续。

Agent 层:专职执行

这是整个框架的核心。8 个 Agent,每个有明确的职责、工具权限和禁止事项。

Agent职责关键约束
intent-resolver意图识别 + 阶段路由只路由不执行,不确定时询问用户
requirement-analyst需求文档创建/更新/归档不碰技术知识,每条业务规则标注来源
design-planner技术方案 + 实施规格不写代码,设计前必须通过 6 维 DoR 检查
review-arch架构合规审查只写审查文件,关注分层违规
review-risk风险覆盖审查只写审查文件,对照历史坑点
review-impact影响面审查只写审查文件,识别跨服务遗漏
code-implementer编码实施不做需求分析和设计,改代码前必须先读代码
experience-depositor经验沉淀不改代码,先查已有文件避免重复

为什么要做这种严格的角色分工?因为 Cursor 团队的实践已经证明了"平等协作"的失败。在他们的 FastRender 项目中,让多个 Agent 以平等地位自由协作,结果 20 个 Agent 的吞吐量退化为 2-3 个的水平——因为 Agent 互相等待锁,或者在乐观并发模式下变得过于保守,回避困难任务。

最终奏效的架构是角色分层:Planner 负责规划,Worker 负责执行,Judge 负责评审。/deliver 采用了类似的思路——intent-resolver 做路由决策,专职 Agent 做具体执行,三个 reviewer 做质量审查。每个 Agent 只看自己需要的上下文,只有自己需要的工具权限,不越界。

这里有一个容易被忽视的设计细节:所有 Agent 都以 subagent 模式运行,不使用 Agent Team。这意味着每个 Agent 都有独立的上下文窗口,完成任务后只返回结果摘要给主会话。主会话保持精简——它不需要知道 requirement-analyst 读了哪些文件、做了哪些中间推理,只需要知道最终产出的需求文档路径。这样的好处是主会话可以轻松编排 5-6 个阶段的工作,而不会因为上下文过载而"忘记"前面的阶段。

知识层:结构化上下文

知识按用途分为四个区:

context/
├── rules/              ← 硬规则(所有 Agent 始终加载)
├── knowledge/
│   ├── business/       ← 业务知识(需求分析时加载)
│   ├── tech/           ← 技术知识(方案设计时加载)
│   └── patterns/       ← 经验模式(设计+实施时加载)
├── product-specs/      ← 需求文档(全流程可用)
├── design-docs/        ← 技术方案
└── exec-plans/         ← 实施规格

每个 Agent 通过 INDEX.md 总索引按"分区 → 阶段 → 领域 → 关键词"四步协议筛选要读的文件。比如 code-implementer 在实施一个 Case 服务的需求时,它的加载路径是:rules/(始终加载)→ patterns/(实施阶段)→ Case 领域 → 找到 spi-ownership.mdhome-service-boundary.md

这个设计解决了一个实际问题:我的项目有 12 个服务,每个服务的技术总结文档超过 500 行。如果全部加载,光知识文件就能吃掉大半个上下文窗口。JIT 加载确保 Agent 只看和当前任务相关的知识,上下文利用率最大化。

守护层:确定性校验

这是我认为整个框架中投入产出比最高的部分

守护层由两个 Pre-tool Hooks 组成,配置在 .claude/settings.json 中:

Hook触发条件校验内容
check-layer-violation.sh编辑 Controller 文件时Controller 是否直接注入了 Dao/Mapper/Manager
check-cross-service-db.sh编辑 Mapper XML 文件时XML 中引用的表是否属于其他服务

为什么不把这些规则写在 CLAUDE.md 里?因为 CLAUDE.md 是建议,Hooks 是法律。CLAUDE.md 写"Controller 不允许注入 Dao",Claude 大约 70% 的情况下会遵守。但 Hook 是 shell 脚本——每次 EditWrite 操作触发 Controller 文件时,脚本自动执行,检查注入列表,违规则返回 exit 1 并阻止写入。100% 拦截率,没有例外。

flowchart LR
    Agent["Agent 写入代码"] --> Trigger{"触发条件匹配?"}
    Trigger -->|"Controller 文件"| H1["check-layer-violation.sh<br>检查注入列表"]
    Trigger -->|"Mapper XML"| H2["check-cross-service-db.sh<br>检查表归属"]
    Trigger -->|"其他文件"| Pass["直接写入"]
    H1 & H2 --> Result{"校验结果"}
    Result -->|通过| Allow["允许写入"]
    Result -->|违规| Block["exit 1 阻止写入<br>返回错误信息"]

    style Block fill:#F44336,color:#fff
    style Allow fill:#4CAF50,color:#fff

这两个简单的脚本,让我从"每次代码审查都要逐行检查分层违规"中彻底解放出来。搭建成本不到一小时,但节省的审查时间是持续的、累积的。如果你什么都不想搭建,只想从这篇文章带走一个东西——那就是 Pre-tool Hooks

工作流:需求如何流过管道

完整的交付流程分为 5 个阶段,每个阶段有明确的准入条件和产出物。

flowchart LR
    A["用户输入"] --> B["意图路由"]
    B --> C["需求分析"]
    C -->|"人工确认"| D["方案设计 + 三审"]
    D -->|"人工确认"| E["编码实施"]
    E --> F["归档 + 经验沉淀"]

    style C fill:#FF9800,color:#fff
    style D fill:#FF9800,color:#fff
    style E fill:#FF9800,color:#fff

阶段 1:意图路由

用户输入 /deliver <描述>intent-resolver 读取 product-specs/INDEX.md,判断这是新需求、已有需求的继续、需求补充还是经验沉淀,然后路由到对应的 Agent。

关键设计:intent-resolver 禁止执行任何工作,它只做路由。如果无法判断用户意图(比如用户只说了"催收列表"三个字),它会给出 2-3 个选项让用户确认,而不是猜测。这个约束看似简单,但避免了一类常见问题——Agent 在意图不明确时自行脑补需求,然后沿着错误方向走了半天。

阶段 2:需求分析

requirement-analyst 创建结构化的需求文档,包含需求描述、业务边界、实现约束、复杂度评估和风险提示。每条业务规则必须标注来源([用户][文档:路径][待确认])。

完成后暂停等待人工确认。这是整个管道中的第一个人工检查点。需求理解错了,后面所有工作都是浪费。

复杂度评估在这个阶段确定,它直接决定后续的审查深度:

复杂度判定标准审查策略
S单服务单层,无 DB/SPI 变更跳过审查,直接编码
M单服务多层或 2 个服务正常审查,最多 2 轮
L3+ 服务或 SPI 变更扩展审查,最多 3 轮

这个分级不是为了走形式。S 级需求(比如改一个页面的查询条件)不需要三审并行,那只是浪费 token 和时间。L 级需求(比如新增一个跨三个服务的业务流程)则必须经过充分审查,因为跨服务影响遗漏的代价远大于多花几轮审查的成本。

阶段 3:方案设计 + 三审并行

design-planner 生成技术方案和实施规格。设计前必须通过 6 维 DoR(Definition of Ready)检查:需求类型、业务形态、数据归属、字段映射、服务职责、国家差异。任何一维未通过就暂停,回去问用户补充信息。

方案完成后,三个 reviewer 并行启动——这是一个重要的效率优化。架构审查、风险审查、影响面审查互相独立,没有依赖关系,可以同时执行。

flowchart TD
    DP["design-planner 生成方案"] --> Par["三审并行启动"]
    Par --> RA["review-arch<br>架构合规"]
    Par --> RR["review-risk<br>风险覆盖"]
    Par --> RI["review-impact<br>影响面"]
    RA & RR & RI --> Judge{"有 P0/P1?"}
    Judge -->|是| Fix["design-planner 修改方案"]
    Fix --> ReReview["仅重审有问题的维度"]
    ReReview --> Judge
    Judge -->|否| Confirm["人工确认方案"]

    style RA fill:#F44336,color:#fff
    style RR fill:#F44336,color:#fff
    style RI fill:#F44336,color:#fff
    style Confirm fill:#FFC107,color:#000

审查结果分为三个严重级别:P0(必须修复,阻塞交付)、P1(建议修复)、P2(可优化)。只有 P0 和 P1 会触发修改-重审循环,且有轮次上限(M 级 2 轮,L 级 3 轮)。达到上限仍有 P0 时,升级到人工决策——因为 Agent 如果两三轮还解决不了一个 P0 问题,说明需要人类介入了。

这里有一个我特别看重的机制:审查模式沉淀。每次审查发现的 P0/P1 问题会被记录到 review-patterns.md,包含问题模式和出现频次。当某个模式出现频次超过 3 次,它会被自动升级为 design-constraints.md 中的硬规则。比如"SPI 归属必须跟数据走"这条规则,就是从审查中反复发现同类问题后硬化出来的。

这意味着系统会从自己的错误中学习。第一次犯错是意外,第二次是模式,第三次就变成了硬规则——以后的所有方案设计都必须遵守。

flowchart LR
    Issue["审查发现 P0/P1"] --> Compare["对比 review-patterns.md"]
    Compare -->|新模式| Add["追加条目<br>频次 = 1"]
    Compare -->|已有模式| Inc["频次 +1"]
    Add & Inc --> Check{"频次 >= 3?"}
    Check -->|否| Keep["保留在 patterns"]
    Check -->|是| Upgrade["升级到<br>design-constraints.md<br>成为硬规则"]

    style Upgrade fill:#F44336,color:#fff

这种从实践到规则的闭环,是我认为这个框架最有价值的部分之一。

阶段 4:编码实施

code-implementer 按实施规格中的任务列表逐个执行。任务有序号和依赖关系,严格按顺序进行。

对于超过 3 个任务的需求,采用分批策略:每 3 个任务为一批,每批由独立的 subagent 执行,批间串行保证依赖顺序。每批启动时重新加载 rules/INDEX.md。为什么要分批?因为编码是最消耗上下文的阶段——读代码、改代码、处理错误,每个任务都会产生大量中间内容。分批执行让每个 subagent 从一个干净的上下文开始,避免第 5 个任务时 Agent 已经"记不清"前面读过的规则。

flowchart LR
    Tasks["读取 exec-plans<br>任务列表"] --> Count{"任务数 > 3?"}
    Count -->|否| One["单个 subagent<br>执行全部任务"]
    Count -->|是| B1["Batch 1<br>任务 1-3<br>subagent A"]
    B1 -->|"串行衔接"| B2["Batch 2<br>任务 4-6<br>subagent B"]
    B2 -->|"串行衔接"| B3["Batch 3<br>任务 7-9<br>subagent C"]

    B1 & B2 & B3 -.->|"每批重新加载"| Rules["rules/ + INDEX.md"]

在编码过程中,守护层的 Pre-tool Hooks 自动执行。code-implementer 不需要"记住"分层规则——即使它忘了,Hook 也会在写入时拦截违规。这是"概率遵守"到"确定性保证"的关键转变。

阶段 5:归档 + 经验沉淀

代码提交后,requirement-analyst 将需求文档从 active/ 移到 done/,并提取本次交付中可沉淀的经验。experience-depositor 将这些经验结构化写入 context/knowledge/

下一次有类似需求时,对应阶段的 Agent 通过 JIT 加载协议读到这些经验,自动获得上一次的教训。这就是知识沉淀闭环——实践发现 → 结构化沉淀 → JIT 加载 → 下次同类任务自动获得经验。没有这个闭环,Agent 永远是"金鱼记忆",每次都从零开始。

flowchart LR
    A["实践中发现坑点"] --> B["experience-depositor<br>结构化沉淀"]
    B --> C["context/knowledge/<br>写入知识文件"]
    C --> D["下次 JIT 加载<br>INDEX.md 索引匹配"]
    D --> E["同类任务<br>自动获得经验"]
    E --> A

    style B fill:#9C27B0,color:#fff
    style C fill:#4CAF50,color:#fff

误区拆解:三个"直觉正确但实际有害"的做法

误区 1:"多 Agent 自然比单 Agent 更强"

多 Agent 的收益来自结构,不是来自数量。

搭建 /deliver 的直接动机就是单 Agent 的上下文窗口撑不住。十几个服务的架构知识、分层规范、业务规则、历史经验——全部塞进一个会话,Agent 在第三个任务时就开始"忘记"第一个任务时读过的规则。多 Agent 是为了让每个 Agent 在独立的上下文窗口里只处理自己那部分工作:requirement-analyst 只看业务知识,code-implementer 只看实施规格和编码规范,互不干扰。

但"多"本身不解决问题。Google Research 与 MIT 的联合研究发现非结构化的多 Agent 网络可以将错误放大 17.2 倍,token 消耗膨胀 4-220 倍。微软 Azure SRE Agent 团队在扩展到 50+ sub-agent 后发现,Agent 间的 handoff 呈现二态分布——要么全对要么全丢,他们最终停止依赖这种"handoff roulette"。Cursor 团队在 FastRender 项目中让 20 个 Agent 以平等地位自由协作,结果因锁竞争导致吞吐量退化到 2-3 个的水平。

这些反例的共同点不是"用了多 Agent",而是没有结构的多 Agent——Agent 之间平等协作、自由通信、互相等待,最终陷入混乱。/deliver 能工作,是因为它有明确的结构:intent-resolver 做路由决策而不执行工作,专职 Agent 各管一段而不越界,三个 reviewer 并行审查而不互相依赖,所有状态通过文件传递而不靠内存。角色分层(planner/worker/judge)而不是自由网络——这才是多 Agent 产生收益的前提。

如果你的项目只有一个服务、几千行代码,单 Agent 的上下文窗口完全够用,一个好的 CLAUDE.md + 两个 Hooks 就够了。多 Agent 要解决的是上下文装不下的问题,如果你没有这个问题,就不需要这个方案。

误区 2:"把所有规则、知识都写进上下文,Agent 就能做得更好"

恰恰相反。研究反复证明,指令量超过一定阈值后 Agent 性能开始下降。一个 500 行的 CLAUDE.md 文件不会让 Claude 更聪明,只会让它在关键规则上"走神"——因为重要的约束被淹没在了大量无关信息中。

JIT 加载是这个问题的解决方案。requirement-analyst 只看 rules/ + knowledge/business/,它不需要知道 MyBatis XML 的命名规范;code-implementer 只看 rules/ + knowledge/patterns/ + exec-plans/,它不需要知道业务边界的定义方式。每个 Agent 看到的上下文都是为它的任务量身定制的,精简、相关、可执行。

误区 3:"AI Agent 不需要人工流程,让它自己迭代就行"

UC San Diego 和 Cornell 的联合研究观察了 3-25 年经验的专业开发者使用 AI 编码工具的行为,结论很明确:"专业开发者不 vibe code,他们 control。" Stack Overflow 2025 年调查也显示 72% 的开发者说 vibe coding 不属于他们的职业工作。

/deliver 在两个关键节点设置了人工检查点:需求确认和方案确认。这不是因为 Agent 不够好,而是因为需求理解和技术决策是人类决策。AI 可以分析、建议、生成方案,但"我们到底要做什么"和"我们选择哪个方案"的最终判断必须由人类做出。省掉这两个确认步骤看似提高了效率,实际上是在需求理解错误时付出十倍的返工成本。

你的项目需要这个吗?一个决策框架

搭建 /deliver 这样的框架前期投入不小:8 个 Agent 定义文件、7 个规则文件、知识索引体系、两个 Hook 脚本。不是所有项目都值得这个投入。

我建议分三级逐步搭建:

第一级:最小可用(1-2 小时)

  • 写一个精简的 CLAUDE.md(控制在 60 行以内,只写最核心的规则)
  • 加两个 Pre-tool Hooks(分层校验 + 你项目中最常犯的那类错误)
  • 这就够你获得 80% 的收益了

第二级:结构化知识(半天到一天)

  • 建立 context/ 目录结构
  • /load-service 给核心服务生成技术总结
  • 建立 INDEX.md 索引和 JIT 加载协议
  • 写 2-3 个最重要的规则文件

第三级:完整管道(2-3 天)

  • 定义 8 个 Agent 角色
  • 搭建 /deliver 命令和完整工作流
  • 建立审查机制和经验沉淀闭环

判断标准:

你应该搭建第三级,如果——

  • 代码库超过 5 万行,有明确的分层架构
  • 团队需要反复交付同类需求(不是一次性项目)
  • 有多个服务需要协同变更
  • 已经有了人工版的交付 SOP(需求评审→技术方案→代码审查→上线),想让 AI 接管其中的重复环节

你应该停在第一级,如果——

  • 个人项目或早期创业,代码库还很小
  • 技术栈和架构还在频繁变动
  • 需求类型高度多样化,没有"同类需求"的概念

写在最后

回到开头的结论:AI Agent 写代码最不需要的能力是"写代码"。

模型的编码能力已经足够好了。真正的瓶颈在于:如何让 Agent 理解你的架构约束?如何确保它在第 50 次任务中不重复第 1 次的错误?如何在多个 Agent 之间可靠地传递上下文?如何在关键节点保留人类决策权?

这些问题的答案不是"等更好的模型出来"。Anthropic 自己的工程团队说得很清楚——最成功的 Agent 工作流强制执行"先规划再编码"。有人把这叫做"15 分钟的瀑布模型",但我觉得一个更准确的说法是:我们在用工程方法驯服概率系统

/deliver 框架就是这个思路的一个实现。它不完美——前期搭建成本高,对小项目来说大材小用,审查流程有时会过于严格。但对于需要长期维护的大型代码库,它把 Claude Code 从一个"聪明但不可靠的助手"变成了一个"有流程、有记忆、有约束的开发团队"。

如果你也在用 Claude Code 做严肃的软件交付,我建议至少从第一级开始:一个精简的 CLAUDE.md 和两个 Pre-tool Hooks。这一小步的投入产出比,可能会让你重新思考 AI 辅助开发的边界在哪里。