引子

如果你最近在用 AI 写代码,大概率会遇到这样的尴尬:需求讲清楚了,AI 也给你写出能跑的东西,但跑着跑着发现它把范围扩出去了;换个会话,上次定好的规矩它忘得一干二净;让它同时管前后端,前端组件直接用了数据库的 snake_case 字段名,到运行时才崩。

模型一直在变强,但这些问题没有因此消失。原因不在模型——在模型外面。

模型本身是个能力很强的”执行体”,它需要一个工程化的运行时环境来约束行为、提供反馈、积累经验。这个运行时环境,业界称为 Harness(马具)。马具不让马跑得更快,是让马跑得有方向、有节奏、可控制

这篇文章想讲清一件事:一套生产可用的 Harness 应该长什么样。它不是某个具体工具的使用手册,而是一组可以被任何 AI 编程平台(CodeBuddy、Claude Code、Cursor、Aider……)实例化的工程原则。本文的核心立场是:AI agent 之间没有平级统筹,所有调度由唯一的 Orchestrator 完成——这是经过反复推敲后才稳定下来的设计。

一、Harness 到底是什么

> Harness = 围绕 AI Agent 的运行时环境,由「约束输入 → Agent 执行 → 反馈验证 → 经验沉淀」构成的工程闭环,建立在通用工程基线之上。

四环缺一不可:少了”约束”,AI 自由发挥不可控;少了”反馈”,错了不知道;少了”沉淀”,同一个坑反复踩。

需要再强调一点:这四环都预设了一层不在 AI 视野里的通用工程基线(git hook / CI / 类型系统 / 测试),它对人和 AI 一视同仁。这层基线就是后文的 L0,是四环的共同前置——基线塌了,上面四环再精巧也是浮沙。

很多团队搭 Harness 时只关注前两环——写了 rules,加了 lint,就以为完事了。但真正决定 Harness 能不能”活下去”的是第三环:它能不能从每次失败里学到东西,把人工纠错转化为自动化护栏

二、六层架构总览

L5 治理层 Memory + Metrics + Changelog ← 如何演进
L4 AI 护栏层 CodeBuddy Hooks ← AI 特有检查
L3 能力层 MCP + Commands + Skills ← 用什么做
L2 执行层 Orchestrator + 专家 agents ← 谁来做、谁调度
L1 契约层 CODEBUDDY.md + Proposal + OpenSpec ← 做什么/不做什么
L0 共用基线层 git hooks + CI + tests + types ← 不依赖 AI

每层职责正交,禁止跨层耦合。下面分层展开。

三、L0 共用基线层

很多团队跳过这一层直接上 AI 工具,这是最大的设计错误。

核心原则:质量门禁必须人和 AI 共用,离开 AI 工具也成立。

git pre-commit 跑 prettier + eslint + tsc,pre-push 跑单元测试,CI 跑构建和 e2e。这套门禁人提交、AI 提交、机器人提交都走同一条路,没有任何侥幸通道。

为什么强调这点?因为很多文章会建议你”在 CodeBuddy Hook 里跑 tsc 拦截 commit”——听起来聪明,实际上一旦有人不用 AI 工具直接 git commit,整个门禁就形同虚设。质量门禁的本质是给提交流程把关,不是给 AI 把关

L0 是地基。地基歪了,上面盖什么都不稳。

四、L1 契约层

L0 解决”代码必须符合什么标准”,L1 解决”AI 必须知道什么、不许做什么”。

4.1 CODEBUDDY.md:项目铁律

AI 每次启动会读的项目规则文件。很多团队的 CODEBUDDY.md 从最初的 30 行膨胀到 800 行,最后没人维护,AI 也读不进去。

正确做法:拆成三段,严格控制总长度不超过 200 行

  • 🔒 STABLE 段:几乎不改的硬约束(技术栈、绝对禁止项、命名规范)
  • 🔧 EVOLVING 段:当前阶段的临时约定,由 /init 自动维护
  • 📦 INDEX 段:只放指针,不写细节

超过 200 行就该拆——这是个硬性指标。

4.2 Proposal:轻量任务的契约

任何超过 100 行代码的功能,开工前必须有 proposal。四段:Why、What、Out of scope、Acceptance。

Out of scope 是最重要的一段。AI 默认倾向”过度发挥”,你不显式告诉它”购物车不在这次范围里”,它很可能顺手就给你做了——结果代码量翻三倍,重构比重做还慢。

Proposal 适合单功能、单模块、不跨多人协作的场景。一份 markdown 文件就能锁住需求边界,不需要更重的工具。

4.3 OpenSpec:复杂任务的契约工作流

当功能复杂到「一份 proposal.md 装不下」时,需要把契约结构化。这里以 OpenSpec 为例展开,但工具可替换(4.3.6 会说明)。

4.3.1 何时升级到 OpenSpec

满足任一条件即引入:

  • 涉及 ≥3 个文件且跨前后端
  • 多 agent 并行开发
  • 需要状态机 / 协议 / 数据契约
  • 跨 sprint、跨会话延续
  • 已有相关 spec 需要 MODIFIED

否则用轻量 proposal 就够。默认原则:能用 proposal.md 就别上 OpenSpec

与 4.2 阈值的衔接:4.2 用”100 行代码”作为是否需要 proposal 的阈值,本节用”文件数 + 跨栈”等结构性指标作为是否升级到 OpenSpec 的阈值。两套阈值是互补的——前者管”要不要写需求文档”,后者管”需求文档要不要结构化拆开”。当两套阈值给出不同信号时(例如 50 行代码但跨 4 个文件),按更重的一条走:宁可前期多花点结构化的成本,也比中途从 proposal 升级到 OpenSpec 返工便宜。

4.3.2 四种 artifact 各管一种判断

openspec/changes//
├── proposal.md ← Why / What / Out of scope / Acceptance
├── design.md ← 技术方案、数据模型、API 契约
├── specs/ ← 行为契约(ADDED / MODIFIED 区块)
└── tasks.md ← 带 checkbox 的任务清单
Artifact 回答什么 防止什么失败
proposal.md 为什么做、做什么、不做什么 范围爆炸
design.md 怎么做(技术方案、API、数据) 实现到一半发现路径错
specs/ 具体行为契约 验收标准模糊
tasks.md 拆成可勾选的执行项 进度不可见

4.3.3 命令序列(Orchestrator 内部使用)

下面这套命令是 Orchestrator 调度 OpenSpec 的内部工具不是给人类敲的。人类只输入需求(自然语言或前缀),由 Orchestrator 在合适时机自主调用:

/opsx:explore <需求> 探索方案,列利弊(不写文件)
↓ 人类选定方案
/opsx:new 创建变更目录骨架
↓
/opsx:continue × N 逐文档生成(每步可审)
或
/opsx:ff 一次生成全部 artifact
↓
/opsx:apply 实现(调度专家 agents)
↓
/memory-save (正面) 沉淀正面经验:可复用模式、决策记录
↓
/opsx:verify 三维度检查:完整性 / 正确性 / 一致性
↓
/memory-save (failure) verify 暴露的问题在人类签字后写入 failures/
↓
/opsx:archive 归档到 openspec/archive/

为什么 /memory-save 拆两次:正面经验在 apply 完成时已经成型,提前沉淀避免遗忘;而 failure 必须等 verify 通过后由人类签字才能入库(见 8.1.6 规则三),否则会把误报永久记录。

人类的视角是另一回事——见 4.3.8。

4.3.4 continue 与 ff:Orchestrator 自主决策

continue 还是 ff 是 OpenSpec 内部决策,由 Orchestrator 通过自检决定,不暴露给人类。Orchestrator 检查四个客观信号,任一不通过即用 continue:

信号 通过条件 不通过则 continue 的理由
1. 先例可参照 .memory/topics/archive/ 有相似 spec 无先例,AI 一次产出 4 份文档难以自洽
2. 不动外部依赖 无新增包/表/接口、不改契约 外部依赖一动,design 设计空间指数级扩大
3. 行为契约清晰 验收标准明确、状态机/数据流清晰 specs/ 阶段需要反复打磨
4. 审阅承受力 人类能 30 分钟连续审完 4 份产出 不影响是否用 ff,影响审阅节奏

信号 1-3 任一不通过 → continue(一票否决)。信号 4 不否决,只调节节奏。

对人类暴露的入口是”快/慢”偏好,不是 ff/continue

人类: feat: 用户头像支持上传

Orchestrator 自检后报告:
我打算用「快速模式」:一次性产出 proposal/design/specs/tasks,
完成后请你一次性审。
原因:archive/ 有 2 个相似 spec,无外部依赖变更,验收标准清晰。

你也可以选择「逐步模式」(每份产出后停下来让你审)。

人类可以接受、可以指定改慢速、可以中途打断切回慢速。反向不允许:continue 中途升级到 ff 等于跳过剩余审阅,是 AI 的”自信”覆盖人类的”谨慎”。这条规则没有例外——任何”剩余部分简单到不用审”的判断本身就是价值判断(见 5.2 铁律一),必须由人类在审完当前一步后显式说”剩下的合并产出”才允许,且需要在会话日志里留痕。

4.3.5 接口契约的冻结点

specs/ 写定即接口冻结。这是 L2 执行层「并行开发的安全边界」

> specs 冻结之前:所有相关 agent 必须串行 > specs 冻结之后:可以基于契约并行

这条铁律比 OpenSpec 这个工具本身更重要——就算不用 OpenSpec,也要找别的方式锁定接口

4.3.6 OpenSpec 不是不可替代的

OpenSpec 解决的问题(结构化锁定需求)可以用其他方式实现——GitHub Issues+PR、自建模板、TAPD/Jira+文档都行。OpenSpec 的优势是当前最 AI-friendly 的 spec 工作流:现成、轻量、命令化、能被 AI 直接消费。

Harness 真正需要的是「把需求结构化锁定」这件事,工具叫什么不重要。

OpenSpec 的 archive/ 和 8.1.6 的 failures 库共享同一条 Harness 原则:只保留不删除——历史可追溯、回滚有依据、长期数据可用于评估 AI 的进步。这是 Harness 治理层的一致性设计。

4.3.7 复杂度通过拆 spec 解决,不通过 agent 套娃

当一个 spec 大到 tasks.md 列了 50 个任务、单个 Orchestrator 上下文扛不住时,正确的做法不是套娃出子 Orchestrator,而是把 spec 本身拆成多个独立 spec。每个子 spec 仍由一个 Orchestrator 负责,按串行规则推进。

为什么这样选?因为 agent 套娃带来的代价(监控失明、错误处理链复杂、Memory 归属不清、价值判断升级路径不清)远大于它解决的问题;而拆 spec 的代价小得多,还顺带得到了”每个 spec 可独立审、可独立归档”的好处。这条规则配合 5.1 的”Orchestrator 扁平唯一”是配套的。

4.3.8 人类介入 OpenSpec 的合法时机

OpenSpec 的命令(/opsx:explore/opsx:archive全部由 Orchestrator 调用,人类不需要、也不应该亲手敲这些命令。这是和 L2 执行层共识配套的设计:人类只跟 Orchestrator 对话,不直接操作 OpenSpec 内部工具。

那人类什么时候”出现”在 OpenSpec 流程里?只有三类合法时机:

1. 审阅产出

OpenSpec 各阶段产出的文档(proposal/design/specs)必须经过人类签字才能进入下一步。具体强制审阅点:

  • proposal 完成后 → 审 Why / What / Out of scope(这是价值判断的核心)
  • design 完成后 → 审技术方向是否合理(可能升级回 proposal 修改)
  • specs 冻结前 → 审接口契约(冻结后并行,签字不可撤回)
  • verify 阶段 → 审最终实现是否还在 proposal 范围内
  • archive 前 → 最后一次确认变更归档

2. 选择方案

/opsx:explore 阶段会列出多个方案候选,由人类选定走哪个;ff/continue 节奏由 Orchestrator 自荐,人类可以接受或要求改。这都是”做选择”,不是”敲命令”。

3. 显式打断

任何时候人类觉得 Orchestrator 跑偏了,可以用自然语言打断:”等一下,先暂停”、”这个方案不对,重新探索”、”改用慢速模式”、”放弃这次变更”。打断也是自然语言,不是命令。

关键设计:以上三类都是「审阅、选择、打断」,不是「敲命令」。把 OpenSpec 的实现细节(哪些命令、什么参数、什么顺序)对人类隐藏,是让 OpenSpec 真正能用的关键——否则就退化成”用户记命令”的体验。

五、L2 执行层

L0 在工程界已是常识,L1 是 AI 时代新增但相对成熟的契约层,L2 是当前 Harness 设计中最容易出错的地方。本节是经过反复迭代后稳定下来的执行层设计——核心是把 AI agent 之间的角色关系彻底想清楚

5.1 角色清单:Orchestrator 是一个 agent

Harness 体系外:人类。永远的 boss 和甲方,价值判断的最终决策者。人类不在 agent 清单里——它是默认前提,不需要在体系内”显式声明”。

Harness 体系内(共 7 个 AI agent,分三层):

入口层 Orchestrator 会话主持人 + 全局协调者
↓ 调度
专家层 AI PM (可选) 需求理解 + proposal 起草
frontend-engineer 前端实现
backend-engineer 后端实现
tester 测试实现
↓ 交付
质检层 reviewer 代码审查(无 Write)
auditor (可选) spec 一致性、安全审计(无 Write)

下文为简洁起见,用 “Dev” 泛指 frontend-engineer / backend-engineer——按项目栈实例化即可,纯前端/纯后端项目可只保留一个。

关键澄清:Orchestrator 就是一个普通 agent。

它跟 PM、Dev、Reviewer 形态完全相同——LLM + system prompt + 工具集 + 上下文。特殊性在职责,不在形态

  • 它是 runtime 默认调用的第一个 agent
  • 它的 system prompt 限定它”只调度,不产出”
  • 它的工具集包含 call_agent()ask_human() 等调度工具

它不是后台进程,不是抽象协议,不是”始终在场的监听者”。它就是一个被赋予了”主持人职责”的 agent。

Orchestrator 是扁平唯一的,不允许套娃。同一会话同一时刻只能有一个 Orchestrator 实例。复杂度通过拆 spec 解决,不通过 agent 分层管理;并发由 runtime 层控制,不靠 AI 层级协调。具体规则:

  • 单会话内禁止并行多 active change——用户在已有 active change 时提新 feat,必须先做选择(暂停当前/完成当前/合并范围),不许并行推进
  • 大型 spec 不靠子 Orchestrator 拆——靠拆成多个独立 spec 解决
  • 多人协作时每人独立 Orchestrator,是兄弟关系不是父子关系,spec 边界隔离 + runtime 锁

为什么不套娃?因为套娃带来的代价(监控失明、错误处理链复杂、Memory 归属不清、价值判断升级路径不清)远大于它解决的问题。始终维持「一个会话一个 Orchestrator」这条扁平规则。

为什么叫 Orchestrator 而不是”主 agent”:避免歧义。”主 agent”容易被理解为”啥都能干的全能 agent”,但 Orchestrator 明确不写代码、不做价值判断——它只做调度。

5.2 Orchestrator 三条铁律

Orchestrator 既然要接所有原始输入,必然要做某种”判断”。判断分两种:

  • 路由判断:这是需求型还是执行型?要走哪条流程?→ 可以下放给 Orchestrator
  • 价值判断:这个需求值不值得做?范围在哪?优先级如何?→ 绝不下放

为了让 Orchestrator 守住这条边界,它的 system prompt 必须明文写下三条铁律。

铁律一:不做价值判断

碰到任何”该不该做”、”做到什么程度”、”优先级”的问题,必须 stop & ask 升级给人类。让 PM 跟人类对话来决定,不是让 Orchestrator 自己拍板

判定方法:如果一个判断会影响”是否做、范围、优先级、成本边界”中任何一项,必须升级。

铁律二:模糊输入必反问

人类输入意图不清晰时(如”统一一下按钮风格”——是 bugfix 还是 feature?),Orchestrator 不许猜,必须反问:

> “请问这是新需求(feat:)还是已有功能的修复(fix:)?”

宁可让用户多说一句,也不让 AI 误判为执行型直接派活——后者是最严重的失败模式。

铁律三:需求型必拉 PM

识别为需求型输入时(feat:、explore:、或反问后用户确认是新需求),必须启动 PM 流程,不能跳过直接派给生产 agent。

这条防止 Orchestrator 为了”高效”自己起草 proposal——起草权属于 AI PM,签字权属于人类,Orchestrator 只做调度。


这三条铁律是执行层设计的核心:它们让”统一 Orchestrator 接所有输入”这件事变得安全。没有这三条,Orchestrator 就退化成了”AI 守门员”,不可靠;有了这三条,统一入口的便利性才能落地。

5.3 协助请求协议:Orchestrator 如何被触发

回答一个真实的实现问题:PM 在跟人类讨论需求时,人类突然问”现在头像存储是怎么实现的?”——PM 不该读源码,谁去叫 Dev?

答:Orchestrator。但 Orchestrator 是个 agent,它不会”自动监听”PM 的对话——LLM 没有这种能力。它通过三种机制被触发。

机制 A:专家 agent 主动求助(主流方式)

每个专家 agent 的 system prompt 里明文写好”遇到什么情况要怎么做”。例如 AI PM:

你只负责需求理解和文档撰写。
你**没有权限**读取源代码、运行命令、查看技术实现。

遇到以下情况,停止当前回应,输出结构化求助 JSON:

1. 用户问技术实现细节("现在是怎么做的"、"用了什么库")
→ {"request": "consult", "to": "backend-engineer",
"question": "<原问题>", "reason": "技术细节超出 PM 职责"}

2. 用户提的范围明显超出当前 proposal
→ {"request": "escalate", "to": "human",
"reason": "范围决策"}

外层 runtime(普通代码,不是 LLM)解析这个 JSON,调用 Orchestrator agent,由它决定调用谁。

机制 B:人类显式触发(兜底)

人类可以用 @dev@arch 等显式指令,绕过专家 agent 的自我识别,直接让 Orchestrator 切角色。

PM ↔ 人类讨论中...

人类: "@dev 现在头像怎么存的?"
↓
runtime 识别 @dev → 调 Orchestrator → 切到 Dev

这是当机制 A 漏识别时的兜底。

机制 C:外层包装(重要会话用)

所有 PM ↔ 人类的对话都先经 Orchestrator 看一眼,由它决定透传还是切换。

人类输入 → Orchestrator → 透传给 PM 或切给别人 → 回复 → Orchestrator → 人类

代价是每轮对话额外多一次 Orchestrator 决策——token 开销大致翻倍,延迟取决于 Orchestrator 的决策粒度(短决策几乎无感,调用 LLM 完整推理则会有秒级增加)。仅在生产环境改动等高风险任务用。

推荐组合

层级 机制 何时生效
默认 机制 A 95% 场景
兜底 机制 B 机制 A 漏识别时
重要 机制 C 高风险任务

核心思路:靠 system prompt 让专家自治,留人类兜底通道,避免依赖 AI 100% 准确。

5.4 输入前缀:可选快捷方式

人类可以用前缀显式声明意图,让 Orchestrator 跳过路由判断:

feat: 新需求/新功能 → Orchestrator 直接拉 PM
fix: bugfix → Orchestrator 直接调度执行
refactor: 重构 → Orchestrator 调度执行 + auditor
chore: 杂项 → Orchestrator 直接派 agent
docs: 文档变更 → 直接派 agent
ask: 提问/解释代码 → 直接对话
explore: 方案探索 → 拉 PM(无 commit 意图)

前缀的定位:可选快捷方式,不是必选协议。

  • 新用户不用学:Orchestrator 智能路由自动判断
  • 熟手用前缀:节省判断 token、提高确定性
  • 模糊输入:Orchestrator 必须反问(铁律二),无论有没有前缀

前缀语法借自 conventional commits,输入前缀的 type 可以直接对应这次任务最终 commit 的 type——一种意外的可观测性。

需要明确的是:前缀只决定路由,不决定 OpenSpec 内部节奏feat: 进入后,Orchestrator 自主决定何时调用 /opsx:explore、用 ff 还是 continue、什么时候请人类审——这些都是 4.3 的内部决策,跟前缀无关。前缀的作用边界仅限于”这是不是需求型/执行型/对话型”这一层判断。

5.5 OpenSpec 工作流 × 角色调度

把 4.3 的 OpenSpec 工作流映射到本节的角色,得到完整的”谁在哪个阶段做什么”的对应表。注意:表中”OpenSpec 命令”全部由 Orchestrator 在合适时机自主调用,不是人类敲的——人类的视角参见 4.3.8。

阶段 OpenSpec 命令(Orchestrator 内部) 主导角色 协作角色 人类侧动作 关键铁律
探索 /opsx:explore Orchestrator AI PM 与人类对话 提需求、选方案 价值判断由人类做
立项 /opsx:new Orchestrator 用户选定方案后自动调用
起草 proposal /opsx:continue/opsx:ff Orchestrator → AI PM 起草 必须审 Why/Out of scope 价值判断不下放
起草 design /opsx:continue/opsx:ff Orchestrator → architect 或 Dev AI PM 仅复核”是否还在 proposal 范围内” 审技术方向 与 CODEBUDDY.md 对齐
起草 specs /opsx:continue/opsx:ff Orchestrator 主导 Dev 提议字段 冻结点必审 冻结后才能并行
起草 tasks /opsx:continue/opsx:ff Orchestrator 一个 task 一次交付
实现 /opsx:apply Orchestrator 调度 Dev + reviewer + tester 签字”开始干” 触发实现 默认串行,并行需契约冻结
沉淀(正面) /memory-save Orchestrator 触发 全员 apply 完成即触发,沉淀可复用经验
验证 /opsx:verify Orchestrator auditor + reviewer 最终验收 三维度检查
沉淀(failure) /memory-save Orchestrator 触发 审 failure 草稿才入库 verify 暴露的问题需人类签字才写入 failures/
归档 /opsx:archive Orchestrator 不删除,保留审计线索(与 failures 库一致)

三个值得展开的设计点:

1. AI PM 起草 proposal 但不主导 design

proposal(Why / Out of scope)由 AI PM 起草,人类必审签字——这是「价值判断不下放」的具体落地。design.md 主导权交给 architect 或 Dev:因为 design 必然要看现有代码、技术栈约束,而 AI PM 按 5.6.2 没有 Read 源码权限。AI PM 在 design 阶段只做一件事——复核”技术方案是否还在 proposal 范围内”,不参与字段设计。

2. Dev 不写 specs,但参与提议字段

specs 是契约,由 Orchestrator 主导以保证一致性;具体字段名、类型由实现方按 5.3 求助协议提议——他们最懂技术约束。”契约民主化、审定权集中”。

3. PM 流程中遇到技术问题,按 5.3 协议求助

人类问”现在怎么实现的” → AI PM 输出 consult 请求 → Orchestrator 调 Dev 答 → 答完 Dev 退场 → 回到 PM 继续。整个过程对人类透明。

5.6 AI PM Agent 的设计原则

5.5 把 AI PM 放进了角色调度表,但还没说清这个 agent 该怎么设计。AI PM 这个角色没有现成参照——传统 PM 由人类充当,引入 AI PM 是为了把”价值判断的助手工作”显式化,因此它的设计必须从原则推导

适用前提:AI PM 是 5.1 标注为”可选”的角色——按第九节规模化裁剪,中型项目以上才需要引入。小型应用和个人脚本由人类自己充当 PM 即可,本节设计原则在引入 AI PM 时才适用。即便不引入,5.6.3 列的几条专业性要求也可以作为”人类自己当 PM 时的自检清单”。

5.6.1 核心定位

> AI PM 不是用 AI 替代 PM,而是用 AI 加速「人类的 PM 思考过程」。

PM 真正的价值不是写文档、不是记录需求、不是召集会议——是通过提问帮决策者想清楚自己要什么。AI PM 应该继承这个本质,而不是退化成”自然语言到文档的翻译器”。

这个定位决定了所有后续设计的取舍线:所有让 PM 更接近「思考助手」的能力都该有,所有让 PM 更接近「独立决策者」的能力都该没有

5.6.2 权限边界

PM 的权限设计延续 5.2 三铁律和 5.3 求助协议,本节不重复,只列 PM 独有的额外约束:

  • 不能读源代码——Read 权限只覆盖 proposal/ 和已冻结的 specs/不含 design.md 和源码。理由:避免技术细节绑架需求讨论,让”用户要什么”退化为”代码能做什么”。
  • 不主导 design.md——design 由 architect 或 Dev 主导(5.5)。AI PM 在 design 阶段只做”是否还在 proposal 范围内”的复核,不参与字段设计。
  • 价值判断升级、协助求助走 5.3 协议——和其他 agent 一致。

5.6.3 专业性:PM 独有的几条要求

下面四条是 PM 区别于”温顺需求记录员”的关键能力,必须写进它的 system prompt。

主动澄清,不许猜。模糊关键词触发反问:

  • “之类的””差不多””什么的” → 必须列出具体范围
  • “好用一点””友好一些” → 必须翻译成可验收的标准
  • “支持 XX 功能” → 问清楚”支持到什么程度”
  • 隐含主语缺失(”那个东西””原来那个”)→ 必须确认指代

AI 自动补全用户未明示的需求是最常见的失败模式。在 PM 阶段问 3 个问题,比让 Dev 写完返工省 100 倍成本。

主动写 Out of scope。每个 proposal 必须包含 Out of scope 段。用户描述需求时”什么不要做”通常不会主动说,PM 必须反向追问”边界扫描”:跟当前需求容易混淆的相邻需求?容易顺手做的扩展?前置依赖在范围内还是外?这是 PM 区别于”记录员”的关键。

软指标必翻译成硬指标。”加载快一点” → “首屏 ≤ 1.5s” 或反问”快到什么程度算可接受”。常见映射:

  • “快/慢” → 时间数字
  • “好用/友好” → 可观测的交互(点击次数、屏幕跳转数)
  • “稳定” → 错误率/SLA
  • “灵活” → 必须列出具体支持的变化点

软指标是验收灾难——AI 生产端无法理解,测试端无法验证。

输出可审。proposal 是给人类审的,措辞要让非技术人员能读懂。禁止:实现细节(”用 Redux 管状态”——这是 design.md 的事)、技术选型(”用 PostgreSQL 还是 MongoDB”)、代码片段(除非是 API 契约示例)。

5.6.4 三个反主流陷阱

PM 是”专家”,不是”秘书”。敢于挑战用户:

  • 用户说”加个分享按钮” → “为什么需要?现有的复制链接不够吗?”
  • 用户说”做得跟 X 产品一样” → “你欣赏 X 的哪一点?我们的用户场景跟 X 一样吗?”

挑战不是抬杠,是帮用户自己想清楚

输出”够用”的 proposal,不输出”完美”的。完美主义的代价是:写得太详细,人类没耐心审,价值判断又被绕过。标准:长度够人类 5 分钟读完;80% 细节留给 design.md;只回答”做不做、做什么、不做什么”。

显式留下”未决问题”清单。任何讨论都不可能一次想清楚所有问题。假装”全想清楚了”是最不诚实的 proposal——Dev 会自己脑补,又回到 AI 越界做决策的问题。

5.6.5 设计主线小结

1. 核心定位:思考助手 ≠ 决策替代
2. 权限边界:参见 5.2 三铁律 + 5.3 求助协议;额外不读源代码
3. 专业性:主动澄清 / 主动写 Out of scope / 软指标必翻译 / 输出可审
4. 反陷阱:专家不秘书 / 够用不完美 / 显式留未决

具体的 system prompt 模板代码从这套思路推导,模板落地是后续工作。

5.7 从人类视角看整个工作流

5.1 到 5.6 全是 AI 视角——讲 Orchestrator 如何调度、PM 如何求助、specs 如何冻结。但人类用户实际感受到的是另一回事,把这层透明度讲清楚很重要。

人类只需要做四类事

  1. 提需求:用自然语言或前缀(feat: / fix: / 等)描述要做什么
  2. 选方案:在 /opsx:explore 阶段选定走哪个候选
  3. 审产出:在 proposal、specs 冻结点等强制审阅点签字
  4. 显式打断:觉得跑偏时随时暂停或调整

人类不需要知道

  • OpenSpec 有哪些命令、什么参数、什么顺序
  • ff 和 continue 的判定标准(除非主动想要”快/慢”偏好)
  • 哪个 agent 在做哪一步、谁在向谁求助
  • Memory 怎么沉淀、failures 怎么归档
  • runtime 怎么解析求助 JSON、agent 之间怎么交接

整个流程对人类的实际样子大概是这样

人类: feat: 用户头像支持上传
↓
Orchestrator: (列了 3 个方案候选)
人类: 选方案 B
↓
Orchestrator: (AI PM 起草 proposal 给人类审)
人类: 范围对,开始干
↓
(中间 Orchestrator 自动调度 PM/Dev/reviewer/tester 完成实现,
期间偶尔 Dev 通过 PM 问人类一些技术细节澄清)
↓
Orchestrator: (把成品给人类审)
人类: 通过
↓
Orchestrator: (归档完成)

整段对话里人类没敲过任何 OpenSpec 命令,没接触过任何 agent 内部协议。这是 Harness 工程的核心承诺:让 AI 协作的复杂度,留在 AI 一侧;让人类做的事,仍然是「想清楚要什么、判断做得对不对」——这两件事永远是人类的核心价值。

六、L3 能力层

L2 解决”谁来做”,L3 解决”用什么做”。能力层有三种形态,职责严格不重叠

  • MCP 接外部数据源(库文档、数据库、API)——需要实时/外部信息时用
  • Commands 封装重复操作(.codebuddy/commands/*.md)——同一段 prompt 用过 3 次就该 Command 化
  • Skills 封装专项能力(.codebuddy/skills//)——多步骤工作流 + 多文件资产时才用

最大的反模式是工具崇拜——看到别人配 5 个 MCP 自己也配 5 个。每新增一项能力都要回答三个问题:这个问题真的需要它吗?维护成本多高?退出策略是什么?

推荐最小命令集:/init/git/spec:new/memory-save/harness:health。先把这些做扎实,比铺一堆花哨命令有用得多。

七、L4 AI 护栏层

这一层最容易越权。很多方案把”类型检查””lint””测试”全塞进 CodeBuddy Hook,看似护栏完备,实际上和 L0 的 git hook 严重重复——而且只在 AI 工具内生效。

L4 的正确定位是:只补 git hook 干不了的事。 具体只做四类:

  1. 节省 token:Write/Edit 后立刻 prettier
  2. 防止误伤:写入 .env / migrations/ / .harness/ 前要二次确认
  3. 高危拦截rm -rfdrop databasegit push --force 等命令直接拦截
  4. 工作流提示:会话结束前提醒 /memory-save,长任务前提醒切到 Plan Mode

绝对不做:类型检查、lint、单元测试——这些是 L0 的事。

八、L5 治理层

到这里,前五层已经能让 Harness 跑起来了。但真正决定它能不能”活下去”的是 L5——治理。

8.1 Memory:与 OpenSpec 协同的经验沉淀

Memory 不是孤立功能,它和 OpenSpec 是配套的——一个管「当前任务的契约」,一个管「跨任务可复用的经验」。

8.1.1 职责切分

维度 OpenSpec Memory
时间尺度 单次任务(开始→归档) 跨任务、跨会话长期
内容 当前任务的契约 通用经验、踩坑、铁律
形态 结构化文档树 索引 + topics + failures
归档 archive/ 保留完整记录 _expired/ 不再加载
加载 显式触发 自动 + 必读项

协作点:每次 OpenSpec 任务结束,Orchestrator 触发 /memory-save,把可复用经验从「这次怎么做」提炼成「以后类似情况怎么做」。

8.1.2 安装顺序:先 OpenSpec 再 memory-init

硬性约束。memory-init 会检测 openspec/ 目录,自动注入 Memory 上下文到 openspec/config.yaml

# Step 1
npm install -g @fission-ai/openspec@latest
openspec config profile && openspec init

# Step 2
cp -r memory-init .codebuddy/skills/
/memory-init openspec

8.1.3 标准结构 + 三个扩展

memory-init 默认结构是 index.md + topics/。本文在标准结构上增加三个机制,解决 LLM 决定”读哪些经验”不可靠的问题:

.memory/
├── AGENTS.md
├── index.md
├── topics/
├── ALWAYS_LOAD.md ← 【扩展】铁律级经验,每会话必读(≤50 行)
├── failures/ ← 【扩展】失败案例库
├── _expired/ ← 【扩展】过期归档
└── audit.log ← 【扩展】加载/更新日志
  • ALWAYS_LOAD:绕过 AI 的相关性判断,确定性兜底。放绝对不能违反的铁律。
  • failures/:单独维护踩坑案例。告诉 AI”该怎么做”远不如告诉它”千万别做什么”有效
  • audit.log:让 memory 命中率可度量,是后续清理决策的依据。

8.1.4 /memory-save 的位置

不是事后想起来再存,是流程的一环。按 4.3.3 的命令流,/memory-save 在一次变更里触发两次

  • 第一次(正面经验):在 /opsx:apply 之后、/opsx:verify 之前。沉淀本次变更里产生的可复用模式、关键决策、新建立的 topic。
  • 第二次(failure):在 /opsx:verify 之后、/opsx:archive 之前。把 verify 暴露的问题(reviewer 打回、tester 红灯等)经人类签字后写入 failures/(详见 8.1.6 规则三)。

每次触发都由 Orchestrator 执行:

  1. 分析对话内容,提取有价值的经验
  2. 跟已有 topic 匹配——匹配上的追加,匹配不上的用模板创建新 topic
  3. 写入对应文件(正面经验进 topics、踩坑教训进 failures、绝对铁律提升到 ALWAYS_LOAD)
  4. 更新 index.md

分桶判断由 Orchestrator 做,不下放给生产 agent——后者视角割裂。

8.1.5 新会话的加载顺序

1. 必读:CODEBUDDY.md(项目铁律)
2. 必读:.memory/ALWAYS_LOAD.md(跨项目铁律级经验)
3. 必读:.memory/index.md(topic 元数据)
4. 按需:根据当前任务关键词,从 index 选相关 topic
5. 按需:failures/ 中匹配当前场景的案例

绝对不能丢的信息确定性加载,可选信息按需加载。

8.1.6 failures 库的写入与演进规范

8.1.3 把 failures 库吹得很高,但不给写入规范它会快速退化成”垃圾堆”或”荣誉墙”。本节定下五条规则。

规则一:什么算 failure——只记被外部机制拦下来的客观事件,五类触发源:reviewer 打回、tester 红灯、Hook 拦截、auditor 否决、人类显式打回。AI 中途调整方向、prettier 自动修复、Plan Mode 调整、Token 超预算都不算

规则二:谁来写——触发方仅发结构化信号(from / task_id / evidence / suggested_root_cause),由 Orchestrator 集中判断、起草、归类。否则会出现重复条目和视角割裂。

规则三:何时写入——不立即写,由 Orchestrator 起草后等到 OpenSpec verify 阶段连同变更一起请人类审,批准后才入库。避免误报被永久记录。

规则四:写成什么样——固定模板(详见附录 A · failures 条目模板),关键字段:id(用于交叉引用)、occurrence_count(高频→优先转护栏)、status(active/resolved/expired)、preventions(已部署护栏)、验证机制(可观测的”已修好”指标)。

规则五:保留多久——三档生命周期,只降级不删除

active ──[护栏覆盖 + Orch+人类双签]──→ resolved ──[2 季度无再现自动迁移]──→ expired

active → resolved 必须人类双签——AI 自评”我修好了”不可信。不允许直接删除:历史可追溯、回滚有依据、长期数据可评估 AI 进步。

与其他机制的协作:failures 库不是孤岛,最有价值的内容应”毕业”流向更确定性的机制——

协作对象 联动方式
CODEBUDDY.md 反复出现的 failure → 提升到 STABLE 段
L4 Hooks 高频且可机器检测的 → 转化为 Hook
Skills 涉及多步骤防御的 → 转化为 Skill
ALWAYS_LOAD 跨任务的根本性 failure → 提升到 ALWAYS_LOAD
Metrics 任务返工率 = 触发 failure_signal 次数 / 总任务数

健康度指标active failure 数量随时间应该缓慢下降——上升说明护栏没建立起来。

反模式:让生产 agent 自己写 failure(视角割裂);失败发生立即自动写入(可能记录误报);删除”已修复”的(历史断裂);不带 occurrence_count(无法识别高频)。

8.2 Metrics

Harness 自己也是产品,必须有度量:

指标 含义
任务完成率 一次过验收的比例
返工率 被 reviewer/tester 打回的比例
求助命中率 专家 agent 主动求助 vs 人类兜底触发的比例
Hook 拦截率 拦住真问题 vs 误报
Memory 命中率 加载的 topic 中被实际引用的比例
Token 成本 每个 spec / bugfix 的平均消耗
Spec 准确度 spec 与最终实现的一致性

8.3 Harness 自己的演进

.harness/
├── CHANGELOG.md ← 配置版本化记录
├── retire-list.md ← 待退役清单
├── reviews/.md ← 季度复盘
└── health.md ← 自动生成的健康报告
  • 每周:跑 /harness:health 检测规则冲突、未使用的 skill
  • 每月:审视 metrics,决定调哪些规则
  • 每季度:复盘 failures/,把高频失败转化为 Hook 或 Skill;同时清一批不用的能力

能加就要能删。Harness 必须可瘦身。

九、规模化裁剪

项目规模 L0 L1 Orchestrator 专家 agents L3 L4 L5
个人脚本 CODEBUDDY (≤30) 极简版(≤10 行 system prompt) 1 1 hook
小型应用 + Proposal 轻量版(≤30 行) 单 agent + reviewer 2-3 cmd 2-3 hook
中型项目 + Glossary ✅ 完整三铁律 + Dev × 2 + tester + 1-2 MCP 完整 Memory
大型项目 + Spec ✅ 完整三铁律 + AI PM + auditor + Skills 完整 完整
团队项目 共享规则库 ✅ 每人一个 多人多 agent 团队 Skills 仓库 完整 完整 + 度量平台

裁剪原则:能不加就不加,痛点驱动升级。Orchestrator 在所有规模都需要——它是会话入口,没了它连用户输入都没人接;区别只在 system prompt 复杂度。团队项目里多个 Orchestrator 是兄弟关系,不是层级关系:每人持有自己的 Orchestrator,通过 spec 边界隔离 + runtime 层并发控制(git 锁、文件锁)避免冲突,不引入”主 Orchestrator”协调——协调由人类完成。

十、落地路线图

第一周做 L0 + L1 骨架:husky + lint-staged + CI,CODEBUDDY.md 的 STABLE 段,proposal 模板。同时配一个最简版 Orchestrator——它的 system prompt 可能只有 30 行(三条铁律 + 求助协议解析),但必须先有,否则连用户输入都没有 agent 接。

第二周加能力:1-2 个真正用得上的 MCP,3-5 个高频 Command。先不上 Skills 和 Memory——它们是后期才需要的。

第一个月引入专家 agent:Dev + reviewer 先到位,由 Orchestrator 调度。复杂任务再考虑 Orchestrator 的 system prompt 加更详细的求助协议。

第二、三个月规范化:复杂功能引入 spec,初始化 Memory(重点维护 ALWAYS_LOAD 和 failures),评估是否引入 AI PM。

每季度复盘:跑 metrics 看求助命中率和返工率,做 retire 列表,把高频失败转化为自动化护栏。

十一、十二条铁律索引

正文已分散展开各条铁律的论证,此处仅作索引便于回查:

  1. 质量门禁人机共用——L0 不可省,L4 不可越权 → 三、七
  2. 写「不做什么」比「做什么」更重要——Out of scope 是核心 → 4.2、5.6.3
  3. 价值判断永远归人类——Orchestrator 必须 stop & ask → 5.2 铁律一
  4. 模糊输入必反问——AI 不许猜 → 5.2 铁律二
  5. 需求型必拉 PM——Orchestrator 不许跳过 PM 直接派活 → 5.2 铁律三
  6. AI agent 之间通过 Orchestrator 调度——禁止专家间直接通信 → 5.1、5.3
  7. Reviewer 不许有 Write 权限——审改分离 → 5.1 角色清单
  8. 接口契约冻结后才能并行——否则一定撞车 → 4.3.5
  9. CODEBUDDY.md 不超过 200 行——超了就拆 → 4.1
  10. 能用 Command 不用 Skill,能不用 MCP 不用 MCP——能力层最小化 → 六
  11. 失败案例库比正面经验库更有价值——优先维护 → 8.1.6
  12. Harness 必须可度量、可瘦身——能加就要能删 → 8.2、8.3

十二、结语

回到开头那个问题:为什么 AI 越来越能写代码,工程问题反而越来越多?

因为我们一直在升级模型,但没有同步升级模型外面的环境。模型像一匹会跑的马,没有马具的时候它能跑,但你没法让它跑得既快又准。Harness 工程不是限制 AI,而是让 AI 的能力真正变成可交付的产品

模型会继续变强,但 Harness 不会因此消失——车速越快,底盘和刹车越重要。Harness 的具体形态会随模型能力进化(某些机制会从”工程兜底”退化为”模型自带”),但”约束输入 / 反馈验证 / 经验沉淀 / 价值判断归人类”这四件事的工程位置不会消失。

> Harness 是一个能呼吸的系统:它要能随项目长大,也要能定期瘦身; > 价值判断永远归人类,调度统一归 Orchestrator,执行各司其职; > 路径要按任务复杂度选择,而不是一刀切走全套


附录 A · failures 条目模板

id: F-2026-0042 # 全局唯一,用于交叉引用
title: "frontend 误用 snake_case 字段"
status: active # active / resolved / expired
first_seen: 2026-05-10
last_seen: 2026-05-12
occurrence_count: 3 # 触达阈值后优先转护栏
trigger:
source: reviewer # reviewer / tester / hook / auditor / human
task_id: change-avatar-upload
evidence: "PR#1287 review comment"
root_cause: "design.md 未明确 API 字段命名风格"
suggested_root_cause: "(触发方填,最终由 Orchestrator 校订)"
preventions: # 已部署的护栏,按层归属
- layer: L1
action: "CODEBUDDY.md STABLE 段补一行 '前端禁止直接消费 snake_case 字段'"
- layer: L4
action: "(待评估)Hook 检测前端文件含 snake_case 字段名时提示"
verification: # 可观测的"已修好"指标
metric: "类似 PR review 评论再现次数"
threshold: "2 季度内 = 0"
related:
spec: openspec/archive/2026-05-12-avatar-upload/
topic: .memory/topics/api-naming.md
notes: |
自由文本,记录上下文与未决问题。

字段约束:

  • status 只允许从 active → resolved → expired 单向迁移(8.1.6 规则五)
  • active → resolved 必须有 preventions 至少一项 + 人类签字记录
  • occurrence_count ≥ 3 触发”优先转护栏”评估(季度复盘必看)