SDD文档先行:AI编程时代的高效开发方法论

SDD文档先行:AI编程时代的高效开发方法论 SDD 这个词最近在 AI 编程圈里被反复提起。我最早听到它时以为是“软件设计文档”那套老东西真用起来才发现它跟过去那种先写几十页 Word、再让开发照着做的模式完全是两码事。简单说SDD 就是文档先行在写任何业务代码之前先把你想要的东西用结构化的文档定义清楚再让 AI 编程工具去实现。这套方法论解决的核心问题很直接AI 生成代码的质量天花板往往不取决于模型多强而取决于你喂给它的规格有多清楚。这篇文章我会把我过去一年在真实项目里用 SDD 配合 AI 写代码的完整做法、工具链、踩坑记录都摊开来讲适合正在用或者准备用 AI 写代码的开发者、技术负责人以及 AI 应用产品的同学们参考。1. SDD 不是“多写文档”而是“把规格前置”1.1 一句话说清楚 SDD 和传统文档的本质区别先抛掉对“文档”这个词的刻板印象。传统开发里也有文档需求文档、设计文档、接口文档但绝大多数是“事后补的”。项目启动先开会代码写一半才补设计说明上线以后再整理接口文档给下游用。文档在这套模式里是个“记录者”跟在代码屁股后面跑代码写完了它才登场。SDD 完全反过来。文档在 SDD 里是“契约”是代码的源头。写代码之前你先把问题定义清楚、把输入输出约定清楚、把验收标准写清楚代码只是这份契约的一种实现。所以 SDD 里的文档不是写给评审委员会看的是写给两类读者看的一类是执行者也就是 AI 编程工具和开发工程师另一类是校验者也就是测试用例和代码审查者。文档写得清楚执行者才能做得明白校验者才有依据判断对错。这个区别看起来只是个顺序问题实际影响非常大。我见过很多团队抱怨“AI 写出来的代码不能用”其实不是模型不行而是需求根本没成型就丢给 AI 了。你让 AI“写一个下单接口”它能给你写出十种不同的风格和业务假设但你给它一份“输入什么、校验什么、依赖哪个表、返回什么错误码”的规格它生成的结果基本一次就能对齐。文档先行不是多写东西而是把该想清楚的事提到最前面想清楚让 AI 的每一次输出都建立在确定的语义之上。1.2 AI 编程工具为什么格外需要“文档先行”要解释这个得先理解 AI 代码生成模型的工作方式。本质上这类模型是在做“条件下文预测”根据你提供的上下文和指令预测最可能的后续代码。它不像人那样会追问“你这个需求到底什么意思”你给什么它就顺着什么往下编。如果上下文里只有一句模糊的需求它就只能靠训练数据里的“统计惯性”去猜猜出来的代码自然跟你的真实业务对不上。这跟我们带新人是一个道理。你把一个刚毕业的工程师叫过来说“你去把支付模块优化一下”他一定无从下手。但如果你把现状、目标、约束、边界、验收标准都告诉他他就能独立干活。AI 比新人还更需要规格因为它连“不懂装懂问一句”的能力都没有。所以在 AI 时代文档承担了一个新角色它就是你给 AI 的“超级提示词”。一段写清楚的结构化文档效果远胜过在对话框里反复调 prompt。这个洞察是整个 SDD 方法论的基石理解了这一点你就能明白为什么很多团队换了更强的大模型代码质量却没有明显提升——问题出在输入侧而不在模型侧。1.3 文档先行的适用范围与边界是不是所有项目都要文档先行我自己的实践结论是越是 AI 参与度高、越是业务逻辑复杂、越是多人协作的项目越需要文档先行。反过来一次性的脚本、纯探索性质的 demo、随手验证某个库能不能用的代码直接写就好没必要上流程。SDD 的适用边界可以用一个问题来判断这份代码会不会被别人包括三个月后的你自己维护会不会被 AI 反复改动只要答案是“会”就值得先写文档。这里也给你一个反面提醒文档先行不等于设计先行。SDD 不要求你在一开始就把系统架构、类图、时序图全部画完那是重量级的传统设计流程会拖慢 AI 时代该有的快速试错节奏。SDD 的文档讲究“刚好够用”问题清楚、契约清楚、边界清楚、验收标准清楚剩下的实现细节交给 AI 去探索反而能发挥它生成代码的优势。这个“度”拿捏好了文档先行就是利器拿捏不好就容易退回老路的文档病——写了没人看看了没指导意义纯属增加团队负担。2. 六步实践指南完整走一遍 SDD 流程网上关于 SDD 的讨论很多国内也有人喊出“SDD 六步实践指南”的说法。我结合自己的经验把各种版本收敛成一套一直在用的六步流程每一步都有明确的产出物和检查点。这套流程不是死规矩你可以根据项目大小做裁剪但骨架建议保留。2.1 第一步写清楚问题而不是写清楚功能第一步产出物是“一页纸问题描述”。你要回答四个问题当前痛点是什么、目标用户是谁、成功标准是什么、不做哪些事。注意第四点“不做哪些事”特别关键它是范围控制的第一道防线也是 AI 最容易自作主张的地方。举个例子我最近做一个项目清单助手工具最初的需求是“帮我把每天要做的事自动排优先级”。这个描述写进文档是没法落地的AI 无法知道什么叫“自动排优先级”到底是按截止日期排、按紧急程度排还是按老板喜好排。我改成这样痛点团队成员每天花大量时间在手动整理任务清单跨项目事项互相冲突。 目标用户3 到 10 人规模的产品研发团队。 成功标准用户录入任务后系统根据截止日期和项目权重给出排序建议人工可覆盖调整。 不做不接入日历不做自动调度不做多人协作审批。这样一改AI 就能明确知道边界在哪里不会自作主张去帮你接日历 API也不会给你设计一个审批流出来。很多时候 AI 生成代码“过度发挥”根源就是问题描述里没有“不做什么”的部分。2.2 第二步定义验收标准用例子说话第二步产出物是验收标准列表我强烈建议用“Given-When-Then”格式。这个格式先描述前置条件Given再描述操作When最后描述预期结果Then。它比“系统应该支持排序”这种笼统描述具体得多而且天然适合转化成自动化测试用例。继续拿上面的任务助手举例验收标准可以写成这样Given 一个任务列表为空When 用户添加一条带截止日期的任务Then 新任务出现在清单顶部状态为“待处理”截止日期显示清晰。Given 两个任务截止日期相同When 系统排序Then 权重高的项目任务排在前面。Given 用户将某任务标记为“已完成”When 用户返回清单Then 该任务不再出现在待处理列表但仍可在“完成列表”中查询。验收标准是后面所有工作的锚点。测试用例从它生成AI 生成的代码按它验证连 prompt 都围绕它组织。我在实践里把这步当作 SDD 最不能省的一步省了后面必然返工。一个没有验收标准的需求就像没有评分标准的考试AI 写得再热闹你也没法判断它到底答对了没有。2.3 第三步约定接口契约和数据结构第三步产出物是接口定义。不管你是做 Web 服务、纯函数库还是 AI Agent都需要把“输入长什么样、输出长什么样、错误怎么表达”定下来。现在的项目大量使用 TypeScript我习惯直接写类型定义如果是后端服务OpenAPI 描述文件也是好选择。接口契约是 AI 生成代码时最依赖的部分写得越精确AI 跑偏的概率越低。还是用任务助手举例核心接口长这样type Task { id: string title: string dueDate?: Date projectId: string priority: number // 数字越大优先级越高 status: todo | done | archived } type SortTasksRequest { tasks: Task[] projectWeights: Recordstring, number } type SortTasksResponse { sortedTasks: Task[] reason: string // 说明每条任务排序的依据 }注意这里我连reason字段都定义进去了。这个字段是给 AI Agent 用的——当用户问“为什么这个任务排在最上面”时系统能直接把理由展示出来而不是让用户自己去猜。这样的细节如果不提前在文档里定义AI 生成的代码大概率不会有因为用户没提模型想不到。契约文档的价值就在这把所有业务假设和设计决策固化到接口层面而不是让 AI 在代码里自由发挥。2.4 第四步给出一页纸的实现方案第四步产出物是极简实现方案。不需要写完整架构但要写清楚三件事技术选型、核心数据流、关键算法或规则。这一页纸的目的不是限制 AI而是给它一个“脚手架”让它生成代码时不会跑偏。还是任务助手项目一页纸实现方案可以这样写技术选型前端 React TypeScript后端 Node.js 服务数据存 SQLite排序逻辑先采用规则引擎实现后续再评估是否引入模型。核心数据流前端录入 → 后端保存任务 → 排序服务读取任务和项目权重 → 生成排序结果 → 返回前端展示。关键规则截止日期优先同日期按项目权重排序权重相同的按创建时间倒序。AI 编程工具在生成后端逻辑时如果上下文里有明确的数据流描述它会非常自然地沿着这条线去实现。这一页纸不需要写得很长写多了反而束缚 AI。给它足够的框架和自由度才是正确姿势——大方向你定细节让它发挥这样既保证质量又能享受 AI 编码带来的效率红利。2.5 第五步把文档喂给 AI 生成代码第五步就是正式跟 AI 编程工具协作。这里有个关键技巧不要把六步文档一次性全塞给 AI而是按层次喂。第一步和第二步给 AI“为什么做”的上下文第三步和第四步给“怎么做”的约束然后分模块让 AI 逐个生成而不是让它一口气写出整个系统。我在 Cursor、GitHub Copilot 这类工具里常用的做法是在项目根目录维护一个docs/spec.md文件把前四步的文档都放进去。现在的 AI 编程工具基本都支持将项目文档作为上下文引用比如 Copilot 的workspace、Cursor 的docs都可以直接读取仓库里的文件。接着我会按模块拆任务比如“请根据 docs/spec.md 中排序规则的描述实现 src/sort.ts 的排序函数并导出对应类型”。当 AI 生成完代码后我会把第二步的验收标准改写成测试用例交给同一个 AI 或另一个测试助手去生成测试代码让“验收”这件事也自动化起来。整条链路里文档不是一次性输入而是 AI 每写一段代码时都要回头查阅的“需求真相源”。这样做的好处是对话窗口换了、模型换了、甚至工具换了只要文档还在AI 的输出质量就能保持稳定。2.6 第六步校验结果、同步文档、形成闭环六步法的最后一步是闭环。AI 生成代码后要跑测试、做代码审查然后回头检查文档是否需要修订。因为 SDD 里的文档是“活的”它跟着需求和实现一起演进绝不是写完就束之高阁的“一次性产物”。我习惯在每轮迭代结束前做一个“三方对照”文档里的验收标准、测试用例、AI 生成的实际行为三者必须对齐。任何一方对不上都要找到原因并修掉。如果测试挂了先看是代码实现问题还是验收标准本身写错了如果文档和代码对不上先看是代码没按文档写还是文档没跟上代码的演进。这个习惯帮我避免了大量“文档写了旧的、代码改了新的、测试测的又是另一个”的混乱局面。到这一步一次完整的 SDD 循环就结束了接下来进入下一个需求迭代循环往复文档和代码始终咬合在一起。3. 实操案例用 SDD 让 AI 写一个知识库问答 Agent光讲流程容易飘我拿一个真实的小项目完整演示一遍。这个项目的背景是团队内部有一个散乱的知识库全是 Markdown 文件大家想做一个“问知识库的 AI Agent”输入问题输出答案和出处。这个项目用到 Agent 开发、大模型接入、检索增强、文档处理等多个环节非常适合用来展示 SDD 的完整流程。3.1 从一句话需求到一页纸规格原始需求只有一句话“做一个能回答知识库问题的 AI Agent”。这句话直接丢给 AI它大概率会给你生成一个调用大模型 API 的 demo但完全没有考虑知识库怎么加载、支持哪些文件格式、答案要不要给引用等关键问题。最后你拿到一个能跑但没法用的玩具。按照 SDD 步骤我先把它写成完整规格。成功标准定为用户输入自然语言问题Agent 返回三段式答案——结论、依据、出处文件路径知识库格式限定为 Markdown 文件无匹配内容时明确提示“知识库中未找到相关答案”单文件超过一定大小自动分块。边界定为不支持图片和 PDF不做对话记忆不做权限管理。这些边界条件都是我在和业务方沟通过程中挖出来的如果只盯着原始一句话需求根本不会意识到这些坑。验收标准我写了两条关键的Given 知识库中存在“部署流程”相关文件When 用户提问“怎么部署”Then 返回结论包含部署步骤出处指向对应文件路径。Given 知识库中不存在“预算审批”相关内容When 用户提问“预算怎么审批”Then 提示“知识库中未找到相关答案”不猜测不编造。这两条验收标准直接决定了 Agent 的行为边界。第一条约束了召回的正确性——答案必须有据可查第二条约束了“不胡说八道”——这是问答类 Agent 最容易翻车的地方。很多 AI Agent 在没有可靠答案时会选择“编一个”因为大模型的训练目标就是流畅地接话而 SDD 的验收标准能把这种“接话本能”拦在门外。3.2 把规格文档组织成 AI 友好的上下文规格写好后我把它整理成docs/spec.md结构是项目目标 → 成功标准 → 验收标准 → 接口 → 数据流 → 实现约束。每一层都用清晰的三级标题分隔关键规则用列表逐条列出接口用 TypeScript 类型定义或者 JSON 示例写死。AI 对结构化文本的理解明显优于大段散文这也是 SDD 文档跟传统 Word 文档的一个重要区别——它是“机器优先”的格式人读着也不累。然后我开始让 AI 工具工作。我给 Cursor 发的第一轮任务是“阅读 docs/spec.md先不要写代码帮我确认以下三点知识库加载模块的技术选型、向量化存储用什么方案、答案检索流程怎么设计。”这一步很关键我把它叫作“AI 预审”——让 AI 先读文档、复述它理解到的要求确认理解正确之后再动手。如果它这一步的理解就有偏差我会先改文档而不是跳到写代码这能省下大量返工时间。这种做法对很多开发者的习惯是反着的。大家通常拿到 AI 工具就急着开写写歪了再回来补需求。但 SDD 的思路是“先对齐再动手”把 AI 当作一个需要带教的新同事先确保它听懂了任务再让它执行。多花五分钟做预审往往能省下后面几十分钟甚至几小时的调试时间。3.3 对照验收标准逐项核对生成结果AI 开始生成代码后我没有直接信任输出而是把两条验收标准转成自动化测试。第一条测试构造一个小型知识库目录放入一篇带“部署流程”的 Markdown提问后断言返回结果包含部署步骤和对应文件路径第二条测试只放一篇关于“环境搭建”的文章提问预算审批断言返回的是“未找到”提示。结果第一轮就跑出问题AI 在无匹配时选择了“基于大模型推测答案”它认为这样做更“聪明”但这违反了第二条验收标准。问题根源是文档里写了“不猜测不编造”但生成实现时 prompt 没有把这条验收标准同步过去。我把验收标准原文贴回 prompt 后AI 重新实现了“无匹配即返回提示”的逻辑测试通过。这个案例很典型地说明了 SDD 的运作模式文档先行不是一次性的它是“文档定义行为 → AI 生成实现 → 测试校验行为”的循环。每轮循环都让规格更精确AI 的输出也更稳定。最终这个 Agent 从开始写规格到功能可运行总共花了一个下午其中一半时间是在打磨文档而不是修改代码。放到以前这种带检索增强的 Agent 项目光调研和联调就得两三天SDD 加 AI 编程的组合拳确实把效率拉高了一个量级。4. 配套工具链与工程化落地SDD 如果只是个人习惯价值有限真正让它在团队里产生杠杆效应的是工程化。下面聊一下我目前在用的工具链和协作方式这些工具不是唯一的答案但代表了一条验证过的路径。4.1 用 Markdown OpenAPI 类型定义搭建文档体系我的文档体系分成三层。第一层是docs/spec.md用 Markdown 写面向 AI 和全体成员存放每个模块的需求规格、验收标准、实现约束。第二层是接口契约后端项目用 OpenAPI 描述文件前端和函数库用 TypeScript 类型定义这份契约是代码自动生成的重要输入源也是 AI 生成代码时最常引用的部分。第三层是架构决策记录只有影响到整体方向的决策才写避免文档无序膨胀。这三层之间有明确的分工spec 回答“做什么”接口契约回答“怎么交互”架构决策记录回答“为什么这么定”。每一层都保持精简任何一层超过一定体量就要考虑拆文档。比如一个 spec 文件超过 500 行我会按模块拆成多个 spec 文件并在 README 里维护索引。这个做法类似代码结构的单一职责原则每个文档内聚性好AI 引用起来也不容易混淆团队成员查找信息也更快。4.2 AI Prompt 与文档的绑定策略用 AI 编程时最怕的就是 prompt 和文档脱节。很多人一边维护一份详尽的文档一边在对话框里手写一套跟文档无关的 prompt最后文档成了摆设AI 也得不到准确的上下文。我的策略是“prompt 的最小化原则”能引用文档就绝不在 prompt 里重复写需求细节。比如我在 Cursor 里会直接用docs/spec.md引用整个规格文件然后只补一句“请实现文件列表解析功能遵循 spec 中第 3 章的格式约定”。如果某个项目有比较复杂的领域规则我会在 spec 里单独开一个“AI 提示词要点”小节把最容易让 AI 跑偏的点用显式语句写出来。这样 prompt 变短了上下文也干净AI 反而更聚焦。需要提醒的是不同的 AI 工具对文档引用的支持不太一样。Cursor 支持引用GitHub Copilot 支持workspace语义搜索JetBrains 系的 AI 助手也有类似的上下文功能。不管你用哪家都要先花一点时间搞明白它的文档引用机制这是 SDD 工程化的第一道工序。工具用熟了文档先行才能真正跑起来否则每次都要手动复制粘贴文档内容效率会大打折扣。4.3 把 SDD 接进 CI/CD 和团队协作流文档先行要真正落地光靠自觉不够要把检查点嵌到自动化和协作流程里。我常用三个检查点每个都不复杂但能把文档和代码的同步问题解决掉一大半。第一PR 模板里强制加入“本次改动是否导致文档需要更新”的勾选项不勾选不能提交。这个选项看起来只是个形式但它逼着每个开发者在提交代码前思考一次文档同步问题。第二CI 流水线里加一个文档完整性检查脚本扫描代码里新增的公开函数是否在接口文档中有对应定义扫描验收标准是否都有对应的测试用例标记。脚本逻辑不复杂无非是解析代码里的导出符号、再解析文档里定义的接口清单做对比但能自动挡住很多低级漂移。第三代码审查时审查者除了看代码逻辑还要看“代码行为是否与 spec 描述一致”不一致的需要修改 spec 或代码两者二选一修到一致为止。团队协作层面我建议把 SDD 文档放在与代码同一个仓库里方便 AI 引用和版本追踪。产品经理负责维护第一层需求规格资深工程师负责接口契约和架构决策记录测试工程师把验收标准转化为自动化用例AI 开发助手负责把规格翻译成代码。这个分工让每个角色的产出都沉淀成文档而不是散落在沟通群里的碎片信息。5. 常见问题与避坑经验最后这部分是我最想跟同行分享的全是踩过坑才总结出来的经验。SDD 听起来不难但实际操作中会遇到各种“磨损”把这些坑提前告诉你能省下不少试错成本。5.1 文档写得太重团队坚持不下去这是 SDD 失败最常见的原因。很多团队一听“文档先行”下意识就按传统规格说明书的标准去写一写就是几十页写到第二周就没人愿意动了然后得出结论文档先行不适合我们团队。解决办法是给文档设“字数红线”。我个人的经验是单个模块的 spec 控制在 200 行以内超过就要拆验收标准控制在 10 条以内超过的合并或推迟到后续迭代实现方案那一页只允许写三到五条核心决策。轻量是 SDD 的生命线它跟重量级文档的根本区别不在“写不写”而在“写到什么粒度”。记住一个原则文档的粒度只要精确到能让 AI 不跑偏就够了多出来的都是负担。如果你发现团队在文档上花的时间超过了写代码的时间那一定是什么地方出了问题赶紧砍。5.2 文档与代码漂移最后没人信文档文档和代码漂移是 SDD 的第二大杀手。代码改了文档忘了同步过几个迭代文档就变成“僵尸文档”没人看也没人信。一旦团队失去对文档的信任文档先行这套方法论就彻底崩了。对抗漂移我有三个土办法。第一个是“改代码先改文档”把修改顺序固定成文档在前、代码在后凡是不按这个顺序改的代码不允许合入。第二个是在核心模块的代码注释里写上 spec 文件的链接打开代码就能看到对应文档减少“懒得去翻文档”的心理阻力。第三个是在 CI 里跑一个简单的死链检查确保 spec 里引用的代码路径真实存在——这个检查实现成本低但能挡住很多低级漂移。说到底文档漂移本质上是流程问题不是技术问题要靠习惯和检查点去解决不能靠个人自觉。我在实践中把这个检查做成了项目模板的一部分所有新项目自动带上省心很多。5.3 AI 生成代码与需求不一致先排查文档而不是 prompt很多人在 AI 生成结果不对时第一反应是疯狂调整 prompt来回试十几轮越试越乱。我的建议是先回头改文档。因为 prompt 是即时性的改 prompt 只影响当前这一次输出而文档是持久性的改文档影响所有后续生成包括新开的对话窗口。AI 生成结果与需求不一致大概率是文档里某条规则表述有歧义、遗漏了边界条件、或者验收标准本身写得互相矛盾。把这些问题在文档层面修好AI 下一轮的输出会明显改善。反过来如果你在 prompt 里强行修正AI 虽然这次做对了但下次换个对话窗口同样的错误还会再来因为根本问题在文档里没解决。这个经验我几乎每次都会用上。有一次 AI 生成的任务排序函数总是把“已完成任务”混进待处理列表我调了三次 prompt 都没效果最后检查文档发现验收标准里只定义了“已完成任务不出现在待处理列表”但接口的数据流描述里没有给出过滤的触发时机。把数据流补清楚后AI 一次就写对了。文档比 prompt 更重要这就是 SDD 的核心理念在排错场景下的体现。5.4 常见问题速查表我把这些年踩过的坑整理成一个速查表方便你按图索骥。这六类问题是我在项目中被问得最多、也最容易反复出现的对应排查顺序都是亲身验证过的。症状可能原因排查顺序AI 生成的接口字段跟文档不一致文档接口定义不够明确被 AI 自由发挥先核对文档中的类型定义再检查 prompt 是否引用了最新的 specAI 总返回编造的答案问答类 Agent缺少“不支持时如何响应”的验收标准在验收标准中显式定义未知问题处理规则并同步到 prompt文档与代码逐渐对不上缺少同步检查点检查 PR 勾选项、CI 死链检查、代码注释中的 spec 链接团队不愿意写文档文档粒度太粗或太重设置字数红线拆小模块让文档只记录关键决策和契约AI 在不同会话里行为不一致prompt 没绑定统一文档各聊各的使用 引用把 spec 嵌入上下文prompt 只写增量指令测试用例无法对应需求验收标准不可测或过于笼统用 Given-When-Then 格式重写验收标准逐条映射测试用例最后再分享一个我个人的体会。以前我带项目总觉得代码写得快是本事代码写得好看是本事直到 AI 编程普及以后我才发现真正的本事是把“想做什么”这件事说清楚的能力。SDD 本质上练的就是这个能力你用文档把模糊的想法变成精确的规格AI 才有机会帮你把规格变成高质量代码。从我这一年的实践看文档在 SDD 里花的时间不是成本而是杠杆——前面想得越清楚后面返工越少AI 用起来也越顺手。下次你准备让 AI 写代码之前可以先问自己一句如果我把这份文档交给一个新人他能不追问就做出我想要的东西吗如果能再打开你的 AI 编程工具不迟。