上下文体系
Claude 怎么「知道」你的项目?CLAUDE.md、Rules、Auto Memory、Skills、MCP 的加载机制与最佳实践。
Part 1: 上下文体系
Claude Code 的上下文不是一个单一的「记忆」,而是由多个来源、多种加载时机、多层优先级构成的复合系统。以下按加载优先级从高到低排列。
1. CLAUDE.md — 用户规则文件
CLAUDE.md 是你与 Claude Code 之间最重要的「合约」。它是一个纯文本文件,内容会在每次会话启动时被注入到 system prompt 中,相当于你在每次对话开始前先说了一段话。
两个层级
| 层级 | 路径 | 作用范围 | 典型内容 |
|---|---|---|---|
| 项目级 | ./CLAUDE.md(项目根目录) |
仅在该项目目录下的会话中生效 | 技术栈说明、代码规范、提交规则、测试命令、架构约定 |
| 用户级 | ~/.claude/CLAUDE.md |
在所有项目的所有会话中生效 | 全局偏好、通用规则(如「所有回复用中文」「不要用 emoji」) |
最佳实践
CLAUDE.md 的全部内容都会被注入 system prompt,直接占用上下文窗口。太长会:
- 浪费宝贵的上下文空间,挤占实际对话内容
- 包含太多信息时,重要规则的「权重」会被稀释
- 增加 auto-compact 触发频率
如果超过 200 行:拆分到 .claude/rules/ 目录中,利用路径匹配按需加载。把最核心、最通用的规则留在 CLAUDE.md 中。
- 优先级最高的放最前面:Claude 对靠前内容的遵循度更高
- 用命令式语气:「使用 TypeScript strict mode」比「我们一般用 TypeScript strict mode」效果更好
- 避免解释性文字:CLAUDE.md 不是文档,是「指令集」。不需要解释为什么,只需要说怎么做
- 分节用 Markdown 标题:便于 Claude 定位特定规则
CLAUDE.md 示例结构 示例
# 项目概览
这是一个 Next.js 14 + TypeScript + Prisma 的全栈项目。
# 代码规范
- 使用 TypeScript strict mode
- 函数参数超过 3 个时使用对象解构
- 所有组件使用 named export,不用 default export
- 测试文件放在 __tests__ 目录,用 Vitest
# Git 规范
- commit message 用中文
- 不要自动 push
- 每次 commit 前运行 pnpm lint
# 运行命令
- 开发: pnpm dev
- 测试: pnpm test
- 构建: pnpm build
- lint: pnpm lint
2. Rules (.claude/rules/*.md)
Rules 是 CLAUDE.md 的扩展机制。当你的规则太多、或者某些规则只在特定场景下需要时,Rules 系统比把所有内容塞进一个 CLAUDE.md 要优雅得多。
两种类型
| 类型 | 配置方式 | 加载时机 | 适用场景 |
|---|---|---|---|
| 无条件规则 | 直接放在 .claude/rules/ 目录下的 .md 文件,没有 frontmatter |
每次会话启动时自动加载(和 CLAUDE.md 一样) | 通用但不适合放在 CLAUDE.md 里的补充规则 |
| 路径匹配规则 | .md 文件中包含 YAML frontmatter,声明 paths 字段 |
仅当 Claude 操作的文件路径匹配 paths 中的模式时才加载 |
特定子目录或文件类型的专属规则 |
paths 字段的匹配方式
paths 字段使用 glob 语法匹配文件路径。当 Claude 读取或修改的文件匹配到某条规则的 paths 模式时,该规则会被动态注入到上下文中。
路径匹配规则示例 示例
---
paths:
- "src/components/**/*.tsx"
- "src/components/**/*.ts"
---
# React 组件规范
- 所有组件使用函数式写法
- Props 类型单独定义,命名为 XxxProps
- 使用 forwardRef 包装需要 ref 的组件
- CSS 使用 Tailwind,不写内联样式对象
这个规则只有在 Claude 操作 src/components/ 下的 .tsx 或 .ts 文件时才会被加载。操作其他目录的文件时,这些规则不会浪费上下文空间。
另一个实用示例:数据库迁移规则 示例
---
paths:
- "prisma/**"
- "src/db/**"
---
# 数据库操作规范
- 修改 schema 后必须运行 npx prisma generate
- 每次迁移都要写明确的迁移名称
- 不要直接修改已有的 migration 文件
- 添加字段时考虑默认值和 nullable
3. Auto Memory — 自动记忆系统
CLAUDE.md 和 Rules 是你手动维护的。Auto Memory 是 Claude 自己维护的——它会从对话中自动提取重要信息并持久化保存。
记忆的存储结构
每个项目的 .claude/ 目录下会有一个 MEMORY.md 文件,作为记忆的索引和主存储。
- 大小限制:前 200 行或 25KB(取较小者)会被加载到上下文
- 超过限制的部分:不会被加载,等于不存在
- 格式:Markdown,每条记忆通常是一个简短的要点
当 MEMORY.md 变得太大,或者某个主题的记忆特别多时,Claude 会自动创建主题文件:
- 存放在
.claude/memory/目录下 - 按主题命名,如
testing.md、deployment.md - MEMORY.md 中会包含指向这些主题文件的引用
- 加载时根据当前上下文相关性决定是否加载具体主题文件
记忆分为两个级别:
- 用户级记忆:
~/.claude/下的 MEMORY.md 和 memory/ 目录,跨项目共享 - 项目级记忆:项目
.claude/下的 MEMORY.md 和 memory/ 目录,仅在该项目中生效
记忆的触发方式
| 触发方式 | 说明 |
|---|---|
| 自动提取 | Claude 在对话中发现值得记住的模式或偏好时,自动写入记忆 |
/memory 命令 |
打开交互式面板,手动查看、编辑或添加记忆 |
| 对话中明确要求 | 你说「记住这个」或「以后都这样做」时,Claude 会将其写入记忆 |
4. Skills 的两层加载
Skills 是 Claude Code 的能力扩展机制。但如果所有 Skill 的完整内容都在启动时加载,上下文会被撑爆。所以 Skills 使用了一个巧妙的两层加载策略。
Layer 1: 摘要层
- 每个 Skill 只占用约 100 tokens
- 包含:Skill 名称、一句话描述、触发条件
- 作用:让 Claude 知道「有这个能力存在」,以便在合适的时机调用
- 即使有 50 个 Skills 安装,Layer 1 总共也只占约 5000 tokens
Layer 2: 完整内容层
- 每个 Skill 的完整内容约 2000 tokens(有的更多)
- 包含:详细指令、工作流步骤、配置参数、示例
- 触发:当 Claude 决定使用某个 Skill 时,通过
Skill工具调用加载完整内容 - 加载后的内容会进入当前对话上下文,直到 compact 或 clear
实际流程示例 流程
5. MCP 工具的延迟装配
MCP(Model Context Protocol)工具是外部服务通过标准协议暴露给 Claude 的能力。和 Skills 类似,MCP 工具也不是一次性全部加载的。
两阶段加载
Claude Code 连接到已配置的 MCP Server,获取所有可用工具的名称和简短描述。这些信息被写入 system prompt 的 deferred tools 列表中。
- 占用极少的 tokens(每个工具仅名称 + 一句话)
- 让 Claude 知道「这个工具存在,可以调用」
- 但此时 Claude 不知道工具的参数结构
当 Claude 决定调用某个 MCP 工具时,会先通过 ToolSearch 工具获取完整的 JSON Schema 定义。
- 包含:参数名称、类型、是否必填、描述、默认值
- 获取后 Claude 才能构造正确的调用参数
- Schema 会留在当前对话上下文中,后续调用同一工具不需要重复获取
ToolSearch 的查询方式 技术细节
ToolSearch 支持三种查询形式:
select:Read,Edit,Grep— 按名称精确匹配,一次获取多个工具的 schemanotebook jupyter— 关键字搜索,返回最相关的工具(最多 max_results 个)+slack send— 要求名称中包含「slack」,再按其他关键字排序
这个设计让 Claude 能高效地按需发现和使用 MCP 工具,而不需要在启动时把所有工具的完整定义都塞进上下文。
6. 为什么 Claude 有时像「忘了以前说过的话」
这是新用户最困惑的体验之一:你明明十分钟前告诉了 Claude 一件事,它现在却好像完全不记得了。这不是 bug,而是上下文管理机制的副作用。
三个主要原因
原因 1:/compact 和 auto-compact 替换了历史 最常见
当对话长度接近上下文窗口上限时,系统会自动触发 compact(你也可以手动执行 /compact)。Compact 的工作方式是:
- 让模型生成一份最多 2000 token 的对话摘要
- 用这份摘要替换所有之前的对话消息
- 替换是彻底的——原始对话内容不再存在于上下文中
后果:如果你在之前的对话中提到过某个偏好或细节,但它没有被包含在摘要中,Claude 就「忘了」。摘要毕竟只有 2000 token,不可能保留所有细节。
好消息:原始对话会保存在 .transcripts/ 目录,不会真正丢失。但 Claude 在当前会话中确实无法访问了。
原因 2:内容没有被持久化
只存在于对话历史中的内容,生命周期仅限于当前会话。一旦 compact 或开新会话,就会丢失。只有写入以下位置的内容才能跨会话存活:
CLAUDE.md— 手动维护的规则.claude/rules/— 分类规则文件MEMORY.md/.claude/memory/— 自动或手动记忆
建议:如果一个信息很重要且需要跨会话保留,主动告诉 Claude「把这个记住」或者自己手动写入 CLAUDE.md。
原因 3:权重稀释
即使信息仍在上下文中,当上下文非常长时,模型对单条信息的「注意力」会下降。这是大语言模型的固有特性:
- 靠前的内容(system prompt、CLAUDE.md)权重较高
- 中间的内容权重最低(「迷失在中间」效应)
- 靠后的内容(最近的对话)权重较高
实际影响:如果你在会话早期提到过一条规则,随着对话变长,Claude 可能会「忽略」它——不是真的忘了,而是其他更近的信息抢占了注意力。
诊断工具
| 命令 | 作用 | 何时使用 |
|---|---|---|
/memory |
查看和编辑 Claude 的自动记忆 | 怀疑 Claude 没有记住某个偏好时 |
/context |
查看当前加载的所有上下文来源 | 想确认 CLAUDE.md、Rules、Memory 是否被正确加载 |
/compact |
手动压缩对话,可以附带自定义提示来控制摘要内容 | 觉得对话太长影响质量时,主动压缩并强调关键信息 |
/cost |
查看当前上下文 token 消耗 | 想判断是否快要触发 auto-compact |
/resume 恢复会话)。
上下文全景图
所有上下文来源在一次会话中的加载方式: