1. 项目概述:为什么我们需要一份“AI契约”

在过去的几个月里,我深度使用了Claude Code,也尝试了市面上其他几款主流的AI编程助手。一个越来越强烈的感受是:和AI协作,尤其是让它帮你写代码,本质上是一场“人机对话”。但这场对话,如果缺乏一个清晰、稳定的“对话基础”,很容易就变成鸡同鸭讲,或者陷入“改来改去,越改越乱”的循环。你让它写一个登录功能,它可能给你生成一个没有密码加密的版本;你让它优化一段算法,它可能把核心逻辑改得面目全非。问题出在哪?不是AI不够聪明,而是我们和AI之间,缺少一份共同的“工作说明书”。

这就是“CLAUDE.md”文件,或者说“AI契约”的核心价值。它不是一个冰冷的配置文件,而是一份动态的、由你主导的“协作章程”。想象一下,你新招了一个实习生,你会怎么带他?你肯定不会只说一句“去写代码吧”,你会告诉他:我们团队用什么编程规范(比如Airbnb的JavaScript规范)、我们项目的整体架构是什么(比如前后端分离,前端用Vue 3 + TypeScript)、我们常用的工具库有哪些(比如用Axios做HTTP请求,用Day.js处理时间)、甚至我们代码仓库的提交信息格式是什么(比如遵循Conventional Commits)。你交代得越清楚,他上手越快,产出的代码越符合预期。

和Claude Code协作,道理一模一样。CLAUDE.md就是你给这位“AI实习生”的入职培训手册。它明确地定义了你们之间的协作边界、技术栈偏好、代码质量标准以及沟通方式。没有它,Claude Code就像是一个空降的、对你们团队文化一无所知的天才程序员,它可能写出很炫技的代码,但大概率不符合你的项目上下文,你需要花费大量时间去纠正和解释。有了它,你们就从“随机问答”升级到了“定向协作”,效率和质量都会有质的飞跃。

2. 契约的核心:CLAUDE.md文件的设计哲学与结构

一份好的CLAUDE.md,不应该是一份事无巨细的百科全书,而应该是一份高度结构化、重点突出的“协作指南”。它的设计哲学是: 为AI提供最大化上下文,同时最小化歧义 。它不是用来教AI编程语法(那是它的强项),而是用来告诉AI“在这个特定的项目里,我们应该怎么做事”。

2.1 文件定位与命名规范

首先,这个文件应该放在你项目的 根目录 。这是最显眼、最容易被AI识别的位置。文件名就叫做 CLAUDE.md (全大写),这是一种约定俗成的做法,类似于 README.md ,能清晰地表明这份文件的用途。有些项目也会用 .clauderc ai_context.txt 之类的名字,但 CLAUDE.md 因其简洁和明确,正在成为社区事实上的标准。

这个文件的内容,我建议用Markdown格式编写。Markdown结构清晰,支持标题、列表、代码块,非常适合组织这种说明性文档。AI对Markdown的解析也非常友好。

2.2 契约的四大核心模块

一份完整的CLAUDE.md,我通常会把它拆解成四个核心模块,这构成了契约的骨架:

  1. 项目全局上下文 :告诉AI“我们是谁,我们在做什么”。包括项目简介、核心目标、目标用户、技术栈全景图。
  2. 代码规范与风格 :告诉AI“代码应该长什么样”。包括编程语言版本、代码格式化工具(如Prettier)、Linter规则(如ESLint)、命名约定、文件组织规范。
  3. 架构与设计模式约束 :告诉AI“我们应该怎么构建系统”。包括使用的框架(如React、Spring Boot)、状态管理方案、API设计风格(RESTful/GraphQL)、数据库ORM选择、以及鼓励或禁止的设计模式。
  4. 交互与工作流指令 :告诉AI“我们应该如何合作”。包括如何理解你的需求描述、如何给出修改建议、输出代码的格式要求、以及遇到模糊需求时的默认处理原则。

下面,我们就深入到每个模块,看看具体该怎么写,以及为什么要这么写。

3. 模块一:奠定协作基础——项目全局上下文

这个模块的目标是让Claude Code在写第一行代码之前,就对项目的全貌有一个清晰的认知。这能有效避免它给出一些“技术上正确,但场景上离谱”的建议。

3.1 项目简介与技术栈声明

这里你需要用最简洁的语言描述项目。不要假设AI知道你的项目是干嘛的。

# CLAUDE.md - AI协作契约

## 项目概述
- **项目名称**:用户中心微服务(User-Center-Microservice)
- **核心目标**:为整个产品体系提供统一的用户认证、授权、基础信息管理服务。
- **关键特性**:JWT令牌认证、RBAC角色权限管理、用户资料CRUD、第三方登录(微信/谷歌)集成。
- **目标用户**:内部其他微服务(通过API调用)以及管理后台(Web前端)。

## 技术栈
- **后端语言**:Java 17
- **主要框架**:Spring Boot 3.1.x
- **构建工具**:Gradle (Kotlin DSL)
- **数据库**:PostgreSQL 14, 使用Flyway进行数据库版本管理。
- **ORM框架**:JPA (Hibernate实现), 但复杂查询鼓励使用JdbcTemplate或MyBatis。
- **API风格**:RESTful, 遵循JSON API最佳实践(错误码统一格式, 分页响应结构固定)。
- **关键依赖**:Spring Security (认证/授权), JJWT (JWT处理), MapStruct (对象映射)。

为什么这么写?

  • 明确技术栈 :直接告诉AI用Java和Spring Boot,它就不会给你推荐Python的Django或者Node.js的Express方案。
  • 指定版本 :“Java 17”和“Spring Boot 3.1.x”非常重要。Spring Boot 3.x和2.x的API有不少变化,AI如果用了旧版本的API,你的项目可能编译不过。
  • 表明倾向 :“鼓励使用JdbcTemplate或MyBatis”这句话,直接引导AI在遇到复杂查询时,避免生成过于复杂或低效的JPA Criteria API,而是采用更直接可控的方式。这是基于项目历史经验和团队习惯的决策。

3.2 架构模式与核心原则

这部分是契约的“战略层”,定义了项目的高层设计哲学。

## 架构与设计原则
- **整体架构**:基于领域驱动设计(DDD)的轻量级实践。核心域是`User`和`Role`。
- **分层结构**:严格遵循Controller -> Service -> Repository分层。Service层承载核心业务逻辑。
- **依赖注入**:统一使用构造器注入(Constructor Injection), 禁止字段注入(Field Injection)。
- **异常处理**:使用Spring的`@ControllerAdvice`实现全局异常处理。业务异常使用自定义的`BusinessException`及其子类, 并映射到特定的HTTP状态码和错误信息。
- **日志规范**:使用SLF4J + Logback。Service层重要方法入口和出口必须记录INFO级别日志, 异常必须记录ERROR级别日志并带上上下文信息。

实操心得 : 在早期没有这份契约时,我让Claude Code生成一个Service,它经常使用 @Autowired 进行字段注入。虽然Spring支持,但这不利于单元测试(因为字段是final的,不能通过构造器传入Mock对象)。在契约中明确“统一使用构造器注入”后,AI生成的代码立刻变得“顺眼”且符合团队规范,省去了大量重构的功夫。这就是契约的力量——将团队的最佳实践固化下来。

4. 模块二:统一代码面貌——规范与风格约束

这是AI契约中最“立竿见影”的部分,直接决定了生成代码的“颜值”和一致性。

4.1 代码格式化与静态检查

## 代码规范
- **代码格式化**:项目已集成Spotless(或Prettier for Java)。所有生成的代码必须符合既定的格式化规则。在提交前, 代码应能通过`./gradlew spotlessApply`。
- **静态分析**:必须通过Checkstyle和SpotBugs(或SonarQube)的检查。重点关注:
    - 避免魔法数字(使用常量)。
    - 方法圈复杂度不超过15。
    - 每个类文件行数建议不超过500行。
- **命名约定**:
    - 类名:大驼峰, 如`UserService`。
    - 方法名/变量名:小驼峰, 如`getUserById`。
    - 常量:全大写+下划线, 如`MAX_LOGIN_ATTEMPTS`。
    - 包名:全小写, 使用逆域名, 如`com.example.usercenter.service`。

注意事项 : 仅仅说“代码要整洁”是没用的,必须给出可执行、可验证的规则。“必须通过 ./gradlew spotlessApply ”就是一个明确的指令。AI在生成代码后,理论上可以在其“脑海”中模拟一次格式化过程,确保输出是合规的。虽然它不能真正运行Gradle命令,但这个指令会引导它遵循更严格的空格、换行和缩进规则。

4.2 文件与目录结构

## 项目结构

src/main/java/com/example/usercenter/ ├── application/ # 应用层(DTO, 控制器等) │ ├── dto/ │ └── web/ ├── domain/ # 领域层(实体, 值对象, 领域服务) │ ├── model/ │ └── service/ ├── infrastructure/ # 基础设施层(仓储实现, 外部服务调用) │ └── persistence/ └── UserCenterApplication.java

- **实体类**放在`domain/model/`下, 使用JPA注解。
- **DTO(数据传输对象)**放在`application/dto/`下, 分为`Request`和`Response`子包。
- **控制器**放在`application/web/`下, 类名以`Controller`结尾。
- **业务逻辑**放在`domain/service/`下, 接口和实现分离, 实现类以`Impl`结尾。

为什么结构如此重要? 当你对AI说“创建一个用户注册的API”,一个没有上下文约束的AI可能会把所有代码(实体、DTO、Controller、Service)都堆在一个文件里,或者放在错误的包下。有了清晰的结构契约,AI会知道:需要先检查 domain/model/ 下是否有 User 实体,然后在 application/dto/ 下创建 UserRegistrationRequest UserResponse ,接着在 application/web/ 下创建 UserController ,最后在 domain/service/ 下创建 UserRegistrationService 接口及其实现。这极大地提升了生成代码的可维护性和可集成性。

5. 模块三:塑造代码骨架——架构与设计模式约束

这个模块深入到具体的技术选型和设计决策,告诉AI“用什么”和“怎么用”。

5.1 框架与库的特定用法

## 框架与库的使用规范
- **Spring Security**:使用基于过滤器的安全配置(`SecurityFilterChain`), 而非已弃用的`WebSecurityConfigurerAdapter`。JWT过滤器需自定义, 并注册在UsernamePasswordAuthenticationFilter之前。
- **数据验证**:在Controller的`@RequestBody` DTO上使用Jakarta Validation注解(如`@NotBlank`, `@Email`), 并在Controller类上使用`@Validated`。**禁止**在Service方法参数中进行JSR-303验证。
- **对象映射**:**禁止**手动编写`new B(a.getX(), a.getY())`这样的赋值代码。统一使用MapStruct。需要为新DTO生成对应的Mapper接口。
- **日期时间**:**禁止**使用`java.util.Date`和`java.sql.Timestamp`。统一使用`java.time`包下的类(`LocalDateTime`, `ZonedDateTime`等)。数据库存储使用`TIMESTAMP WITH TIME ZONE`。

踩过的坑 : 我曾经让AI生成一个带日期字段的API,它很“自然”地用了 Date 类型,因为这是它训练数据里常见的模式。但我们的项目早已迁移到 java.time 。结果就是生成的代码与项目其他部分格格不入,需要手动修改。在契约中明确“禁止”事项后,这类问题再也没出现过。AI会优先从 java.time 中选取合适的类。

5.2 API设计规范

## API设计规范
- **URL规范**:资源使用复数名词, 如`/api/users`。操作通过HTTP方法表达。
    - `GET /api/users`: 获取用户列表(分页)
    - `POST /api/users`: 创建用户
    - `GET /api/users/{id}`: 获取单个用户
    - `PUT /api/users/{id}`: 全量更新用户
    - `PATCH /api/users/{id}`: 部分更新用户
    - `DELETE /api/users/{id}`: 删除用户
- **响应格式**:所有成功响应体统一包裹在`ApiResponse<T>`对象中, 包含`code`, `message`, `data`, `timestamp`字段。错误响应使用`ApiResponse<Object>`并设置相应的错误码。
- **分页**:列表接口必须支持分页。请求参数使用`page`(页码, 从0开始)和`size`(每页大小)。响应中必须包含分页元数据(总记录数、总页数等)。

实操心得 : 统一的响应格式是前后端协作的润滑剂。在契约中定义好 ApiResponse 的结构后,我只需要对AI说“生成一个获取用户列表的接口,需要分页”,它就能自动生成符合规范的Controller方法、Service方法,并返回包装好的 ApiResponse<Page<UserResponse>> 。前端同事拿到这样的接口文档,对接起来非常顺畅,因为所有接口的“外壳”都是一致的。

6. 模块四:优化协作流程——交互与工作流指令

这是最体现“契约”精神的部分,它定义了“人机对话”的协议。让AI知道如何理解你的意图,以及如何呈现它的输出。

6.1 需求理解与拆解指令

## 与Claude的协作协议
1.  **需求澄清**:当我给出的需求比较模糊时(例如“优化一下这个功能”), 你应该主动询问关键细节, 例如:
    - 优化的目标是什么?(性能、可读性、减少内存占用?)
    - 是否有特定的约束?(不能引入新库、必须保持API兼容?)
    - 当前的痛点或性能指标数据是什么?
2.  **方案提供**:对于复杂任务, 请先提供1-3个简要的技术方案思路, 并列出优缺点, 供我选择, 而不是直接生成代码。
3.  **变更范围**:当修改现有代码时, 请首先分析变更的影响范围, 并明确指出可能波及到的其他模块或类。

这个模块的价值 : 它把AI从一个“代码打字机”变成了一个“初级技术顾问”。比如,你说“用户登录太慢了,优化一下”。没有契约的AI可能直接给你一段优化后的代码。但有契约的AI会先问你:“请问是数据库查询慢,还是JWT生成验证慢?有没有APM监控数据?允许引入缓存吗?” 这种交互,能帮你更清晰地定义问题,避免AI在错误的方向上浪费精力。

6.2 输出格式与安全边界

4.  **代码生成格式**:
    - 生成的代码必须完整, 包含必要的`import`语句。
    - 如果修改现有文件, 请使用清晰的代码块差分(diff)格式展示变更, 并说明修改原因。
    - 对于新文件, 给出完整的文件路径和内容。
5.  **安全与合规红线**:
    - **绝对禁止**在代码中硬编码任何敏感信息(密码、API密钥、私钥)。必须使用环境变量或配置中心。
    - **绝对禁止**生成存在已知高危漏洞的依赖版本(如Log4j 2.x < 2.17.0)。应推荐当前项目主分支使用的稳定版本, 或经过安全审计的最新稳定版。
    - **禁止**生成任何涉及绕过系统安全机制、非授权访问的代码模式。
6.  **知识边界**:对于本项目未使用过的、较新的或不稳定的技术/库, 请在推荐时给出明确的风险提示。

注意事项 : “安全红线”是契约的底线条款。我曾经见过没有约束的AI,在示例代码中直接写 String password = "123456" 。在真实的项目中,这是灾难性的。通过契约明确“必须使用环境变量”,AI在生成连接数据库或调用第三方API的代码时,就会自觉地使用 @Value("${db.password}") 或从配置类中读取,从而养成安全编码的习惯。

7. 契约的维护与演进:让CLAUDE.md“活”起来

一份契约签完就扔到一边,很快就会过时。CLAUDE.md必须是一个“活文档”,随着项目一起成长。

7.1 版本管理与更新时机

我建议将CLAUDE.md纳入项目的版本控制系统(如Git)。它的更新应该伴随项目的重大变更。

  • 何时更新?
    1. 技术栈升级 :比如从Spring Boot 2.7升级到3.0,必须更新契约中的版本和可能废弃的API用法说明。
    2. 架构调整 :比如从单体应用拆出第一个微服务,需要更新关于服务间通信的规范。
    3. 引入新工具/模式 :比如团队决定全面采用Reactive编程(WebFlux),契约中就要增加相应的章节。
    4. 踩坑总结 :当团队因为某个共性问题(比如日期序列化格式不统一)而浪费了时间,就应该把解决方案作为规范写入契约,防止AI和新人再次踩坑。

7.2 团队共识与评审

CLAUDE.md不应该只是你一个人和AI的秘密。它应该是 团队共识的体现 。在制定和更新这份契约时,最好能组织一次简短的技术评审,让团队核心成员一起参与。这能确保:

  • 契约中的规范是团队真正认可和执行的。
  • 所有人都知道这份契约的存在和重要性。
  • 新成员 onboarding 时,除了 README,CLAUDE.md 也是必读文档。

你可以把CLAUDE.md的评审和更新,作为团队技术复盘会的一个固定环节。例如,“本周我们在使用AI生成XX功能时,发现它总是用旧模式,我们是不是该在契约里把新范式加进去?”

8. 实战演练:从一个模糊需求到精准代码

让我们看一个完整的例子,感受一下有契约和没契约的巨大差别。

场景 :我们需要在用户中心微服务中,增加一个“根据手机号前缀(区号)查询用户分布情况”的统计功能。

没有CLAUDE.md时,你可能会这样提问

“Claude,帮我写一个根据手机号前缀统计用户的API。”

AI可能生成的代码(问题重重)

  1. 直接在 UserController 里加个新方法,可能叫 countByPhonePrefix
  2. UserRepository 里写一个 @Query ,用 LIKE ‘prefix%’ 来查询。
  3. 返回一个 Map<String, Integer>
  4. 完全没有考虑分页(如果用户量巨大)。
  5. 没有考虑手机号字段的索引问题。
  6. 返回格式不符合项目的 ApiResponse 包装规范。

有了CLAUDE.md后,你的提问可以更精准,甚至可以引用契约

“Claude,请参考我们的CLAUDE.md契约,在用户中心微服务中实现一个功能:统计不同手机号前缀(取前3位)的用户数量。要求:

  1. 这是一个新的REST API,请设计合理的URL和HTTP方法。
  2. 考虑到用户量可能很大,请实现为分页查询。
  3. 响应格式必须符合契约中定义的 ApiResponse 标准。
  4. 请优先考虑查询性能,在契约允许的范围内选择实现方式。
  5. 请生成完整的Controller、Service接口及实现、以及必要的DTO。如果涉及数据库查询,请给出Repository层的建议。”

基于契约,AI会如何思考和生成?

  1. 定位 :读取CLAUDE.md,知道项目是Spring Boot + JPA,结构是DDD风格。
  2. 设计API :根据“URL规范”,它会设计类似 GET /api/users/statistics/phone-prefix 的URL。根据“API设计规范”,它会知道需要支持 page size 参数,并且返回 ApiResponse<Page<PhonePrefixStatResponse>>
  3. 创建DTO :在 application/dto/response/ 下创建 PhonePrefixStatResponse ,包含 prefix count 字段。
  4. 创建Controller :在 application/web/ 下创建 UserStatisticsController (遵循类名以Controller结尾),注入对应的 StatisticsService
  5. 创建Service :在 domain/service/ 下创建 UserStatisticsService 接口及其 UserStatisticsServiceImpl 实现。
  6. 实现查询 :考虑到“复杂查询鼓励使用JdbcTemplate或MyBatis”,且这是统计类查询,AI很可能会建议在 infrastructure/persistence/ 下创建一个 UserStatisticsRepository ,使用JdbcTemplate编写原生SQL进行分组统计,这样效率最高。同时,它会提醒你需要在手机号字段上建立前缀索引( CREATE INDEX idx_phone_prefix ON users (phone(3)) )以优化 LIKE ‘prefix%’ 查询——这是一个很好的性能提示。
  7. 代码风格 :生成的代码会自动符合Spotless格式,使用构造器注入,日志完备。

你看,从一个模糊的需求,到一套符合项目规范、考虑性能、结构清晰的代码方案,差别就在于一份清晰的“契约”。它极大地降低了沟通成本,提高了代码生成的质量和可用性。

9. 常见问题与避坑指南

在实际推广和使用CLAUDE.md的过程中,我和团队也遇到了一些典型问题,这里分享出来,帮你提前避坑。

9.1 契约太冗长,AI“看”不过来怎么办?

这是一个常见的担忧。Claude Code有上下文长度限制,一份上万字的契约它可能无法完全利用。

解决方案 :分层与摘要。

  • 核心契约 :保持CLAUDE.md本身精炼,只包含最核心、最通用的规范(技术栈、架构原则、关键禁令)。
  • 专项补充 :对于特定复杂模块(如支付模块、风控规则引擎),可以在其子目录下创建 MODULE_CLAUDE.md ,存放更细致的规则。在根契约中通过链接或简要说明指向它们。
  • 摘要提示 :在CLAUDE.md的开头,可以增加一个“ 快速摘要 ”部分,用三五句话概括最重要的几点(如“本项目是Spring Boot 3.1 + Java 17, 禁用字段注入, 统一使用MapStruct, API响应包装为ApiResponse”)。AI在处理任务时,会优先抓住这些核心点。

9.2 契约和团队现有规范文档(如Wiki)冲突怎么办?

解决方案 :以契约为准,并同步更新。 CLAUDE.md应该是 唯一 的、面向AI的权威规范源。如果团队有更详细的Wiki,那么CLAUDE.md的职责是提炼出Wiki中对AI生成代码有直接指导意义的部分。如果发现冲突,应该以CLAUDE.md为准进行代码生成,同时 立即 更新团队的Wiki文档,保持两者一致。这个过程本身也是推动团队文档更新和知识同步的好机会。

9.3 AI生成的代码符合契约,但逻辑有误怎么办?

契约不是万能的,它主要约束的是“形式”和“模式”,无法保证“逻辑”百分百正确。

应对策略 :契约+审查。

  1. 契约保障“基本面” :确保代码风格、架构、安全规范没问题,这部分可以节省你大量的审查精力。
  2. 人工聚焦“逻辑层” :你需要像审查人类同事的代码一样,仔细审查AI生成的业务逻辑。特别是边界条件、异常处理、算法复杂度等。这是目前AI的短板,也是你作为工程师不可替代的价值所在。
  3. 将逻辑错误反馈给AI :这是一个迭代过程。当你发现AI在某种逻辑上反复出错(比如对空集合的处理),你可以把正确的模式作为一个“案例”或“最佳实践”补充到CLAUDE.md中,例如:“ 集合处理规范 :遍历集合前必须使用 CollectionUtils.isEmpty() 判空;使用Stream API时,对于可能为null的集合,应使用 Optional.ofNullable(list).orElseGet(Collections::emptyList).stream() 。”

9.4 如何衡量CLAUDE.md带来的价值?

可以从以下几个维度评估:

  • 代码合并率 :AI生成的Pull Request,第一次提交后需要修改的次数是否减少?
  • 沟通成本 :你为了解释“这里应该怎么写”所花费的对话轮次是否减少?
  • 规范一致性 :团队代码库的风格是否更加统一?新成员(包括AI)上手是否更快?
  • 心智负担 :当你看到一个由AI生成的新文件时,是否不再需要先花半天时间去调整格式和基础结构,而是能直接关注业务逻辑?

我个人最深的体会是,自从有了这份契约,我和Claude Code的对话变得非常高效。我从一个“监工+纠错员”,变成了一个“产品经理+架构师”,只需要定义清楚“要什么”和“不要什么”,AI就能交付一份在框架上几乎无需修改的草案,让我可以把全部精力集中在最核心的业务逻辑和创新设计上。这份契约,就是撬动AI这个强大杠杆的那个支点。

更多推荐