CLAUDE.md 写了 300 行还是被无视?五层记忆的正确喂法 你有没有遇到过这种情况写了一份详详细细的 CLAUDE.md技术栈、命名规范、错误码约定、数据库表结构……洋洋洒洒三百行结果 Claude Code 该咋干还咋干你写的统一返回格式它当没看见你强调的不使用 jest它照样给你生成 jest 测试。我碰到过。而且不止一次。第一次我以为是写得不够清楚于是又加了五十行把每个细节展开讲。结果还是老样子。那阵子我甚至怀疑是不是模型本身的问题去 issue 区翻了一圈搜了两个小时没找到答案——后来才想明白问题根本不在内容写得好不好而在喂法错了。一个被无视的 CLAUDE.md 长啥样我一开始写得特别描述式大概是这样# 订单服务 API 这是一个电商平台的后端服务我们团队有5个人项目从2024年3月开始开发。 使用 Node.js 编写是一个 RESTful API 服务。 代码要写得好一些注意性能。 测试要全面。 请遵循最佳实践。现在回头看这写法蠢得可以。“代码要写得好一些”“请遵循最佳实践”——这种话对模型来说等于没说它本来就会遵循最佳实践问题是它脑子里的最佳实践和你团队的最佳实践根本不是一回事。模型读规范吃的是指令式的硬约束不是描述式的形容词。你跟它说列表接口统一支持分页page 从 1 开始limit 默认 20 最大 100它会照办你跟它说注意性能它只会点点头然后该 N1 查询还 N1。改成指令式之后问题没完全解决我把那段重写成指令式# 订单服务 API ## 技术栈 - Node.js 20 TypeScript 5.3严格模式 - Fastify 4 框架不使用 Express - Prisma ORM PostgreSQL 15 - pnpm 8 包管理不使用 npm/yarn ## 关键约定 - API 统一返回格式{ success: boolean, data?: T, error?: { code: string, message: string } } - 错误码使用 UPPER_SNAKE_CASE如 ORDER_NOT_FOUND - 数据库表名 snake_case 复数形式主键 UUID效果好了不少至少技术栈和返回格式它能记住了。但新的麻烦冒出来我把 API 规范、数据库规范、测试规范全塞进同一个 CLAUDE.md文件膨胀到两百多行。当我让它在src/routes/下加个新路由时它有时候照着分页规范来有时候又忘了——三百行的东西对模型来说也是噪音。等一下这里我漏说一个前提CLAUDE.md 不是越全越好而是越精准命中场景越好。三百行堆在一起等于把所有规范一股脑塞进上下文窗口模型每次都得自己判断这条规范现在适不适用判断失误是常态。五层记忆把规范按场景分层喂《Claude Code 实战》这本书里提出一个马具的隐喻——Claude Code 是马具不是马你得把缰绳、马鞍、马镫分别装在该装的位置。记忆系统也是这个思路分五层每层职责不同层级文件作用域第 1 层~/.claude/CLAUDE.md个人偏好跨所有项目第 2 层repo/CLAUDE.md项目说明团队共享第 3 层.claude/rules/*.md条件化规则按路径触发第 4 层repo/CLAUDE.local.md本地备忘gitignore第 5 层CLAUDE.md 里的常用命令段命令速查第 1 层放跨项目的东西比如回复用中文“提交信息走 conventional commits”别硬编码 API Key这种我个人的固定偏好写一次所有项目通用# 个人编码偏好 - 回复使用中文代码注释使用英文 - Git 提交信息格式type(scope): 中文描述 - 优先使用函数式编程风格避免冗余注释 - 变量命名camelCase - 跑测试 → 执行 pnpm test - 起服务 → 执行 pnpm dev第 2 层才是项目说明只放这个项目特有的技术栈、目录结构、关键约定前面那个指令式的 CLAUDE.md 就放这儿。第 4 层CLAUDE.local.md是个人备忘记得加进.gitignore里面塞本地数据库地址、联调端口这种不该提交的东西# 本地开发备忘 - 开发数据库地址postgresql://dev:dev12310.0.1.50:5432/orders_dev - 每周三晚 22:00-23:00 数据库做维护此时段勿跑迁移 - 联调时前端在 5173 端口需要手动配置代理第 5 层其实就是第 2 层 CLAUDE.md 末尾的一段让模型记住跑测试对应哪个命令## 常用命令 pnpm dev # 启动开发服务器端口 3000 pnpm test # 运行全部测试vitest pnpm build # TypeScript 编译 类型检查 pnpm db:migrate # 执行 Prisma 数据库迁移这四层都不是重点。真正解决被无视问题的是第 3 层。条件化规则按路径自动加载的杀手锏.claude/rules/*.md这一层带 frontmatterpaths字段模型读到匹配路径下的文件时自动把对应规则拉进上下文。等于给规范装了个触发器——只在用得上的时候才出现不占常驻上下文。我把原来那三百行 CLAUDE.md 里API 规范“数据库规范”测试规范三块拆出去变成三个独立文件。.claude/rules/api-design.md--- paths: - src/routes/** - src/schemas/** --- # API 设计规范 - 每个路由必须有对应的 Zod schema 做入参验证 - 列表接口统一支持分页page从1开始和 limit默认20最大100 - 错误响应必须包含机器可读的 code 字段和人类可读的 message 字段.claude/rules/database.md--- paths: - prisma/** - src/repositories/** --- # 数据库规范 - 迁移文件一旦提交到 main 分支就不允许修改只能创建新迁移 - 所有查询必须通过 repository 层service 层禁止直接调用 Prisma - 批量操作使用事务包裹超过 100 条记录的写入必须分批.claude/rules/testing.md--- paths: - **/*.test.ts - **/*.spec.ts - tests/** --- # 测试规范 - 使用 vitest 作为测试框架不使用 jest - 每个测试文件必须包含 describe 块describe 名称与被测模块一致 - 使用 vi.mock() 进行模块模拟不使用手动 mock - 异步测试统一使用 async/await不使用 done 回调 - 测试数据使用 factory 函数生成不在测试中硬编码frontmatter 里的paths用的是 glob 语法**匹配任意层级目录。命中规则很简单模型在处理src/routes/order.ts这种文件时api-design.md的paths里有src/routes/**匹配上了规则就被注入处理src/repositories/user.ts时database.md命中api-design.md不动。互不干扰。拆完之后的对比拆完之后我做了个简单验证。原来在 CLAUDE.md 里写不使用 jest让 Claude 在src/services/order.test.ts里补一个测试用例它给我生成的是describe(order service, () { ... })配 jest 的语法规范被无视。拆成.claude/rules/testing.md之后同样让它在那条路径下补测试它直接用了 vitestvi.mock()也对上了。区别在哪路径匹配命中后规则被显式注入模型不需要在三百行里大海捞针。我还做了个对比在src/routes/order.ts下问它分页参数怎么传。原来 CLAUDE.md 时代它答得含糊有时候说 page 从 0 开始规则文件拆出去后它答的是 page 从 1 开始、limit 默认 20 最大 100——和 frontmatter 里写的一字不差。这就是条件触发和常驻上下文的差距。反思回头看我最初犯的错是把 CLAUDE.md 当成项目说明书在写越写越长以为信息越全模型越懂。其实模型吃上下文是有信噪比的——三百行常驻规范里真正和当前任务相关的可能就十几行剩下两百多行全是噪音反而把相关的那十几行冲淡了。五层记忆的核心思路是分层加触发跨项目的放第 1 层写一次项目特有的放第 2 层场景特有的拆成第 3 层按路径触发本地私货放第 4 层命令速查放第 5 层。每层各司其职模型该读哪层读哪层。顺便一提我做雷达鸭一个收录中国一人公司赚钱案例的 App华为应用市场微信小程序Uni-apparkTSUniCloud鸿蒙适配时ArkTS 那套严格类型规范就是靠.claude/rules/arkts.md配paths: [entry/src/**/*.ets]管住的比塞进 CLAUDE.md 强太多。等 Claude Code 后续更新我希望paths能支持更细的触发条件比如按文件类型、按分支、按 commit message 触发那样条件化规则能玩出更多花样。现在这套够用但离想让它干啥它就干啥还差点意思。个人介绍雷达鸭 App 独立开发者10年软件开发经验软件设计师、人工智能应用工程师专注鸿蒙 ArkTS Web 前端正在探索 AI 自动化的工程化路径。MIT 声明本文基于黄佳著《Claude Code 实战Harness 工程之道》第 1-2 章M1 记忆系统整理实践遵循 MIT 协议欢迎转载但请保留原作者署名。