【AI·Coding】TDD × SDD × AI Coding:从“测试驱动“到“规范驱动“的智能协作实践

TDD × SDD × AI Coding:从"测试驱动"到"规范驱动"的智能协作实践

    • [一、引言:AI Coding 时代的"驱动方式"之争](#一、引言:AI Coding 时代的"驱动方式"之争)
    • [二、概念澄清:TDD vs SDD 是什么?](#二、概念澄清:TDD vs SDD 是什么?)
      • [2.1 TDD(测试驱动开发)](#2.1 TDD(测试驱动开发))
      • [2.2 SDD(规范驱动开发)](#2.2 SDD(规范驱动开发))
      • [2.3 核心对比](#2.3 核心对比)
    • [三、整体架构:TDD + SDD 融合的 AI Coding 体系](#三、整体架构:TDD + SDD 融合的 AI Coding 体系)
    • 四、实践流程:五步融合法
      • [Step 1:需求 → 规范(SDD 起点)](#Step 1:需求 → 规范(SDD 起点))
      • [Step 2:规范 → 测试骨架(TDD 前置)](#Step 2:规范 → 测试骨架(TDD 前置))
      • [Step 3:AI 实现代码(受双重约束)](#Step 3:AI 实现代码(受双重约束))
      • [Step 4:重构与规范更新(双向反馈)](#Step 4:重构与规范更新(双向反馈))
      • [Step 5:CI 流水线中的规范守护](#Step 5:CI 流水线中的规范守护)
    • 五、完整实践案例:云安全告警管理模块
      • [5.1 项目结构](#5.1 项目结构)
      • [5.2 SKILL.md:AI 任务规范示例](#5.2 SKILL.md:AI 任务规范示例)
      • [5.3 告警规则 CRUD 的测试先行示例](#5.3 告警规则 CRUD 的测试先行示例)
      • [5.4 AI 驱动实现(Green 阶段)](#5.4 AI 驱动实现(Green 阶段))
    • [六、进阶:AI Coding 中的规范漂移治理](#六、进阶:AI Coding 中的规范漂移治理)
    • 七、工具链推荐
    • 八、常见误区与解答
      • [❌ 误区 1:有了 AI,不需要写测试了](#❌ 误区 1:有了 AI,不需要写测试了)
      • [误区 2:规范文档太重了,敏捷开发不需要](#误区 2:规范文档太重了,敏捷开发不需要)
      • [误区 3:TDD 和 SDD 选一个就够了](#误区 3:TDD 和 SDD 选一个就够了)
      • [误区 4:AI 会自动保持规范更新](#误区 4:AI 会自动保持规范更新)
    • 九、总结:融合方法论的核心思想
    • 参考资料

一、引言:AI Coding 时代的"驱动方式"之争

AI 辅助编程工具(GitHub Copilot、Cursor、WorkBuddy 等)正在快速改变软件开发的范式。但随之而来的一个核心问题浮出水面:

AI 写代码,谁来保证代码是对的?

传统工程界已有两个成熟答案:

  • TDD(Test-Driven Development,测试驱动开发):先写测试,再写实现,让测试成为代码正确性的"守门员"。
  • SDD(Specification-Driven Development,规范驱动开发):先写规范(需求文档、接口约定、类型定义),再驱动 AI 生成代码,让规范成为 AI 的"航线图"。

两者并非对立,而是互补。本文将从理念对比、实践流程、工具链搭建到完整案例,带你深入理解如何在 AI Coding 时代将 TDD 与 SDD 融合,构建可信、可维护、可扩展的 AI 辅助研发体系。


二、概念澄清:TDD vs SDD 是什么?

2.1 TDD(测试驱动开发)

TDD 是 Kent Beck 于 1990 年代提出的极限编程实践,核心循环为"红-绿-重构":

复制代码
Red   →  写一个失败的测试
Green →  写最少的代码让测试通过
Refactor → 在绿灯下优化代码质量

核心价值:

  • 测试即文档,即规格
  • 防止过度设计
  • 持续保障代码可回归

在 AI Coding 中的局限:

  • AI 不会自发写测试,需要人工驱动
  • 测试粒度不统一,AI 生成测试易流于形式(只测 happy path)
  • 缺乏全局视角,难以在架构层约束 AI 输出

2.2 SDD(规范驱动开发)

SDD 是 AI Coding 时代兴起的方法论,核心思路是:用结构化、机器可读的规范文档作为 AI 的输入约束,让 AI 在规范边界内生成代码。

规范的形式包括但不限于:

规范类型 示例
接口规范 OpenAPI / gRPC Proto
类型规范 TypeScript Interface / JSON Schema
行为规范 Gherkin / BDD 场景文本
架构规范 ADR(架构决策记录)
代码规范 ESLint Rules / Checkstyle
AI 任务规范 SKILL.md / .cursorrules

核心价值:

  • 约束 AI 输出范围,提升生成准确率
  • 规范即上下文,减少 AI "幻觉"
  • 跨会话保持一致性

在 AI Coding 中的局限:

  • 规范写得不好,AI 生成的代码同样错误
  • 规范更新滞后,"规范漂移"导致 AI 代码与实际不符
  • 缺少运行时验证,规范停留在"纸面"

2.3 核心对比

维度 TDD SDD
核心产物 测试用例 规范文档
约束时机 运行时(测试执行) 编码前(上下文输入)
AI 协作方式 AI 实现满足测试的代码 AI 根据规范生成代码
质量保障层 功能正确性 结构一致性
适用场景 业务逻辑、算法层 接口层、架构层
维护成本 测试维护成本高 规范维护成本高
AI 友好度 中(需精准描述测试意图) 高(结构化文本天然适合 AI 解析)

三、整体架构:TDD + SDD 融合的 AI Coding 体系

#mermaid-svg-vJPewtoICajQyKUn{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-vJPewtoICajQyKUn .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-vJPewtoICajQyKUn .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-vJPewtoICajQyKUn .error-icon{fill:#552222;}#mermaid-svg-vJPewtoICajQyKUn .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-vJPewtoICajQyKUn .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-vJPewtoICajQyKUn .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-vJPewtoICajQyKUn .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-vJPewtoICajQyKUn .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-vJPewtoICajQyKUn .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-vJPewtoICajQyKUn .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-vJPewtoICajQyKUn .marker{fill:#333333;stroke:#333333;}#mermaid-svg-vJPewtoICajQyKUn .marker.cross{stroke:#333333;}#mermaid-svg-vJPewtoICajQyKUn svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-vJPewtoICajQyKUn p{margin:0;}#mermaid-svg-vJPewtoICajQyKUn .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-vJPewtoICajQyKUn .cluster-label text{fill:#333;}#mermaid-svg-vJPewtoICajQyKUn .cluster-label span{color:#333;}#mermaid-svg-vJPewtoICajQyKUn .cluster-label span p{background-color:transparent;}#mermaid-svg-vJPewtoICajQyKUn .label text,#mermaid-svg-vJPewtoICajQyKUn span{fill:#333;color:#333;}#mermaid-svg-vJPewtoICajQyKUn .node rect,#mermaid-svg-vJPewtoICajQyKUn .node circle,#mermaid-svg-vJPewtoICajQyKUn .node ellipse,#mermaid-svg-vJPewtoICajQyKUn .node polygon,#mermaid-svg-vJPewtoICajQyKUn .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-vJPewtoICajQyKUn .rough-node .label text,#mermaid-svg-vJPewtoICajQyKUn .node .label text,#mermaid-svg-vJPewtoICajQyKUn .image-shape .label,#mermaid-svg-vJPewtoICajQyKUn .icon-shape .label{text-anchor:middle;}#mermaid-svg-vJPewtoICajQyKUn .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-vJPewtoICajQyKUn .rough-node .label,#mermaid-svg-vJPewtoICajQyKUn .node .label,#mermaid-svg-vJPewtoICajQyKUn .image-shape .label,#mermaid-svg-vJPewtoICajQyKUn .icon-shape .label{text-align:center;}#mermaid-svg-vJPewtoICajQyKUn .node.clickable{cursor:pointer;}#mermaid-svg-vJPewtoICajQyKUn .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-vJPewtoICajQyKUn .arrowheadPath{fill:#333333;}#mermaid-svg-vJPewtoICajQyKUn .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-vJPewtoICajQyKUn .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-vJPewtoICajQyKUn .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-vJPewtoICajQyKUn .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-vJPewtoICajQyKUn .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-vJPewtoICajQyKUn .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-vJPewtoICajQyKUn .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-vJPewtoICajQyKUn .cluster text{fill:#333;}#mermaid-svg-vJPewtoICajQyKUn .cluster span{color:#333;}#mermaid-svg-vJPewtoICajQyKUn div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-vJPewtoICajQyKUn .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-vJPewtoICajQyKUn rect.text{fill:none;stroke-width:0;}#mermaid-svg-vJPewtoICajQyKUn .icon-shape,#mermaid-svg-vJPewtoICajQyKUn .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-vJPewtoICajQyKUn .icon-shape p,#mermaid-svg-vJPewtoICajQyKUn .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-vJPewtoICajQyKUn .icon-shape .label rect,#mermaid-svg-vJPewtoICajQyKUn .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-vJPewtoICajQyKUn .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-vJPewtoICajQyKUn .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-vJPewtoICajQyKUn :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 失败反馈
规范不一致
测试通过
🔄 持续集成层
规范 Lint 校验
测试自动执行
覆盖率检测
规范漂移告警
✅ 验证层 (TDD)
单元测试 Unit Test
集成测试 Integration
契约测试 Contract
E2E 测试
🤖 AI 编码层
AI 解析规范上下文
AI 生成代码骨架
AI 补全实现逻辑
AI 自动生成测试
📋 规范层 (SDD)
需求文档 / PRD
接口规范 OpenAPI
类型定义 TypeScript
架构决策 ADR
AI 任务规范 SKILL.md
🚀 部署


四、实践流程:五步融合法

Step 1:需求 → 规范(SDD 起点)

在拿到需求后,不要急于让 AI 写代码,先将需求转化为结构化规范:
规范文件 AI 助手 开发者 产品经理 规范文件 AI 助手 开发者 产品经理 #mermaid-svg-Pdo7f2UXhVXhs8Pa{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Pdo7f2UXhVXhs8Pa .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Pdo7f2UXhVXhs8Pa .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Pdo7f2UXhVXhs8Pa .error-icon{fill:#552222;}#mermaid-svg-Pdo7f2UXhVXhs8Pa .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Pdo7f2UXhVXhs8Pa .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Pdo7f2UXhVXhs8Pa .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Pdo7f2UXhVXhs8Pa .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Pdo7f2UXhVXhs8Pa .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Pdo7f2UXhVXhs8Pa .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Pdo7f2UXhVXhs8Pa .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Pdo7f2UXhVXhs8Pa .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Pdo7f2UXhVXhs8Pa .marker.cross{stroke:#333333;}#mermaid-svg-Pdo7f2UXhVXhs8Pa svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Pdo7f2UXhVXhs8Pa p{margin:0;}#mermaid-svg-Pdo7f2UXhVXhs8Pa .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-Pdo7f2UXhVXhs8Pa text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-Pdo7f2UXhVXhs8Pa .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-Pdo7f2UXhVXhs8Pa .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-Pdo7f2UXhVXhs8Pa .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-Pdo7f2UXhVXhs8Pa .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-Pdo7f2UXhVXhs8Pa #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-Pdo7f2UXhVXhs8Pa .sequenceNumber{fill:white;}#mermaid-svg-Pdo7f2UXhVXhs8Pa #sequencenumber{fill:#333;}#mermaid-svg-Pdo7f2UXhVXhs8Pa #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-Pdo7f2UXhVXhs8Pa .messageText{fill:#333;stroke:none;}#mermaid-svg-Pdo7f2UXhVXhs8Pa .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-Pdo7f2UXhVXhs8Pa .labelText,#mermaid-svg-Pdo7f2UXhVXhs8Pa .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-Pdo7f2UXhVXhs8Pa .loopText,#mermaid-svg-Pdo7f2UXhVXhs8Pa .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-Pdo7f2UXhVXhs8Pa .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-Pdo7f2UXhVXhs8Pa .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-Pdo7f2UXhVXhs8Pa .noteText,#mermaid-svg-Pdo7f2UXhVXhs8Pa .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-Pdo7f2UXhVXhs8Pa .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-Pdo7f2UXhVXhs8Pa .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-Pdo7f2UXhVXhs8Pa .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-Pdo7f2UXhVXhs8Pa .actorPopupMenu{position:absolute;}#mermaid-svg-Pdo7f2UXhVXhs8Pa .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-Pdo7f2UXhVXhs8Pa .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-Pdo7f2UXhVXhs8Pa .actor-man circle,#mermaid-svg-Pdo7f2UXhVXhs8Pa line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-Pdo7f2UXhVXhs8Pa :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} openapi.yaml / types.ts / ADR.md 提交需求文档 (PRD) 请解析需求,生成 OpenAPI 草稿 返回 OpenAPI YAML 草稿 审核 & 提交规范文件 基于规范生成代码骨架

实操示例: 以"用户登录接口"为例

yaml 复制代码
# openapi.yaml(规范先行)
paths:
  /auth/login:
    post:
      summary: 用户登录
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [username, password]
              properties:
                username:
                  type: string
                  minLength: 3
                  maxLength: 50
                password:
                  type: string
                  minLength: 8
      responses:
        '200':
          description: 登录成功
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/LoginResponse'
        '401':
          description: 用户名或密码错误

Step 2:规范 → 测试骨架(TDD 前置)

规范写完后,让 AI 根据规范生成测试骨架(而非直接生成实现代码):
#mermaid-svg-t2O9fBCbd8jbq51T{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-t2O9fBCbd8jbq51T .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-t2O9fBCbd8jbq51T .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-t2O9fBCbd8jbq51T .error-icon{fill:#552222;}#mermaid-svg-t2O9fBCbd8jbq51T .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-t2O9fBCbd8jbq51T .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-t2O9fBCbd8jbq51T .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-t2O9fBCbd8jbq51T .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-t2O9fBCbd8jbq51T .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-t2O9fBCbd8jbq51T .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-t2O9fBCbd8jbq51T .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-t2O9fBCbd8jbq51T .marker{fill:#333333;stroke:#333333;}#mermaid-svg-t2O9fBCbd8jbq51T .marker.cross{stroke:#333333;}#mermaid-svg-t2O9fBCbd8jbq51T svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-t2O9fBCbd8jbq51T p{margin:0;}#mermaid-svg-t2O9fBCbd8jbq51T .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-t2O9fBCbd8jbq51T .cluster-label text{fill:#333;}#mermaid-svg-t2O9fBCbd8jbq51T .cluster-label span{color:#333;}#mermaid-svg-t2O9fBCbd8jbq51T .cluster-label span p{background-color:transparent;}#mermaid-svg-t2O9fBCbd8jbq51T .label text,#mermaid-svg-t2O9fBCbd8jbq51T span{fill:#333;color:#333;}#mermaid-svg-t2O9fBCbd8jbq51T .node rect,#mermaid-svg-t2O9fBCbd8jbq51T .node circle,#mermaid-svg-t2O9fBCbd8jbq51T .node ellipse,#mermaid-svg-t2O9fBCbd8jbq51T .node polygon,#mermaid-svg-t2O9fBCbd8jbq51T .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-t2O9fBCbd8jbq51T .rough-node .label text,#mermaid-svg-t2O9fBCbd8jbq51T .node .label text,#mermaid-svg-t2O9fBCbd8jbq51T .image-shape .label,#mermaid-svg-t2O9fBCbd8jbq51T .icon-shape .label{text-anchor:middle;}#mermaid-svg-t2O9fBCbd8jbq51T .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-t2O9fBCbd8jbq51T .rough-node .label,#mermaid-svg-t2O9fBCbd8jbq51T .node .label,#mermaid-svg-t2O9fBCbd8jbq51T .image-shape .label,#mermaid-svg-t2O9fBCbd8jbq51T .icon-shape .label{text-align:center;}#mermaid-svg-t2O9fBCbd8jbq51T .node.clickable{cursor:pointer;}#mermaid-svg-t2O9fBCbd8jbq51T .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-t2O9fBCbd8jbq51T .arrowheadPath{fill:#333333;}#mermaid-svg-t2O9fBCbd8jbq51T .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-t2O9fBCbd8jbq51T .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-t2O9fBCbd8jbq51T .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-t2O9fBCbd8jbq51T .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-t2O9fBCbd8jbq51T .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-t2O9fBCbd8jbq51T .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-t2O9fBCbd8jbq51T .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-t2O9fBCbd8jbq51T .cluster text{fill:#333;}#mermaid-svg-t2O9fBCbd8jbq51T .cluster span{color:#333;}#mermaid-svg-t2O9fBCbd8jbq51T div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-t2O9fBCbd8jbq51T .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-t2O9fBCbd8jbq51T rect.text{fill:none;stroke-width:0;}#mermaid-svg-t2O9fBCbd8jbq51T .icon-shape,#mermaid-svg-t2O9fBCbd8jbq51T .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-t2O9fBCbd8jbq51T .icon-shape p,#mermaid-svg-t2O9fBCbd8jbq51T .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-t2O9fBCbd8jbq51T .icon-shape .label rect,#mermaid-svg-t2O9fBCbd8jbq51T .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-t2O9fBCbd8jbq51T .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-t2O9fBCbd8jbq51T .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-t2O9fBCbd8jbq51T :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} AI 解析
📋 OpenAPI 规范
🧪 测试骨架生成
正常路径测试
边界条件测试
异常路径测试
性能基准测试
全部失败

Red 状态

AI 提示词模板:

复制代码
根据以下 OpenAPI 规范,生成完整的 Jest 单元测试骨架。
要求:
1. 覆盖所有 HTTP 状态码场景
2. 包含边界值测试(minLength/maxLength)
3. 使用 describe/it 结构,测试描述用中文
4. 先只写测试,不写实现

[粘贴 OpenAPI 规范]

生成的测试骨架示例:

typescript 复制代码
// auth.test.ts
describe('用户登录接口 POST /auth/login', () => {
  describe('正常登录', () => {
    it('正确账号密码应返回 200 和 token', async () => {
      // TODO: 待实现
      expect(true).toBe(false); // Red 状态
    });
  });

  describe('参数校验', () => {
    it('用户名少于3位应返回 400', async () => {
      expect(true).toBe(false);
    });
    it('密码少于8位应返回 400', async () => {
      expect(true).toBe(false);
    });
    it('缺少 username 字段应返回 400', async () => {
      expect(true).toBe(false);
    });
  });

  describe('认证失败', () => {
    it('错误密码应返回 401', async () => {
      expect(true).toBe(false);
    });
    it('不存在的用户应返回 401', async () => {
      expect(true).toBe(false);
    });
  });
});

Step 3:AI 实现代码(受双重约束)

此时 AI 的实现代码同时受到规范约束 (SDD)和测试约束(TDD)的双重限制:
#mermaid-svg-fcra9T94oDSUpTq3{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-fcra9T94oDSUpTq3 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-fcra9T94oDSUpTq3 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-fcra9T94oDSUpTq3 .error-icon{fill:#552222;}#mermaid-svg-fcra9T94oDSUpTq3 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-fcra9T94oDSUpTq3 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-fcra9T94oDSUpTq3 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-fcra9T94oDSUpTq3 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-fcra9T94oDSUpTq3 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-fcra9T94oDSUpTq3 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-fcra9T94oDSUpTq3 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-fcra9T94oDSUpTq3 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-fcra9T94oDSUpTq3 .marker.cross{stroke:#333333;}#mermaid-svg-fcra9T94oDSUpTq3 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-fcra9T94oDSUpTq3 p{margin:0;}#mermaid-svg-fcra9T94oDSUpTq3 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-fcra9T94oDSUpTq3 .cluster-label text{fill:#333;}#mermaid-svg-fcra9T94oDSUpTq3 .cluster-label span{color:#333;}#mermaid-svg-fcra9T94oDSUpTq3 .cluster-label span p{background-color:transparent;}#mermaid-svg-fcra9T94oDSUpTq3 .label text,#mermaid-svg-fcra9T94oDSUpTq3 span{fill:#333;color:#333;}#mermaid-svg-fcra9T94oDSUpTq3 .node rect,#mermaid-svg-fcra9T94oDSUpTq3 .node circle,#mermaid-svg-fcra9T94oDSUpTq3 .node ellipse,#mermaid-svg-fcra9T94oDSUpTq3 .node polygon,#mermaid-svg-fcra9T94oDSUpTq3 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-fcra9T94oDSUpTq3 .rough-node .label text,#mermaid-svg-fcra9T94oDSUpTq3 .node .label text,#mermaid-svg-fcra9T94oDSUpTq3 .image-shape .label,#mermaid-svg-fcra9T94oDSUpTq3 .icon-shape .label{text-anchor:middle;}#mermaid-svg-fcra9T94oDSUpTq3 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-fcra9T94oDSUpTq3 .rough-node .label,#mermaid-svg-fcra9T94oDSUpTq3 .node .label,#mermaid-svg-fcra9T94oDSUpTq3 .image-shape .label,#mermaid-svg-fcra9T94oDSUpTq3 .icon-shape .label{text-align:center;}#mermaid-svg-fcra9T94oDSUpTq3 .node.clickable{cursor:pointer;}#mermaid-svg-fcra9T94oDSUpTq3 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-fcra9T94oDSUpTq3 .arrowheadPath{fill:#333333;}#mermaid-svg-fcra9T94oDSUpTq3 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-fcra9T94oDSUpTq3 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-fcra9T94oDSUpTq3 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-fcra9T94oDSUpTq3 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-fcra9T94oDSUpTq3 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-fcra9T94oDSUpTq3 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-fcra9T94oDSUpTq3 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-fcra9T94oDSUpTq3 .cluster text{fill:#333;}#mermaid-svg-fcra9T94oDSUpTq3 .cluster span{color:#333;}#mermaid-svg-fcra9T94oDSUpTq3 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-fcra9T94oDSUpTq3 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-fcra9T94oDSUpTq3 rect.text{fill:none;stroke-width:0;}#mermaid-svg-fcra9T94oDSUpTq3 .icon-shape,#mermaid-svg-fcra9T94oDSUpTq3 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-fcra9T94oDSUpTq3 .icon-shape p,#mermaid-svg-fcra9T94oDSUpTq3 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-fcra9T94oDSUpTq3 .icon-shape .label rect,#mermaid-svg-fcra9T94oDSUpTq3 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-fcra9T94oDSUpTq3 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-fcra9T94oDSUpTq3 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-fcra9T94oDSUpTq3 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 部分失败
实现逻辑错误
规范理解偏差
✅ 全部通过
🤖 AI 开始实现
读取约束
📋 OpenAPI 规范

接口契约约束
🧪 单元测试

行为约束
AI 生成实现代码
运行测试
测试通过?
AI 分析失败原因
失败类型
重新解析规范
Green 状态
AI 执行重构
再次运行测试确认

AI 提示词模板:

复制代码
现在请实现以下接口,要求:
1. 严格遵循 openapi.yaml 中的接口规范
2. 实现必须让 auth.test.ts 中所有测试通过
3. 使用 Spring Boot 3 + Java 17
4. 包含参数校验(使用 Bean Validation)
5. 不要超出规范范围添加额外字段

规范文件:[openapi.yaml]
测试文件:[auth.test.ts]

Step 4:重构与规范更新(双向反馈)

代码通过测试后,进入重构阶段,同时维护规范的准确性:
#mermaid-svg-oIGdoawoLOHEfmAG{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-oIGdoawoLOHEfmAG .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-oIGdoawoLOHEfmAG .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-oIGdoawoLOHEfmAG .error-icon{fill:#552222;}#mermaid-svg-oIGdoawoLOHEfmAG .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-oIGdoawoLOHEfmAG .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-oIGdoawoLOHEfmAG .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-oIGdoawoLOHEfmAG .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-oIGdoawoLOHEfmAG .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-oIGdoawoLOHEfmAG .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-oIGdoawoLOHEfmAG .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-oIGdoawoLOHEfmAG .marker{fill:#333333;stroke:#333333;}#mermaid-svg-oIGdoawoLOHEfmAG .marker.cross{stroke:#333333;}#mermaid-svg-oIGdoawoLOHEfmAG svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-oIGdoawoLOHEfmAG p{margin:0;}#mermaid-svg-oIGdoawoLOHEfmAG defs #statediagram-barbEnd{fill:#333333;stroke:#333333;}#mermaid-svg-oIGdoawoLOHEfmAG g.stateGroup text{fill:#9370DB;stroke:none;font-size:10px;}#mermaid-svg-oIGdoawoLOHEfmAG g.stateGroup text{fill:#333;stroke:none;font-size:10px;}#mermaid-svg-oIGdoawoLOHEfmAG g.stateGroup .state-title{font-weight:bolder;fill:#131300;}#mermaid-svg-oIGdoawoLOHEfmAG g.stateGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-oIGdoawoLOHEfmAG g.stateGroup line{stroke:#333333;stroke-width:1;}#mermaid-svg-oIGdoawoLOHEfmAG .transition{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-oIGdoawoLOHEfmAG .stateGroup .composit{fill:white;border-bottom:1px;}#mermaid-svg-oIGdoawoLOHEfmAG .stateGroup .alt-composit{fill:#e0e0e0;border-bottom:1px;}#mermaid-svg-oIGdoawoLOHEfmAG .state-note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-oIGdoawoLOHEfmAG .state-note text{fill:black;stroke:none;font-size:10px;}#mermaid-svg-oIGdoawoLOHEfmAG .stateLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-oIGdoawoLOHEfmAG .edgeLabel .label rect{fill:#ECECFF;opacity:0.5;}#mermaid-svg-oIGdoawoLOHEfmAG .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-oIGdoawoLOHEfmAG .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-oIGdoawoLOHEfmAG .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-oIGdoawoLOHEfmAG .edgeLabel .label text{fill:#333;}#mermaid-svg-oIGdoawoLOHEfmAG .label div .edgeLabel{color:#333;}#mermaid-svg-oIGdoawoLOHEfmAG .stateLabel text{fill:#131300;font-size:10px;font-weight:bold;}#mermaid-svg-oIGdoawoLOHEfmAG .node circle.state-start{fill:#333333;stroke:#333333;}#mermaid-svg-oIGdoawoLOHEfmAG .node .fork-join{fill:#333333;stroke:#333333;}#mermaid-svg-oIGdoawoLOHEfmAG .node circle.state-end{fill:#9370DB;stroke:white;stroke-width:1.5;}#mermaid-svg-oIGdoawoLOHEfmAG .end-state-inner{fill:white;stroke-width:1.5;}#mermaid-svg-oIGdoawoLOHEfmAG .node rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-oIGdoawoLOHEfmAG .node polygon{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-oIGdoawoLOHEfmAG #statediagram-barbEnd{fill:#333333;}#mermaid-svg-oIGdoawoLOHEfmAG .statediagram-cluster rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-oIGdoawoLOHEfmAG .cluster-label,#mermaid-svg-oIGdoawoLOHEfmAG .nodeLabel{color:#131300;}#mermaid-svg-oIGdoawoLOHEfmAG .statediagram-cluster rect.outer{rx:5px;ry:5px;}#mermaid-svg-oIGdoawoLOHEfmAG .statediagram-state .divider{stroke:#9370DB;}#mermaid-svg-oIGdoawoLOHEfmAG .statediagram-state .title-state{rx:5px;ry:5px;}#mermaid-svg-oIGdoawoLOHEfmAG .statediagram-cluster.statediagram-cluster .inner{fill:white;}#mermaid-svg-oIGdoawoLOHEfmAG .statediagram-cluster.statediagram-cluster-alt .inner{fill:#f0f0f0;}#mermaid-svg-oIGdoawoLOHEfmAG .statediagram-cluster .inner{rx:0;ry:0;}#mermaid-svg-oIGdoawoLOHEfmAG .statediagram-state rect.basic{rx:5px;ry:5px;}#mermaid-svg-oIGdoawoLOHEfmAG .statediagram-state rect.divider{stroke-dasharray:10,10;fill:#f0f0f0;}#mermaid-svg-oIGdoawoLOHEfmAG .note-edge{stroke-dasharray:5;}#mermaid-svg-oIGdoawoLOHEfmAG .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-oIGdoawoLOHEfmAG .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-oIGdoawoLOHEfmAG .statediagram-note text{fill:black;}#mermaid-svg-oIGdoawoLOHEfmAG .statediagram-note .nodeLabel{color:black;}#mermaid-svg-oIGdoawoLOHEfmAG .statediagram .edgeLabel{color:red;}#mermaid-svg-oIGdoawoLOHEfmAG #dependencyStart,#mermaid-svg-oIGdoawoLOHEfmAG #dependencyEnd{fill:#333333;stroke:#333333;stroke-width:1;}#mermaid-svg-oIGdoawoLOHEfmAG .statediagramTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-oIGdoawoLOHEfmAG :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} SDD → TDD
测试驱动
红→绿
Refactor
实现反哺规范
发现规范不完整
规范变化→新测试
无需更新
规范与实现一致
确认绿灯
合并主干
规范制定
测试编写
AI实现
测试通过
代码重构
规范检视
规范更新
测试补充
CI集成


Step 5:CI 流水线中的规范守护

将 SDD 和 TDD 的质量门控集成到 CI/CD 流水线:
#mermaid-svg-XkJ3wfY5DR1g1L3r{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-XkJ3wfY5DR1g1L3r .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-XkJ3wfY5DR1g1L3r .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-XkJ3wfY5DR1g1L3r .error-icon{fill:#552222;}#mermaid-svg-XkJ3wfY5DR1g1L3r .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-XkJ3wfY5DR1g1L3r .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-XkJ3wfY5DR1g1L3r .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-XkJ3wfY5DR1g1L3r .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-XkJ3wfY5DR1g1L3r .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-XkJ3wfY5DR1g1L3r .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-XkJ3wfY5DR1g1L3r .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-XkJ3wfY5DR1g1L3r .marker{fill:#333333;stroke:#333333;}#mermaid-svg-XkJ3wfY5DR1g1L3r .marker.cross{stroke:#333333;}#mermaid-svg-XkJ3wfY5DR1g1L3r svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-XkJ3wfY5DR1g1L3r p{margin:0;}#mermaid-svg-XkJ3wfY5DR1g1L3r .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-XkJ3wfY5DR1g1L3r .cluster-label text{fill:#333;}#mermaid-svg-XkJ3wfY5DR1g1L3r .cluster-label span{color:#333;}#mermaid-svg-XkJ3wfY5DR1g1L3r .cluster-label span p{background-color:transparent;}#mermaid-svg-XkJ3wfY5DR1g1L3r .label text,#mermaid-svg-XkJ3wfY5DR1g1L3r span{fill:#333;color:#333;}#mermaid-svg-XkJ3wfY5DR1g1L3r .node rect,#mermaid-svg-XkJ3wfY5DR1g1L3r .node circle,#mermaid-svg-XkJ3wfY5DR1g1L3r .node ellipse,#mermaid-svg-XkJ3wfY5DR1g1L3r .node polygon,#mermaid-svg-XkJ3wfY5DR1g1L3r .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-XkJ3wfY5DR1g1L3r .rough-node .label text,#mermaid-svg-XkJ3wfY5DR1g1L3r .node .label text,#mermaid-svg-XkJ3wfY5DR1g1L3r .image-shape .label,#mermaid-svg-XkJ3wfY5DR1g1L3r .icon-shape .label{text-anchor:middle;}#mermaid-svg-XkJ3wfY5DR1g1L3r .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-XkJ3wfY5DR1g1L3r .rough-node .label,#mermaid-svg-XkJ3wfY5DR1g1L3r .node .label,#mermaid-svg-XkJ3wfY5DR1g1L3r .image-shape .label,#mermaid-svg-XkJ3wfY5DR1g1L3r .icon-shape .label{text-align:center;}#mermaid-svg-XkJ3wfY5DR1g1L3r .node.clickable{cursor:pointer;}#mermaid-svg-XkJ3wfY5DR1g1L3r .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-XkJ3wfY5DR1g1L3r .arrowheadPath{fill:#333333;}#mermaid-svg-XkJ3wfY5DR1g1L3r .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-XkJ3wfY5DR1g1L3r .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-XkJ3wfY5DR1g1L3r .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-XkJ3wfY5DR1g1L3r .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-XkJ3wfY5DR1g1L3r .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-XkJ3wfY5DR1g1L3r .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-XkJ3wfY5DR1g1L3r .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-XkJ3wfY5DR1g1L3r .cluster text{fill:#333;}#mermaid-svg-XkJ3wfY5DR1g1L3r .cluster span{color:#333;}#mermaid-svg-XkJ3wfY5DR1g1L3r div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-XkJ3wfY5DR1g1L3r .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-XkJ3wfY5DR1g1L3r rect.text{fill:none;stroke-width:0;}#mermaid-svg-XkJ3wfY5DR1g1L3r .icon-shape,#mermaid-svg-XkJ3wfY5DR1g1L3r .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-XkJ3wfY5DR1g1L3r .icon-shape p,#mermaid-svg-XkJ3wfY5DR1g1L3r .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-XkJ3wfY5DR1g1L3r .icon-shape .label rect,#mermaid-svg-XkJ3wfY5DR1g1L3r .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-XkJ3wfY5DR1g1L3r .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-XkJ3wfY5DR1g1L3r .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-XkJ3wfY5DR1g1L3r :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 结果
质量门控
触发器
全部通过
任一失败
任一失败
任一失败
任一失败
任一失败
任一失败
Pull Request
📋 规范校验

openapi-lint

spectral
🔍 类型检查

tsc --noEmit
🧪 单元测试

jest --coverage
📊 覆盖率门槛

>= 80%
🔄 契约测试

Pact Broker
🤖 AI 规范漂移检测

实现 vs 规范 diff
✅ 准入合并
阻断合并

返回详细报告


五、完整实践案例:云安全告警管理模块

以一个真实场景为例:云安全平台的告警规则管理接口,演示完整的 TDD+SDD+AI 协作流程。

5.1 项目结构

复制代码
alert-rule-service/
├── specs/                    # SDD 规范层
│   ├── openapi.yaml          # 接口规范
│   ├── alert-rule.schema.json # 数据模型规范
│   └── ADR-001-alert-engine.md # 架构决策记录
├── src/
│   ├── main/java/.../
│   │   ├── controller/       # AI 根据规范生成
│   │   ├── service/          # AI + TDD 驱动实现
│   │   └── model/            # 从 schema 生成
│   └── test/java/.../        # TDD 测试用例
├── .workbuddy/
│   └── skills/
│       └── alert-rule-dev/   # 项目级 SKILL
│           └── SKILL.md      # AI 任务规范
└── .spectral.yaml            # 规范 Lint 配置

5.2 SKILL.md:AI 任务规范示例

markdown 复制代码
# SKILL: 告警规则模块开发规范

## 技术栈约束
- Spring Boot 3.2 + Java 17
- MyBatis-Plus ORM
- Jakarta Bean Validation
- JUnit 5 + Mockito

## 接口规范
- 严格遵循 specs/openapi.yaml
- 所有接口返回统一格式:{ code, message, data }
- 分页接口使用 PageResult<T> 包装

## 命名规范
- Controller 方法名与 operationId 一致
- 异常使用 BusinessException(ErrorCode.XXX) 抛出
- 日志使用 @Slf4j,禁止 System.out.println

## 测试要求
- 每个 Service 方法覆盖率 >= 85%
- Controller 层必须有集成测试
- 涉及数据库操作使用 @Transactional + H2 内存库

5.3 告警规则 CRUD 的测试先行示例

java 复制代码
// AlertRuleServiceTest.java(测试骨架,Red 阶段)
@SpringBootTest
@Transactional
class AlertRuleServiceTest {

    @Autowired
    AlertRuleService alertRuleService;

    @Test
    @DisplayName("创建告警规则 - 正常参数应成功持久化")
    void createAlertRule_withValidParams_shouldPersist() {
        // Given
        CreateAlertRuleRequest request = CreateAlertRuleRequest.builder()
            .name("CPU使用率告警")
            .metric("cpu_usage")
            .threshold(85.0)
            .severity(Severity.HIGH)
            .build();

        // When
        AlertRuleVO result = alertRuleService.createAlertRule(request);

        // Then
        assertThat(result.getId()).isNotNull();
        assertThat(result.getName()).isEqualTo("CPU使用率告警");
        assertThat(result.getStatus()).isEqualTo(RuleStatus.ENABLED);
    }

    @Test
    @DisplayName("创建告警规则 - 阈值超出范围(>100)应抛出业务异常")
    void createAlertRule_withThresholdOver100_shouldThrowBusinessException() {
        CreateAlertRuleRequest request = CreateAlertRuleRequest.builder()
            .name("非法规则")
            .metric("cpu_usage")
            .threshold(150.0)  // 非法值
            .severity(Severity.LOW)
            .build();

        assertThatThrownBy(() -> alertRuleService.createAlertRule(request))
            .isInstanceOf(BusinessException.class)
            .hasMessageContaining(ErrorCode.INVALID_THRESHOLD.getMessage());
    }

    @Test
    @DisplayName("查询告警规则列表 - 支持按严重等级过滤")
    void listAlertRules_filterBySeverity_shouldReturnMatchedRules() {
        // Given - 预置不同等级的规则
        createTestRule("高危规则1", Severity.HIGH);
        createTestRule("高危规则2", Severity.HIGH);
        createTestRule("低危规则", Severity.LOW);

        // When
        PageResult<AlertRuleVO> result = alertRuleService.listAlertRules(
            AlertRuleQuery.builder().severity(Severity.HIGH).pageSize(10).build()
        );

        // Then
        assertThat(result.getTotal()).isEqualTo(2);
        assertThat(result.getItems())
            .allMatch(rule -> rule.getSeverity() == Severity.HIGH);
    }
}

5.4 AI 驱动实现(Green 阶段)

AI 收到测试文件 + SKILL.md + OpenAPI 规范后,生成的 Service 实现:

java 复制代码
// AlertRuleServiceImpl.java(AI 生成,受双重约束)
@Slf4j
@Service
@RequiredArgsConstructor
public class AlertRuleServiceImpl implements AlertRuleService {

    private final AlertRuleMapper alertRuleMapper;
    private final AlertRuleConverter converter;

    @Override
    @Transactional
    public AlertRuleVO createAlertRule(CreateAlertRuleRequest request) {
        // 参数校验(规范约束)
        if (request.getThreshold() < 0 || request.getThreshold() > 100) {
            throw new BusinessException(ErrorCode.INVALID_THRESHOLD);
        }

        // 重名检查
        if (alertRuleMapper.existsByName(request.getName())) {
            throw new BusinessException(ErrorCode.ALERT_RULE_NAME_DUPLICATE);
        }

        AlertRule entity = converter.toEntity(request);
        entity.setStatus(RuleStatus.ENABLED);
        entity.setCreateTime(LocalDateTime.now());

        alertRuleMapper.insert(entity);
        log.info("告警规则创建成功: id={}, name={}", entity.getId(), entity.getName());

        return converter.toVO(entity);
    }

    @Override
    public PageResult<AlertRuleVO> listAlertRules(AlertRuleQuery query) {
        Page<AlertRule> page = new Page<>(query.getPageNum(), query.getPageSize());
        LambdaQueryWrapper<AlertRule> wrapper = Wrappers.lambdaQuery(AlertRule.class)
            .eq(query.getSeverity() != null, AlertRule::getSeverity, query.getSeverity())
            .eq(query.getStatus() != null, AlertRule::getStatus, query.getStatus())
            .orderByDesc(AlertRule::getCreateTime);

        alertRuleMapper.selectPage(page, wrapper);
        return PageResult.of(page, converter::toVO);
    }
}

六、进阶:AI Coding 中的规范漂移治理

随着项目演进,规范与实现之间会出现"漂移",这是 SDD 面临的最大挑战:
#mermaid-svg-78KZB785at5cIlUi{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-78KZB785at5cIlUi .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-78KZB785at5cIlUi .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-78KZB785at5cIlUi .error-icon{fill:#552222;}#mermaid-svg-78KZB785at5cIlUi .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-78KZB785at5cIlUi .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-78KZB785at5cIlUi .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-78KZB785at5cIlUi .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-78KZB785at5cIlUi .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-78KZB785at5cIlUi .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-78KZB785at5cIlUi .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-78KZB785at5cIlUi .marker{fill:#333333;stroke:#333333;}#mermaid-svg-78KZB785at5cIlUi .marker.cross{stroke:#333333;}#mermaid-svg-78KZB785at5cIlUi svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-78KZB785at5cIlUi p{margin:0;}#mermaid-svg-78KZB785at5cIlUi .edge{stroke-width:3;}#mermaid-svg-78KZB785at5cIlUi .section--1 rect,#mermaid-svg-78KZB785at5cIlUi .section--1 path,#mermaid-svg-78KZB785at5cIlUi .section--1 circle,#mermaid-svg-78KZB785at5cIlUi .section--1 path{fill:hsl(240, 100%, 76.2745098039%);}#mermaid-svg-78KZB785at5cIlUi .section--1 text{fill:#ffffff;}#mermaid-svg-78KZB785at5cIlUi .node-icon--1{font-size:40px;color:#ffffff;}#mermaid-svg-78KZB785at5cIlUi .section-edge--1{stroke:hsl(240, 100%, 76.2745098039%);}#mermaid-svg-78KZB785at5cIlUi .edge-depth--1{stroke-width:17;}#mermaid-svg-78KZB785at5cIlUi .section--1 line{stroke:hsl(60, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-78KZB785at5cIlUi .lineWrapper line{stroke:#ffffff;}#mermaid-svg-78KZB785at5cIlUi .disabled,#mermaid-svg-78KZB785at5cIlUi .disabled circle,#mermaid-svg-78KZB785at5cIlUi .disabled text{fill:lightgray;}#mermaid-svg-78KZB785at5cIlUi .disabled text{fill:#efefef;}#mermaid-svg-78KZB785at5cIlUi .section-0 rect,#mermaid-svg-78KZB785at5cIlUi .section-0 path,#mermaid-svg-78KZB785at5cIlUi .section-0 circle,#mermaid-svg-78KZB785at5cIlUi .section-0 path{fill:hsl(60, 100%, 73.5294117647%);}#mermaid-svg-78KZB785at5cIlUi .section-0 text{fill:black;}#mermaid-svg-78KZB785at5cIlUi .node-icon-0{font-size:40px;color:black;}#mermaid-svg-78KZB785at5cIlUi .section-edge-0{stroke:hsl(60, 100%, 73.5294117647%);}#mermaid-svg-78KZB785at5cIlUi .edge-depth-0{stroke-width:14;}#mermaid-svg-78KZB785at5cIlUi .section-0 line{stroke:hsl(240, 100%, 83.5294117647%);stroke-width:3;}#mermaid-svg-78KZB785at5cIlUi .lineWrapper line{stroke:black;}#mermaid-svg-78KZB785at5cIlUi .disabled,#mermaid-svg-78KZB785at5cIlUi .disabled circle,#mermaid-svg-78KZB785at5cIlUi .disabled text{fill:lightgray;}#mermaid-svg-78KZB785at5cIlUi .disabled text{fill:#efefef;}#mermaid-svg-78KZB785at5cIlUi .section-1 rect,#mermaid-svg-78KZB785at5cIlUi .section-1 path,#mermaid-svg-78KZB785at5cIlUi .section-1 circle,#mermaid-svg-78KZB785at5cIlUi .section-1 path{fill:hsl(80, 100%, 76.2745098039%);}#mermaid-svg-78KZB785at5cIlUi .section-1 text{fill:black;}#mermaid-svg-78KZB785at5cIlUi .node-icon-1{font-size:40px;color:black;}#mermaid-svg-78KZB785at5cIlUi .section-edge-1{stroke:hsl(80, 100%, 76.2745098039%);}#mermaid-svg-78KZB785at5cIlUi .edge-depth-1{stroke-width:11;}#mermaid-svg-78KZB785at5cIlUi .section-1 line{stroke:hsl(260, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-78KZB785at5cIlUi .lineWrapper line{stroke:black;}#mermaid-svg-78KZB785at5cIlUi .disabled,#mermaid-svg-78KZB785at5cIlUi .disabled circle,#mermaid-svg-78KZB785at5cIlUi .disabled text{fill:lightgray;}#mermaid-svg-78KZB785at5cIlUi .disabled text{fill:#efefef;}#mermaid-svg-78KZB785at5cIlUi .section-2 rect,#mermaid-svg-78KZB785at5cIlUi .section-2 path,#mermaid-svg-78KZB785at5cIlUi .section-2 circle,#mermaid-svg-78KZB785at5cIlUi .section-2 path{fill:hsl(270, 100%, 76.2745098039%);}#mermaid-svg-78KZB785at5cIlUi .section-2 text{fill:#ffffff;}#mermaid-svg-78KZB785at5cIlUi .node-icon-2{font-size:40px;color:#ffffff;}#mermaid-svg-78KZB785at5cIlUi .section-edge-2{stroke:hsl(270, 100%, 76.2745098039%);}#mermaid-svg-78KZB785at5cIlUi .edge-depth-2{stroke-width:8;}#mermaid-svg-78KZB785at5cIlUi .section-2 line{stroke:hsl(90, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-78KZB785at5cIlUi .lineWrapper line{stroke:#ffffff;}#mermaid-svg-78KZB785at5cIlUi .disabled,#mermaid-svg-78KZB785at5cIlUi .disabled circle,#mermaid-svg-78KZB785at5cIlUi .disabled text{fill:lightgray;}#mermaid-svg-78KZB785at5cIlUi .disabled text{fill:#efefef;}#mermaid-svg-78KZB785at5cIlUi .section-3 rect,#mermaid-svg-78KZB785at5cIlUi .section-3 path,#mermaid-svg-78KZB785at5cIlUi .section-3 circle,#mermaid-svg-78KZB785at5cIlUi .section-3 path{fill:hsl(300, 100%, 76.2745098039%);}#mermaid-svg-78KZB785at5cIlUi .section-3 text{fill:black;}#mermaid-svg-78KZB785at5cIlUi .node-icon-3{font-size:40px;color:black;}#mermaid-svg-78KZB785at5cIlUi .section-edge-3{stroke:hsl(300, 100%, 76.2745098039%);}#mermaid-svg-78KZB785at5cIlUi .edge-depth-3{stroke-width:5;}#mermaid-svg-78KZB785at5cIlUi .section-3 line{stroke:hsl(120, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-78KZB785at5cIlUi .lineWrapper line{stroke:black;}#mermaid-svg-78KZB785at5cIlUi .disabled,#mermaid-svg-78KZB785at5cIlUi .disabled circle,#mermaid-svg-78KZB785at5cIlUi .disabled text{fill:lightgray;}#mermaid-svg-78KZB785at5cIlUi .disabled text{fill:#efefef;}#mermaid-svg-78KZB785at5cIlUi .section-4 rect,#mermaid-svg-78KZB785at5cIlUi .section-4 path,#mermaid-svg-78KZB785at5cIlUi .section-4 circle,#mermaid-svg-78KZB785at5cIlUi .section-4 path{fill:hsl(330, 100%, 76.2745098039%);}#mermaid-svg-78KZB785at5cIlUi .section-4 text{fill:black;}#mermaid-svg-78KZB785at5cIlUi .node-icon-4{font-size:40px;color:black;}#mermaid-svg-78KZB785at5cIlUi .section-edge-4{stroke:hsl(330, 100%, 76.2745098039%);}#mermaid-svg-78KZB785at5cIlUi .edge-depth-4{stroke-width:2;}#mermaid-svg-78KZB785at5cIlUi .section-4 line{stroke:hsl(150, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-78KZB785at5cIlUi .lineWrapper line{stroke:black;}#mermaid-svg-78KZB785at5cIlUi .disabled,#mermaid-svg-78KZB785at5cIlUi .disabled circle,#mermaid-svg-78KZB785at5cIlUi .disabled text{fill:lightgray;}#mermaid-svg-78KZB785at5cIlUi .disabled text{fill:#efefef;}#mermaid-svg-78KZB785at5cIlUi .section-5 rect,#mermaid-svg-78KZB785at5cIlUi .section-5 path,#mermaid-svg-78KZB785at5cIlUi .section-5 circle,#mermaid-svg-78KZB785at5cIlUi .section-5 path{fill:hsl(0, 100%, 76.2745098039%);}#mermaid-svg-78KZB785at5cIlUi .section-5 text{fill:black;}#mermaid-svg-78KZB785at5cIlUi .node-icon-5{font-size:40px;color:black;}#mermaid-svg-78KZB785at5cIlUi .section-edge-5{stroke:hsl(0, 100%, 76.2745098039%);}#mermaid-svg-78KZB785at5cIlUi .edge-depth-5{stroke-width:-1;}#mermaid-svg-78KZB785at5cIlUi .section-5 line{stroke:hsl(180, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-78KZB785at5cIlUi .lineWrapper line{stroke:black;}#mermaid-svg-78KZB785at5cIlUi .disabled,#mermaid-svg-78KZB785at5cIlUi .disabled circle,#mermaid-svg-78KZB785at5cIlUi .disabled text{fill:lightgray;}#mermaid-svg-78KZB785at5cIlUi .disabled text{fill:#efefef;}#mermaid-svg-78KZB785at5cIlUi .section-6 rect,#mermaid-svg-78KZB785at5cIlUi .section-6 path,#mermaid-svg-78KZB785at5cIlUi .section-6 circle,#mermaid-svg-78KZB785at5cIlUi .section-6 path{fill:hsl(30, 100%, 76.2745098039%);}#mermaid-svg-78KZB785at5cIlUi .section-6 text{fill:black;}#mermaid-svg-78KZB785at5cIlUi .node-icon-6{font-size:40px;color:black;}#mermaid-svg-78KZB785at5cIlUi .section-edge-6{stroke:hsl(30, 100%, 76.2745098039%);}#mermaid-svg-78KZB785at5cIlUi .edge-depth-6{stroke-width:-4;}#mermaid-svg-78KZB785at5cIlUi .section-6 line{stroke:hsl(210, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-78KZB785at5cIlUi .lineWrapper line{stroke:black;}#mermaid-svg-78KZB785at5cIlUi .disabled,#mermaid-svg-78KZB785at5cIlUi .disabled circle,#mermaid-svg-78KZB785at5cIlUi .disabled text{fill:lightgray;}#mermaid-svg-78KZB785at5cIlUi .disabled text{fill:#efefef;}#mermaid-svg-78KZB785at5cIlUi .section-7 rect,#mermaid-svg-78KZB785at5cIlUi .section-7 path,#mermaid-svg-78KZB785at5cIlUi .section-7 circle,#mermaid-svg-78KZB785at5cIlUi .section-7 path{fill:hsl(90, 100%, 76.2745098039%);}#mermaid-svg-78KZB785at5cIlUi .section-7 text{fill:black;}#mermaid-svg-78KZB785at5cIlUi .node-icon-7{font-size:40px;color:black;}#mermaid-svg-78KZB785at5cIlUi .section-edge-7{stroke:hsl(90, 100%, 76.2745098039%);}#mermaid-svg-78KZB785at5cIlUi .edge-depth-7{stroke-width:-7;}#mermaid-svg-78KZB785at5cIlUi .section-7 line{stroke:hsl(270, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-78KZB785at5cIlUi .lineWrapper line{stroke:black;}#mermaid-svg-78KZB785at5cIlUi .disabled,#mermaid-svg-78KZB785at5cIlUi .disabled circle,#mermaid-svg-78KZB785at5cIlUi .disabled text{fill:lightgray;}#mermaid-svg-78KZB785at5cIlUi .disabled text{fill:#efefef;}#mermaid-svg-78KZB785at5cIlUi .section-8 rect,#mermaid-svg-78KZB785at5cIlUi .section-8 path,#mermaid-svg-78KZB785at5cIlUi .section-8 circle,#mermaid-svg-78KZB785at5cIlUi .section-8 path{fill:hsl(150, 100%, 76.2745098039%);}#mermaid-svg-78KZB785at5cIlUi .section-8 text{fill:black;}#mermaid-svg-78KZB785at5cIlUi .node-icon-8{font-size:40px;color:black;}#mermaid-svg-78KZB785at5cIlUi .section-edge-8{stroke:hsl(150, 100%, 76.2745098039%);}#mermaid-svg-78KZB785at5cIlUi .edge-depth-8{stroke-width:-10;}#mermaid-svg-78KZB785at5cIlUi .section-8 line{stroke:hsl(330, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-78KZB785at5cIlUi .lineWrapper line{stroke:black;}#mermaid-svg-78KZB785at5cIlUi .disabled,#mermaid-svg-78KZB785at5cIlUi .disabled circle,#mermaid-svg-78KZB785at5cIlUi .disabled text{fill:lightgray;}#mermaid-svg-78KZB785at5cIlUi .disabled text{fill:#efefef;}#mermaid-svg-78KZB785at5cIlUi .section-9 rect,#mermaid-svg-78KZB785at5cIlUi .section-9 path,#mermaid-svg-78KZB785at5cIlUi .section-9 circle,#mermaid-svg-78KZB785at5cIlUi .section-9 path{fill:hsl(180, 100%, 76.2745098039%);}#mermaid-svg-78KZB785at5cIlUi .section-9 text{fill:black;}#mermaid-svg-78KZB785at5cIlUi .node-icon-9{font-size:40px;color:black;}#mermaid-svg-78KZB785at5cIlUi .section-edge-9{stroke:hsl(180, 100%, 76.2745098039%);}#mermaid-svg-78KZB785at5cIlUi .edge-depth-9{stroke-width:-13;}#mermaid-svg-78KZB785at5cIlUi .section-9 line{stroke:hsl(0, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-78KZB785at5cIlUi .lineWrapper line{stroke:black;}#mermaid-svg-78KZB785at5cIlUi .disabled,#mermaid-svg-78KZB785at5cIlUi .disabled circle,#mermaid-svg-78KZB785at5cIlUi .disabled text{fill:lightgray;}#mermaid-svg-78KZB785at5cIlUi .disabled text{fill:#efefef;}#mermaid-svg-78KZB785at5cIlUi .section-10 rect,#mermaid-svg-78KZB785at5cIlUi .section-10 path,#mermaid-svg-78KZB785at5cIlUi .section-10 circle,#mermaid-svg-78KZB785at5cIlUi .section-10 path{fill:hsl(210, 100%, 76.2745098039%);}#mermaid-svg-78KZB785at5cIlUi .section-10 text{fill:black;}#mermaid-svg-78KZB785at5cIlUi .node-icon-10{font-size:40px;color:black;}#mermaid-svg-78KZB785at5cIlUi .section-edge-10{stroke:hsl(210, 100%, 76.2745098039%);}#mermaid-svg-78KZB785at5cIlUi .edge-depth-10{stroke-width:-16;}#mermaid-svg-78KZB785at5cIlUi .section-10 line{stroke:hsl(30, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-78KZB785at5cIlUi .lineWrapper line{stroke:black;}#mermaid-svg-78KZB785at5cIlUi .disabled,#mermaid-svg-78KZB785at5cIlUi .disabled circle,#mermaid-svg-78KZB785at5cIlUi .disabled text{fill:lightgray;}#mermaid-svg-78KZB785at5cIlUi .disabled text{fill:#efefef;}#mermaid-svg-78KZB785at5cIlUi .section-root rect,#mermaid-svg-78KZB785at5cIlUi .section-root path,#mermaid-svg-78KZB785at5cIlUi .section-root circle{fill:hsl(240, 100%, 46.2745098039%);}#mermaid-svg-78KZB785at5cIlUi .section-root text{fill:#ffffff;}#mermaid-svg-78KZB785at5cIlUi .icon-container{height:100%;display:flex;justify-content:center;align-items:center;}#mermaid-svg-78KZB785at5cIlUi .edge{fill:none;}#mermaid-svg-78KZB785at5cIlUi .eventWrapper{filter:brightness(120%);}#mermaid-svg-78KZB785at5cIlUi :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Sprint 1 规范与实现完全一致 OpenAPI v1.0 = 实际接口 Sprint 3 快速迭代导致规范更新滞后 实现新增字段未更新规范 Sprint 6 规范成为"装饰" AI 生成代码开始偏离预期 Sprint 8 技术债爆发 新人困惑·测试失败·AI 幻觉增加 规范漂移的典型演进路径

治理方案:三道防线

#mermaid-svg-tsLgRGMq5OuYds8v{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-tsLgRGMq5OuYds8v .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-tsLgRGMq5OuYds8v .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-tsLgRGMq5OuYds8v .error-icon{fill:#552222;}#mermaid-svg-tsLgRGMq5OuYds8v .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-tsLgRGMq5OuYds8v .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-tsLgRGMq5OuYds8v .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-tsLgRGMq5OuYds8v .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-tsLgRGMq5OuYds8v .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-tsLgRGMq5OuYds8v .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-tsLgRGMq5OuYds8v .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-tsLgRGMq5OuYds8v .marker{fill:#333333;stroke:#333333;}#mermaid-svg-tsLgRGMq5OuYds8v .marker.cross{stroke:#333333;}#mermaid-svg-tsLgRGMq5OuYds8v svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-tsLgRGMq5OuYds8v p{margin:0;}#mermaid-svg-tsLgRGMq5OuYds8v .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-tsLgRGMq5OuYds8v .cluster-label text{fill:#333;}#mermaid-svg-tsLgRGMq5OuYds8v .cluster-label span{color:#333;}#mermaid-svg-tsLgRGMq5OuYds8v .cluster-label span p{background-color:transparent;}#mermaid-svg-tsLgRGMq5OuYds8v .label text,#mermaid-svg-tsLgRGMq5OuYds8v span{fill:#333;color:#333;}#mermaid-svg-tsLgRGMq5OuYds8v .node rect,#mermaid-svg-tsLgRGMq5OuYds8v .node circle,#mermaid-svg-tsLgRGMq5OuYds8v .node ellipse,#mermaid-svg-tsLgRGMq5OuYds8v .node polygon,#mermaid-svg-tsLgRGMq5OuYds8v .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-tsLgRGMq5OuYds8v .rough-node .label text,#mermaid-svg-tsLgRGMq5OuYds8v .node .label text,#mermaid-svg-tsLgRGMq5OuYds8v .image-shape .label,#mermaid-svg-tsLgRGMq5OuYds8v .icon-shape .label{text-anchor:middle;}#mermaid-svg-tsLgRGMq5OuYds8v .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-tsLgRGMq5OuYds8v .rough-node .label,#mermaid-svg-tsLgRGMq5OuYds8v .node .label,#mermaid-svg-tsLgRGMq5OuYds8v .image-shape .label,#mermaid-svg-tsLgRGMq5OuYds8v .icon-shape .label{text-align:center;}#mermaid-svg-tsLgRGMq5OuYds8v .node.clickable{cursor:pointer;}#mermaid-svg-tsLgRGMq5OuYds8v .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-tsLgRGMq5OuYds8v .arrowheadPath{fill:#333333;}#mermaid-svg-tsLgRGMq5OuYds8v .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-tsLgRGMq5OuYds8v .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-tsLgRGMq5OuYds8v .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-tsLgRGMq5OuYds8v .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-tsLgRGMq5OuYds8v .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-tsLgRGMq5OuYds8v .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-tsLgRGMq5OuYds8v .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-tsLgRGMq5OuYds8v .cluster text{fill:#333;}#mermaid-svg-tsLgRGMq5OuYds8v .cluster span{color:#333;}#mermaid-svg-tsLgRGMq5OuYds8v div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-tsLgRGMq5OuYds8v .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-tsLgRGMq5OuYds8v rect.text{fill:none;stroke-width:0;}#mermaid-svg-tsLgRGMq5OuYds8v .icon-shape,#mermaid-svg-tsLgRGMq5OuYds8v .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-tsLgRGMq5OuYds8v .icon-shape p,#mermaid-svg-tsLgRGMq5OuYds8v .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-tsLgRGMq5OuYds8v .icon-shape .label rect,#mermaid-svg-tsLgRGMq5OuYds8v .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-tsLgRGMq5OuYds8v .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-tsLgRGMq5OuYds8v .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-tsLgRGMq5OuYds8v :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 通过
通过
漂移告警
阻断
阻断
阻断
第三道防线:AI 主动感知
PR 提交时 AI diff 分析
实现与规范语义对比
自动生成规范更新 PR
第二道防线:运行时契约
Pact Consumer-Driven Contract
Spring Cloud Contract
自动生成契约测试
第一道防线:静态检测
spectral lint 规范格式检查
openapi-diff 检测接口变更
tsc 类型守门
开发者修复
PR 不可合并


七、工具链推荐

场景 推荐工具 说明
规范编写 Stoplight Studio / Swagger Editor 可视化 OpenAPI 编辑
规范 Lint Spectral 自定义规范校验规则
契约测试 Pact.io Consumer-Driven Contract
AI 编码 WorkBuddy / Cursor 结合 SKILL.md 使用
测试框架 JUnit 5 + AssertJ(Java)/ Jest(TS) 可读性强
覆盖率 JaCoCo / Istanbul CI 集成门槛检查
规范版本管理 Git + Conventional Commits 规范变更可追溯
接口 Mock WireMock / MSW 基于规范自动 Mock
代码生成 openapi-generator / swagger-codegen 规范生成代码骨架

八、常见误区与解答

❌ 误区 1:有了 AI,不需要写测试了

实际情况: AI 生成的代码不能自证正确,测试是唯一客观标准。没有测试的 AI 代码库,熵增速度是人工代码库的 3 倍。

误区 2:规范文档太重了,敏捷开发不需要

实际情况: SDD 的规范不是传统的 Word 文档,而是机器可读的 YAML/JSON/TS 文件。写好一份 OpenAPI,AI 可以反复生成:测试、Mock、文档、代码------这是杠杆效应。

误区 3:TDD 和 SDD 选一个就够了

实际情况: SDD 管"写什么 ",TDD 管"对不对"。两者是正交关系,缺一不可。规范告诉 AI 边界,测试告诉 AI 预期。

误区 4:AI 会自动保持规范更新

实际情况: AI 不会主动识别规范漂移,需要在 CI 中设置强制检查点,或使用 AI 定期执行规范审计任务。


九、总结:融合方法论的核心思想

#mermaid-svg-ndlEvwPNMFbzlIeJ{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-ndlEvwPNMFbzlIeJ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ndlEvwPNMFbzlIeJ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ndlEvwPNMFbzlIeJ .error-icon{fill:#552222;}#mermaid-svg-ndlEvwPNMFbzlIeJ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ndlEvwPNMFbzlIeJ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ndlEvwPNMFbzlIeJ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ndlEvwPNMFbzlIeJ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ndlEvwPNMFbzlIeJ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ndlEvwPNMFbzlIeJ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ndlEvwPNMFbzlIeJ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ndlEvwPNMFbzlIeJ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ndlEvwPNMFbzlIeJ .marker.cross{stroke:#333333;}#mermaid-svg-ndlEvwPNMFbzlIeJ svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ndlEvwPNMFbzlIeJ p{margin:0;}#mermaid-svg-ndlEvwPNMFbzlIeJ .edge{stroke-width:3;}#mermaid-svg-ndlEvwPNMFbzlIeJ .section--1 rect,#mermaid-svg-ndlEvwPNMFbzlIeJ .section--1 path,#mermaid-svg-ndlEvwPNMFbzlIeJ .section--1 circle,#mermaid-svg-ndlEvwPNMFbzlIeJ .section--1 polygon,#mermaid-svg-ndlEvwPNMFbzlIeJ .section--1 path{fill:hsl(240, 100%, 76.2745098039%);}#mermaid-svg-ndlEvwPNMFbzlIeJ .section--1 text{fill:#ffffff;}#mermaid-svg-ndlEvwPNMFbzlIeJ .node-icon--1{font-size:40px;color:#ffffff;}#mermaid-svg-ndlEvwPNMFbzlIeJ .section-edge--1{stroke:hsl(240, 100%, 76.2745098039%);}#mermaid-svg-ndlEvwPNMFbzlIeJ .edge-depth--1{stroke-width:17;}#mermaid-svg-ndlEvwPNMFbzlIeJ .section--1 line{stroke:hsl(60, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-ndlEvwPNMFbzlIeJ .disabled,#mermaid-svg-ndlEvwPNMFbzlIeJ .disabled circle,#mermaid-svg-ndlEvwPNMFbzlIeJ .disabled text{fill:lightgray;}#mermaid-svg-ndlEvwPNMFbzlIeJ .disabled text{fill:#efefef;}#mermaid-svg-ndlEvwPNMFbzlIeJ .section-0 rect,#mermaid-svg-ndlEvwPNMFbzlIeJ .section-0 path,#mermaid-svg-ndlEvwPNMFbzlIeJ .section-0 circle,#mermaid-svg-ndlEvwPNMFbzlIeJ .section-0 polygon,#mermaid-svg-ndlEvwPNMFbzlIeJ .section-0 path{fill:hsl(60, 100%, 73.5294117647%);}#mermaid-svg-ndlEvwPNMFbzlIeJ .section-0 text{fill:black;}#mermaid-svg-ndlEvwPNMFbzlIeJ .node-icon-0{font-size:40px;color:black;}#mermaid-svg-ndlEvwPNMFbzlIeJ .section-edge-0{stroke:hsl(60, 100%, 73.5294117647%);}#mermaid-svg-ndlEvwPNMFbzlIeJ .edge-depth-0{stroke-width:14;}#mermaid-svg-ndlEvwPNMFbzlIeJ .section-0 line{stroke:hsl(240, 100%, 83.5294117647%);stroke-width:3;}#mermaid-svg-ndlEvwPNMFbzlIeJ .disabled,#mermaid-svg-ndlEvwPNMFbzlIeJ .disabled circle,#mermaid-svg-ndlEvwPNMFbzlIeJ .disabled text{fill:lightgray;}#mermaid-svg-ndlEvwPNMFbzlIeJ .disabled text{fill:#efefef;}#mermaid-svg-ndlEvwPNMFbzlIeJ .section-1 rect,#mermaid-svg-ndlEvwPNMFbzlIeJ .section-1 path,#mermaid-svg-ndlEvwPNMFbzlIeJ .section-1 circle,#mermaid-svg-ndlEvwPNMFbzlIeJ .section-1 polygon,#mermaid-svg-ndlEvwPNMFbzlIeJ .section-1 path{fill:hsl(80, 100%, 76.2745098039%);}#mermaid-svg-ndlEvwPNMFbzlIeJ .section-1 text{fill:black;}#mermaid-svg-ndlEvwPNMFbzlIeJ .node-icon-1{font-size:40px;color:black;}#mermaid-svg-ndlEvwPNMFbzlIeJ .section-edge-1{stroke:hsl(80, 100%, 76.2745098039%);}#mermaid-svg-ndlEvwPNMFbzlIeJ .edge-depth-1{stroke-width:11;}#mermaid-svg-ndlEvwPNMFbzlIeJ .section-1 line{stroke:hsl(260, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-ndlEvwPNMFbzlIeJ .disabled,#mermaid-svg-ndlEvwPNMFbzlIeJ .disabled circle,#mermaid-svg-ndlEvwPNMFbzlIeJ .disabled text{fill:lightgray;}#mermaid-svg-ndlEvwPNMFbzlIeJ .disabled text{fill:#efefef;}#mermaid-svg-ndlEvwPNMFbzlIeJ .section-2 rect,#mermaid-svg-ndlEvwPNMFbzlIeJ .section-2 path,#mermaid-svg-ndlEvwPNMFbzlIeJ .section-2 circle,#mermaid-svg-ndlEvwPNMFbzlIeJ .section-2 polygon,#mermaid-svg-ndlEvwPNMFbzlIeJ .section-2 path{fill:hsl(270, 100%, 76.2745098039%);}#mermaid-svg-ndlEvwPNMFbzlIeJ .section-2 text{fill:#ffffff;}#mermaid-svg-ndlEvwPNMFbzlIeJ .node-icon-2{font-size:40px;color:#ffffff;}#mermaid-svg-ndlEvwPNMFbzlIeJ .section-edge-2{stroke:hsl(270, 100%, 76.2745098039%);}#mermaid-svg-ndlEvwPNMFbzlIeJ .edge-depth-2{stroke-width:8;}#mermaid-svg-ndlEvwPNMFbzlIeJ .section-2 line{stroke:hsl(90, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-ndlEvwPNMFbzlIeJ .disabled,#mermaid-svg-ndlEvwPNMFbzlIeJ .disabled circle,#mermaid-svg-ndlEvwPNMFbzlIeJ .disabled text{fill:lightgray;}#mermaid-svg-ndlEvwPNMFbzlIeJ .disabled text{fill:#efefef;}#mermaid-svg-ndlEvwPNMFbzlIeJ .section-3 rect,#mermaid-svg-ndlEvwPNMFbzlIeJ .section-3 path,#mermaid-svg-ndlEvwPNMFbzlIeJ .section-3 circle,#mermaid-svg-ndlEvwPNMFbzlIeJ .section-3 polygon,#mermaid-svg-ndlEvwPNMFbzlIeJ .section-3 path{fill:hsl(300, 100%, 76.2745098039%);}#mermaid-svg-ndlEvwPNMFbzlIeJ .section-3 text{fill:black;}#mermaid-svg-ndlEvwPNMFbzlIeJ .node-icon-3{font-size:40px;color:black;}#mermaid-svg-ndlEvwPNMFbzlIeJ .section-edge-3{stroke:hsl(300, 100%, 76.2745098039%);}#mermaid-svg-ndlEvwPNMFbzlIeJ .edge-depth-3{stroke-width:5;}#mermaid-svg-ndlEvwPNMFbzlIeJ .section-3 line{stroke:hsl(120, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-ndlEvwPNMFbzlIeJ .disabled,#mermaid-svg-ndlEvwPNMFbzlIeJ .disabled circle,#mermaid-svg-ndlEvwPNMFbzlIeJ .disabled text{fill:lightgray;}#mermaid-svg-ndlEvwPNMFbzlIeJ .disabled text{fill:#efefef;}#mermaid-svg-ndlEvwPNMFbzlIeJ .section-4 rect,#mermaid-svg-ndlEvwPNMFbzlIeJ .section-4 path,#mermaid-svg-ndlEvwPNMFbzlIeJ .section-4 circle,#mermaid-svg-ndlEvwPNMFbzlIeJ .section-4 polygon,#mermaid-svg-ndlEvwPNMFbzlIeJ .section-4 path{fill:hsl(330, 100%, 76.2745098039%);}#mermaid-svg-ndlEvwPNMFbzlIeJ .section-4 text{fill:black;}#mermaid-svg-ndlEvwPNMFbzlIeJ .node-icon-4{font-size:40px;color:black;}#mermaid-svg-ndlEvwPNMFbzlIeJ .section-edge-4{stroke:hsl(330, 100%, 76.2745098039%);}#mermaid-svg-ndlEvwPNMFbzlIeJ .edge-depth-4{stroke-width:2;}#mermaid-svg-ndlEvwPNMFbzlIeJ .section-4 line{stroke:hsl(150, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-ndlEvwPNMFbzlIeJ .disabled,#mermaid-svg-ndlEvwPNMFbzlIeJ .disabled circle,#mermaid-svg-ndlEvwPNMFbzlIeJ .disabled text{fill:lightgray;}#mermaid-svg-ndlEvwPNMFbzlIeJ .disabled text{fill:#efefef;}#mermaid-svg-ndlEvwPNMFbzlIeJ .section-5 rect,#mermaid-svg-ndlEvwPNMFbzlIeJ .section-5 path,#mermaid-svg-ndlEvwPNMFbzlIeJ .section-5 circle,#mermaid-svg-ndlEvwPNMFbzlIeJ .section-5 polygon,#mermaid-svg-ndlEvwPNMFbzlIeJ .section-5 path{fill:hsl(0, 100%, 76.2745098039%);}#mermaid-svg-ndlEvwPNMFbzlIeJ .section-5 text{fill:black;}#mermaid-svg-ndlEvwPNMFbzlIeJ .node-icon-5{font-size:40px;color:black;}#mermaid-svg-ndlEvwPNMFbzlIeJ .section-edge-5{stroke:hsl(0, 100%, 76.2745098039%);}#mermaid-svg-ndlEvwPNMFbzlIeJ .edge-depth-5{stroke-width:-1;}#mermaid-svg-ndlEvwPNMFbzlIeJ .section-5 line{stroke:hsl(180, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-ndlEvwPNMFbzlIeJ .disabled,#mermaid-svg-ndlEvwPNMFbzlIeJ .disabled circle,#mermaid-svg-ndlEvwPNMFbzlIeJ .disabled text{fill:lightgray;}#mermaid-svg-ndlEvwPNMFbzlIeJ .disabled text{fill:#efefef;}#mermaid-svg-ndlEvwPNMFbzlIeJ .section-6 rect,#mermaid-svg-ndlEvwPNMFbzlIeJ .section-6 path,#mermaid-svg-ndlEvwPNMFbzlIeJ .section-6 circle,#mermaid-svg-ndlEvwPNMFbzlIeJ .section-6 polygon,#mermaid-svg-ndlEvwPNMFbzlIeJ .section-6 path{fill:hsl(30, 100%, 76.2745098039%);}#mermaid-svg-ndlEvwPNMFbzlIeJ .section-6 text{fill:black;}#mermaid-svg-ndlEvwPNMFbzlIeJ .node-icon-6{font-size:40px;color:black;}#mermaid-svg-ndlEvwPNMFbzlIeJ .section-edge-6{stroke:hsl(30, 100%, 76.2745098039%);}#mermaid-svg-ndlEvwPNMFbzlIeJ .edge-depth-6{stroke-width:-4;}#mermaid-svg-ndlEvwPNMFbzlIeJ .section-6 line{stroke:hsl(210, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-ndlEvwPNMFbzlIeJ .disabled,#mermaid-svg-ndlEvwPNMFbzlIeJ .disabled circle,#mermaid-svg-ndlEvwPNMFbzlIeJ .disabled text{fill:lightgray;}#mermaid-svg-ndlEvwPNMFbzlIeJ .disabled text{fill:#efefef;}#mermaid-svg-ndlEvwPNMFbzlIeJ .section-7 rect,#mermaid-svg-ndlEvwPNMFbzlIeJ .section-7 path,#mermaid-svg-ndlEvwPNMFbzlIeJ .section-7 circle,#mermaid-svg-ndlEvwPNMFbzlIeJ .section-7 polygon,#mermaid-svg-ndlEvwPNMFbzlIeJ .section-7 path{fill:hsl(90, 100%, 76.2745098039%);}#mermaid-svg-ndlEvwPNMFbzlIeJ .section-7 text{fill:black;}#mermaid-svg-ndlEvwPNMFbzlIeJ .node-icon-7{font-size:40px;color:black;}#mermaid-svg-ndlEvwPNMFbzlIeJ .section-edge-7{stroke:hsl(90, 100%, 76.2745098039%);}#mermaid-svg-ndlEvwPNMFbzlIeJ .edge-depth-7{stroke-width:-7;}#mermaid-svg-ndlEvwPNMFbzlIeJ .section-7 line{stroke:hsl(270, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-ndlEvwPNMFbzlIeJ .disabled,#mermaid-svg-ndlEvwPNMFbzlIeJ .disabled circle,#mermaid-svg-ndlEvwPNMFbzlIeJ .disabled text{fill:lightgray;}#mermaid-svg-ndlEvwPNMFbzlIeJ .disabled text{fill:#efefef;}#mermaid-svg-ndlEvwPNMFbzlIeJ .section-8 rect,#mermaid-svg-ndlEvwPNMFbzlIeJ .section-8 path,#mermaid-svg-ndlEvwPNMFbzlIeJ .section-8 circle,#mermaid-svg-ndlEvwPNMFbzlIeJ .section-8 polygon,#mermaid-svg-ndlEvwPNMFbzlIeJ .section-8 path{fill:hsl(150, 100%, 76.2745098039%);}#mermaid-svg-ndlEvwPNMFbzlIeJ .section-8 text{fill:black;}#mermaid-svg-ndlEvwPNMFbzlIeJ .node-icon-8{font-size:40px;color:black;}#mermaid-svg-ndlEvwPNMFbzlIeJ .section-edge-8{stroke:hsl(150, 100%, 76.2745098039%);}#mermaid-svg-ndlEvwPNMFbzlIeJ .edge-depth-8{stroke-width:-10;}#mermaid-svg-ndlEvwPNMFbzlIeJ .section-8 line{stroke:hsl(330, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-ndlEvwPNMFbzlIeJ .disabled,#mermaid-svg-ndlEvwPNMFbzlIeJ .disabled circle,#mermaid-svg-ndlEvwPNMFbzlIeJ .disabled text{fill:lightgray;}#mermaid-svg-ndlEvwPNMFbzlIeJ .disabled text{fill:#efefef;}#mermaid-svg-ndlEvwPNMFbzlIeJ .section-9 rect,#mermaid-svg-ndlEvwPNMFbzlIeJ .section-9 path,#mermaid-svg-ndlEvwPNMFbzlIeJ .section-9 circle,#mermaid-svg-ndlEvwPNMFbzlIeJ .section-9 polygon,#mermaid-svg-ndlEvwPNMFbzlIeJ .section-9 path{fill:hsl(180, 100%, 76.2745098039%);}#mermaid-svg-ndlEvwPNMFbzlIeJ .section-9 text{fill:black;}#mermaid-svg-ndlEvwPNMFbzlIeJ .node-icon-9{font-size:40px;color:black;}#mermaid-svg-ndlEvwPNMFbzlIeJ .section-edge-9{stroke:hsl(180, 100%, 76.2745098039%);}#mermaid-svg-ndlEvwPNMFbzlIeJ .edge-depth-9{stroke-width:-13;}#mermaid-svg-ndlEvwPNMFbzlIeJ .section-9 line{stroke:hsl(0, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-ndlEvwPNMFbzlIeJ .disabled,#mermaid-svg-ndlEvwPNMFbzlIeJ .disabled circle,#mermaid-svg-ndlEvwPNMFbzlIeJ .disabled text{fill:lightgray;}#mermaid-svg-ndlEvwPNMFbzlIeJ .disabled text{fill:#efefef;}#mermaid-svg-ndlEvwPNMFbzlIeJ .section-10 rect,#mermaid-svg-ndlEvwPNMFbzlIeJ .section-10 path,#mermaid-svg-ndlEvwPNMFbzlIeJ .section-10 circle,#mermaid-svg-ndlEvwPNMFbzlIeJ .section-10 polygon,#mermaid-svg-ndlEvwPNMFbzlIeJ .section-10 path{fill:hsl(210, 100%, 76.2745098039%);}#mermaid-svg-ndlEvwPNMFbzlIeJ .section-10 text{fill:black;}#mermaid-svg-ndlEvwPNMFbzlIeJ .node-icon-10{font-size:40px;color:black;}#mermaid-svg-ndlEvwPNMFbzlIeJ .section-edge-10{stroke:hsl(210, 100%, 76.2745098039%);}#mermaid-svg-ndlEvwPNMFbzlIeJ .edge-depth-10{stroke-width:-16;}#mermaid-svg-ndlEvwPNMFbzlIeJ .section-10 line{stroke:hsl(30, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-ndlEvwPNMFbzlIeJ .disabled,#mermaid-svg-ndlEvwPNMFbzlIeJ .disabled circle,#mermaid-svg-ndlEvwPNMFbzlIeJ .disabled text{fill:lightgray;}#mermaid-svg-ndlEvwPNMFbzlIeJ .disabled text{fill:#efefef;}#mermaid-svg-ndlEvwPNMFbzlIeJ .section-root rect,#mermaid-svg-ndlEvwPNMFbzlIeJ .section-root path,#mermaid-svg-ndlEvwPNMFbzlIeJ .section-root circle,#mermaid-svg-ndlEvwPNMFbzlIeJ .section-root polygon{fill:hsl(240, 100%, 46.2745098039%);}#mermaid-svg-ndlEvwPNMFbzlIeJ .section-root text{fill:#ffffff;}#mermaid-svg-ndlEvwPNMFbzlIeJ .section-root span{color:#ffffff;}#mermaid-svg-ndlEvwPNMFbzlIeJ .section-2 span{color:#ffffff;}#mermaid-svg-ndlEvwPNMFbzlIeJ .icon-container{height:100%;display:flex;justify-content:center;align-items:center;}#mermaid-svg-ndlEvwPNMFbzlIeJ .edge{fill:none;}#mermaid-svg-ndlEvwPNMFbzlIeJ .mindmap-node-label{dy:1em;alignment-baseline:middle;text-anchor:middle;dominant-baseline:middle;text-align:center;}#mermaid-svg-ndlEvwPNMFbzlIeJ :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} TDD + SDD\nAI Coding
SDD 规范层
OpenAPI 接口约定
TypeScript 类型定义
ADR 架构决策
SKILL.md AI任务规范
TDD 验证层
单元测试
集成测试
契约测试
E2E 测试
AI 协作层
规范→代码骨架
测试→驱动实现
AI→补全逻辑
CI→守护质量
工程文化
规范即文档
测试即规格
AI 是工具
人是决策者

三句话总结:

  1. SDD 是 AI 的"航线图":先定义清楚要去哪里,AI 才能飞得准。
  2. TDD 是 AI 的"落地检查":飞到了之后,测试告诉你有没有偏航。
  3. 融合是必然趋势:AI Coding 不是替代工程实践,而是让工程实践的价值被放大。

在 AI 时代,代码的质量取决于规范的质量测试的密度,而不仅仅是 AI 模型的能力。工程师的核心竞争力,正在从"能写代码"转变为"能定义规范、能设计测试、能驾驭 AI"。


参考资料


本文首发于 CSDN,转载请注明出处。如有技术交流,欢迎评论区留言。

相关推荐
云烟成雨TD1 小时前
Spring AI Alibaba 1.x 系列【78】沙箱(Sandbox)
java·人工智能·spring
tq10862 小时前
基于SLIP的防幻觉的指南
人工智能
甲维斯2 小时前
Kimi版超级玛丽效果“惊人”,配额不足5厘米!
前端·人工智能
console.log('npc')3 小时前
AI前端工程与生成式UI学习路线
前端·人工智能·ui
秋94 小时前
3年经验Python后端转AI Engineer:3个月实战转型计划(2026版)
开发语言·人工智能·python
圣殿骑士-Khtangc4 小时前
GPT-5.5 技术深度解析与企业级生产落地实战:从幻觉率下降到百万Token工程化
人工智能·gpt
2601_961963384 小时前
技术解剖:哈希值、区块链与CA认证如何守护电子合同安全?
网络·人工智能·安全·区块链·智能合约·政务
2601_961963384 小时前
从“电子化”到“自动化”:2026年智能合约与电子合同融合的技术逻辑与法律适配
网络·人工智能·区块链·智能合约·政务
米小虾4 小时前
AI Skills 工程化:当每个开发者都有一支「AI 小队」,你该怎么管理?
人工智能