ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

让 AI 助手真正懂你的项目:如何写好 CLAUDE.md

让 AI 助手真正懂你的项目:如何写好 CLAUDE.md 让 AI 助手真正懂你的项目我给 AQ-Chat 补了一份 CLAUDE.md如果你也遇到过这种情况——AI 编程助手代码写得飞快但总是在不该改的地方动刀或者把消息队列当成普通数组来处理——那这篇文章应该能帮你省下不少时间。事情起因很简单我们的聊天产品 AQ-Chat 进入迭代密集期每天都有大量新代码进来AI 助手参与度越来越高但它对项目背景的理解却一直“缺课”。它知道消息要入库却不知道哪张表才是主表它知道要做实时推送却总是忽略心跳机制。直到我认真写好并维护起一份 CLAUDE.md情况才有了本质改观。很多人以为 CLAUDE.md 就是把 README 改个名字放进仓库其实远远不止。它更像是一份专门写给 AI 协作工具看的工作手册里面浓缩了项目的架构约定、技术选型原因、常见坑位和下意识容易踩雷的地方。这份文件不需要面面俱到但必须一针见血。下面我就以 AQ-Chat 这个实际的聊天项目为例把我是怎么设计、编写、验证和维护这份文件的全过程拆开来讲。无论你接手的是一个老项目、还是准备从零搭建一个新项目这套思路应该都能派上用场。1. 为什么要在 AQ-Chat 项目里专门写一份 CLAUDE.md1.1 它解决的其实是“上下文缺失”的问题先说说 AQ-Chat 的背景。它不是一个简单的网页聊天室而是一个带智能客服路由、工单记录、多租户隔离的在线对话系统。前端有 Web 端、小程序端后端是微服务架构核心链路涉及网关、会话服务、消息存储、实时推送等多个模块。代码量不算特别大但业务规则非常密集一个细小的概念混淆就可能导致数据错乱。问题在于AI 编程助手每次面对你的代码仓库时它看到的是“静态快照”而不是“团队记忆”。它不会自己去翻几十个文件更不会主动理解某个字段命名背后的业务含义。你如果问它“消息列表为什么不显示”它可能只从最近的代码 diff 里找线索而不是先去查消息状态机的定义。这就是典型的上下文缺失。CLAUDE.md 存在的意义就是把这些关键背景以最直接的方式写到 AI 助手每轮对话都能看到的位置。它不是给人类看的文档它更像是给 AI 的“入职培训材料”。就像一个新人刚进团队你不可能让他自己读完三个月的历史邮件才能开始干活而是把最重要的规则、警惕点、常见误区直接告诉他。1.2 它和 README、普通文档的本质区别很多团队其实已经有 README 了为什么还要另外搞一份 CLAUDE.md我个人的理解是两者服务对象和表达方式完全不同。README 默认读者是人类它描述的是“如何把这个项目跑起来”“有哪些模块”“部署方式是什么”。它的语言是说明式的、静态的并且往往会尽量避免主观判断。而 CLAUDE.md 的读者是 AI 模型它的语言应该是命令式的、约束性的甚至带着一点“红线”的口吻。拿 AQ-Chat 举例我们的 README 里写了“消息通过 Redis 发布订阅进行实时推送”但 CLAUDE.md 里我会写得更加具体“消息路由禁止直接依赖 Redis 的 Key 过期失效来保证可靠性未确认消息必须走定时补偿任务。”前者告诉你系统的现状后者告诉你 AI 在生成代码时不能越过哪些约定。另外普通文档常会被“堆”在 docs 目录里等真需要时根本找不到。CLAUDE.md 放在仓库根目录AI 工具读项目的第一眼就会看到它。这就像你在工位上贴了一张便签而不是把注意事项放进柜子里锁起来。1.3 聊天类项目的特殊性可能有人会问为什么偏偏拿聊天项目来举例因为聊天系统的坑实在太多了。消息顺序、会话超时、连接状态、在线用户列表的一致性、消息内容的敏感词过滤、单条消息的幂等性……这些业务规则不是靠“代码写得优雅”就能解决的它们往往藏在系统的边界条件里。例如 AQ-Chat 里有一个很经典的事故AI 助手在生成代码时为了追求性能把用户的会话数据直接从 Redis 读出来回写数据库忽略了所有写操作必须经过统一的状态机校验。结果就是有些会话在“已关闭”状态下还能继续收发消息后台工单记录直接乱掉。这种问题如果你不提前在 CLAUDE.md 里把“会话状态迁移规则”写清楚AI 助手靠代码反推是几乎不可能发现的。所以对聊天项目来说CLAUDE.md 的优先级很高因为它承载的不是“风格偏好”而是“业务正确性”。2. 给 AQ-Chat 设计 CLAUDE.md 的核心思路2.1 先做减法别把文件写成百科全书我在第一版 CLAUDE.md 里踩过一个严重错误什么都想写。架构图放进去、接口文档放进去、数据库表结构放进去、代码规范放进去……最后洋洋洒洒写了三千多行AI 助手反而变得“什么都不敢干”或者说它读取文件的时候注意力被大量无关信息稀释了。后来我冷静下来重新审视这份文件的核心价值。CLAUDE.md 里的每一句话都在占用模型的上下文空间如果你塞入的信息 80% 都能从代码库里直接看出来那这个文件就失去了意义。真正需要写进去的应该是那些“看代码看不出来但不知道就一定会出错”的内容。我后来的原则是一个字“省”省到每一段都有存在的理由。一份好的 CLAUDE.md 应该像一张作战地图而不是一本教科书。地图上只需要标注关键地形、雷区和补给线剩下的空地让 AI 自己去探索。2.2 从 AI 最容易犯错的地方反推指令设计 CLAUDE.md 最有效的方法之一不是从“我想让它知道什么”出发而是从“它最近犯了什么错”出发。我建了一张问题清单把过去几周我和同事们通过 Code Review 拦下的 AI 错误全部列出来然后归纳成几个高频类别。以 AQ-Chat 为例高频错误大概有这么几类第一持久化层误用。AI 经常分不清哪些数据应该走 MySQL哪些应该走 Redis。比如它会把用户的在线状态直接写进 MySQL 然后在应用层做条件判断这把数据库当成了缓存来用导致接口响应时间飙升。第二消息时序处理。聊天消息的落库和推送是两条链路的但 AI 经常把它们当成一个事务来处理要么重复推送要么漏推送。第三多租户隔离漏洞。AI 在写查询时经常忘记加租户 ID 条件这在单租户应用里没什么问题但在 AQ-Chat 这种多租户系统里就是严重的数据安全事故。第四外部接口调用方式不统一。有的地方用了同步 HTTP 调用有的地方用了异步事件混乱不堪。有了这份错误清单CLAUDE.md 的骨架其实已经自动浮出水面了。因为每一条错误的背后都对应着一个必须写清楚的“规则”。2.3 把“禁止事项”写进核心章节我不太喜欢把 CLAUDE.md 写成纯正面指导因为对 AI 助手来说“不要做什么”往往比“应该做什么”更有约束力。正面指导容易流于空泛比如“请编写高质量的代码”这句话模型听了等于没听。但“禁止在查询中省略租户 ID”这种话听一遍几乎不会忘。所以我在 AQ-Chat 的 CLAUDE.md 里专门设置了一个章节叫“红线”里面列举的每一条都是经历过线上问题总结出来的硬性要求。比如禁止在非事务环境下批量更新会话在线状态。禁止绕过统一网关直接调用内部服务。禁止将明文 Token 写入日志。禁止在聊天消息存储中使用 SELECT *哪怕是为了节省开发时间。这些条目的语气必须很强硬。我在实际使用中发现只要措辞稍微委婉一点比如“建议考虑”“尽量使用”AI 助手就会在某些角落里偷偷违背约定。而一旦换成明确的“禁止”“必须”它在生成代码时的自我约束力会强很多甚至会在明显违反这些规则时主动停下来和你确认。2.4 架构信息要写在“指令”之前CLAUDE.md 另一个需要注意的细节是信息的顺序。最开始我把架构描述放在文件的末尾结果 AI 助手的很多回答里都暴露出它并没有真正理解系统的数据流向。后来我调整了结构把“项目定位与架构速览”放到了最前面并且在架构描述里直接点出一句话“消息发送链路客户端 → 网关 → 会话服务 → 消息存储 → 推送服务消息只进不出禁止反向依赖。”这句话非常短但它相当于给 AI 画了一条无法绕开的主干道后续它在生成任何与消息相关的代码时都会沿着这条路径去推理而不是自己脑补出各种奇怪的调用关系。从产品逻辑上讲这就和你给新人安排工位是一样的道理。你不可能让新人第一天就去处理所有边缘情况但至少要让他知道公司大门朝哪开、茶水间在哪、老板办公室在哪。先把主干地图画清楚剩下的细节再慢慢锻炼。3. 实操从零到一编写 AQ-Chat 的 CLAUDE.md3.1 落地前的素材准备写 CLAUDE.md 不能凭空硬写准备工作本身就是一次很好的项目复盘。我当时做了这么几件事把项目的 README 重新读了一遍把 CI 流水线里的检查脚本看了一遍把核心模块的目录结构列了出来再拉上后端同事聊了一个小时专门收集他们心里默认但没写下来的隐形规则。这期素材收集阶段有一个容易忽略的点不要只盯着“现有代码”看还要看“团队的近期规划”。比如 AQ-Chat 当时正在从单体应用往微服务迁移很多代码写出来就是要做服务拆分的如果你没把这一目标写进 CLAUDE.mdAI 助手就可能在生成新代码时进一步加重单体耦合给未来的拆分增加大量成本。另外一个很实际的做法是看看你的测试文件。测试里往往藏着很多业务边界条件比如某个接口的幂等性校验、某个事件的重复消费容忍策略这些边界条件同样应该在 CLAUDE.md 里有所体现。3.2 一个可以直接改用的结构模板下面是我经过多轮迭代后认为对 AQ-Chat 这类聊天/实时交互项目最适用的 CLAUDE.md 核心模板。你可以复制下来替换成自己的项目信息。# CLAUDE.md ## 项目定位 AQ-Chat 是一个面向企业客户的在线对话平台核心能力包括 - 多渠道接入Web、小程序、第三方客服平台 - 会话路由与智能分派 - 消息存储与历史记录查询 - 实时在线状态管理 ## 技术架构速览 - 前端React TypeScript状态管理使用 Zustand - 后端Node.js NestJSORM 为 Prisma - 消息实时链路Socket.IO Redis Pub/Sub - 数据库MySQL消息主存储Redis在线状态、分布式锁 关键链路客户端 → API 网关 → 会话服务 → 消息存储 → 推送网关 → 客户端 ## 命令 - 安装依赖pnpm install - 启动本地服务pnpm dev - 运行测试pnpm test - 检查类型pnpm typecheck - 数据库迁移pnpm prisma:migrate ## 核心领域规则 1. 消息具有唯一消息 ID客户端重试时必须幂等去重。 2. 会话状态机opening → active → closing → closed禁止跳级。 3. 所有消息内容入库前必须经过敏感词过滤过滤逻辑在 lib/sensitive.ts。 4. 离线消息只能通过补偿队列重推禁止在查询时直接修改未读标记。 ## 红线绝对不允许触犯 - 禁止在写请求中使用 Redis 当成最终数据源。 - 禁止在多租户查询条件中省略 tenant_id 参数。 - 禁止修改 shared/types.ts 中的消息结构而不同步迁移脚本。 - 禁止在网关层处理业务逻辑网关只做鉴权和转发。 - 禁止将第三方回调的错误信息直接暴露给前端。 ## 常见踩坑点 - 消息时间统一使用服务端时间禁止信任客户端传过来的时间戳。 - Socket.IO 重连时会触发重复的 room join 事件代码需做去重处理。 - 缓存会话信息时key 必须包含租户 ID 和会话 ID 两个维度避免跨租户碰撞。 - 历史消息的分页查询禁止使用 offset 深度翻页超过 10000 条必须改用游标分页。你可能会觉得这些规则很“啰嗦”但恰恰是这些看似琐碎的内容才能真正提升 AI 助手的代码质量。例如“禁止修改 shared/types.ts”这行字说白了我就是把“共享类型是雷区”写在明面上AI 在犹豫要不要修改这个文件时会优先选择新建类型而不是贸然动它。3.3 用三类验证任务“考核”这份文件写完 CLAUDE.md 以后我建议你花半小时做一次“验收测试”。光是写完然后祈祷 AI 能理解是不够的你至少应该测试以下三个场景。第一个场景是信息检索类。直接用问答的方式问 AI“AQ-Chat 的消息发送链路是什么样的”如果它能准确说出“客户端→网关→会话服务→消息存储→推送”这条链路并且没有画蛇添足说明它已经把核心架构记住了。第二个场景是代码生成类。让 AI 实现一个“发送消息并推送给接收方”的接口然后检查它是否天然包含了幂等去重处理、是否在写操作中加入了租户隔离、是否在推送时走了推送网关而不是直接操作数据库。如果它前几步就想到这些说明指令文件起效了。第三个场景是错误识别类。故意给它一段带“雷点”的代码比如一段缺少租户条件的查询问它“这段代码有什么问题”。如果它能指出租户隔离的隐患说明红线章节确实写进了它的行为逻辑。我把这三个测试称为“基准测试”因为每次修改 CLAUDE.md 之后都可以用同样的场景重新跑一遍观察得分是否有提升。这个方法能让你非常直观地判断哪一段指令是在帮忙、哪一段指令是无效噪音。4. 使用过程中的常见问题与维护心得4.1 文件明明写了AI 却视而不见在我分享这份经验的时候问得最多的问题就是我也创建了 CLAUDE.md但 AI 好像完全无视里面的规则怎么办我复盘过几次发现导致这种情况的原因通常有三个。第一个原因是文件放错位置了。根目录的 CLAUDE.md 和子目录里的 CLAUDE.md 是有优先级之分的很多工具在读取时越靠近当前工作目录的文件消息权重越高。如果你把规则放在了 aq-chat/packages/web/CLAUDE.md但当 AI 主要工作在后端目录时它可能根本不会去读取这份文件。解决方法是遵循“入口即全局规则”的原则把通用且最重要的内容放在仓库根目录只在真正需要局部强约束的子模块里放细分文件。第二个原因是文件里的有效信息密度太低。如果你的 CLAUDE.md 前 30 行都在写“欢迎来到本仓库”“该仓库是一个高质量开源项目”这类废话AI 前几次对话可能没问题但在上下文窗口紧张的时候它就可能选择性忽略后面的重点。所以我建议把最重要的“红线”和“核心领域规则”尽量往文件前部塞必要时放在项目定位之后立即出现。第三个原因比较隐晦你文件里的规则和代码现状互相矛盾。比如你写着“禁止使用 Redis 进行消息持久化”但代码里某处却这么写了。AI 在读取代码时会发现自己观察到的事实与 CLAUDE.md 冲突这时它可能会选择相信代码现状而不是文档。解决方式很简单要么修改代码满足文档要么修改文档承认现状不要留着一个自相矛盾的指令文件。4.2 定期做减法防止文件“发福”CLAUDE.md 是一个活文档但它和代码一样会腐化。我见过不少团队的 AI 指令文件刚开始只有一两百行过了一年变成了两千行里面充斥着过时的架构描述和已经废弃的规范这个时候文件的作用已经变成反效果了。我给自己定了一条纪律每迭代一个大的功能版本就把 CLAUDE.md 通读一遍删掉那些已经变成“常识”的条目。如果一个规则连项目里最马虎的开发人员都不会再违反那它就不需要继续写在 AI 的上下文里了。例如早期我们写过“不要在代码里出现硬编码的密钥”这是一条通用的编码常识但因为它占用了篇幅而且 AI 本来就知道不该硬编码密钥保留它纯属浪费。删除这类冗余条目后真正重要的规则会显得更突出AI 的执行率反而更高。4.3 团队协作中的维护节奏CLAUDE.md 不只是给 AI 看的它同时也应该是团队知识沉淀的一部分。我强烈建议把 CLAUDE.md 的变更纳入 Code Review 流程并且要在 PR 描述中明确说明为什么要改这份文件。比如我们团队内部形成了一条不成文的约定如果某次线上事故的复盘结论可以用一句话写进 CLAUDE.md那么这句话必须被提交到仓库里。这样做有一个意想不到的好处CLAUDE.md 变成了一份“踩坑手册”的集合。新入职的同事不用再去翻事故系统的历史记录只要花半小时读一遍这个文件就能避开团队过去一年多积累的绝大多数陷阱。对 AI 助手而言它每次读取的也是同一套文本相当于它和新同事共享了同一个入职记忆。另外我建议专门留一个小节记录“最近变更”。当 AI 因规则理解出现偏差时你可以快速追查是不是某次修改引入的。这个小节不需要太长用简单的日期加说明即可比如“2025-06-10新增会话状态机禁止跳级的约束原因是线上出现了闭环前强制关闭导致丢消息的事故。”4.4 多模块项目的拆分与继承最后谈一下“子目录级 CLAUDE.md”的使用场景。AQ-Chat 不是单模块项目前端、后端、推送服务各自的业务特点差异很大所以我在根目录放一个总纲然后在两个业务复杂度最高的子目录里各放了一份细化的 CLAUDE.md。子文件不需要重复根目录的内容它只需要描述“这个子模块特有的逻辑”。比如推送服务目录里我写了一句话“本服务不感知业务语义只负责收到事件后推送到指定连接任何业务判断放到上层。”这句话如果不写AI 很容易在推送服务里开始做业务判断导致本应该无状态的服务变成了状态持有者。需要注意的是子文件与根文件发生冲突时以哪个为准要非常明确。我在根目录里写了一行说明“子目录中的 CLAUDE.md 如果与根目录冲突以子目录为准冲突解决不了时保持现有代码兼容模式。”这样一来AI 在决策时就不会陷入两难。写在最后小技巧不能省最后分享一个我后来才摸索出来的小技巧CLAUDE.md 的措辞颗粒度要和项目的“错误容忍度”匹配。像 AQ-Chat 这种敏感数据比较多的系统措辞要绝对强硬多用“禁止”“必须”“唯一”。但如果项目是一个低风险的工具类脚本指令文件反而应该多用“优先考虑”“推荐使用”这样的弹性措辞因为过强的约束会严重压缩 AI 的创造力让它写出千篇一律的笨代码。还有一点是我个人的习惯在每次开始大功能开发之前我会主动打开 CLADUE.md 把红线部分重新读一遍就当是给自己做一次开工提醒。这份文件不仅是写给 AI 的也顺带帮我理清了项目的核心边界。毕竟最了解项目的永远是我们自己CLAUDE.md 只是一个把这份了解结构化的容器。
返回列表