前言

在实际使用 Claude Code 等 AI 编程工具的过程中,开发者普遍遇到一个痛点:描述了功能需求,代码能跑,但完全不符合项目的实际约束。本文从问题根源出发,结合 Spec Kit 方法论和 Claude Code 原生的 CLAUDE.md 机制,系统介绍规范驱动开发的思路与落地方式。


一、AI 编程的「需求漂移」从何而来

先看几个典型场景:

  • 你说「做一个用户登录功能」,它给你写了 JWT + bcrypt 的完整方案,但项目用的是 session-based auth。
  • 你说「优化一下这个查询」,它直接重构了整个数据层。
  • 你说「加个分页」,它顺手把 REST API 改成了 GraphQL。

这不是 Claude Code 的 bug,而是大模型的结构性工作方式决定的。

1.1 根本原因:语义缺口的默认填充

大模型生成代码时,依赖的是训练数据里的「概率最优解」。prompt 越模糊,模型越倾向于输出统计意义上最常见的实现方式。

链路如下:

模糊的 prompt
  → 模型填补语义缺口
  → 用通用最佳实践替代未说清的约束
  → 输出结果偏离实际项目约束

具体来看这个例子:

❌ 模糊 prompt:
"帮我写一个文件上传功能"

✅ AI 的「合理」推断:
- 用 multer 处理 multipart/form-data
- 文件存到 /uploads 目录
- 返回文件 URL
- 加上文件大小限制

❌ 但项目实际约束:
- 已有 AWS S3 封装好的 upload util
- 文件路径有特定格式规则
- 需要与现有 audit log 系统集成
- 有自己的 error handling 约定

四个约束,一个没出现在 prompt 里,AI 全部用默认方案替代。代码能跑,但接入系统需要大量改造。

1.2 为什么多轮纠正不解决问题

很多开发者的第一反应是「多轮对话逐步纠正」。这条路走得通,但有两个隐藏陷阱:

  1. 上下文消耗:每次纠正都在消耗上下文窗口,后续任务不保证记住之前确立的约束。
  2. 会话隔离:新开一个对话,之前所有纠正全部清零,需要重新建立 context。

在 vibe coding 场景下问题更突出:跟着 AI 节奏走,一边生成一边微调,等回过头来,代码架构已经和最初设想相差甚远。


二、Spec Kit:把约束写成文档

GitHub Spec Kit (11 万+ Stars)解决的正是这个问题。核心思路很直接:与其每次重新解释约束,不如把约束写成文档,让 AI 每次工作前先读它。

Spec Kit 的核心是一个 spec.md 文件,示例结构如下:

# 项目规范

## 技术栈约束
- Runtime: Node.js 18, TypeScript 5.x
- 数据库: PostgreSQL via Prisma ORM(禁止直接写 SQL)
- 认证: 使用 /lib/auth 的 session 封装,不引入新的 JWT 库
- 文件存储: 统一使用 /lib/storage 的 S3 封装

## 代码风格
- 错误处理: 统一 throw AppError 类,不使用 console.error
- API 响应格式: { data, error, meta } 结构
- 文件命名: kebab-case,组件用 PascalCase

## 禁止事项
- 不修改 /lib 目录下的基础设施代码
- 不引入 spec 里未列出的新依赖
- 不修改数据库 schema,只读操作

## 当前任务
[在这里描述具体任务]

AI 读完这份规范再开始写代码,语义缺口被规范填充,漂移空间大幅压缩。


三、CLAUDE.md:Claude Code 的原生规范方案

如果使用的是 Claude Code,有一个更原生的方式:CLAUDE.md 配置文件。这是 Claude Code 使用技巧里最容易被忽视的功能之一。

3.1 工作机制

在项目根目录创建 CLAUDE.md,Claude Code 会自动读取它作为每次会话的系统上下文,无需在每次对话里手动粘贴约束说明。

3.2 CLAUDE.md 模板

# CLAUDE.md

## 项目背景
这是一个 SaaS 产品的后端服务,使用 Express + TypeScript + PostgreSQL。

## 核心约束
1. 所有数据库操作通过 `src/db/` 里的 repository 层,不直接调用 Prisma
2. 认证逻辑在 `src/middleware/auth.ts`,不要重复实现
3. 日志统一用 `src/lib/logger`,基于 pino

## 代码生成规则
- 新增 API endpoint 必须在 `src/routes/` 对应文件里注册
- 数据验证用 zod,schema 放在 `src/schemas/`
- 错误处理继承 `AppError`,定义在 `src/errors/`

## 测试约定
- 单元测试用 vitest
- 测试文件和源文件同目录,命名 `*.test.ts`

## 当前上下文
Sprint 目标:完成用户权限模块,本周不做性能优化

3.3 团队协作价值

CLAUDE.md 提交到 Git 仓库,团队里所有人使用 Claude Code 时都会自动加载这份上下文。这相当于把 AI 的 onboarding 文档版本化管理,新成员和 AI 都能从同一份规范出发。


四、两种方案的核心逻辑

Spec Kit 和 CLAUDE.md 解决的是同一个问题:让 AI 在你的约束空间里工作,而不是在统计意义上的最优解空间里工作。

维度 传统 prompt 工程 规范驱动开发
约束表达 散落在每次 prompt 里 集中在规范文档里
会话持久性 新对话重置 通过文件持久化
团队一致性 依赖个人习惯 版本化、可共享
维护成本 每次重复描述 一次写入,持续生效
漂移风险

用一个类比来理解:你不会跟新入职的工程师说「写个登录功能」然后等交付。你会先给他项目文档、代码规范、架构说明,再分配具体任务。AI 需要同样的 onboarding,只是它每次「入职」都要重新来一遍——除非你把这个文档固化下来。


五、实操:5 分钟搭起规范体系

Step 1:列出「AI 最容易搞错的地方」

通常包括以下几类:

  • 自定义工具库和封装(已有的 util、helper)
  • 特殊的目录结构约定
  • 团队代码风格要求(命名、注释、错误处理)
  • 不能动的遗留代码区域
  • 禁止引入的依赖或技术栈

Step 2:创建 CLAUDE.md

touch CLAUDE.md

按模板填充,重点放在两类内容:

  1. 禁止做什么:明确列出不允许的操作,比「请遵循最佳实践」更有效。
  2. 必须用哪些现有封装:列出路径,避免 AI 重新实现已有功能。

Step 3:迭代完善

每次 Claude Code 跑偏,问自己:这条约束,CLAUDE.md 里有没有写? 没有就补进去。一两个 sprint 之后,你会有一份相当完善的规范文件。

进阶用法:任务级 spec 文件

对于复杂功能模块,可以在 CLAUDE.md 基础上再加一个任务级的 spec 文件:

# 目录结构建议
.claude/
  specs/
    payment-module.md
    user-permissions.md
    notification-system.md

在 Claude Code 对话里显式引用:

"请先读 .claude/specs/payment-module.md,然后实现支付回调处理"

这种方式特别适合需要多次对话才能完成的大型功能模块,每次对话都从同一份 spec 出发,保证实现方向一致。


六、常见问题

Q:CLAUDE.md 写多长合适?

没有固定标准,但有个原则:只写「AI 容易用错误方式实现的约束」,不要把所有项目文档都塞进去。过长的 CLAUDE.md 会稀释关键约束的权重。建议控制在 100 行以内,核心约束用列表格式清晰表达。

Q:CLAUDE.md 和 prompt 里的约束冲突怎么办?

CLAUDE.md 作为系统上下文加载,优先级高于单次 prompt。如果某个任务需要临时突破某条约束,在 prompt 里明确说明「本次任务例外」即可。

Q:非 Claude Code 工具也能用这套方法吗?

可以。Spec Kit 的 spec.md 方案与工具无关,手动在对话开始时粘贴规范内容同样有效。CLAUDE.md 是 Claude Code 的原生机制,其他工具需要查看各自的系统 prompt 或上下文配置方式。


总结

AI 编程的需求漂移本质上是信息缺口问题,不是 AI 不够聪明。把隐式约束显式化,让 AI 在有边界的空间里工作,漂移问题基本可以得到解决。

核心建议:

  • 把 CLAUDE.md 列为每个新项目 checklist 的第一项
  • 重点写「禁止事项」和「必须使用的现有封装」
  • 每次跑偏后反手补充到规范文档里,形成迭代闭环
  • 复杂模块使用任务级 spec 文件进一步约束

前期 20 分钟建立规范体系,节省的是后期几十次纠错往返的时间成本。


参考资源


如果需要使用 Claude Code,可以私我。也欢迎有需求的企业进行深度合作。

Logo

欢迎加入DeepSeek 技术社区。在这里,你可以找到志同道合的朋友,共同探索AI技术的奥秘。

更多推荐