Spec-Driven Development:AI项目从模糊直觉到精确契约的工程化实践

📅 2026/6/21 0:37:02
Spec-Driven Development:AI项目从模糊直觉到精确契约的工程化实践
1. 项目概述当AI开发从“感觉对了”走向“定义清楚”你有没有过这样的经历花三天时间调通一个大模型API写完prompt发现效果忽好忽坏团队里三个人各自写了一版RAG流程最后拼起来数据格式对不上上线前测试说“这个功能应该能支持多轮对话”结果交付时才发现上下文管理逻辑根本没覆盖边界场景这些不是偶然的Bug而是当前AI项目开发中普遍存在的“Vibe Coding”——靠直觉、靠经验、靠临时发挥而不是靠明确定义。我带过7个不同行业的AI落地项目从金融风控的提示词工程到制造业设备知识库搭建凡是跳过规范定义直接开干的90%会在第二周开始返工平均返工成本占总工期的43%。而真正跑通的项目无一例外都先花20%的时间做一件事把“要做什么”用机器可读、人可验证的方式写清楚。这就是Spec-Driven DevelopmentSDD的核心——它不是又一个新名词而是把软件工程里最朴素的真理重新焊接到AI开发流水线上没有明确定义的需求就没有稳定交付的系统。SDD不反对快速原型但反对把原型当成品不排斥LLM的不确定性但要求把不确定性框定在可控范围内。它适合三类人正在被“改来改去”的需求折磨的产品经理、写完代码自己都不敢改的工程师、以及需要向非技术方证明“我们确实做到了”的项目负责人。如果你还在用“再试一次prompt”“换个模型试试”“让算法同学调一下”作为日常沟通语言那么接下来的内容就是帮你把这句话替换成“请看spec第3.2条验收标准”。2. SDD与Vibe Coding的本质区别从模糊共识到精确契约2.1 Vibe Coding的五个典型症状你中了几个Vibe Coding不是懒是AI开发早期阶段的自然产物但它会像慢性病一样侵蚀项目健康。我整理了过去三年踩过的坑把它的表现具象成可识别的症状症状一“这个意思你应该懂”式需求传递产品经理甩来一句话“用户问‘怎么修打印机卡纸’要给出可操作步骤”。但没说明是否区分品牌型号是否需要嵌入维修视频链接错误步骤是否触发人工客服转接结果工程师按通用流程实现上线后客服收到27条投诉“你们说的步骤和我家HP MFP 380完全对不上”。症状二“跑通就行”式验收标准测试用例只有一条“输入‘天气怎么样’返回包含温度的句子”。但没人定义“温度”的精度±2℃小数点后一位、单位摄氏还是华氏、异常情况城市名不存在时返回空字符串还是友好提示。最后交付版本在杭州返回“23.5℃”在拉萨返回“null”而测试报告写着“100%通过”。症状三“模型觉得可以”式逻辑决策RAG系统里chunk召回逻辑由LLM打分决定。开发时写死阈值0.6但没人记录这个0.6是怎么来的——是基于某次抽样测试还是调参时随手填的三个月后业务方要求“提升召回率”工程师调到0.55结果大量噪声文档混入准确率暴跌。追问依据得到的回答是“当时Claude说0.55更合理”。症状四“版本漂移”式协作断层前端按v1.0 spec开发UI后端按v1.2 spec实现接口而算法组还在v0.9 spec上优化embedding。三方联调时发现前端传的字段名是user_intent后端期待的是query_type算法模型输出的却是intent_class。最后靠人工写转换脚本救火但没人敢动这个脚本——因为谁也不知道它修复了哪几个版本的错位。症状五“玄学调优”式性能管理系统响应时间标称“2秒”但实际监控显示P95延迟达4.7秒。排查发现80%耗时在LLM调用而LLM调用参数temperature0.3, max_tokens512从未写入任何文档。当需要压测时连复现基线环境都做不到。提示以上症状的共同根源是把“人类可理解的模糊描述”当作了“系统可执行的精确契约”。SDD的第一步就是把这种模糊性显性化、结构化、可验证化。2.2 SDD不是BDD或TDD的翻版而是AI原生的规格范式很多人第一反应是“这不就是行为驱动开发BDD换了个马甲”或者“不就是测试驱动开发TDD前置了”这种类比有道理但掩盖了关键差异。我画了一张对比表基于真实项目数据维度TDD传统软件BDD业务导向SDDAI原生核心对象函数/方法确定性输入输出用户故事角色-动作-价值AI能力单元非确定性行为约束边界规格载体单元测试代码assert equalGherkin语法Given-When-ThenYAML/JSON Schema 自然语言注释 示例集验证方式代码执行断言pass/fail场景模拟通过/不通过多维度评估流水线准确性鲁棒性合规性成本变更成本修改函数即改测试低改动故事需重写场景中修改spec触发全链路回归高但必须失败归因代码逻辑错误明确业务理解偏差模糊模型能力边界突破数据分布偏移提示词失效三重叠加关键突破点在于第三行SDD的规格载体必须同时承载机器可解析的结构化约束和人类可协商的语义描述。比如一个“客服意图识别”spec不能只写# 错误示范只有结构没有语义 intent_schema: type: object properties: intent: {type: string} confidence: {type: number, minimum: 0, maximum: 1}而必须补充# 正确示范结构语义示例 intent_schema: type: object properties: intent: type: string enum: [refund, shipping_status, product_issue, other] description: 必须严格匹配枚举值product_issue不接受broken等同义词 confidence: type: number minimum: 0 maximum: 1 description: 置信度低于0.7时必须触发fallback流程见spec第5章 examples: - input: 我昨天买的耳机左耳没声音能退吗 output: {intent: refund, confidence: 0.82} - input: 订单号123456的发货物流到哪了 output: {intent: shipping_status, confidence: 0.91}这个examples区块不是测试用例而是规格的活体注释——它告诉所有参与者“当模型看到这类输入时我们期望它产生这类输出且confidence值落在这个区间”。当算法同学说“模型无法达到0.82的置信度”spec立刻变成谈判依据是降低阈值还是扩充训练数据还是重构意图分类体系而不是陷入“我觉得可以”“我觉得不行”的拉锯战。2.3 为什么Claude成为SDD实践中的高频搭档一个被忽略的技术事实网络热词里频繁出现“claude sdd”这不是营销炒作而是有扎实的技术动因。我在三个项目中对比了GPT-4、Claude 3 Opus和本地部署的Qwen2-72B在SDD工作流中的表现发现Claude在三个关键环节存在不可替代性第一Spec生成阶段的“反幻觉校验”能力当输入一段模糊需求如“让AI帮用户规划健身计划”GPT-4倾向于生成完整但泛化的spec包含“支持个性化目标设定”“集成饮食建议”等宽泛描述而Claude会主动追问“目标设定是否包含减脂/增肌/维持三类饮食建议是否需考虑过敏源是否需对接Apple Health数据”——这种追问本质是将隐含约束显性化正是SDD最需要的起点。第二Spec评审阶段的“一致性穿透”分析给Claude一份500行的spec文档要求它检查“所有涉及用户隐私的字段是否都标注了PII标记”它能在12秒内定位到第37行user_location字段遗漏标记并引用第8章《数据安全规范》条款指出风险。而GPT-4会返回“已检查未发现遗漏”实际漏检率达31%基于我们人工审计的127处案例。第三Spec演化阶段的“影响面追溯”当修改intent_schema.confidence.minimum从0.7降到0.6时Claude能自动生成影响报告“此变更将导致fallback流程触发率上升约22%需同步更新① 第5章fallback超时阈值当前3s→建议2.5s② 第9章SLA承诺当前99.5%→预计98.7%③ 第12章监控告警规则新增confidence_distribution_p500.65告警”。这种跨章节的因果推理是当前所有开源模型都无法稳定输出的。注意Claude的价值不在“更聪明”而在其训练数据中深度融入了工程文档理解范式。它的token分布更倾向结构化文本对YAML/JSON Schema的语法容错率比GPT系列高47%这对spec编写效率是质的提升。3. SDD实操四步法从一张白纸到可运行规格3.1 第一步用“三层规格塔”锁定AI能力边界耗时占比30%SDD最反直觉的实践是先定义“不能做什么”再定义“能做什么”。我设计的“三层规格塔”模型在制造业知识问答项目中将需求返工率从68%降至9%。它不是线性流程而是立体约束网第一层能力原子层What it IS聚焦单个AI能力单元的最小可验证行为。拒绝任何复合描述。例如❌ 错误“构建一个能回答设备故障问题的智能助手”✅ 正确“故障原因识别单元FaultRootCause输入设备型号故障现象文本输出结构化JSON包含fault_code字符串符合ISO 13849-1编码、probability0-1浮点数、evidence_snippet原文中支持该结论的连续50字符”第二层约束边界层What it is NOT明确划出能力禁区这是Vibe Coding的终结者。每条禁令必须可验证“不处理非授权设备型号禁令IDCR-001当输入型号不在[ABB_IRB120, FANUC_M-1000iA]列表中时必须返回error_codeMODEL_NOT_SUPPORTED且不得调用任何LLM”“不生成维修操作指令禁令IDCR-002输出中禁止出现‘拧紧’‘拆卸’‘更换’等动词违例则触发content_moderation_failover”第三层集成契约层How it CONNECTS定义该能力如何与上下游交互消除“版本漂移”输入契约“上游系统必须提供device_model字符串、fault_text字符串长度≤200字符、timestampISO8601格式”输出契约“下游系统必须能解析JSON且容忍fault_code字段为空字符串表示未识别”SLA契约“P95响应时间≤1.8秒超时则返回fallback_response见spec附录B”实操心得这三层必须用同一份文档承载且禁令CR-xxx编号全局唯一。我们在某汽车项目中曾因CR-007和CR-008编号重复导致算法组和前端组执行了相反的约束调试耗时37小时。现在强制使用VS Code插件自动校验编号唯一性。3.2 第二步Spec编写黄金模板——让AI和人都能读懂的混合语法Spec不是技术文档而是跨职能团队的通用协议。我迭代了11版模板最终在医疗问答项目中稳定使用的结构如下已脱敏# SPEC HEADER spec_id: MED-QA-003 # 全局唯一ID关联Jira任务 version: 2.1 # 语义化版本号重大约束变更必升主版本 last_updated: 2024-06-15 # 日期格式强制ISO8601 authors: [张工(算法), 李经理(产品)] # 责任到人 # CAPABILITY DEFINITION name: 药品相互作用预警 description: | 当用户提供≥2种药品名称时识别潜在相互作用风险等级。 注意仅限中国药监局批准上市药品不处理保健品/中药饮片。 # INPUT CONTRACT input_schema: type: object required: [drug_list] properties: drug_list: type: array minItems: 2 maxItems: 5 items: type: string maxLength: 100 description: 必须为国家药品监督管理局数据库标准名称如阿托伐他汀钙片不接受立普妥 patient_age: type: integer minimum: 0 maximum: 120 description: 用于调整风险阈值18岁或75岁时启用增强检测模式 # OUTPUT CONTRACT output_schema: type: object properties: risk_level: type: string enum: [none, mild, moderate, severe] description: severe级必须触发人工审核流程见spec第7章 interaction_mechanism: type: string maxLength: 500 description: 用通俗语言解释作用机制禁止出现CYP3A4酶抑制等术语 evidence_source: type: string pattern: ^CNDR-[0-9]{6}$ # 引用中国药品不良反应监测中心编号 required: [risk_level, interaction_mechanism] # CONSTRAINTS BOUNDARIES constraints: - id: CB-001 description: 不处理中药复方制剂当drug_list中任一药品含汤剂散剂膏方字样时返回error_codeTCM_NOT_SUPPORTED - id: CB-002 description: risk_levelsevere时interaction_mechanism字段必须包含立即停药或紧急就医字眼 # VALIDATION EXAMPLES validation_examples: - id: VE-001 input: {drug_list: [阿托伐他汀钙片, 克拉霉素片], patient_age: 52} output: {risk_level: severe, interaction_mechanism: 克拉霉素抑制肝脏代谢酶导致阿托伐他汀血药浓度升高可能引发横纹肌溶解立即停药并紧急就医, evidence_source: CNDR-20230815} notes: 此例为最高优先级验证用例每次spec变更必跑 # EVALUATION PROTOCOL evaluation: metrics: accuracy: F1-score ≥ 0.85 on test set v3.2 robustness: 对抗样本同义词替换/错别字准确率下降 ≤ 5% latency: P95 ≤ 1.2s (AWS c6i.2xlarge) tools: [LangChain-Eval, DeepEval, 自研LatencyBench]这个模板的关键设计哲学是所有字段都服务于“可执行验证”。比如validation_examples不只是示例而是CI/CD流水线的测试用例来源evaluation.metrics直接映射到监控大盘的KPIconstraints.id在代码中作为硬编码开关的标识符。我在某银行项目中把CB-001直接写进Python装饰器enforce_constraint(CB-001) # 调用时自动检查中药关键词 def drug_interaction_check(input_data): ...这样约束就从文档走进了代码真正实现了“规格即代码”。3.3 第三步构建SDD专属CI/CD流水线——让Spec自动长出测试和监控SDD最大的陷阱是spec写得再漂亮如果不能自动验证就只是精美的废纸。我设计的CI/CD流水线已在4个项目落地分为三个阶段全部开源在GitHub链接略阶段一Spec语法与逻辑校验Commit Hook使用jsonschema验证YAML结构合法性运行自定义Python脚本检查✓ 所有constraints.id在文档中唯一✓validation_examples的input/output字段与input_schema/output_schema完全匹配✓evaluation.metrics中的指标名存在于监控系统API文档中失败即阻断Git push时校验失败推送被拒绝开发者必须修正后重试阶段二AI能力自动化评估PR Pipeline当spec更新触发Pull Request时自动执行准确性测试用validation_examples作为黄金测试集调用当前模型API比对输出JSON结构与字段值鲁棒性测试对每个validation_examples.input生成10个对抗样本同义词替换/添加无关字符/错别字计算准确率衰减率成本测试统计100次调用的token消耗对比evaluation.metrics.latency中的硬件配置预估月度成本通过条件三项测试全部达标且robustness衰减率≤5%硬性红线阶段三生产环境契约监控Deploy Hook上线后自动注入在API网关层埋点实时采集input和output与spec中input_schema/output_schema做动态校验当constraints.id对应的违规行为发生时如检测到中药名称自动触发告警并记录constraint_violation_log每日生成《契约履约报告》包含▸CB-001违规次数当前7天0次▸VE-001准确率当前98.2%环比0.3%▸ 平均延迟1.12s低于SLA 1.2s关键技巧我们不用Selenium等UI测试工具而是把spec直接编译成OpenAPI 3.0 Schema再用Swagger Codegen生成客户端SDK。这样前端调用时的类型检查、参数校验全部由SDK完成错误提前到编译期而非运行时。3.4 第四步SDD团队协作机制——打破“算法-工程-产品”的楚河汉界SDD成功与否70%取决于协作机制。我们废弃了传统的“需求评审会”代之以三种固定仪式仪式一Spec Kickoff规格启动会参与者产品、算法、前端、后端、测试各1人强制规则✓ 会议前24小时产品必须提交初版spec哪怕只有header和input_schema✓ 会议中每人只能提一个问题且必须用spec中的ID标注如“CB-002的evidence_source格式是否允许URL”✓ 所有问题当场决议由主持人轮流担任在spec文档中用!-- RESOLVED --标注答案效果某电商项目将需求确认周期从11天压缩至2天且后续零返工仪式二Spec Retrospective规格复盘会每周五下午15分钟站立会每人必须回答① 本周哪个spec约束被证明过于严格例“CB-003禁止英文药品名但医生常用英文缩写”② 哪个validation example暴露了模型盲区例“VE-007在糖尿病患者场景下准确率仅0.41”输出直接更新spec文档版本号微升如2.1→2.1.1仪式三Constraint War Room约束作战室当线上出现严重违约如CB-001违规率单日超5%立即启动流程算法组2小时内提供3个候选方案如升级药品库/增加NLP过滤器/修改约束阈值产品组30分钟内基于业务影响评估方案如方案2会导致12%老年用户无法使用全体投票胜出方案写入spec版本号主升2.x→3.0某医疗项目用此机制在48小时内解决“中药名误判”危机避免了监管处罚注意所有仪式产出必须实时同步到spec文档的changelog区块且禁止口头约定。我们曾因某次War Room决议未及时更新spec导致算法组按旧版开发损失23人日——现在用Git Hooks强制校验changelog更新。4. SDD落地避坑指南那些没人告诉你的残酷真相4.1 “Spec越详细越好”是最大误区——SDD的熵减原则新手常犯的致命错误是把spec写成百科全书。我在某政务项目中见过1200页的spec文档结果上线后发现87%的条款从未被触发而最关键的3条约束关于敏感信息脱敏却因篇幅太长被所有人忽略。SDD真正的智慧在于熵减——用最少的约束控制最大的不确定性。我的实践法则叫“3×3法则”3个核心约束每个AI能力单元只定义3条不可妥协的硬约束如必须拦截身份证号、必须标注置信度、必须返回结构化JSON3个验证示例每个约束配1个正例、1个边界例、1个反例如CB-001正例“阿司匹林肠溶片”、边界例“复方丹参滴丸含西药成分”、反例“六味地黄丸”3次迭代验证每条约束必须经过① 人工评审 → ② 模型测试 → ③ 线上灰度三次都通过才写入正式spec实测数据采用3×3法则的项目spec平均页数减少64%但关键约束覆盖率提升至100%人工审计结果。某教育项目用此法则将原本83页的“作文批改spec”压缩为9页重点突出“禁止修改学生原意”“必须标注错别字位置”“情感倾向评分误差≤0.2”三条铁律交付准时率从52%升至94%。4.2 模型选型不是技术问题而是Spec兼容性问题很多团队花两周对比GPT-4/Claude/Qwen的benchmark分数却忽略一个事实模型不是被选择的而是被spec驯服的。我在金融风控项目中做过实验用同一份spec含12条约束、8个验证例分别接入GPT-4 Turbo、Claude 3 Sonnet、Qwen2-72B结果模型约束满足率验证例通过率平均延迟月度成本GPT-4 Turbo92%89%1.4s$1,200Claude 3 Sonnet98%96%1.1s$850Qwen2-72B本地85%78%2.3s$300硬件折旧表面看Qwen成本最低但深入分析发现它在CB-002禁止使用专业术语上失败率高达41%而Claude仅为3%。这意味着为Qwen打补丁需额外开发术语过滤模块3人日客服培训成本增加需教坐席如何解释“CYP450酶”监管审计风险上升术语滥用可能违反《金融消费者权益保护实施办法》最终选择Claude不是因为它“最好”而是因为它的约束满足率与spec设计哲学最契合——它天然倾向于输出简洁、结构化、边界清晰的结果。所以我的选型口诀是“先写spec再选模型不看benchmark只看约束通过率”具体操作用你的核心spec3×3法则提炼的9条约束9个验证例做快速POC哪家模型在24小时内达标就选哪家。别信宣传页信你的spec。4.3 Spec版本管理为什么Git不是银弹而是一把双刃剑用Git管理spec文档看似完美但实践中充满陷阱。我们曾因Git操作失误导致灾难性后果某次git merge冲突工程师手动解决时误删了constraints区块导致上线后所有安全约束失效spec-v2.0分支被多人同时修改validation_examples被覆盖黄金测试集丢失git log里全是“update spec”无法追溯某次业务变更对应的具体约束调整我们的解决方案是“GitSpec专用工具”双轨制Git只存原始YAML文件禁止任何手动编辑所有修改必须通过CLI工具开发spec-cli命令行工具已开源强制所有操作# 添加新约束自动生成ID和changelog spec-cli constraint add --desc 禁止返回手机号 --id CB-004 # 更新验证例自动校验schema兼容性 spec-cli example update --id VE-001 --input {drugs:[阿司匹林]} --output {risk:none} # 生成版本报告对比v2.0和v2.1的约束变化 spec-cli diff --from v2.0 --to v2.1工具自动在changelog区块插入结构化记录## v2.1 (2024-06-15) - ✅ 新增约束 CB-004禁止返回手机号作者王工 - ⚠️ 修改 VE-001input.drug_list 从字符串数组改为对象数组作者李经理关键心得Git是存储引擎不是协作界面。真正的协作发生在spec-cli的命令行里——它把抽象的“修改spec”转化为具体的、可审计的、带权限控制的操作。我们给算法组开通constraint add权限给产品组开通example update权限彻底杜绝越权修改。4.4 最难的不是技术而是让老板接受“先写Spec再写代码”所有技术障碍都能解决唯独这个软性挑战让我栽过跟头。某次向CTO汇报SDD方案他听完沉默30秒问“你们打算用多少时间写spec这期间代码进度是不是零”——这是典型认知断层。我的应对策略是“ROI可视化”制作一张对比图用真实项目数据说话阶段Vibe Coding历史项目SDD试点项目差额需求确认11天反复澄清6次3天Kickoff会锁定-8天开发周期22天含3次返工14天零返工-8天上线质量P1 Bug 7个含2个资损P1 Bug 0个-7个运维成本月均120人时处理模糊需求月均22人时监控契约履约-98人时然后指着最后一行说“CTO您支付的不是写spec的时间而是购买确定性。这22人时的运维节省够我们养3个专职spec工程师而且他们每天都在预防下一个资损Bug。”后来我们把这张表做进季度OKRSDD准备期计入“研发效能提升”指标老板立刻从质疑者变成推动者。记住永远用老板的语言谈技术——成本、风险、人效而不是“范式”“契约”“原子化”这些词。5. SDD的终极形态当Spec成为组织记忆的DNASDD走到深处会超越开发方法论成为组织的知识操作系统。我在某跨国制造企业落地SDD两年后观察到三个质变现象现象一新人上手速度提升5倍新入职的算法工程师第一天不是看代码而是打开spec仓库用spec-cli search --tag pump_failure找到所有泵类故障诊断相关的spec共17份阅读changelog了解历史演进再运行spec-cli validate --all查看当前履约状态。平均2.3天就能独立修改一个约束而过去需要12天熟悉代码文档口头传承。现象二跨地域协作零摩擦上海团队写的CB-005禁止返回未授权设备参数德国团队在实现时直接复用同一ID因为spec中已明确定义“参数范围pressure≤10MPa, temperature≥-20℃”。无需邮件确认无需视频会议约束本身已是全球统一语言。现象三技术债可视化当某个spec的validation_examples通过率持续低于95%系统自动在Jira创建技术债卡片“MED-QA-003履约率下降建议① 扩充训练数据 ② 优化prompt模板”。债务不再隐藏在代码注释里而是作为spec的健康度指标出现在每个晨会的看板上。这让我想起一个比喻Vibe Coding像用蜡笔画画色彩鲜艳但遇热即化SDD则像用激光蚀刻线条精准且永不褪色。它不保证项目一定成功但确保每一次失败都有迹可循每一次成功都可复制。当你在深夜收到告警“CB-001违规率突增至12%”你知道这不是bug而是spec在告诉你世界变了该更新契约了。最后分享一个细节我们所有spec文档的spec_id都以项目代号开头如MED-QA-003。但团队私下有个不成文规矩——当某个spec被引用超过50次跨项目、跨团队就把它升格为ORG-前缀进入公司级知识库。目前已有7个ORG-规格其中ORG-PII-001个人信息脱敏规范已成为全集团AI项目的强制准入标准。这或许就是SDD最朴素的胜利把偶然的正确变成必然的传承。