这两年我最大的感受是:AI 编程工具已经足够强,但绝大多数人用不好它,问题不在模型,而在方法。
你有没有过这种体验——让 AI 写个功能,它咔嚓一下给你吐出一大段代码,能跑,但你不敢改,改一处崩三处,加个字段就要重构。你说“帮我加个删除功能”,它把整个 Service 层都给你重写了。几次下来,代码比你自己写还难维护。
我摸索了很久,最后发现破局点不是更好的提示词,而是换一套开发思路:SDD(Spec-Driven Development,规格驱动开发)。简单说就是先写清楚“软件应该做什么”,再让 AI 写“怎么实现”。这套方法和 AI 编程结合起来,效果比我用过的任何提示词技巧都明显。这篇文章是我这段时间的实战笔记,适合正在用 AI 写代码但觉得失控的人,也适合想把 AI 从“代码生成器”升级成“协作者”的开发者。
1. SDD 是什么,以及它为什么在 AI 时代重新被重视
1.1 一句话理解 SDD 的核心思想
SDD 不是什么新东西。它的核心思想就一句话:先写规格,后写代码。规格(Spec)描述的是软件的行为、输入输出、约束条件,而不是具体的实现方式。传统开发里,规格往往以需求文档、接口文档、设计文档的形式存在,但大多数团队写文档是走过场,代码写完文档就进回收站了。
AI 时代把这事彻底改变了。因为 AI 写代码的依据就是你给它的文字描述。你给得越模糊,它写得越随意;你给得越精确,它写得越贴合需求。规格说明刚好就是“精确描述”的最佳载体。换句话说,SDD 过去是软件工程里的一门“纪律”,现在变成了使用 AI 编程时的“杠杆”。
我试过直接让 AI“写一个用户注册接口”,它确实能写出来,但参数命名风格、错误处理方式、返回结构每次都不一样。而当我先把接口规格写清楚,包括请求字段、校验规则、响应结构、异常码定义,再扔给 AI,它生成的质量直接上一个台阶,几乎不用返工。
1.2 为什么 AI 编程让 SDD 从“文档负担”变成“核心生产力”
过去写规格文档最大的问题是:投入产出比低。你花三天写文档,开发还不一定看,看了也不一定按文档写。所以敏捷开发盛行之后,大家恨不得连设计文档都省了。
但 AI 编程出现后,情况反过来了。
第一,AI 没有“直觉”。人读需求能脑补出上下文,AI 只能从你给的文本里推理。规格说明就是它的“上下文”,写得越完整,它就越接近你心里的“标准答案”。第二,AI 没有“责任心”。它不会主动问你“这个字段要不要校验”“这个异常要不要处理”,你不写清楚,它就默认不做。规格里写清楚每条约束,它就会老老实实加上。第三,AI 的产出需要验收标准。你怎么判断 AI 写的代码对不对?靠测试。而规格恰恰是写测试用例的最佳蓝本。先有规格,再有测试用例,然后再让 AI 实现,这就形成了一个完整的闭环:规格指导测试,测试验证代码,代码反馈规格。
所以我的结论是:在 AI 编程工作流里,规格文档不是负担,而是你用来“遥控” AI 的遥控器。没有规格,你只能在 AI 给的代码上拆东墙补西墙;有了规格,你可以在动手之前就把大部分坑填平。
1.3 SDD 和 TDD、DDD 的关系,别搞混
既然聊到方法论,顺便说一下 SDD 和另外两个常见缩写的关系。TDD(Test-Driven Development,测试驱动开发)是先写测试再写实现,重点关注“代码是否正确”;DDD(Domain-Driven Design,领域驱动设计)是先建领域模型再写代码,重点关注“业务逻辑如何映射到代码”。SDD 关注的是“系统应该有什么行为”,它比 TDD 更靠前一步,比 DDD 更轻量、更通用。
实际使用中它们并不冲突。我现在的工作流是:用 SDD 写清楚行为规格,然后从规格直接生成测试用例,这相当于把 TDD 的“测试先行”也一起做了。至于 DDD,如果项目足够复杂,我才会在规格里加入领域模型描述。对小项目、原型项目来说,SDD 加 AI 已经是性价比最高的组合。
2. 用 SDD + AI 开发软件的完整工作流
2.1 五个阶段:需求梳理、规格编写、任务拆分、AI 编码、验证反馈
整套流程可以分成五个阶段,我按平时执行的顺序列一下:
- 需求梳理:把模糊的想法变成明确的功能列表。这阶段不碰任何代码,只回答“系统要做什么”。我习惯用一页纸把所有功能点写下来,每个功能点一句话说清楚。
- 规格编写:把功能列表变成可验证的规格。每个功能点展开成输入、处理、输出、约束、异常五部分。这是整个流程的核心阶段,占的时间也最长。
- 任务拆分:把规格拆分成 AI 能够一次完成的小任务。每个任务对应一个文件、一个接口、一个组件,大小控制在 AI 一次能正确完成的范围内。一个经验值是单个任务生成的代码量不超过 300 行。
- AI 编码:把单个任务的规格作为提示词喂给 AI,让它生成实现代码。这阶段需要做上下文管理,必要的时候把相关文件内容也传给 AI,但每次只给它看它需要的那一小部分。
- 验证反馈:运行测试、检查代码、把发现的问题反馈给 AI 修复。这个阶段要像审普通人代码一样审 AI 的代码,发现问题就用带上下文的反馈让它改,而不是直接手动改。
这五个阶段里,最容易跳过的就是第二阶段“规格编写”。很多人(包括我最初)觉得,功能都想清楚了,直接让 AI 写不就行了,为什么还要多写一份文档?但实际跑过一次完整流程你就知道,跳过规格省下的一小时,后面至少用三小时来填。AI 生成的代码会缺校验、缺边界处理、缺统一异常结构,最后你花在“缝缝补补”上的时间远超写规格的时间。
2.2 规格说明书怎么写:一个可以直接套用的模板
我写规格有一套固定模板,无论项目大小都按这个来。这里用“用户注册功能”举个例子:
## 功能名称 用户注册 ## 功能描述 用户提供手机号、密码和昵称,系统验证后创建账号,并返回用户信息。 ## 输入规格 - phone:string,必填,11 位数字,需以 1 开头 - password:string,必填,8~20 位,需包含字母和数字 - nickname:string,必填,1~20 个字符 ## 处理逻辑 1. 校验输入参数,任一不合法则返回对应错误码 2. 检查手机号是否已注册,已注册则返回错误码 REGISTERED 3. 密码使用 bcrypt 加密后入库 4. 生成用户 ID(UUID)和初始用户状态 ## 输出规格 - 成功:返回 201,响应体为 { id, phone, nickname, createdAt } - 失败:返回 400,响应体为 { code, message } ## 错误码 - PARAM_INVALID:参数校验失败 - PHONE_REGISTERED:手机号已注册 - INTERNAL_ERROR:服务内部错误 ## 约束条件 - 需要在事务中处理用户创建和初始记录写入 - 密码明文禁止出现在日志中这个模板的好处是,它把所有 AI 需要知道的信息都结构化地表达出来了。输入输出、错误码、约束条件,每一项都是 AI 生成代码时容易遗漏或乱发挥的地方。你把这个模板填好,后面不管是直接丢给 AI 生成代码,还是丢给 AI 生成测试用例,它都能给出高质量结果。
规格不是越详细越好,而是关键信息不缺失。什么是关键信息?会影响代码行为的都算。比如字段是否必填、长度限制、唯一性约束、错误码定义、事务要求——这些如果不写,AI 就会自己发挥,而它发挥的方向往往不是你想要的。
2.3 AI 编程工具怎么选:通用型、IDE 插件、Agent 型工具怎么搭配
规格写好了,接下来要选工具。现在市面上的 AI 编程工具大致分三类,我用下来各有适用场景。
第一类是通用型大模型,比如 ChatGPT、Claude、Kimi 这类,直接在网页里对话。适合做前期规划和方案讨论。我会把规格文档贴上去,问“这个模块有没有更好的设计思路”“这里还有什么边界情况我没想到”,让它在“设计层面”帮我补充。这类工具的好处是对话上下文长,适合一次性处理整个规格文件;坏处是它对项目代码没有感知,生成的代码需要你自己贴到项目里。
第二类是 IDE 插件,比如 GitHub Copilot、通义灵码、CodeGeeX,以及 PyCharm 里的 AI Assistant。它们能读取你当前打开的文件,在编辑器里直接补全代码,适合在“实现阶段”用。比如根据规格提示词,在编辑器里让它补全函数体、生成测试用例、修复报错。我实际用下来,这类工具对“改动现有代码”的场景比通用大模型更顺手,因为它能看到你项目里的真实类名、函数名、导入路径,不用你反复解释。
第三类是 Agent 型工具,比如 Cursor、Windsurf,以及基于自建流程的 AI Agent。它们能自主地读取项目目录、修改多个文件、运行命令。这类工具潜力最大,也最容易翻车——如果规格不清楚,它会用最“想当然”的方式把功能写出来,而且一次动很多文件,出问题不好排查。我的建议是:Agent 型工具必须配合前面说的“小任务拆分”使用,让它在明确的小范围内自主执行,而不要让它一口气把一个模块全部写完。
我的日常搭配是:方案讨论用通用大模型,单文件实现用 IDE 插件,跨文件重构或批量生成测试用 Agent 型工具。工具不用多,关键是你手里有一份写得足够好的规格,换什么工具都好使。
3. 核心实操:把规格变成 AI 看得懂的提示词
3.1 从规格到提示词的一个完整示例
规格写完了,怎么喂给 AI?直接整个文档复制进去?可以,但效果不是最优。因为规格文档里有相当一部分是给人看的背景说明,AI 需要的是“任务定义 + 约束条件 + 验收标准”这三件事。
我通常会把规格转换成“任务式提示词”,模板大概是这样的:
请实现以下功能。 【功能名称】 用户注册接口 【输入参数】 - phone: string, 必填, 11位数字, 以1开头 - password: string, 必填, 8-20位, 包含字母和数字 - nickname: string, 必填, 1-20个字符 【处理流程】 1. 参数校验失败返回 400 + {code: "PARAM_INVALID", message: "<具体原因>"} 2. 手机号已注册返回 400 + {code: "PHONE_REGISTERED", message: "手机号已注册"} 3. 密码使用 bcrypt 加密 4. 创建用户记录, 返回 201 + 用户信息(不含密码) 【技术栈】 - Python 3.11 - FastAPI - SQLAlchemy 2.x - MySQL 8.x 【代码风格】 - 采用依赖注入方式获取数据库会话 - 错误处理使用自定义异常 + 全局异常处理器 【验收标准】 1. 提供完整的接口代码 2. 包含参数校验逻辑 3. 不包含密码明文返回 4. 数据库操作包含事务处理注意几个细节。第一,我把“处理流程”写成了编号列表,AI 对有序列表的执行顺序理解比段落描述精确得多。第二,我明确指定了“技术栈”,否则它可能会用你项目里根本不存在的库。第三,我写了“代码风格”这一节,这能避免 AI 生成和你项目现有代码风格不一致的代码。第四,“验收标准”看起来是给代码提要求的,实际上也是给 AI 自己核对用的,它在生成时会自动对照这些标准。
3.2 让 AI 先写测试用例,再写实现代码
这是一个能明显提升代码质量的小技巧:在让 AI 写实现代码之前,先让它按规格生成测试用例。
为什么?因为测试用例是规格的“机器可读版本”。AI 生成测试用例的过程,相当于它把规格里的每条规则都翻译成具体的断言。如果规格里某条规则写得不清楚,它在生成测试用例时就会暴露出来——要么它跳过这条规则,要么它用错误的理解去写断言。你检查测试用例时,就能发现自己规格里的漏洞,此时修正规格的成本几乎为零。
等测试用例通过评审之后,再让 AI 写实现代码。这个过程会顺很多,因为测试用例其实已经替实现代码“探好路”了,AI 会在写代码时自动去满足这些测试。
具体操作时,我会在提示词里加一句:
请先阅读以下规格,生成对应的 pytest 测试用例。测试用例需要覆盖所有成功路径、失败路径和边界情况。生成时不要写实现代码。测试用例通过评审后,我会再让你基于这些测试用例实现功能代码。实测下来,这个“先测试后实现”的顺序,能减少大概一半的返工。尤其是边界情况——比如字段长度、空值、特殊字符——AI 在写测试用例时会认真考虑,而这些边界处理恰恰是直接生成代码时最容易漏掉的。
3.3 上下文管理:如何让 AI 始终“想”起规格约束
AI 对话的上下文窗口是有限的,而且会出现“聊久了就忘了前面的要求”的问题。特别是在长对话里,你前面说“密码要用 bcrypt 加密”,聊了半小时后它可能就给你生成一个明文存储的版本。
解决这个问题有两个办法。一个是把规格文件放在项目目录里,并在提示词里标注“实现前请先阅读 SPEC.md 第 2.3 节”。Cursor、Copilot 这类工具支持引用项目文件。只要规格文件在项目里,AI 就能随时读取,不用反复粘贴。另一个办法是每次开始一个新任务时,都重新贴一遍相关的规格片段。很多人怕麻烦,觉得之前说过了就不用再贴,但 AI 的记忆远没有你想象的可靠。每次任务都“重置上下文”,是保证它不跑偏最稳妥的方式。
实际项目中,我通常会在项目根目录维护一个spec/目录,每个模块一个文件。AI 需要时就让它读对应文件,需要针对性修改时再贴片段。这样规格既是给 AI 用的“操作手册”,也是给团队看的“项目文档”,一举两得。
3.4 不要一开始就引入 AI Agent,先手动跑通全流程
关于 AI Agent,我多提醒一句。如果你是第一次尝试 SDD + AI 的工作流,我强烈建议先在普通对话式 AI 里手动跑通一遍,不要一开始就用 Agent 自动执行。
原因是:Agent 自动执行时,你很难观察到每一步 AI 做决策的过程,出了问题也不好定位是“规格不清”还是“执行错误”。手动跑一遍能让你清楚知道每个环节可能出现什么问题,哪些规格写得不明确,哪些任务拆得太大。等你对流程足够熟悉了,再把这些经验固化到 Agent 的配置和执行逻辑里。
我现在用的 Agent 流程其实是把“手动流程”自动化了:读取规格文件 → 按任务清单逐项实现 → 运行测试 → 汇报结果。但它背后的规则,全部是从手动实践中沉淀下来的。一上来就追求全自动,往往会得到一个跑得很快但方向经常跑偏的 Agent。
4. 实战记录:用 SDD + AI 从零开发一个待办事项 API
4.1 需求与规格定义
空谈方法论没用,我用一个实际项目来串一遍完整流程。项目是一个待办事项 API,我给它的需求定义就一句话:“用户可以创建待办事项,查看列表,标记完成,删除事项。”这个项目很小,但麻雀虽小五脏俱全,足够演示 SDD 的完整闭环。
按照模板,我写出了第一版规格。这里直接展示核心部分:
## 功能清单 1. 创建待办事项 2. 查看待办事项列表(支持按完成状态筛选) 3. 更新待办事项(修改标题、标记完成) 4. 删除待办事项 ## 数据模型 Todo: - id: integer, 主键, 自增 - title: string, 必填, 1~100 字符 - completed: boolean, 默认 false - created_at: datetime, 默认当前时间 ## 接口定义 ### POST /todos - 请求体: { title: string } - 成功: 201, 返回创建的 Todo - 失败: 400, title 为空或超过 100 字符时返回 {code: "INVALID_TITLE"} ### GET /todos?completed=true|false - 成功: 200, 返回 Todo 数组 - completed 参数可选, 不传返回全部 ### PATCH /todos/{id} - 请求体: { title?: string, completed?: boolean }(至少一个字段) - 成功: 200, 返回更新后的 Todo - 失败: 404, 不存在时返回 {code: "NOT_FOUND"} - 失败: 400, 请求体为空或字段不合法时返回 {code: "INVALID_PARAMS"} ### DELETE /todos/{id} - 成功: 204, 无响应体 - 失败: 404, 不存在时返回 {code: "NOT_FOUND"}关于技术栈,我选择了 Python + FastAPI + SQLite。原因很简单:项目是演示性质,FastAPI 自带 OpenAPI 文档,便于验证;SQLite 不需要额外配置数据库服务,拿到就能跑。如果你的项目是生产级的,把技术栈替换成 MySQL、PostgreSQL 等,流程完全一样。
4.2 让 AI 生成测试用例并评审
规格到位后,我没有直接让 AI 写接口实现,而是先让它生成测试用例。提示词大概是这样:
项目使用 FastAPI 和 pytest。请依据以下规格生成测试用例文件 test_todos.py。测试需要覆盖: 1. 每个接口的成功路径 2. 每个接口的失败路径(非法参数、不存在的 ID 等) 3. 边界情况(空字符串、超长 title、布尔值过滤等) 不要编写实现代码,只生成测试用例。测试需要能在测试数据库中独立运行。重点说下评审测试用例时我看什么。第一,看它是否覆盖了所有“失败路径”——没有失败路径测试的用例集基本是摆设。第二,看它的断言是不是足够严格——测试里如果只断言状态码 200 而不检查响应体内容,那就没抓住规格的核心。第三,看它有没有把“数据准备”和“测试逻辑”分开——这样后续维护更清晰。
AI 第一次生成的测试用例,通常会有 80% 能直接用,剩下 20% 需要修改。比如它会用 Mock 替代真实数据库,方便是方便,但对这个项目来说反而复杂化了。我会直接告诉它“不要用 Mock,直接使用 SQLite 临时文件作为测试数据库”,它会重新生成一份更贴合项目的版本。
4.3 让 AI 生成实现代码并运行测试
拿到评审通过的测试用例后,我下一步就是让 AI 生成实现代码。提示词依然是基于规格,但会增加一条:“请实现代码,确保所有测试用例全部通过。”
这次 AI 生成的代码质量明显就高多了。数据结构、参数校验、异常处理都规规矩矩,没有出现“只写快乐路径”的老毛病。运行 pytest 之后,一多半测试直接通过。剩下几个失败的,都是些小问题,比如 PATCH 接口的字段校验和预期不一致、DELETE 返回了 200 而不是 204、标题校验的边界条件没处理好。
这些问题的共同规律是:规格文档里写了,但 AI 在实现时“略过了”。它看到“标题长度 1~100 字符”这个描述,却不一定会在代码里真正去校验。这也是为什么我会把“验收标准”写在提示词里的原因,它能一定程度降低这种情况的发生,但不能完全消除。
4.4 修复 bug 的正确姿势:反馈回规格,而不是直接改代码
测试发现的这些小问题,处理方式有讲究。很多人遇到 AI 代码出 bug,会直接把错误信息和代码贴给 AI 说“帮我改掉”。这确实能解决问题,但容易“修一个冒一个”——因为 AI 修改代码时没有全局视角,它可能会在别处引入新问题。
我的做法是:把测试失败的详细信息(包括断言、期望值、实际值)反馈回去,并且指出规格对应的条款编号。比如:
test_todos.py 中的 test_delete_todo 失败了。 规格中使用 DELETE /todos/{id},成功时返回 204,当前实现返回了 200。 请对照规格第 4.5 节修正实现,确保仅修改 delete 相关代码,不改变其他接口行为。这样做的关键是:不要让 AI 自己判断“应该是什么”,而是明确告诉它“按规格应该怎样”。它就没有再自由发挥的空间了。整个修复过程迭代了两轮,耗时不到十分钟,就完成了全部测试通过。
这个项目从开始写规格到测试全绿,总共用了大约一个下午。刨掉吃饭休息,纯工作时间大概三个小时,其中写规格用了将近一个小时。这个“浪费”在传统开发里可能觉得不值,但在 AI 编程里,它就是让你“省下后面十个返工小时”的投资。
5. 常见问题与排查技巧实录
5.1 AI 生成代码偏离规格,怎么办
这是最常遇到的问题,几乎每个项目都会碰上。我整理出的排查思路有三个:
- 检查规格是否写清楚了“不能做什么”。AI 最容易在“约束”上跑偏。规格里写了“title 必填”,但你没写“title 为空时不能通过校验”,它就会漏掉这一步校验。规格不光要写“要做什么”,还要写“不允许发生什么”。
- 检查任务是不是拆得太大。如果你让 AI 一次实现“用户注册 + 登录 + 找回密码”三个功能,它很可能顾此失彼。拆小任务,每个任务只解决一个功能,偏离的概率会直线下降。
- 用测试用例“框住”它。有测试用例在,AI 跑偏的代价就变小了。反正测试会失败,失败后再让它按反馈修正即可。
5.2 规格本身写错了,如何低成本修正
AI 时代修改规格的成本比传统开发低得多,因为改规格后只需要让 AI 同步更新测试用例和实现代码。但这里有个关键步骤:修改规格时,要同时修改测试用例,然后让 AI 根据新测试用例重新实现。如果你只改规格不改测试,测试就会成为“旧规格”的守护者,阻碍新需求的落地。
我自己的习惯是,每个功能点都建立一个“规格条目标识”(比如SPEC-2.3)。当需求变更时,我只需要说“更新 SPEC-2.3 的描述,并同步修改测试用例”,AI 就能精准定位范围,而不会把不相关的功能也改掉。这个标识体系在项目变大之后特别有用,否则你很难和 AI 定位“到底要改哪一部分”。
5.3 上下文窗口不够用,怎么管理大型规格
随着项目变大,规格文档会越来越长,AI 的上下文窗口装不下。我的策略是**“按模块拆文件 + 按需加载”**。不再维护一个巨大的规格文件,而是在spec/目录下按模块拆分成多个文件。每个文件只描述一个模块的行为。需要开发哪个模块,就让 AI 读哪个文件。如果确实有些跨模块的公共约束(比如统一的错误码规范),那就单独维护一个spec/common.md,在需要时一并提供给 AI。
还有个小技巧:规格文件头部放一个“简要说明”和“变更记录”,让 AI 只读取这个文件的最近几节就能快速了解上下文,而不是每次都要扫描整个文件。这能有效减少 token 消耗,同时保持信息不缺失。
5.4 AI 生成了“正确但没用”的代码,怎么避免
比“错误代码”更难发现的是“正确但没用”的代码——它语法正确、逻辑清晰,但实现的东西和你真正想要的不一样。比如你让它“删除 todo”,它认为“删除应该是软删除,即在数据库里加一个 deleted 字段”,于是在原来的表结构上增加了一列,还改了查询逻辑,整个改动范围超出预期。
解决这个问题,核心还是规格。你对“删除”如果真是“物理删除”,就要在规格里明确写:“DELETE 接口执行物理删除,从数据库中彻底移除该记录”。如果你觉得“可能会做回收站功能”,那软删除也是合理方案。规格的价值就是把这种“想当然”的空间压到最小。
我的经验是,在规格里专门留一节“非目标”,列清楚“本模块不做 X”。比如“本模块不做用户权限区分,所有请求一律视为同一用户”“本模块不做数据软删除,所有删除均为物理删除”。这个反向定义的效果出奇地好,AI 看到“非目标”之后,基本不会再发挥多余功能。
6. 热词背后的实战关联:AI Agent、Spring AI 和本地部署
6.1 AI Agent 为什么必须和规格绑定
最近 AI Agent 这个词在开发圈里特别热,很多人把 AI Agent 当成“上传需求自动出软件”的万能工具。但我用下来的感受是:没有规格约束的 Agent,就像没有剧本的演员,自由发挥是天性,但你不敢让它上台演正剧。
Agent 的自主性是一把双刃剑。有规格的时候,它能自动拆任务、自动写代码、自动跑测试,把整个 SDD 流程变成一条流水线;没规格的时候,它会自作主张地设计数据模型、选择技术实现、甚至添加你没要求的功能,而这些“自主行为”往往就是 bug 和返工的源头。所以我在和 Agent 协作时,最先输入的不是需求描述,而是规格文件本身,并且明确告诉它:“所有实现必须符合规格文件里的定义,超出规格的部分一律不做。”这句话能把 Agent 的创造力引导到正确的方向上。
6.2 Spring AI 这类框架能帮你省什么
如果你的技术栈是 Java,Spring AI 是值得关注的方向。它把大模型调用、Prompt 模板、结构化输出这些能力封装成了 Spring 生态的组件,让 AI 功能可以像配数据库一样配置。这和 SDD 有什么关系?在我看来,Spring AI 本身解决的问题是“让 AI 能力容易接入”,而 SDD 解决的问题是“让 AI 输出可预期”。两者是互补的。
比如你用 Spring AI 开发一个 AI 客服系统,Spring AI 负责管理模型调用和上下文,SDD 则负责定义客服的应答规范、话术边界、转人工条件。没有 SDD 定义这些行为,Spring AI 接入得再顺,客服也会乱说话。所以我的建议是:框架可以用,但别指望框架解决“需求不清晰”的问题。
6.3 本地部署大模型,SDD 会有什么变化
本地部署 AI 大模型也是热门方向。成本、隐私、离线可用这些原因都好理解,但从 SDD 的角度看,本地模型和在线模型有个关键区别:本地模型的指令跟随能力通常弱于顶级在线模型,对模糊信息的容忍度更低。
这反而让 SDD 的价值更突出了。本地模型更需要结构化的规格输入,更需要明确的验收标准,更需要小任务拆分。我用本地模型跑过同样的待办事项项目,规格不清时,它生成的代码比在线模型更容易“缺胳膊少腿”;但规格写得足够好时,它也能完成任务,而且因为上下文不占在线额度,可以反复试错。本地部署模型时的配置门槛(显存、量化、推理框架)是一个独立话题,但如果你已经在折腾本地模型了,我的建议是从 SDD 流程开始,规格文件会让你调试模型输出的成本大幅下降。
6.4 Python 开发软件的角色分工
最后说回 Python。当前 AI 编程生态下,Python 几乎成了事实上的标准语言,原因很简单:AI 训练数据里 Python 代码的占比最高,所以 Python 生成质量最好;同时 AI 相关的框架基础设施也主要是 Python 生态。用 SDD + AI 开发软件,选择 Python 能最大化 AI 编码的“战斗力”。
但这不意味着 Python 项目不需要规格。恰恰相反,因为 Python 的动态类型特性,AI 生成代码时更容易在数据结构上“自由发挥”。我习惯在规格里额外强调数据模型和类型定义,并让 AI 使用pydantic或dataclass做显式建模。这相当于把规格里的定义用代码固化下来,AI 后续生成的逻辑就不会在这个基础上跑偏。
7. 最后补充几个实战环节的细节心得
这套流程跑了几十个项目之后,我沉淀了一些零散但实用的经验,一并分享在这里。
第一个是关于规格文档的维护节奏。每逢需求变更,我会先改规格文档,再改测试用例,最后才让 AI 改代码。顺序不能反。如果让 AI 先改代码,测试用例还是旧逻辑,就会出现“代码已实现新需求,但测试还在验证旧需求”的尴尬状态。反过来,先改测试用例、让测试先挂掉,再实现新代码,整个流程就顺理成章。
第二个是关于“验收标准”的书写细节。不要写“代码质量要高”这种没法验证的描述,而要写可检查的条目,比如“所有数据库操作包含事务”“所有 API 返回统一的 JSON 结构”“不包含明文密码”。可验证的标准才能真正约束 AI 的行为。
第三个是善用 AI 做规格本身的“评审官”。写完一份规格后,我会把它丢给 AI 问:“如果我是开发工程师,按这份规格实现,有哪些地方语义不明确?有没有遗漏的异常情况?”它通常能挑出几个我没想到的边界问题,比如“如果 title 只有空格,算不算合法输入?”这类问题,在写规格阶段发现并及时补充,比到编码阶段让 AI 自己猜测要好得多。
第四个是关于贴代码时的“圈地”意识。让 AI 修改某个文件时,我会明确告诉它“只修改 XXX 函数,其他代码保持不变”。这听起来像是废话,但 AI 确实经常顺手把无关代码改了,特别是格式化工具版本的差异,会导致它重排你整个文件的代码格式。加一句“不要改动与本任务无关的代码”,能减少大量无谓的 code review 消耗。
还有一个小技巧:每次让 AI 完成任务后,让它用一句总结它做了什么、改了什么、没做什么。比如:
完成后请用三句话总结:1. 本次做了哪些改动;2. 哪些测试通过了;3. 还有哪些遗留问题。这个小动作能逼着 AI 对自己的输出做一次检查,很多“看起来完成其实没完成”的情况在这一步就会被暴露出来。
我现在已经离不开“规格先行”这套流程了。以前让 AI 写代码,像在跟一个记忆力很差的天才合作——他能写出漂亮的代码,但总是忘记你 30 分钟前说过的话。现在有了 SDD,他不再需要记那么多话,只需要每次打开规格,按文件执行。感觉就像终于拿到了这份协作者的完整说明书。
如果你也想试,建议从一个小项目开始,不要找那种一两个接口的玩具项目,而是选一个有那么三五个模块、二十来个接口的真实需求,完整地把这套流程走一遍。第一次跑通的时候你可能会觉得繁琐,但等你看到 AI 在规格约束下生成的代码能被测试用例完整验证,那种“一切尽在掌控”的感觉,就是这套方法论真正的回报。