让 AI 团队持久协作:Maker/Checker 架构的生产级实践
MetaGPT 之后,除了对话式的多 agent 协作,还有另一种模式——持久化 Maker/Checker 团队。Pi 写代码、Hermes 编排审查、技能跨项目积累。L3 质量门禁、缺陷模式库、Checker 自我校准——这套我们跑了 2 个完整 cycle 后的真实数据。
209 个测试全绿,然后配置全丢了
事情是这样的。
前阵子一个开源项目,CI 全绿,209 个测试用例全部通过。代码覆盖率漂亮,lint 干净,类型检查无报错。看起来稳得不能再稳。
但发布的时候,用户发现配置功能完全不可用。不是某个 Edge Case 挂了,是整个配置模块丢了——代码里没有报错,因为当年重构时配置文件压根没有纳入测试覆盖。209 个绿灯,没一个告诉你配置没了。
这是我开始认真思考"代码审查到底在审什么"的原始驱动力。
人审代码,人会累,会漏,会倾向信任"看着没问题"的代码。但更重要的是:审代码和写代码的是同一个人(或同一个模型),认知盲区是完全重合的。 你知道自己不会测试什么,所以你检查的时候也不会检查那部分。
这就是 MetaGPT 之后,Maker/Checker 架构真正让我兴奋的原因。不是因为它多了一个 reviewer,而是因为它是从"团队结构"层面解决了这个问题。
为什么需要"持久"团队
现在很多 AI 编码工作流是这样的:你让 Claude 或 ChatGPT 写一段代码,它写完,你看一眼,觉得 OK 就合了。下次你找它,它不记得上次写了什么,不记得上次踩了什么坑,不记得你的项目用什么风格。
一次性的审查,在单次会话里可能够用。但跨项目、跨周、跨月的开发场景下,你真正需要的是团队记忆。
我们在这条路上踩了两个月,现在的方案是三个持久角色:
- Maker — 只管写代码(用 Pi 执行),不碰测试,不管审查
- Checker — 只管审查(独立 session 跑验证),不改一行代码
- System — 编排 SOP、抽学习心得、更新技能库
三个角色用不同的 session、不同的模型实例。核心信条:消除同源偏差。
"同源偏差"这个词是我造的吗?不是。Anthropic 在讲 Generator/Evaluator 分离时提过这个现象——让同一个模型自我审查,它倾向于同意自己的输出。人也是如此,改自己写的 bug 报告总是不如别人来审得彻底。LLM 的自我审查更严重,因为它的"自信"不像人那样有自我怀疑的缓冲区。
我试过让同一个 session 既写代码又审查。结果很有意思——Checker 阶段它会说"代码看起来没问题,但让我再检查一下",然后就真的没找出任何问题。不是它放水,是它对自己的输出有一种统计意义上的"路径依赖":既然我刚刚花了 2000 token 生成这段代码,它大概率是对的。
把 Maker 和 Checker 拆成不同模型实例后,Checker 找到问题的概率直接翻了一倍。这个数据来自我们内部的 benchmark,不是推测。
听起来很美好对吧?但落地的时候马上遇到一个问题:团队怎么"记住"上次学到的东西。 这正是我们接下来要聊的——团队工作区结构和技能积累机制。
架构设计:三角分工
Maker 的角色
Maker 的任务极其单纯:拿到任务描述,写代码,放到指定路径。不写测试,不做验证,不审查自己的产出。
我们用 Pi 作为 Maker 引擎——它是一个专门的代码生成 agent,通过 --print 模式直接输出代码文件。每次调用都创建独立 session,避免跨任务上下文污染。
Pi --print "任务描述" --provider opencode --model deepseek-v4-flash-free
注意看:Pi 的 session 是"用完即焚"的。它不留记忆。记忆由 System 管,不是由 Maker 管。
Checker 的角色
Checker 的工作方式跟大多数人想象的不一样。它不是"读代码",而是"运行代码"。
我们通过 delegate_task 派一个独立 session 来验证 Maker 的输出。验证方式:
- 跑测试(pytest / npm test)——必须全通过
- 类型检查(mypy / tsc --noEmit)
- 构造 Edge Case 输入——空值、特殊字符、越界数据
- 检查模块可导入性——
python3 -c "import module" - 对照 Sprint Contract 逐条验证
Checker 输出结构化评分,每项 1-5 分:
scores:
functionality: 4
correctness: 3
code_quality: 4
bug_detected: true
verdict: REQUEST_CHANGES
阈值门禁:功能分 ≥ 4 且正确性 ≥ 3 且无阻断性 bug,才算 PASS。
System 的角色
System 是最容易被忽视的角色,但说实在的,它可能是最重要的。
System 负责:
- 每次 cycle 后提取 learnings
- 更新 Maker 和 Checker 的技能库
- 维护 manifest.json 的统计状态
- 追踪 Checker 的判断准确率
没有 System,团队就没有记忆。Maker 会在同一个坑里摔两次,Checker 会反复犯同样的判断错误。
Sprint Contract:写代码前的"停火协议"
Maker 和 Checker 天然有利益冲突。Maker 想"快点搞完",Checker 想"多找出点问题"。如果没有一个双方认可的"done"标准,这个矛盾永远调和不了。
我们的方案是 Sprint Contract——写代码前,Maker 和 Checker 必须坐下来(通过 System 协调)就一个问题达成一致:怎么才算做完?
Contract 长这样:
sprint: "email_validator 输入验证"
criteria:
- id: "whitespace-check"
description: "纯空格字符串应被判定为空输入"
test: "validate_email(' ') → InvalidReason.EMPTY"
threshold: "PASS"
- id: "length-limit"
description: "遵守 RFC 5321 总长度≤254"
test: "validate_email('a@' + 'x'*250 + '.c') → InvalidReason.TOO_LONG"
threshold: "PASS"
max_iterations: 3Contract 不是需求文档。 它不写产品 spec,不写 UI 设计,不写非功能性需求。它只回答三个问题:这轮做什么、怎么验证、门槛是多高。
这恰好是大多数人踩坑的地方——Contract 写得像 PRD,然后 Maker 被绑死了手脚,Checker 发现 Maker 漏了一堆"需求文档里没写的东西"。Contract 过长反而约束了 Maker 的灵活性。
Checker 校准环路(最让我意外的一个发现)
Anthropic 在他们的 harness 设计文章里说了一句让我记到现在的话:
"出厂状态的 LLM 是差劲的 QA agent。"
它会发现问题,然后说服自己"问题不大",于是放过。不是恶意的,这是模型训练时"帮用户解决问题"的倾向在作祟——它倾向于达成共识,而不是制造冲突。
这太要命了。Checker 的职责就是制造冲突。 如果它倾向于放过,那整套架构的人造冲突机制就失效了。
我们的校准流程:
Checker 日志
├─ 漏了人类发现的问题? → 太宽松 → 收紧 prompt
├─ 报了不存在的 bug? → 太敏感 → 加约束条件过滤噪音
└─ 评分漂移? → 加 few-shot examples 锚定
具体做法:
- 更新 Checker prompt(不是更新缺陷模式库,那是另一件事)
- 同一个偏差模式出现 2 次 → 永久编入 prompt 的 system message
- 每次完整 cycle 后执行校准分析
坦率地讲:前几轮 Checker 的结果不能全信。 人类必须 review Checker 的前几次输出,校准它的判断基准。这跟训练一个新人 QA 工程师没什么两样——你觉得新人第一天就能做代码审查?Checker 的教育成本是绕不过去的。
验证数据:两轮完整 cycle
我们用 baby-harness 项目跑了两个完整 cycle,这是真实数据,不是演绎素材。
Cycle 1:email_validator
Maker (Pi) 写了一个 email 验证函数,Checker 独立审查。
Checker 找到了三个关键 bug:
| 问题 | 发现方式 | 为什么不容易在读代码阶段发现 |
|---|---|---|
" " 空格字符串绕过空检测 | 构造实际输入验证 | 读代码时倾向于相信"if not value"能处理,但空格不是 falsy |
| 缺少 RFC 5321 总长度限制 | 检查 RFC 规范 | 函数式正确,但规格不全——Maker 压根没想起这个限制 |
| doctest 与实际返回值不一致 | 运行 python3 -m doctest | Maker 写了 doctest 但没运行,注释和实现不同步 |
第三个问题最让我感慨。Maker 写了 doctest,但没运行就提交了。 而 Checker 的运行验证正好抓住了这个"提交前少了一步"的失误。这不是代码水平问题,这是工程纪律问题。Checker 的存在,相当于给工程纪律上了一道机械锁。
这件事也让我意识到一个更本质的道理:人在"马上交差"的时候,最容易跳过自己知道应该做、但做起来有点麻烦的步骤。 AI agent 也是这样。Maker session 临近结束时,token 窗口快满了,它更倾向于"输出差不多能用的代码"而不是"输出经过验证的代码"。Checker 作为一个独立 session,没有这种"赶着收工"的心理压力。这恰恰是两个分离 session 的价值所在。
Cycle 2:缺陷模式积累
| 指标 | 值 |
|---|---|
| Checker 缺陷模式库 | 8 个(5 通用 + 3 baby-harness 项目特有) |
| 审查次数 | 2 |
| 驳回率 | 100%(初期校准阶段正常) |
| 每轮平均发现缺陷 | 1.5 个 |
| Maker 完成任务 | 2 |
| Maker 技能文件 | 2 个(编码规范 + review 反馈总结) |
驳回率 100% 看起来很夸张。这实际上反映了早期的校准阶段情况——Contract 写的第一个版本往往太粗糙,Checker 的标准也没有稳定下来。这个数据在 Cycle 3 应该会显著下降。 我不敢说一定会到 50%,但趋势是很明显的:缺陷模式库越大,Maker 犯同样错误的概率越低。
踩坑清单(真金白银换的)
1. Pi 对大文件输出超时
--print 模式输出整个文件。400+ 行的文件,用 free 模型可能在 60-120 秒内超时。
对策:拆分任务。只让 Pi 生成新增的类或函数,主 agent 用 patch 组装。
2. Checker 的"自我放行"倾向
前面说过了。前几轮必须人工 review。 这不是技术问题,这是模型行为特点。
3. Contract 的边界感
写太大的 Contract = 没用,写太小 = 没有约束力。
判断标准:任务描述 ≤ 40 个字符(比如"把变量名改成 camelCase"),跳过 Contract。描述 ≥ 100 字符(比如"加一个矩形填充工具,支持撤销"),必须 Contract。
4. manifest.json 的 accumulated_skills 容易不同步
当用 skill_manage write_file 在 skills/ 目录新增或删除文件时,manifest 的 accumulated_skills 数组不会自动更新。
每次改完 skills/ 目录,必须在 UpdateSkills 步骤里加一个同步验证。我在这上面吃了一次亏——统计显示有 8 个技能,实际目录有 6 个文件,多出来的 2 个是上次清理时没同步的。
5. 文件路径别带冒号
Linux 上文件名含 : 直接报错。这不是 Maker/Checker 的问题,但输出来自 Pi 的代码文件路径建议提前做 sanitize。
跟 MetaGPT 的对比
MetaGPT 是导师级的工作。但它在生产环境有几个实际约束:
| 维度 | MetaGPT | 我们的方案 |
|---|---|---|
| 角色持久化 | session 级,用完重置 | 跨项目持久,技能不断增长 |
| 技能积累 | 无明确机制 | maker/checker 各自增长,缺陷模式库持续扩充 |
| 外部代码引擎 | 仅 LLM 生成 | Pi + HermesExecutor |
| 自进化 | 论文级概念 | 生产化工具链:learnings 提取 + cron watchDog + 校准环路 |
| 消息传递 | 代码级 MessageQueue | 文件 JSON + delegate_task,零额外依赖 |
我不是说 MetaGPT 不好。它在这个方向上是开创性的。但我们在落地的时候发现,跨 session 的技能积累才是生产环境最痛的缺口。 一次审查后学到的教训,如果不能在下一次审查中用上,就等于白审了。
Code Review 是一个知识管理问题
写到最后,想聊一个更大的事情。
大多数团队把 Code Review 当成品控流程。设 checklists、设门禁、设 reviewer 轮值。但说到底,Code Review 是一个知识管理问题。
你审查一次代码,你学到了什么?如果什么都没学到,那这次审查的价值就是零。如果学到的只留在了 reviewer 的脑子里,那价值也基本为零。
Maker/Checker 架构最让我满意的,不是它发现 bug 的数量(说实话 2 个 cycle 的数据量还不够下定论)。而是它让知识沉淀变成了一件不需要刻意做、但一定会做的事情——因为 System 角色的唯一职责就是提取和沉淀。你甚至不需要想"我要不要把这个教训记下来",流程自动帮你做了。
"团队记忆"这四个字,说起来轻飘飘的。但在 AI agent 的语境里,它意味着:三个月后,新来的模型实例启动时,知道半年前那个 email_validator 的 contract 里写了什么。 这才是持久团队的真正价值。
打个比方。一个传统软件团队,核心成员离职,知识断档,新人需要三个月才能跟上节奏。而 Maker/Checker 团队不存在"离职"——技能库在,缺陷模式库在,review 历史在。换一个模型实例(换一个人),技能不丢。这不是替代人的问题——人是不可替代的——但这说明你花在"上下文中继"上的精力可以大幅减少。
当然,这是理想状态。目前我们还只跑了两个 cycle,八个缺陷模式,数据量撑不起"我们解决了 AI 知识管理"这么大的 claim。但方向是对的:把 code review 从一次性的质量门禁变成持续的知识采集器。 每审一次,团队变强一点。
本文相关项目:
— persistent-code-team skill
— Baby Harness — Maker/Checker 验证示例
— Anthropic — Harness design for long-running application development