EDD:证据驱动开发——让 AI 编程从“聊天“变成可验证的工程流程
摘要: 本文提出 EDD(Evidence-Driven Development)范式,通过双层架构和类型化前置矩阵,将 AI 辅助软件开发从不可观测的黑盒对话,转变为可验证、可审计、可复现的工程流程。EDD 不约束模型"怎么做",但要求模型在进入下一阶段前,必须产出可验证的中间工件。
实践
npm i -g peaks-cli
一、AI 编程的三个时代,以及同一个盲区
过去三年,AI 辅助软件开发经历了三次范式跃迁:
- 提示词工程(Prompt Engineering):精心构造一次性输入,让 Codex 等模型生成代码。产出有用但缺乏迭代和工作流支持。
- 氛围编程(Vibe Coding):2025 年由 Karpathy 提出的术语,指的是开发者通过对话式交互"感受"代码,工具如 GitHub Copilot、Cursor 提供行内建议。提升了生产力,但流程执行的全部负担仍在人类开发者身上。
- 约束模式(Harness Mode):当前最前沿,通过定义工具权限、Hooks 和子代理委托来编排 AI 代理。SWE-Agent、OpenHands、AutoGen、MetaGPT 等系统提供了能力级约束——控制代理"能用什么工具"以及多个代理如何交互。
但这三种范式共享一个根本性局限:它们约束的是 AI 能用什么工具,而不是 AI 必须产出什么中间工作产物、以什么顺序产出。
这意味着什么?一个处于约束模式下的 LLM 仍然可以:
- 跳过架构分析,直接写代码
- 不写测试用例就提交
- 绕过代码审查
- 产出不可审查的变更历史
更严重的是,约束模式没有可靠的方式来检测模型何时悄然偏离了它声明的任务。一旦漂移发生在会话的不透明中间段,结果不是一个"减速",而是一个风险:一个编译通过但有缺陷的重构、一个没有测试覆盖的授权检查、一个从未产出的安全审查。
一个具体的例子
假设一个需求是添加认证端点。在约束模式下,一个宽松的代理可以:读取需求 → 直接写端点 → 运行现有测试套件 → 打开 PR——整个过程没有产出技术设计、安全审查、测试计划,也没有记录其新测试覆盖了哪些验收标准。
每个单独的工具调用都是有效的;但整个工作流不是。
如果缺失的授权检查在设计阶段被发现,修复是 5 分钟改一个 Markdown 文件;如果在单元测试阶段被发现,需要重新编译;如果在生产环境被发现,那就是事故报告、值班轮转、潜在数据泄露和事后合规审查。
发现同一个缺陷的成本,在每个阶段之间以数量级增长——而约束模式没有任何结构化机制来尽早发现它。
二、EDD:从"约束工具"到"约束证据"
我们提出**证据驱动开发(Evidence-Driven Development, EDD)**作为这个演进的下一步。
EDD 的核心洞察是:
AI 辅助开发应该遵循标准操作流程(SOP)——一个定义好的工程阶段序列,每个阶段产出可验证的中间工件——但不约束模型如何完成每个单独的步骤。
约束模式限制代理"能调用什么工具";EDD 限制的是"在流程推进之前,什么证据必须存在"。模型在每个阶段内保留完全的创造性自由;它只需要在进入下一阶段前证明自己完成了当前阶段。
EDD 不发明新方法论
软件行业已经花了几十年精炼基于角色的 SOP——需求、设计、实现、审查、测试、变更控制、知识沉淀——贯穿瀑布、螺旋、敏捷、CMMI 和阶段-关口传统。这些 SOP 是有效的;在 LLM 时代缺失的,是一种让它们对速度超过任何人类审查者实时监督能力的代理可执行的方式。
EDD 的贡献不是 SOP 本身,而是让现有 SOP 对 AI 协作者可执行的机器可检查关卡。
三、双层架构:声明与执行的彻底分离
EDD 通过双层架构实现,将声明式工作流描述与命令式工作流执行彻底分离:
┌─────────────────────────────────────────────┐
│ 声明式层(Skills) │
│ 角色、状态机、必需工件、行为边界 │
└──────────────────┬──────────────────────────┘
│ 声明
▼
┌─────────────────────────────────────────────┐
│ 命令式层(Runtime) │
│ 前置检查 → 允许通过 / 阻止(exit 1) │
└──────────────────┬──────────────────────────┘
│ 验证
▼
┌─────────────────────────────────────────────┐
│ 会话工作空间(文件系统) │
└─────────────────────────────────────────────┘
架构不变量:Skills 描述"应该发生什么";Runtime 是"实际发生了什么"的唯一事实来源。LLM 可以提议状态转换(例如,将开发角色从 implemented 移动到 qa-handoff),但如果前置工件文件不在磁盘上物理存在,Runtime 会以非零退出码拒绝转换。LLM 被物理性地阻止继续,直到它产出所需的中间工件。
七个角色技能
EDD 定义了七个角色,每个负责软件开发的一个明确阶段:
| 角色 | 职责 |
|---|---|
| Orchestrator | 编排门面。选择执行模式(全自动、辅助、集群、严格),协调角色交接,执行跨角色关卡序列 |
| PRD | 产品需求。定义目标、非目标、验收标准和前端增量 |
| UI | 用户界面设计。确立视觉方向、排版、色板、交互约束和无障碍最低要求 |
| RD | 研发。产出项目扫描、技术文档、切片规格、代码审查、安全审查和实现证据 |
| QA | 质量保证。生成测试用例、测试报告、回归矩阵、安全发现和浏览器 E2E 证据 |
| SC | 源码控制和变更管理。记录变更影响、工件留存、提交边界和回滚点 |
| TXT | 知识压缩。产出上下文胶囊、决策记录和从工作流中提取的可复用经验 |
每个角色运行一个固定的有限状态机。例如 RD 角色的状态流转:
draft → spec-locked → implemented → qa-handoff → handed-off
任何非终止状态都可以转换到 blocked,表示工作流遇到了不可恢复的条件(例如超过修复周期上限)。
角色间的工作流
PRD → UI → RD → QA → SC → TXT
│
└── return-to-rd(≤3次修复循环)
│
└── cap reached → blocked → TXT
四、类型化前置矩阵:EDD 的核心机制
EDD 的核心执行机制是类型化前置矩阵。对于每种请求类型和目标状态转换的组合,矩阵指定了在允许转换之前必须物理存在于会话工作空间目录中的一组工件文件路径。
请求类型分类
每个 EDD 工作流会话被分配六种请求类型之一:feature、bugfix、refactor、docs、config、chore。类型决定了门控的严格程度:
| 类型 | 门控严格度 |
|---|---|
feature / refactor |
最严格:全套中间工件 |
bugfix |
较轻量:用 bug 分析文档替代完整技术文档 |
config |
仅需安全审查 |
docs / chore |
无工件门控 |
关键设计:声明的类型会与版本控制 diff 的文件类别分解进行交叉验证。如果一个分类为 docs 的工作流显示了源文件的变更,验证会报告 consistent: false 并阻止推进——防止 LLM 通过错误分类工作来跳过门控。
前置矩阵示例
| 转换 | feature / refactor | bugfix | config | docs / chore |
|---|---|---|---|---|
prd:handed-off |
prd/req/<rid>.md† |
同上 | 同上 | ∘ |
rd:implemented |
rd/tech-doc.md |
rd/bug-analysis.md |
∘ | ∘ |
rd:qa-handoff |
tech-doc + rd/code-review.md + rd/security-review.md |
bug-analysis + code-review + security-review | security-review | ∘ |
qa:running |
qa/test-cases/<rid>.md |
同上 | ∘ | ∘ |
qa:verdict-issued |
test-cases + qa/test-reports/<rid>.md + qa/security-findings.md + qa/performance-findings.md |
test-cases + test-report + security-findings | security-findings | ∘ |
† PRD 工件还要求文件内容中包含 ## Goals 和 ## Acceptance 段落标题。
核心检查逻辑(TypeScript)
type Prereq = {
relativePath: string; // e.g. "rd/code-review.md"
description: string;
mustContain?: ReadonlyArray<string>;
};
async function checkPrerequisites(
sessionId: string,
requestType: RequestType,
transition: `${Role}:${State}`,
): Promise<{ ok: boolean; missing: ReadonlyArray<Prereq> }> {
const required = PREREQUISITES_BY_TYPE[requestType]?.[transition] ?? [];
const missing: Prereq[] = [];
for (const prereq of required) {
const path = resolveInsideWorkspace(sessionId, prereq.relativePath);
if (!(await fileExists(path))) {
missing.push(prereq);
continue;
}
if (prereq.mustContain) {
const body = await readFile(path, "utf8");
const lower = body.toLowerCase();
const absent = prereq.mustContain.filter(
(marker) => !lower.includes(marker.toLowerCase()),
);
if (absent.length > 0) missing.push(prereq);
}
}
return { ok: missing.length === 0, missing };
}
这个函数很小,但它是 EDD 执行力的核心:声明式前置条件从类型矩阵中查找,然后逐一对文件系统进行验证。任何缺失或内容不完整的工件都会引发结构化错误,CLI 以退出码 1 表面化处理。
五、反漂移机制:让 LLM 偏离变得可见且可阻止
LLM 辅助开发的一个关键挑战是模型可以从声明的状态中漂移——声称在做 X 实际在做 Y,或静默跳过步骤。EDD 部署了四种独立的反漂移机制:
1. 技能存在性过期检测
每个活跃技能将其存在信息(技能名、执行模式、当前关卡)写入工作空间的已知位置。项目仪表板命令检查 setAt 时间戳;如果超过 24 小时,存在性被标记为过期,工作流被阻止。
解决的问题:LLM 声称某个技能处于活跃状态,但早已漂移到不相关的工作。
2. 类型合理性检查
类型合理性验证将声明的工作流类型与版本控制 diff 的文件类别分解进行对比。如果声明的是 docs 但 diff 中出现了源文件,验证报告 consistent: false,阻止推进。
解决的问题:LLM 将功能工作错误分类为 docs 或 chore 来跳过工件门控。
3. 修复周期上限
当 QA 返回 return-to-rd 裁决时,工作流进入修复循环。修复状态操作通过解析 RD 工件体中匹配周期号模式的转换笔记来计数。达到 3 次周期时,atCap 被设为 true,阻止进一步转换,强制执行 blocked 交接。
解决的问题:RD-QA 修复循环可以无限继续。
4. Runbook 审计
Skill-doctor 操作解析每个技能定义的 runbook 部分,搜索缺少授权邻近注释(例如"仅在用户明确批准后运行")的破坏性 apply 命令。未门控的 apply 调用会导致 Runtime 以错误退出。
解决的问题:技能静默包含自我授权的破坏性命令。
六、六大已知失效模式的覆盖
EDD 在设计层面覆盖了 AI 辅助开发中六种常见失效模式:
| # | 失效模式 | 问题描述 | EDD 处理方式 |
|---|---|---|---|
| 1 | 跳过架构分析 | LLM 直接实现,不分析现有代码库 | rd:implemented 关卡强制要求技术设计文档 |
| 2 | 省略测试 | LLM 生成代码但不生成对应测试 | qa:running 关卡要求测试工件存在;验收覆盖率扫描验证每个 PRD 验收标准都有对应测试 |
| 3 | 绕过代码审查 | 产出未经审查的代码 | rd:qa-handoff 关卡要求代码审查和安全审查工件 |
| 4 | 工作流分类作弊 | 将功能工作分类为 docs 跳过门控 |
类型合理性验证将声明类型与 VCS diff 交叉对比 |
| 5 | 无限修复循环 | RD-QA 修复循环无限继续 | 修复周期上限为 3 次,达到上限强制 blocked |
| 6 | 未记录决策历史 | 多轮 AI 开发后无结构化的决策记录 | 每次状态转换记录带时间戳的笔记;SC 边界记录提交哈希和工件路径 |
七、跨模型审计:单模型自查升级为多模型交叉验证
EDD 最具架构意义的特性之一是跨模型审计。
因为每个 EDD 阶段将其工作产物作为已知位置的纯文件发出,这些文件可以被任何 LLM 读取,而不仅是产出它们的那个模型。这使得跨模型审计成为一等公民能力:第二个模型可以被指向 rd/code-review.md 或 qa/security-findings.md,要求它针对所描述的源码验证工件——无需共享上下文窗口,也不会继承作者的盲区。
约束模式在结构上做不到这一点——当单个会话结束时,其中间的推理过程就消失了。
三种审计模式
-
二审意见(Second-Opinion Review):模型 A 产出
rd/code-review.md;模型 B(不同厂商或不同规模级别)独立阅读相同的 diff 并写rd/code-review.second-opinion.md。两者之间的实质性分歧阻止转换,直到人工裁决。 -
专家路由(Specialist Routing):通用模型处理 PRD 和 RD 阶段,安全专业模型被专门调用审计
rd/security-review.md和qa/security-findings.md。路由是按工件的,不是按会话的——保持通用模型的吞吐量,同时将安全关键的注意力集中在真正重要的地方。 -
对抗性审计(Adversarial Audit):审计模型被明确提示寻找缺口——缺失的测试用例、未处理的错误路径、威胁模型覆盖漏洞——并将发现写入专用工件。产出阶段的状态在对抗性发现被解决或通过审计逃逸舱显式豁免之前不能推进。
八、五分钟上手:如何在现有项目中叠加 EDD
EDD 设计为在现有约束模式编码代理之上叠加,无需重写。目标是让采用成为"几小时"的事,而不是"几周"。
第一步:选择最小角色集
从三个角色开始,而不是七个:prd、rd、qa。第一天跳过 UI、SC、TXT 和 Orchestrator。最小可行的 EDD 切片是:
prd:handed-off → rd:implemented → rd:qa-handoff → qa:verdict-issued
这已经获得了大部分价值:一个带有明确目标和验收标准的 PRD、进入 QA 前的代码审查和安全审查、以及与测试报告关联的最终裁决。
第二步:布置工作空间
.peaks/
2026-05-26-password-reset/
prd/
req/REQ-1247.md
rd/
tech-doc.md
code-review.md
security-review.md
qa/
test-cases/REQ-1247.md
test-reports/REQ-1247.md
security-findings.md
隐藏目录让工件不妨碍正常的源码控制浏览,同时仍然可版本化。每个会话是一个独立文件夹;检出旧提交会揭示产出它的完整工件链。
第三步:接入一条执行命令
实现一个 CLI 命令 transition <role> <newState>,执行前置检查并在失败时以退出码 1 退出。通过系统提示或技能定义指示代理:必须在每次状态转换时调用此命令,且在非零退出码时不得继续。
这一个集成点就是将对话转变为门控工作流的关键。
为了更高级别的保障,还可以在 git pre-commit hook 中调用相同的命令,以便即使代理忘记调用,门控也会被执行。
第四步:按项目调优
最小矩阵可以按项目收紧或放松:
- 收紧:添加
mustContain标记(例如 RD 技术文档必须包含## Risks;QA 测试报告必须包含## Coverage) - 放松:扩大请求类型分类范围(创业原型代码库可以将所有变更视为
feature,但去掉安全审查前置条件) - 审计:每周审查转换笔记,查看哪些关卡最常被逃逸舱绕过,相应地提升或移除那些关卡
九、SOP 配置文件:不同项目,不同关卡
不同项目有不同的 SOP。受监管的医疗设备团队和两人的创业 MVP 不应该共享相同的关卡集,即使两者都从 EDD 的执行机制中受益。
EDD 提供SOP 配置文件——一个小型的命名、预配置前置矩阵库:
| 配置文件 | 必需关卡 | 典型用途 |
|---|---|---|
startup-mvp |
仅 PRD 目标/验收;安全审查可选;QA 测试按需 | PMF 前产品,创始人每天都在动,吞吐量比审计重要 |
growth-saas |
完整 PRD;RD 技术文档 + 代码审查 + 安全审查;QA 测试用例 + 测试报告;SC 边界记录 | 默认配置。多人团队,付费客户,变更历史必须可审查 |
regulated |
growth-saas + 威胁模型工件 + 可追溯性矩阵;类型合理性严格;逃逸舱禁用 |
金融、医疗、汽车等有外部审计员的领域 |
open-source-lib |
PRD 目标;RD 技术文档 + 代码审查;QA 测试用例 + 基准报告;CHANGELOG 作为 SC 工件 | 有外部贡献者的库或框架 |
配置文件是一等公民:可版本化、可继承(regulated-finance 扩展 regulated 并添加交易监控工件)、可项目本地化(.peaks/profile.json 提交到仓库,确保每个贡献者的 Runtime 应用相同的关卡)。
十、事故响应:从"调 diff"到"走工件链"
EDD 的关卡主要是预防性的:让缺陷从引入阶段逃脱变得昂贵。但没有预防系统能捕获一切,成熟的工程流程还必须支持少数确实到达生产环境的事故。
EDD 通过驱动关卡的同一条工件链来处理这个问题。
每个 SC 提交边界记录将特定的提交哈希链接到产出它的会话;会话目录又包含 PRD 需求、RD 技术文档、代码审查和安全审查工件、QA 测试用例和测试报告,以及任何审计工件。
因此,值班工程师响应事故时可以回答一个 diff 无法回答的问题:
- 这个场景在原始验收标准中吗? → 检查
prd/req/*.md - 安全审查考虑了这个威胁吗? → 检查
rd/security-review.md - 哪些测试用例声称覆盖了这个代码路径? → 检查
qa/test-cases/*.md
工件链是从问题提交向后追溯的,而不是从记忆中向前重建的。
这在三个工作流中尤为重要:
-
根因分析:事故后的第一个问题是故障模式是否被预判。EDD 通过检查对应提交的
rd/security-review.md和qa/test-cases/*.md,在几分钟内就能给出答案——而不是要求原作者回忆六个月前的一个决策。 -
无责复盘:工件链捕获了决策的"为什么",而不仅仅是"改了什么"。复盘可以聚焦于"是哪个关卡让缺陷通过了"——缺失的
mustContain标记?逃逸舱被调用了?配置文件太宽松?——而不是归咎于个人。 -
关卡加固:一旦根因被识别,修复通常是一个前置矩阵变更(添加标记、将可选关卡提升为必需、收紧配置文件)。复盘结果直接流回执行运行时,关闭了事故学习与预防系统之间的循环。
十一、与约束模式的关系:不是替代,而是包裹
EDD 不是约束模式的替代品——它是约束模式之上的一层,就像约束模式没有替代氛围编程,氛围编程没有替代提示词工程一样。
| 层级 | 范式 | 约束什么 |
|---|---|---|
| 会话级 | 约束模式 | 代理在会话内能访问哪些工具 |
| 工作流级 | EDD | 哪些工程阶段必须完成、必须产出什么证据、阶段的顺序 |
在成熟的 AI 辅助开发流水线中,两层同时存在。EDD 中的每个关卡本身可以作为约束模式会话执行:PRD 阶段在阻止代理修改源文件的约束下运行;RD 阶段在授予代码编辑工具但阻止部署的约束下运行;QA 阶段限制代理只能使用验证和报告工具。
EDD 确保正确的阶段以正确的顺序发生;约束模式确保每个阶段内发生正确的行为。 两者共同形成一个二维安全网:会话深度 × 工作流广度。
十二、设计哲学:编码,而非发明
EDD 最好被理解为一种编码(codification),而非发明。EDD 执行的角色分解、门控推进和工件前置条件,与 Cooper、Humphrey、CMMI 和更广泛的 SDLC 文献所记录的是相同的。
在 LLM 时代缺失的是一种让这些长期存在的 SOP 对运行速度超过任何人类审查者实时监督能力的协作者可执行的方式。EDD 的贡献是文件系统检查关卡,而非 SOP 本身;因此团队可以在不学习新方法论的情况下采用 EDD,人工编写的工件与 AI 编写的工件满足相同的门控。
价值排序是有意的:安全 → 可审计性 → 吞吐量。
一个以 30% 更快速度交付功能但静默省略安全审查的 AI 代理,不是生产力提升,而是一个被推迟的事故。软件工程经济学中有一个经典的论点:修复缺陷的成本在相邻阶段之间以数量级增长。EDD 本质上是 Shift-Left 的结构化实现:通过使每个阶段的中间工件成为推进的前提条件,原本会在 QA 或生产环境中暴露的缺陷被迫在已经需要审查的工件中暴露——在那里修复是一个 Markdown 编辑,而不是一个热修复部署。
十三、面向未来
EDD 有几个有前景的扩展方向:
-
工件质量评分:当前 Runtime 验证工件存在性和结构完整性,但不评估内容质量。轻量级的基于 LLM 的质量评分(例如评估 PRD 的具体性或代码审查的彻底性)可以在不增加人工审查开销的情况下加强门控。
-
多开发者工作流:扩展阶段-关口模型以支持并发分支、工件级别的合并冲突解决和团队级别的关卡审批。
-
形式化跨模型审计协议:将跨模型审计模式形式化——审计工件的模式、分歧解决策略、置信度加权的关卡决策,以及哪些模型组合能捕获哪些失效类别的实证表征。
总结
AI 辅助开发正在从"约束工具"走向"约束证据"。EDD 提出了一种务实的、立即可采用的架构:任何使用约束模式编码代理的团队,都可以在一个下午内将双层模式叠加到他们现有设置之上,将 AI 会话不透明的中间段转变为可寻址、可审计的工件链。
核心理念很简单:
不约束模型"怎么做",但要求模型"证明做了"。
在安全必须优先于吞吐量的场景中,这不是一个权衡——这是一个必要条件。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)