深挖Claude Code源码:CLAUDE.md注入机制与优先级详解
速览
本文深入剖析Claude Code源码,纠正CLAUDE.md被拼入System Prompt的误区,指出其实际作为User Message注入。文章详细解释了加载顺序决定的优先级机制,即后加载内容权重更高,并建议编写具体可验证的指令以对抗降权信号。
AI 深度解读
背景
在 AI 辅助编程领域,Claude Code 作为 Anthropic 推出的基于终端的代码智能体,其配置灵活性深受开发者关注。其中,CLAUDE.md 文件常被用户视为自定义 AI 行为的关键入口。然而,许多用户在使用中存在认知误区:往往随意编写几条模糊规则,发现效果不佳后便放弃使用。这种低效的根源在于用户并不清楚 CLAUDE.md 的内容在模型底层是如何被解析、注入以及赋予优先级的。
本文基于 Claude Code 的开源源码(如 utils/api.ts、utils/claudemd.ts 等),深入剖析其底层逻辑,揭示 CLAUDE.md 的真实工作机制、加载优先级、外部引用规则以及与 Memory 系统的交互方式,旨在帮助开发者从“盲目配置”转向“基于底层逻辑的精准调控”。
核心内容
1. CLAUDE.md 的注入机制与优先级真相
最大的认知误区在于认为 CLAUDE.md 的内容被直接拼接到 System Prompt 中。源码分析显示,事实并非如此。
注入方式
CLAUDE.md 的内容通过 prependUserContext() 函数(位于 utils/api.ts:449-474)注入。它被包裹在 <system-reminder> 标签内,作为第一条 User Message 插入到对话历史的最前端,而非 System Prompt 的一部分。
优先级后果
这种注入方式导致 CLAUDE.md 的优先级天然低于 System Prompt。
- 宪法 vs 法律:System Prompt 是模型的“宪法”,拥有最高权威;User Message 是“法律”。当两者冲突时,System Prompt 通常胜出。
- 显式降权信号:注入内容中包含一句关键提示:“IMPORTANT: this context may or may not be relevant to your tasks.” 这是一条显式的降权指令,暗示模型这些内容可能不相关。
对抗降权的策略
尽管存在降权信号,CLAUDE.md 开头包含一条强指令(utils/claudemd.ts:89):“Codebase and user instructions are shown below. Be sure to adhere to these instructions. IMPORTANT: These instructions OVERRIDE any default behavior and you MUST follow them exactly as written.”
这条指令试图用强语气覆盖默认行为。然而,其效果取决于指令的具体性:
- 模糊指令无效:如“尽量简洁”、“保持专业”等模糊要求,极易被模型忽略。
- 具体指令有效:如“回答不超过 3 句话”、“不要向未修改的代码添加注释”等可验证、可执行的具体指令,更容易被模型遵守。
2. 文件加载顺序与优先级层级
Claude Code 并非只读取项目根目录的 CLAUDE.md,而是从当前工作目录开始,逐级向上遍历至文件系统根目录,并在多个层级检查特定文件。
文件类型与位置
- Project 类型:可版本控制。包括
CLAUDE.md、.claude/CLAUDE.md以及.claude/rules/*.md(递归扫描子目录)。 - Local 类型:不应提交到版本控制。即
CLAUDE.local.md。 - User 类型:个人全局指令。位于
~/.claude/CLAUDE.md和~/.claude/rules/*.md。 - Managed 类型:企业管理员策略。位于
/etc/claude-code/CLAUDE.md和/etc/claude-code/.claude/rules/*.md。
加载顺序与优先级 源码注释明确指出:“Files are loaded in reverse order of priority... the latest files are highest priority with the model paying more attention to them.” 即最后加载的文件优先级最高,这利用了模型对输入末尾内容的“近因偏差”(recency bias)。
完整的加载顺序(从低优先级到高优先级)如下:
/etc/claude-code/CLAUDE.md(Managed - 企业策略)/etc/claude-code/.claude/rules/*.md(Managed)~/.claude/CLAUDE.md(User - 个人全局)~/.claude/rules/*.md(User)/repo-root/CLAUDE.md(Project - 仓库根)/repo-root/.claude/CLAUDE.md(Project)/repo-root/.claude/rules/*.md(Project)/repo-root/src/CLAUDE.md(Project - 更近目录)/repo-root/src/.claude/rules/*.md(Project)/repo-root/src/feature/CLAUDE.md(Project - 当前目录)/repo-root/src/feature/CLAUDE.local.md(Local - 最高优先级)
最佳实践建议
- 仓库根目录:放置通用的
.claude/rules/规则。 - 个人偏好:放在
~/.claude/CLAUDE.md。 - 子目录特定规则:例如在
frontend/CLAUDE.md中指定“使用 React 不用 Vue”。 - 就近原则:离当前工作目录越近的文件,优先级越高。
3. @include 指令与模块化配置
CLAUDE.md 支持使用 @ 语法引入外部文件,实现配置的模块化。
解析逻辑
@./path或@path:相对于当前CLAUDE.md文件的路径。@~/path:相对于 Home 目录。@/path:绝对路径。- 支持转义空格:
@./my\ file.md。 - 支持
#fragment后缀(被忽略):@./rules.md#section-1。
安全与限制
- 扩展名白名单:仅支持文本文件,包括
.md,.txt,.json,.yaml,.ts,.py,.go,.rs,.sql等约 80 种扩展名。二进制文件被静默忽略。 - 循环引用检测:通过
processedPathsSet 追踪已处理路径,并设置最大递归深度MAX_INCLUDE_DEPTH防止无限循环。 - 代码块免疫:
@指令仅在 Markdown 的文本节点中生效。代码块(code blocks)或行内代码(inline code)中的@不会被解析。 - 外部文件审批:引入工作目录以外的文件需要配置项
claudeMdExternalIncludesApproved启用。User 类型的CLAUDE.md默认允许引入,但 Project 类型需要显式审批。 - 静默忽略:如果引用的文件不存在,系统不会报错或中断加载。
模块化示例
# 项目根目录 CLAUDE.md
@.claude/rules/code-style.md
@.claude/rules/git-conventions.md
@.claude/rules/testing.md
4. Memory 系统机制
Memory 系统(位于 memdir/)与 CLAUDE.md 是两套独立机制,但在 System Prompt 中紧密相邻。
加载与截断
Memory 通过 loadMemoryPrompt() 加载,注入到 System Prompt 的动态部分(SYSTEM_PROMPT_DYNAMIC_BOUNDARY 之后)。
- 硬编码限制:
MAX_ENTRYPOINT_LINES = 200行,MAX_ENTRYPOINT_BYTES = 25,000字节(25KB)。 - 截断逻辑:先按行截断至 200 行,若仍超限,则在最后一个换行符处切断。
- 警告信息:截断后会追加警告:“WARNING: MEMORY.md is 350 lines (limit: 200). Only part of it was loaded. Keep index entries to one line
