深色模式
写好一个 CLAUDE.md
作者:Kyle Mistele · 2025 年 11 月 25 日 (约 10 分钟阅读) (HumanLayer)
注:这篇文章同样适用于
AGENTS.md—— 对于像 OpenCode、Zed、Cursor、Codex 等 agent/harness 的开源替代方案。 (HumanLayer)
原则:LLM(大模型)基本是无状态的
LLM 是无状态(stateless)的函数。当你用它进行推理时,它的权重是固定的 — 它不会因为之前使用过而“记住”你的代码库。模型对你代码库的了解,仅限于你这次会话中喂给它的 tokens。 (HumanLayer)
同样地,用于编程的 agent 框架(例如 Claude Code)通常要求你显式管理 agent 的“记忆”。而 CLAUDE.md(或 AGENTS.md)是默认会 每次对话 时被包含进去的文件。 (HumanLayer)
这意味着三件事:
- 每次会话开始时,agent 对你的代码库一无所知。 (HumanLayer)
- 如果有重要信息,必须在每次启动会话时告诉 agent。 (HumanLayer)
CLAUDE.md是最合适的方法来做这件事。 (HumanLayer)
CLAUDE.md — 帮助 Claude “上手”你的代码库
因为 Claude 每次对话开始时都对代码库一无所知,所以你应当通过 CLAUDE.md 来引导它“认识”你的项目。大体上,它应涵盖以下三类内容: WHAT / WHY / HOW。 (HumanLayer)
- WHAT(是什么):告诉 Claude 项目的技术栈、结构、代码库地图。对于 monorepo(多子项目)特别重要 —— 说明有哪些应用 (apps)、共有 packages、每部分用途等等,这样它才知道该去哪里找东西。 (HumanLayer)
- WHY(为什么):说明这个项目的目标、目的,以及仓库里每个部分为什么存在、各自承担什么功能。 (HumanLayer)
- HOW(怎么做 / 如何操作):告诉 Claude 如果参与这个项目,它该怎么做才有意义。例如:你是用 bun 而不是 node 吗?你希望它如何验证它自己的修改 — 如何运行测试、类型检查、编译等步骤。 (HumanLayer)
不过 —— 写得方式非常重要!不要试图把 Claude 可能需要运行的「每一个命令」都塞进 CLAUDE.md。那样往往不会得到理想结果。 (HumanLayer)
Claude 常常忽略 CLAUDE.md
不管你用哪个模型,你可能会发现 Claude 时不时会忽略 CLAUDE.md 里的内容。 (HumanLayer)
如果你用 Claude Code CLI + Anthropic API,可以通过插入一个日志代理 (logging proxy) 来验证这一点。因为每次它把 CLAUDE.md 的内容作为 system-reminder 注入:
<system-reminder>
IMPORTANT: this context may or may not be relevant to your tasks.
You should not respond to this context unless it is highly relevant to your task.
</system-reminder>也就是说,如果 Claude 认为 CLAUDE.md 提供的信息与当前任务不相关,它就有可能忽略它。文件里包含的那些并不具有普遍适用性的信息越多,它越可能被忽略。 (HumanLayer)
为什么会这样?我们无法确定 — 但我们可以推测。很多 CLAUDE.md 文件里包含了大量并不普适的指令。很多用户喜欢把这个文件当作一种“快速修补”方法,通过不断追加具体指令来修正它们不喜欢的行为。这样的做法并不一定可靠。 (HumanLayer)
因此,当 CLAUDE.md 太杂、太针对特定情形,它反而可能降低 Claude 的表现。 (HumanLayer)
如何写一个好的 CLAUDE.md
接下来是一些建议 / 最佳实践 — 适用于大多数情况。但并非所有规则都总是适用。正如作者所说 —— 你可以打破它们,只要你知道何时、为何这么做。 (HumanLayer)
越少越好(少即是多)
把可能用到的所有命令、代码风格指南、格式化规则全都放进去,可能会很诱人。但我们不推荐这样。 (HumanLayer)
一些研究(虽不完备)表明:最前沿 LLM 大约能可靠遵循 150–200 条指令。较小的模型或能力较低的模型能遵循的指令更少。随着指令数量上升,遵循能力会大幅下降。 (HumanLayer)
- LLM 通常偏向 prompt 的两端 —— 最开始 (system prompt +
CLAUDE.md) 和末尾 (最新 user message) 的指令更容易被采纳。 (HumanLayer) - 随着文件中指令数量增加,模型的整体遵循质量会统一下降。并不是只有“后面”的指令会被忽略 —— 整体质量下降。 (HumanLayer)
在使用 Claude Code 时,其系统提示自身就包含约 50 条指令。对于一些模型来说,这已经占了它可可靠遵循指令总数的三分之一 —— 这还不包括你自己加的指令、插件、skills 或用户消息。 (HumanLayer)
因此,CLAUDE.md 中的指令应该尽可能少,只包含对任务普遍适用的重要规则。 (HumanLayer)
文件长度与适用性
如果上下文窗口 (context window) 被不相关的信息塞满,LLM 的表现会比上下文清晰、有重点时差得多。 (HumanLayer)
因为 CLAUDE.md 会被注入到每次 session 中,所以你应确保它的内容是高度通用 (universally applicable) 的 —— 而不是针对某些特定任务。 (HumanLayer)
就长度而言,业内共识是让它保持在 300 行以下 —— 越短越好。有的团队根 CLAUDE.md 文件只有不到 60 行。 (HumanLayer)
渐进式披露 (Progressive Disclosure)
对于大型项目,要在保持简洁和覆盖必要信息之间找到平衡并不容易。为了解决这个问题,可以使用 “渐进式披露原则”。也就是说 —— 把那些特定任务 / 特定情境下才需要的信息,放在单独 markdown 文件里 (not in CLAUDE.md),然后在 CLAUDE.md 中放上指向它们的引用 (pointers)。
例如,你的项目结构里可以有:
agent_docs/
├── building_the_project.md
├── running_tests.md
├── code_conventions.md
├── service_architecture.md
├── database_schema.md
└── service_communication_patterns.md然后在 CLAUDE.md 中,只列出这些文件名 + 简短描述,告诉 Claude 在它需要的时候,决定是否读取它们。或者先让 Claude 列出它想读的文件给你批准,再去读。 (HumanLayer)
总原则:用指针,不要复制内容。如果可以,不要在这些文件里包含代码片段 — 因为代码片段很快就会过时。更好的做法是使用 file:line 引用,指向最权威、最新的代码。 (HumanLayer)
这种做法概念上很像 Claude Skills 系统 —— 虽然 skills 更偏重工具使用,不是指令。 (HumanLayer)
不要让 Claude 做 “昂贵的 linter / 格式器 (formatter)”
我们经常看到人们把代码风格指南 (style guidelines) 放到 CLAUDE.md 里。作者建议:永远不要让一个 LLM 去做 Linter 的工作。因为和传统 deterministic (确定性) 的 linter / formatter 相比,LLM 既慢又昂贵。 (HumanLayer)
把风格指南、格式化规则以及大量代码片段放进上下文,不仅会填满上下文窗口,而且很可能导致模型性能下降、忽略指令、浪费资源。 (HumanLayer)
更好的做法是:用确定性工具 (如 linter / 自动 formatter) 来处理格式/风格问题。如果你真的很想自动化,你可以考虑为你的开发流程设置一个 “Stop hook” —— 让 linter / formatter 先运行,当它发现问题时,再把错误交给 Claude 来修复; 而不要让 Claude 自己去发现风格 / 格式问题。 (HumanLayer)
另外,也可以使用 “slash command” (斜杠命令) —— 把你的代码指南封装在命令里,让它指向版本控制里的变更 (git status) 或其他类似机制,以便把格式化 / 风格管理与实际实现区分开。这样会得到更好、更稳定的结果。 (HumanLayer)
不要用 /init 自动生成 CLAUDE.md
无论是 Claude Code 还是其他使用 OpenCode 的框架,都提供了自动生成 CLAUDE.md (或 AGENTS.md) 文件的方法(例如 /init 命令)。看似方便,但作者认为这是个高风险操作。因为 CLAUDE.md 将影响你工作流中的每个阶段和生成的每件产物 —— 写得不好,后果可能很严重。 (HumanLayer)
一句糟糕的指令,就可能导致大量糟糕代码 / 错误设计 /混乱流程。鉴于它的影响非常广 (coverage wide),你应该认真、谨慎地编写每一行内容。不要简化、敷衍。好好设计、反复斟酌、手动维护 —— 而不是依赖 auto-generated 起点。 (HumanLayer)
总结
CLAUDE.md的核心用途是帮助 Claude 认识并理解你的代码库 — 用于“onboard Claude into your codebase”。它应该回答项目的 WHY / WHAT / HOW。 (HumanLayer)- 遵循 “少即是多”:不要把所有可能的命令、风格指南、规范都塞进去 —— 只放那些通用、必要、有意义的指令。 (HumanLayer)
- 内容应尽可能简洁且通用。很多团队的根
CLAUDE.md都控制在几十行以内。 (HumanLayer) - 对于详细、场景特定、容易过时的内容 (构建流程、测试流程、数据库 schema、通信模式等),尽量使用“渐进式披露”:放到独立 markdown 文件里,并在
CLAUDE.md中以指针或说明的形式引用。让 Claude 在需要时再读取。 (HumanLayer) - 不要把 LLM 当作 linter / formatter。使用确定性工具来处理代码风格和格式问题。 (HumanLayer)
- 避免自动生成
CLAUDE.md:你应该手动、认真地设计和维护它,因为这是对整个开发流程影响最大的一个配置点。 (HumanLayer)
