**辅助开发&工程化:**Claude Code / Cursor / GitHub Copilot;掌握 **SDD(规范驱动开发)**方法论,通过 Spec 文件驱动 AI 生成符合团队规范的代码,管理系统模块开发效率提升约 60%

开发中 SDD(Spec-Driven Development)的实际案例

下面是四个案例的详细话术,面试时可以直接讲:
案例 1 — 搜索组件
"以前开发一个搜索组件,我直接打开 IDE 开始写,遇到问题就问 AI,复制粘贴进来调。但后来我改成 SDD 的方式:先写一份
search.spec.md,里面定义输入 props、防抖时间、空结果 / loading / error 三种状态的 UI 行为、以及无障碍访问要求。Spec 写完后,直接把它喂给 Claude Code,组件一次生成,符合预期。最关键的是,三个月后再改需求,我只需要改 Spec,意图不会丢。"
案例 2 — API 接口变更
"后端改了一个用户信息接口,把
userName拆成firstName+lastName。传统做法我要全局搜索、一个个改、还怕漏。SDD 做法是先把改动更新到user-api.spec.md,包括请求/响应结构、错误码、分页边界。然后让 AI 重新读 Spec 生成 service 层,整个过程可控、可追溯,不依赖我记住'当时 AI 是怎么写的'。"
案例 3 — 多人协作表单
"我们三个人分别写一个申请流程里的表单模块,最后合进去风格不一:有人用
ElForm、有人手写校验、错误提示格式也不同。后来统一改成 SDD:先把表单规范写进共享的form.spec.md,字段名、校验规则、错误提示模板都定好,大家各自让 AI 读同一份 Spec 生成代码。结果风格高度一致,新同学接手直接看 Spec,不用猜代码。"
案例 4 — AI Agent 项目(最有说服力)
"我做极速购 AI 客服系统时,早期 Agent 逻辑都是在 Cursor 对话里一点点迭代出来的,意图散落在聊天记录里。后来改成 SDD:先写
agent-flow.spec.md,定义用户意图的分类(查订单 / 退款 / 问产品)、每种意图对应哪个 Tool、失败时的 fallback 策略。这份 Spec 变成 Agent 的'说明书',需求一变,改 Spec 就行,AI 重新生成代码有理有据,团队协作也不会因为'AI 当时怎么想的'而撕扯。"
具体的实操案例
搜索组件开发
从需求到可运行组件,全程 Spec 驱动
Step 1 — 写 Spec 文件(不碰代码)
新建 search.spec.md,用自然语言把组件的所有"意图"写清楚
# search.spec.md
## 组件职责
用户输入关键词,300ms 防抖后触发搜索,结果列表展示
## Props
- modelValue: string — 当前搜索词(v-model)
- placeholder?: string — 默认"请输入关键词"
- debounce?: number — 防抖时间,默认 300ms
## Emits
- search(keyword: string) — 触发搜索
- clear() — 清空输入框
## 状态定义
| 状态 | 触发条件 | UI 表现 |
| ------- | ------------- | ---------------- |
| idle | 初始/清空后 | 显示 placeholder |
| loading | search 触发后 | 输入框右侧转圈 |
| empty | 返回结果为空 | 显示"暂无结果" |
| error | 接口报错 | 显示错误提示 |
## 边界场景
- 输入纯空格 → 不触发 search
- 连续输入期间只取最后一次
Step 2 — 把 Spec 喂给 AI 生成组件
打开 Claude Code 或 Cursor,用以下 Prompt:
请阅读 @search.spec.md,基于 Vue3 + TypeScript + Element Plus
生成 SearchBar.vue 组件,严格按照 Spec 中的 Props / Emits /
状态定义实现,不要添加 Spec 中未描述的功能。
Step 3 — 生成单元测试
继续让 AI 读同一份 Spec 生成测试,测试覆盖所有边界场景
请基于 @search.spec.md 中的"边界场景"和"状态定义",
生成 SearchBar.test.ts(Vitest + Vue Test Utils)
Step 4 — 需求变更只改 Spec
产品说要加"历史搜索记录"→ 在 Spec 里加一节,再跑一次 Step 2,代码自动更新,意图永远可查
API 接口字段变更
后端改字段,前端如何可控地跟进
Step 1 — 项目初期就建 api.spec.md
和后端对接时,第一件事不是写代码,而是把接口写进 Spec
# user-api.spec.md
## GET /api/user/profile
### 请求
无需参数(从 token 解析用户)
### 响应(200)
````json
{
"userId": "string",
"userName": "string", ← 旧字段
"email": "string",
"avatar": "string | null"
}
```text
### 错误码
- 401: token 失效,前端跳登录页
- 404: 用户不存在,显示"账号异常"
##### **Step 2 — 后端改字段,先更新 Spec**
收到后端通知 `userName` 拆为 `firstName + lastName`,先改 Spec,再动代码
```markdown
- "userName": "string" ← 删除
* "firstName": "string" ← 新增
* "lastName": "string" ← 新增
* "displayName": "string" ← 新增(firstName + lastName 拼接)
```
##### **Step 3 — 让 AI 根据新 Spec 重新生成 service 层**
```markdown
@user-api.spec.md 已经更新,请重新生成:
1. userService.ts 中的 getUserProfile() 方法
2. 对应的 TypeScript interface UserProfile
3. 检查 UserCard.vue / UserAvatar.vue 是否用到
旧字段 userName,如有,同步更新
```
##### **Step 4 — 用 TypeScript 做编译期兜底**
生成完成后跑 `tsc --noEmit`,所有还在用 `userName` 的地方会报类型错误,一个不漏
#### **多人协作大型表单**
3 人同时开发,风格统一不撕扯
##### **Step 1 — 开工前写共享 form.spec.md(负责人写)**
```markdown
# apply-form.spec.md
## 通用规范(所有人遵守)
- 校验时机:失焦 onBlur 触发,不是 onChange
- 错误提示:字段下方红色 12px 文字,不用 alert
- 必填标识:label 后加红色 \*,不在 placeholder 里写"必填"
- 提交按钮:loading 状态期间禁用 + 显示 spinner
## 模块分工
- 模块 A(小张):基本信息 — 姓名/手机/邮箱
- 模块 B(小李):教育经历 — 动态增删列表
- 模块 C(小王):附件上传 — 简历/证书,最大 5MB
## 字段规范示例(每人按此格式补充自己模块)
| 字段名 | 类型 | 必填 | 校验规则 |
| ------ | ------ | ---- | ---------------- |
| name | string | 是 | 2~20个汉字或字母 |
| phone | string | 是 | 11位手机号 |
| email | string | 否 | 标准邮箱格式 |
```
##### **Step 2 — 每人各自补充自己模块的 Spec**
小李负责"教育经历"模块,在 Spec 里追加自己的字段和交互说明,PR 合入主 Spec 后再写代码
```markdown
Step 3 — 各自让 AI 读同一份 Spec 生成模块
```
```markdown
请阅读 @apply-form.spec.md 中的【通用规范】 和【模块 B:教育经历】部分,
生成 EduForm.vue 注意:校验时机、错误提示、提交按钮行为
必须严格遵循通用规范,不得自行决定
```
##### **Step 4 — Code Review 只审"是否符合 Spec"**
Review 标准清晰:对着 Spec 逐条检查,不再靠个人风格争论。新人接手直接读 Spec,5 分钟上手
#### **AI 客服 Agent 系统(最有说服力)**
LangChain.js 项目,意图不丢失在聊天记录里
##### **Step 1 — 写 agent-flow.spec.md(上代码之前)**
```markdown
# agent-flow.spec.md(极速购 AI 客服系统)
## Agent 职责
接收用户消息 → 识别意图 → 调用对应 Tool → 返回结果
## 意图分类与路由
| 用户意图 | 关键词示例 | 调用 Tool |
| ------------- | ------------------ | ----------------- |
| 查订单状态 | 我的订单、物流在哪 | queryOrderTool |
| 申请退款 | 退款、不想要了 | refundApplyTool |
| 商品咨询 | 这个多少钱、有没有 | productSearchTool |
| 闲聊/无法识别 | 其他 | fallbackTool |
## Tool 输入输出规范
### queryOrderTool
- 输入:{ orderId: string }
- 输出:{ status, estimatedDelivery, logistics[] }
- 失败:orderId 不存在 → 返回"未找到订单,请确认订单号"
## Fallback 策略
1. Tool 调用失败(网络/超时)→ 重试 1 次
2. 重试仍失败 → 回复"稍后再试",不暴露错误详情
3. 意图置信度 < 0.6 → 转人工客服
## Memory 设计
保留最近 6 轮对话作为上下文,避免用户重复说订单号
```
##### **Step 2 — 让 AI 读 Spec 生成 Agent 骨架**
```markdown
请阅读 @agent-flow.spec.md,使用 LangChain.js + DeepSeek API
生成以下文件:
1. tools/queryOrderTool.ts
2. tools/refundApplyTool.ts
3. agent/customerServiceAgent.ts(包含意图路由和 Memory)
严格按照 Spec 中的输入输出规范和 Fallback 策略实现
```
##### **Step 3 — 新增 Tool 只需在 Spec 加一行**
产品说要加"积分查询"功能 → 在 Spec 的意图分类表里加一行,写清楚输入输出 → AI 生成新 Tool → 自动接入路由,不用翻之前的聊天记录
##### **Step 4 — Spec 即文档,对接后端直接共享**
把 `agent-flow.spec.md` 发给后端/产品,所有人对齐同一份"事实",不再靠口头沟通和 IM 截图
#### **最容易被追问的问题及答法:**
面试官问"Spec 谁来写,写多细?"→ 答:由负责人在开工前写,细到能让 AI 直接生成可运行代码为止——不够细的地方说明你自己也没想清楚需求。
面试官问"Spec 和注释有什么区别?"→ 答:注释解释代码"怎么做",Spec 定义系统"应该做什么"。Spec 是意图,代码是实现,意图不能丢在代码里,因为代码随时会被重写。
面试官问"实际团队推广难不难?"→ 答:难点在习惯,不在技术。我的做法是先在自己负责的模块跑通,拿可量化的结果说话——比如接口改字段那次,传统方式找漏改的地方花了半天,SDD 方式 10 分钟跑完 `tsc` 全部暴露。