爆肝长文:SDD 实战下篇,从渐进式 SDD 到 Lattice Harness:AI Coding 的团队级闭环
公众号名称:dolphin07
作者名称:Dolphin7
发布时间:2026-07-02 19:45
渐进式 Spec Coding 解决“别跑散”,Harness 把执行和裁判分开,Loop 解决“别从零开始”。
如果说上篇讲的是“怎么让 AI Coding 不要从一句话需求直接跳到随机代码”,那这篇要继续回答另一个更难的问题:
当团队已经有了 Spec,谁来证明这次交付真的做对了?
上篇讲的是我们在团队里落地 Spec Coding 的第一阶段:先试工具,再从工具里抽方法。我们试过 OpenSpec + Superpowers 这种完整流程,也用过 Plan Mode 这种轻量控制点,最后收敛成两条更现实的渐进式 SDD 路线:
| 需求类型 | 上篇方案 | 目的 |
|---|---|---|
| 低风险 / 小改动 | Superpowers + Plan Mode | 先让 AI 出计划,人确认后再改 |
| 中等复杂 / 多人协作 | Plan Mode + 轻量 Spec 摘要 | 锁边界、关键路径和验收标准 |
| 高风险 / 回归风险 | PrismSpec / plan 模式 | 保留 spec.md、plan.md、review.md、verify.md |
| 高不确定 / 关键链路 | PrismSpec / tdd 模式 | 先写失败测试,再实现,再验证 |
这套方案是有效的。它至少解决了三个问题:
- 1. AI 不再直接从一句话需求跳到代码;
- 2. 中高风险需求有了
spec.md、plan.md、review.md、verify.md这些可交接工件; - 3. 团队开始按风险选择控制强度,而不是所有需求都走同一条重流程。
但真实跑下来,提效没有想象中那么完整。
个人编码会更快,方案收敛会更清楚,review 也更有依据。但团队级交付仍然会卡在几个老问题上:业务规则靠人临场补、验收证据不稳定、测试和验收标准脱节、失败经验没有回流。
也就是说,Spec 让 AI 少跑散,但还没有让团队稳定地判断“这次真的做对了”。
这就是我说的:Spec 只能解决 0 到 80。
剩下 20 分,不该继续靠更厚的 Spec 补,而是五个工程缺口:
| 缺口 | 问题 | 需要补什么 |
|---|---|---|
| 上下文缺口 | 关键业务规则没进来,Spec 方向仍然会错 | 可审计的项目上下文 |
| 裁判缺口 | 谁判断做对了,不能让生成者自证 | 独立 Verification |
| 追踪缺口 | 验收标准、测试、代码、证据没有链路 | 验收覆盖与过程证据 |
| 漂移缺口 | API、schema、错误码会和 Spec 腐化 | drift check |
| 学习缺口 | 失败停在终端,下次继续从零猜 | loop state 与 learn draft |
更关键的是,到了团队级交付,不能再默认“同一个 Agent 写完、自己解释、自己宣布通过”。执行者可以修复问题,但最终裁判必须来自独立证据:测试、静态检查、验收覆盖、漂移检查、只读 reviewer 或人工确认。
所以这篇是在上篇渐进式 SDD 的基础上,继续补第二层工程能力:
PrismSpec / 渐进式 SDD
-> Context
-> Orchestrator
-> Verification
-> Evidence / Eval
-> Loop / Learn
-> Lattice Harness
上篇解决的是“流程怎么不变重”,这篇解决的是“交付怎么可证明、可复盘、可复用”,以及“谁有资格宣布通过”。
Lattice 是我在 PrismSpec 之上继续补出来的 repo-local AI Coding control plane / harness:不做 IDE、不做云平台、不接管 Agent,只把团队交付需要的控制点变成仓库内可版本化的 contracts。
一、SDD 落地之后,为什么还差一层 Harness
上篇的自研 PrismSpec 解决的是 Spec Coding 的最小流程:
brainstorm -> plan -> implement(plan|tdd) -> verify -> finish
它关心的是:
- • 需求如何变成
spec.md - • Spec 如何拆成
plan.md - • 什么时候走
plan - • 什么时候必须走
tdd - • 实现结果如何先经过
review.md - • 验证结果如何落到
verify.md
但 PrismSpec 本身不应该膨胀成完整平台。否则它会重新变成一套重流程。
Lattice 接在 PrismSpec 后面,核心不是再加一层流程,而是把团队 AI Coding 的关键控制点落成 repo-local contracts:
| 控制点 | 没有 Harness 时的问题 | Lattice 放在哪里 |
|---|---|---|
| Spec | 需求、假设和边界留在聊天里 | spec.md、plan.md、review.md、verify.md |
| Context | 上下文靠人临场补,下一次不可恢复 | lattice/context/README.md、knowledge/、Context Basis |
| Orchestrator | Agent 靠对话记忆推进任务 | guide.sh、spec-status.sh、task-next.sh、task-complete.sh |
| Verification | 完成靠自然语言总结 | pipeline.sh、gates/、fresh command output |
| Evidence | 测试、review、失败记录散在各处 | eval-runs/*.json、summary、history、dashboard |
| Learning | 失败经验直接丢失或污染知识库 | loop state、escalation、learn draft、promotion |
所以 PrismSpec 的边界很清楚:它负责把需求变成可执行 Spec;Lattice 负责把上下文、验证、证据和学习变成仓库内契约。
这里的 Orchestrator 很关键。它不替 Agent 做语义判断,而是把“下一步该做什么”从聊天记忆变成文件状态和命令协议:guide.sh 根据当前产物路由阶段,spec-status.sh 推进状态,task-next.sh 找下一项任务,task-complete.sh 要求 evidence 后才能完成任务。这样下一位 Agent、下一次会话、CI 或 reviewer 都能从仓库恢复上下文,而不是依赖上一轮对话。
这张图是我对下半场的整体理解:

Lattice 的价值不是多一套文档,而是把团队交付的控制点固化成可恢复、可验证、可审计的 repo-local contracts。
二、Context:不要把知识库做成 Prompt 杂货铺
很多团队一听 Context,就会走向两个极端:
- • 要么什么都不放,靠人每次在 prompt 里解释。
- • 要么什么都塞进去,把 README、会议纪要、事故复盘、代码片段全塞进上下文。
这两个都不对。
Lattice 里 Context 的定位很克制:
Context 不是代码真相源,而是帮助 Agent 少看错、少漏看,并把采用依据写进 Spec。代码、测试和 schema 仍是真相源。
1. Context 只放 AI 推不出来的约束
代码能告诉模型“现在怎么写”,但不一定能告诉它“为什么必须这么写”。
适合进入知识库的内容,是高稳定、高复用、跨需求会反复影响判断的规则:业务不变量、历史事故、架构决策、团队约定、接口契约。临时讨论、大段源码、泛 prompt 技巧都不适合直接进长期知识。
关键标准很简单:
这条信息如果不提前告诉 AI,它会不会做出“能跑但不对”的实现?
会,就值得沉淀。不会,就别污染知识库。
2. Context 要 map-first,再按需检索
Lattice 当前的主入口不是一个“大 prompt”,也不是让 Agent 上来就跑 loader,而是一张给 Agent 读的上下文地图:
lattice/context/
├── README.md # Agent 必读的项目上下文地图
├── external.md # 外部文档、中心知识、第三方协议入口
├── knowledge/
│ ├── architecture.md
│ ├── rules.md
│ ├── pitfalls.md
│ ├── glossary.md
│ └── decisions/
└── drafts/ # 待确认的经验沉淀
这里有三层,不要混在一起:
| 层 | 作用 | 产物 |
|---|---|---|
| Context Map | 告诉 Agent 去哪里找、冲突时信谁 | lattice/context/README.md |
| Project Knowledge | 存长期稳定、可复用、可审计的项目知识 | lattice/context/knowledge/ |
| Context Basis | 记录本次任务实际采用了哪些依据 | spec.md#Context Basis |
一次需求进来,正确顺序是:
- 1. 先读用户本次需求和当前代码、测试、schema;
- 2. 再读
lattice/context/README.md,知道相关知识在哪; - 3. 只选择会影响 Scope、验收标准、Risk、Interface、Compatibility 或 Verification 的事实;
- 4. 把采用的事实写进
spec.md的 Context Basis。
知识条目建议保持短、硬、可审计:
# 支付幂等规则
**关键词**:payment, idempotency, fund
**核心规则**:所有支付类 mutation 都必须带幂等键。
**来源**:2026-06-26 事故复盘
**适用上下文**:支付、扣款、退款、核销等会改变资金或权益状态的写操作。
3. Context 必须进入 Spec,而不是停在聊天里
只把知识读给 Agent 没用。它必须落到 spec.md 里,变成后续 review、plan、test 能引用的约束。
推荐写成这样:
## Context Basis
| 类型 | 来源 | 事实 / 约束 | 决策影响 |
|------|------|-------------|----------|
| knowledge | `rules.md#payment-idempotency` | 支付类 mutation 必须带幂等键 | 验收标准需要覆盖重复提交 |
| decision | `decisions/ADR-12` | 订单状态只能单向流转 | 影响失败恢复和重放语义 |
这样 Context 才从“背景材料”变成“交付契约的一部分”。
4. 项目知识库和中心知识库要分工
团队知识库不能只做一个大仓库。真实落地更适合两层:
| 层级 | 放什么 | 不放什么 | 作用 |
|---|---|---|---|
| 项目知识库 | 当前项目的业务规则、接口边界、历史坑、局部决策 | 跨团队通用但未经验证的经验 | 服务当前 repo 的 Spec 和 Plan |
| 中心知识库 | 多项目反复验证过的通用规则、平台约定、安全红线、工程模板 | 单项目特例、临时讨论、未确认结论 | 给多个项目提供共享基线 |
项目知识库更接近真实业务,中心知识库更接近组织资产。两者不能混成一个池子,否则会出现两个问题:
- 1. 中心规则太重,压死项目差异;
- 2. 项目特例上升太快,污染公共知识。
更稳的方式是:中心知识库默认 read-only,下游项目本地 override。只有经过多个项目验证、来源清楚、owner 明确的规则,才上升为中心知识。

5. 知识要自下而上蒸馏,不要自上而下编目录
很多知识库失败,是因为一开始就按组织架构设计目录:业务域、系统、模块、流程、规范,看起来很完整,但真正写 Spec 时搜不到、用不上、没人维护。
AI Coding 里的知识应该从真实交付里蒸馏出来。
推荐流程是:

这条链路有三个好处:
- • 知识来自真实失败和真实决策,不是凭空写规范;
- • 每条知识都有来源和适用范围,后续可审计;
- • 中心知识库只沉淀 verified 共性,不压制项目差异。
所以 Context 工程不是“建一个知识库”,而是建立一条从交付现场到项目知识、再到中心知识的蒸馏链路。关键不是让 Agent 看更多,而是让它少看错、少漏看,并把采用依据留在 spec.md。
Context 不是越多越好,而是越准越好。真正有价值的是能改变 Scope、验收标准、Risk 和 Policy 的知识。
三、Verification / Evidence:不要让 AI 自己证明自己正确
先把两个词拆开。
| 概念 | 回答的问题 | 典型产物 |
|---|---|---|
| Verification | 这次交付当下能不能过? | pipeline.sh、gates、fresh command output、verify.md |
| Evidence / Eval | 为什么算过?历史上过得怎么样?失败能不能复盘? | eval-runs/*.json、summary、history、dashboard、outcome |
团队级 AI Coding 最危险的不是没有测试,而是没有独立裁判;最难沉淀的也不是测试结果,而是可比较、可查询、可复盘的 evidence。
在团队级 AI Coding 里,Evidence / Eval 至少要回答三个问题:
- 1. 这次交付是否满足 Spec?
- 2. 这次 Agent 的工作过程是否可靠?
- 3. 这个团队的 AI Coding 能力是否在变好?
当前最该先做的是前两个。第三个可以后面再数据化。
这里有一条底线:执行者不能做最终裁判。
同一个 Agent 可以写代码、修失败、补测试,但它不能只凭自己的解释宣布“已经通过”。否则 Verification 会退化成自证:同一套上下文、同一套盲点、同一套合理化能力,既负责生成,也负责证明。
所以核心不是“再让 AI 看一遍”,而是把最终裁决交给独立证据:测试、静态检查、验收覆盖、drift check、只读 reviewer、人工确认。Agent 可以参与修复,但通过与否必须由外部信号决定。
在 Lattice 里,我把证据分成六层:

先做 L1-L4,因为它们确定性强、误报低、能直接进入本地和 CI。L5-L6 先记录、汇总和暴露风险线索,不要过早自动判死刑。
1. Verification 先做确定性卡口
不要一上来就让另一个 LLM 做语义评审。更稳的是先把确定性卡口做扎实。
Lattice 的交付流水线是 manifest-driven:
| Gate | 解决的问题 |
|---|---|
bootstrap | 环境是否具备基本执行条件 |
spec-lint | Spec 结构是否完整,验收标准编号是否连续 |
build | 项目是否能构建 |
lint / type-check | 静态质量是否过线 |
unit-test | 基础行为是否通过 |
ac-coverage | 每条验收标准是否有测试追踪 |
drift-check | Spec 和代码是否开始漂移 |
compliance | 是否有知识引用、澄清记录等过程证据 |
这套卡口的价值不是“高级”,而是“外部”。它不依赖 Agent 自己说自己完成。
随后,pipeline.sh --json-out 会把 gate output、review summary、TDD evidence 和 loop state 汇总成 lattice/state/eval-runs/*.json。这份 JSON 是 Evidence / Eval 的机器事实源,Markdown summary、history、dashboard 和 PR comment 都从它派生。
2. 验收覆盖:把验收标准连到测试
很多团队写了验收标准,但最后测试和验收标准没有关系。结果就是:Spec 写得很好,测试也很多,但没人知道测试到底覆盖了哪个验收点。
Lattice 用一个很土但很有效的方式解决:测试命名追踪验收编号,也就是让每条测试明确对应哪条验收标准。下面示例里的 AC-1、AC-2 只是 Lattice 默认采用的编号格式,你也可以理解为“验收标准 1”“验收标准 2”。
Go:
func TestAC1_RedeemValidCoupon(t *testing.T) {}
func TestAC2_RedeemExpiredCoupon(t *testing.T) {}
Node / TS:
describe("AC-1: 核销有效优惠券", () => {})
it("AC-2: 拒绝已过期优惠券", () => {})
Python:
def test_ac1_redeem_valid_coupon(): ...
然后 ac-coverage.sh 输出矩阵:
| 验收编号 | 验收描述 | 测试函数 | 状态 |
|----|----------|----------|------|
| AC-1 | 创建商品 | TestAC1_CreateItem | 已覆盖 |
| AC-2 | 查询商品 | TestAC2_GetItem | 已覆盖 |
| AC-3 | 商品不存在 | — | 未覆盖 |
这就是最小可用的 Verification evidence:不是看测试总数,而是看验收标准有没有可执行证据。
3. Drift Check 解决“文档和代码谁变了”的问题
Spec 最容易腐化的地方,是接口、数据结构、错误码这些强契约。
Lattice 的 drift-check.sh 先把强契约漂移做成 gate 协议,当前 Go / Gin / GORM 示例已经能演示 route、schema、error code、seed SQL 等检查方向:
| 漂移类型 | 检查什么 |
|---|---|
| DDL drift | Spec 里的 CREATE TABLE 和 ORM model 是否一致 |
| Route drift | Spec API 表和代码路由注册是否一致 |
| Error code drift | Spec 错误码和代码常量是否一致 |
| Seed SQL drift | Spec seed SQL 和 fixture 是否一致 |
| Plugin drift | 用户自定义 OpenAPI / Protobuf / 架构检查 |
这里的关键不是内置支持多少框架,而是协议:任何 drift plugin 只要遵守退出码即可。
drift:
plugins:
- name: proto-check
run: "bash scripts/proto-drift.sh ${SPEC_FILE} ${PROJECT_ROOT}"
退出码约定:
| Exit Code | 含义 |
|---|---|
0 | 通过 |
1 | 失败,可由 Agent 修复后重跑 |
2 | 需要人工介入 |
这比“请 AI review 一下有没有漂移”靠谱得多。AI 可以解释和修复漂移,但是否通过必须由 gate 的退出码和诊断输出决定;Evidence / Eval 再把这些结果沉淀成可复盘、可比较的质量事实。
四、Loop / Learn:让失败进入闭环
有了 Context、Verification 和 Evidence / Eval,还差最后一块:失败怎么回流。
很多 AI Coding 的失败不是“模型不会写”,而是失败信息没有被结构化利用。编译失败、测试失败、漂移失败都只是终端里的一段输出,下一轮 Agent 又重新猜。
Lattice 的最小 Loop 是:
verify -> fail -> fix -> rerun -> pass
└-> retry exhausted -> escalation
当前 pipeline.sh 已经支持最小可用的 Loop:
- • 任一步失败立即停止;
- • 失败后 Agent 可以修复并重跑;
- • 默认最多 3 次重试;
- • 重试耗尽后 exit
2,触发 escalation; - • 在
lattice/state/loops/.json记录 failed step、retry、failure category 和 next action; - • retry 耗尽时生成
lattice/context/drafts/escalation-.md; - • eval run 中嵌入 loop state,后续 summary、history、dashboard 都能汇总。
这看起来简单,但它让 AI Coding 从“自然语言完成声明”变成了“可控循环”。
但这里要守住一个边界:Loop 不是让同一个 Agent 无限自修复、无限自我裁判。更合理的职责拆分是:
| 环节 | 负责什么 | 不能做什么 |
|---|---|---|
| Coding Agent | 实现、修复、补测试、重跑命令 | 不能凭自然语言宣布最终通过 |
| Independent Gates | build、lint、test、验收覆盖、drift check | 不解释业务意图,只给证据 |
| Read-only Reviewer / Human | 审 cannot-verify、残余风险、知识沉淀 | 不直接替执行 Agent 偷改代码 |
| Learn Step | 生成 draft、等待确认后入库 | 不把每次失败自动写成 verified knowledge |
这套分工的目标,是避免“自己写、自己判、自己复盘”的闭环幻觉。
失败要分类,不然没法复盘
建议把失败至少分成这些类别:
| 类别 | 例子 | 默认动作 |
|---|---|---|
| environment | 缺 yq、docker 未启动 | 修环境或提示用户 |
| spec_structure | 缺章节、验收编号跳号 | 修 Spec |
| implementation | build/lint/test 失败 | 修代码 |
| ac_gap | 验收标准没有测试 | 补测试或调整 Spec |
| drift | API/DDL/error code 不一致 | 修代码或更新 Spec |
| compliance | 未引用知识、无澄清记录 | 补记录或人工确认 |
| unknown | 无法判断 | escalation |
失败分类不需要一开始就很复杂。先用 gate name + regex 就够了。Lattice 里可以用 lattice/config/failure-categories.yaml 覆盖默认分类,并用 failure-category-lint.sh 做配置检查。
Escalation 后不要直接污染知识库
很多团队的知识库会越来越脏,是因为每次失败都直接写成“经验”。
更好的方式是先生成 learn draft:
# Draft:创建商品 API 的路由漂移
**失败分类**:drift
**失败步骤**:drift-check
**关联 Spec**:lattice/specs/create-item-api/spec.md
**证据**:Spec 声明了 `POST /items`,但代码里没有注册对应路由。
**建议沉淀**:新增 Gin API 时,需要同时更新 `internal/handler/router.go` 的路由注册,并补充对应的验收编号测试覆盖。
**状态**:draft
人或只读 reviewer 确认后,再通过 knowledge-review.sh 和 learn-draft.sh promote 进入 lattice/context/knowledge/。这样经验会回流,但不会污染 verified knowledge。Loop 的边界也就清楚了:不是无限自修复,而是让失败被分类、被裁判、被升级、被沉淀。
五、展望:Loop 会把一次性提效变成团队复利
前面讲的 Context、Verification、Evidence / Eval,还是围绕单次需求交付。再往后,真正有价值的是 Loop。
没有 Loop,AI Coding 只是一次性加速:这次更快写完,下次仍然从零开始。团队真正需要的是让每次失败、每次 review、每次线上反馈,都能回到研发系统里。
Loop 应该回写四个位置:
| 反馈来源 | 回写到哪里 | 例子 |
|---|---|---|
| Spec 漏约束 | Spec 模板 / 验收标准写法 | 每个幂等需求必须写重复请求语义 |
| Context 缺失 | 项目知识库 / 中心知识库 | 支付 mutation 必须带幂等键 |
| Verification 漏卡口 | Gate / Test / Drift plugin | 新增 error code drift check |
| 执行失败 | Plan 拆分 / Retry 策略 | 某类任务必须拆出独立 RED test |
我理想中的 Loop 不是“Agent 无限自动修”,而是一个有边界、有裁判、有升级机制的状态机:

这里多出来的 Judging 很重要。它代表裁判环节必须独立存在:可以是确定性 gate,可以是只读 reviewer,也可以是人工确认,但不能只是执行 Agent 自己的一段解释。
短期,Loop 的最小心智只需要落三个字段:
failed_step
retry_count
failure_category
中期,要让 pipeline 输出结构化 eval run。Lattice 当前已经在往这个方向走:pipeline.sh --json-out 会产出 lattice/state/eval-runs/*.json,其中包含 pipeline status、metrics、process evidence 和 loop state。形态大概是:
{
"run_id": "2026-06-26T12-34-56Z",
"spec_file": "lattice/specs/create-item.md",
"git_sha": "abc1234",
"pipeline": {
"status": "fail",
"retry_count": 1
},
"metrics": {
"ac_total": 5,
"ac_covered": 4,
"drift_count": 1
}
}
长期,团队才真正能回答这些问题:
- • 哪类需求最容易失败?
- • 哪个 gate 最常拦住问题?
- • 哪些知识条目真的减少了返工?
- • 哪个 Agent / prompt / kernel 版本 first-pass pass rate 更高?
- • 哪些 review 问题应该升级成新的 Eval gate?
这一步才是从“工具提效”走向“团队能力复利”。
六、当前边界
这套东西我现在不会把它包装成生产级平台。它更像一个已经跑通最小闭环的 preview:适合试点、改造和验证团队流程,但还有几个边界要讲清楚。
| 边界 | 当前状态 |
|---|---|
| 语言和框架覆盖 | Go / Gin / GORM 示例较完整,Node / Python drift parser 仍待扩展 |
| Dashboard | 已有静态 dashboard,交互过滤、时间序列趋势和跨项目归因还在演进 |
| 知识治理 | learn draft 有 review / promote / discard 审计,但语义冲突仍需要 reviewer 判断 |
| 自动裁判 | 优先依赖确定性命令和 gate,不把 LLM 主观打分当最终通过条件 |
| 中心化平台 | 当前先稳定 repo-local 文件协议,不急着做服务端平台 |
这也是我更愿意把它叫 Harness,而不是平台的原因:先把控制点、证据和边界跑通,再谈规模化和中心化。
七、把这几句话带走
如果只记住几句话,我希望是这三句:
Spec 解决路径收敛,Harness 解决独立裁判。
Context 要进入 Spec,完成声明要指向外部命令和证据。
Loop 不是无限自修复,而是失败分类、升级和沉淀。
这就是我理解的 AI Coding 下半场:从个人提效,走向团队级正确性工程;从一次性生成,走向可验证、可复盘、可复利的交付闭环。
最后:源码和模板
后面我会继续写 AI Coding、Spec Coding、Context、Verification、Evidence / Eval、Loop 和 Agent 工程化。
如果你想看具体实现,我整理了 Lattice repo-local harness 的源码和模板。私信关键词 lattice,可以拿到:
- 1. 自研
Lattice源码; - 2. Context map 和项目知识示例;
- 3. 验收覆盖检查样例;
- 4. drift-check 模板;
- 5. eval run JSON 和 learn draft 示例。
如果这篇文章对你有启发,欢迎关注、收藏,也欢迎在评论区说说你们团队现在最卡的是哪一段:Spec 太重、Context 太散、Verification 太弱、Evidence 不成体系,还是失败经验无法回流。
如果你还没看上篇,可以先私信关键词 prismspec,领取 PrismSpec 渐进式 SDD skills、需求分级卡片和轻量 Spec 模板,再回来看这篇里的 Harness 和 Loop。
内容效果不满意?点此反馈