给 AI 写一份项目说明书:CLAUDE.md 该填什么
AI 每次开新会话都要重新理解你的项目。CLAUDE.md 就是解决这件事的项目级记忆。这份模板七个板块,我用下来最有用的是「不要改」。
用 AI 写代码有个很具体的问题:它每次开新会话,对你的项目一无所知。
它会重新扫一遍目录,猜你的技术栈,猜你的代码风格,然后给出一个”通用最佳实践”级别的建议——而这往往和你的项目实际约定是冲突的。你得一遍遍纠正它:我们用 Maven 不用 Gradle、这个目录别动、错误不要 throw。
CLAUDE.md 就是解决这个的。它是项目根目录下的一个 Markdown 文件,每次会话开始时会被自动读取,相当于给 AI 一份项目说明书。
这份文档我在用,结构大概是这样。
模板
# [项目名] — CLAUDE.md
本文件优先于 user-level CLAUDE.md。
## 项目本质
一句话说明这个项目是做什么的。
## 技术栈
- Runtime: Node 20
- Framework: Fastify 5
- ORM: Drizzle
- Test: Vitest
## 关键约束
- 所有对外 API 必须有 zod schema 校验
- 禁止引入新的第三方 validation 库(我们用 zod)
- 数据库迁移走 drizzle-kit,不手动改 schema
## 不要改
- `/src/legacy/` 目录下所有文件(迁移中,容易出事)
- `package.json` 里的 node 版本
## 常用命令
- 跑测试:`pnpm test`
- 起开发:`pnpm dev`
- 数据库迁移:`pnpm db:migrate`
## 风格
- import 用绝对路径(`@/xxx`)
- 错误用 Result 类型,不 throw
- 文件名用 kebab-case
## 遇到不确定的时候
- 先看 `/docs/architecture.md`
- 新增 API 前先看 `/src/api/_template.ts`
七个板块,下面说每个板块怎么写才有用。
项目本质:一句话,不是一段话
这个板块最容易写成废话。“这是一个电商后台管理系统”——这种 AI 自己扫两眼目录也能猜到。
写它要有具体信息:这个项目解决什么问题、谁在用、核心业务流程是什么。
## 项目本质
医院患者全生命周期管理系统。核心是围着"患者"这一条主线,
把问诊、检查、用药、随访串起来,供医生和运营使用。
一句话,但 AI 立刻知道:领域是医疗、核心实体是患者、使用者是医生。它后续给的建议就不会往通用 CRUD 上跑了。
技术栈:写版本号
只写”用 Spring Boot”没有意义,写 Spring Boot 3.2 / JDK 17 / MyBatis-Plus 才有。
版本很重要,因为 AI 的训练数据有滞后性。你不写 JDK 17,它可能给你写一堆 Java 8 的写法,或者推荐一个和 Spring Boot 3 不兼容的依赖。
关键约束:写”禁止”
这个板块的名字是”约束”,但真正有用的是禁止项,不是”要做什么”。
因为”要做什么”AI 通常能猜对个七八分,而”不能做什么”它完全猜不到——每个项目的禁忌都不一样:
## 关键约束
- 禁止在 Service 层直接写 SQL,全部走 Mapper
- 禁止引入 lombok 之外的代码生成库
- 所有金额计算必须用 BigDecimal,不允许用 double
尤其是第三条这种,AI 不知道你踩过浮点数精度问题的坑,它给你写 double total = price * count 是完全可能的。写在约束里,它就不会。
不要改:这个板块救过我
这是整份文档里我最推荐加的,也是大部分模板里没有的。
它的作用是圈出雷区:
## 不要改
- `/src/legacy/` 目录下所有文件(迁移中,容易出事)
- 数据库表结构(有下游系统在读,改了会炸)
- `application.yml` 里的线程池配置(调过参数,别动)
没有这个板块,AI 看到”这段旧代码写得不好”就会顺手重构,而它不知道那是正在迁移的、有外部依赖的、或者参数是你压测调出来的。
AI 不知道的信息,你不写进去它就当不存在。
常用命令:别让它猜
## 常用命令
- 跑测试:`mvn test -pl user-service`
- 起开发:`mvn spring-boot:run -Dspring-boot.run.profiles=dev`
- 构建:`mvn clean package -DskipTests`
不写的话,AI 会给你一个”标准”命令——而你的项目可能是多模块的、有 profile 的、跳过测试的。它跑不通,你还得纠正。
风格:写你真正会在 code review 里挑的
## 风格
- 包名全小写,类名 UpperCamelCase
- Controller 不写业务逻辑,只做参数校验和转发
- 异常统一走 GlobalExceptionHandler,不自己 try-catch 返回错误码
- 注释写"为什么",不写"做了什么"
最后一条我特别想强调。AI 默认会写大量描述性注释(// 遍历用户列表),而这恰恰是没价值的。写进风格里,它就会改成解释意图。
遇到不确定的时候:给它一条路
这是第二个我觉得很多人漏掉的板块。
AI 遇到不确定的情况,默认行为是猜,然后闷头做。你得给它一个更好的默认动作:
## 遇到不确定的时候
- 先看 `/docs/architecture.md`
- 新增接口前先看 `/src/modules/user/api.ts` 作为模板
- 都不确定就问我,不要自己假设
最后那句很关键。没有它,AI 会编一个看起来合理的方案往下做;有了它,它会停下来问你。
大部分 AI 写代码的翻车,不是它不会做,是它不确定时选择了硬做。
一个 Java 项目的完整例子
# 患者管理系统 — CLAUDE.md
## 项目本质
医院患者全生命周期管理。围着患者这条主线串起问诊、检查、用药、随访,
主要给医生和运营用,部分接口对公众号开放。
## 技术栈
- JDK 17 / Spring Boot 3.2
- MyBatis-Plus 3.5 / MySQL 8.0
- Redis 7(缓存 + 分布式锁)
- RabbitMQ(异步解耦)
- 构建:Maven 多模块
## 关键约束
- Service 层禁止直接写 SQL,全部走 Mapper
- 金额一律 BigDecimal,禁止 double
- 所有对外接口必须有参数校验注解
- 跨服务调用必须设置超时,不允许无限等待
## 不要改
- `common-legacy` 模块(迁移中)
- 数据库表结构(下游报表系统在直连读)
- `application-prod.yml` 里的线程池和连接池参数
## 常用命令
- 跑测试:`mvn test -pl service-patient`
- 起开发:`mvn spring-boot:run -Dspring-boot.run.profiles=dev`
- 构建:`mvn clean package -DskipTests`
## 风格
- Controller 只做校验和转发,不写业务
- 异常统一走 GlobalExceptionHandler
- 注释解释"为什么",不解释"做了什么"
- 事务注解加在 Service 方法上,不在 Controller
## 遇到不确定的时候
- 先看 `docs/architecture.md`
- 新增接口参考 `PatientController.java` 的写法
- 不确定就问我,别自己假设
两个常见的坑
写太长。 超过一屏之后,AI 对后半部分的遵循度会明显下降。控制在一屏内,实在要写更多就拆成多个文件,主文件里只放索引。
写空话。 “代码要清晰易读""遵循最佳实践”这种句子没有任何约束力。每一条都应该是一条可以被违反、并且违反了你会指出来的规则。
如果你已经有 CLAUDE.md,可以对照看看缺哪几个板块。我猜大多数缺的是「不要改」和「遇到不确定的时候」——这两个恰恰是防止 AI 帮倒忙的。
关注我