☰
打开 Claude Code 的黑匣子:从 CLAUDE.md 到 MCP,一次会话的上下文窗口里到底发生了什么?
2026/9/29 20:19:10 网站建设 项目流程

1. 一次会话里,上下文窗口到底被谁塞满了

很多人第一次用 Claude Code,都会有种错觉:它好像记得住整个项目。你随口问一句“上次那个接口改完了吗”,它真能翻出对应文件;你让它按团队规范写代码,它写出来的风格跟项目里已有的代码几乎一致。这种“提前做过功课”的感觉,容易让人以为它背后挂着一个持久记忆库。

其实不是。Claude Code 没有真正的记忆,它所有的“知道”,都来自一个东西——上下文窗口。你可以把它想成一块每次会话临时搭起来的白板:对话历史、读过的文件、配置指令、工具说明,全都被写到这块白板上,模型每次回应,只看白板此刻摆着什么。白板有容量上限,目前大约是 20 万 token 量级,听起来很大,但真跑起长会话,填满速度比想象中快得多。

这篇就聚焦单次会话的内部机制,拆开看 CLAUDE.md、MCP、子代理各自往窗口里塞了什么、什么时候塞、占多少,以及窗口快满时/compact到底做了什么。目标很实在:给你一份能直接抄的 CLAUDE.md 骨架、一段 MCP 配置片段,再配上/context、/memory这类命令,让你能亲眼看到自己的窗口被谁占着。适合已经在用 Claude Code、但总觉得它“时灵时不灵”的开发者。

2. 前置准备:把 TaoToken 接进 Claude Code

在拆窗口机制之前,得先让 Claude Code 能正常跑起来。Claude Code 本身是个命令行工具,它需要一个能响应 Anthropic 协议的后端。我这边习惯用 TaoToken 来做接入层,它的 API 地址是https://taotoken.net/api,兼容 Anthropic 的接口格式,配置起来不绕。

先拿到访问凭证。打开控制台创建 API Key:

# 控制台地址(创建和管理 API Key) https://taotoken.net/console

创建完 Key 之后,把它写进环境变量。Claude Code 读取的是ANTHROPIC_BASE_URL和ANTHROPIC_API_KEY这两个变量,指向 TaoToken 的 API 地址即可:

# 写入 shell 配置,按你用的 shell 选一个 echo 'export ANTHROPIC_BASE_URL="https://taotoken.net/api"' >> ~/.bashrc echo 'export ANTHROPIC_API_KEY="sk-你的key"' >> ~/.bashrc source ~/.bashrc # 如果你用 zsh echo 'export ANTHROPIC_BASE_URL="https://taotoken.net/api"' >> ~/.zshrc echo 'export ANTHROPIC_API_KEY="sk-你的key"' >> ~/.zshrc source ~/.zshrc

配好之后,在项目根目录直接运行claude就能进会话。如果你还没装 Claude Code,用 npm 全局装一下:

npm install -g @anthropic-ai/claude-code

这里有个细节值得先记住:环境变量是在进程启动时读取的,所以改完配置要重开终端,或者source一下,否则 Claude Code 还是用旧值。这个坑我在排查“为什么换了 Key 还是报 401”的时候踩过,后来发现是终端没刷新。

3. 可复制配置:CLAUDE.md 骨架与 MCP 片段

3.1 CLAUDE.md 到底该写什么

CLAUDE.md 是项目级长期指令的存放处,它在会话启动阶段就被静默读入上下文。也就是说,你还没敲第一个字,它的内容已经躺在白板上了。所以它写得好不好,直接决定窗口的“底噪”有多大。

一个常见的误区是把 CLAUDE.md 写成项目百科,什么都往里塞。结果每次会话一开始,几千 token 就被无关内容占掉。我的建议是分层:项目根目录放全局规范,子目录放局部规则,让规则跟着文件路径按需加载。

下面是一份可以直接改的骨架:

# 项目约定 ## 技术栈 - 语言:TypeScript 5.x,严格模式 - 框架:Next.js 14 App Router - 包管理:pnpm,禁止用 npm 装依赖 ## 代码风格 - 组件用函数式,禁止 class 组件 - 所有导出函数必须写 JSDoc 注释 - 错误处理统一用 Result 类型,不抛裸异常 ## 目录结构 - src/app 路由与页面 - src/lib 纯工具函数,禁止引入 React - src/components 通用组件 ## 禁止事项 - 不要修改 package.json 里的版本号 - 不要自动执行数据库迁移 - 提交前不要跑 git push

这份骨架控制在 200 字以内,占用的 token 很少,但把最关键的约束说清楚了。真正细的规则,放到子目录的 CLAUDE.md 里,比如src/lib/CLAUDE.md只写工具函数的约定,这样只有读到src/lib下的文件时才会加载。

3.2 MCP 配置片段

MCP 是模型上下文协议,它让 Claude Code 能调用外部工具。关键点在于:启动时加载的只是工具的名字和描述,不是工具本身的逻辑。所以 MCP 对窗口的占用,主要来自工具描述文本,而不是工具能干什么。

配置一般写在项目根目录的.mcp.json里:

{ "mcpServers": { "filesystem": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/project"] }, "fetch": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-fetch"] } } }

每加一个 MCP server,它的工具列表就会在启动时进入上下文。工具越多,描述文本越长,底噪越大。所以别一次性挂十几个 server,按当前任务需要开。我实测下来,挂 3 到 5 个常用 server 是比较舒服的区间,再多就能明显感觉到窗口被描述文本吃掉一块。

注意:MCP 工具描述是常驻的,不会因为你没用它就消失。如果某个 server 这个会话根本用不上,直接从配置里去掉,比留着更省空间。

4. 验证请求:用 /context 和 /memory 看窗口占用

配置写完了,怎么知道窗口里到底装了什么?Claude Code 提供了两个命令,一个看占用,一个看加载。

4.1 /context 看实时占用

在会话里直接输入:

/context

它会给出一个分类统计,大致长这样:

Context Usage ───────────────────────────── System prompt 2,340 tokens CLAUDE.md 1,120 tokens MCP tools 3,860 tokens Messages 12,450 tokens Files 8,900 tokens ───────────────────────────── Total 28,670 tokens / 200,000

这个输出能直接回答“窗口被谁占了”。如果 MCP tools 那一栏特别大,说明你挂的 server 太多;如果 Files 涨得飞快,说明读进来的大文件在累积。我一般会在长会话中途跑一次/context,看看是不是该清理了。

4.2 /memory 看加载了哪些指令

/memory

这个命令列出会话启动时成功加载的 CLAUDE.md 文件和自动记忆内容。如果你改了 CLAUDE.md 但感觉没生效,先跑这个确认它到底有没有被读进来。常见情况是文件放错了目录,或者命名不对,导致根本没被识别。

4.3 观察文件读取的累积

想直观感受文件读取的成本,可以做个对比。先跑一次/context记下 Files 的数字,然后让 Claude Code 读一个大文件:

请读取 src/app/page.tsx 并总结它的结构

读完再跑一次/context,Files 那一栏会明显上涨。一个 5000 行的文件读进来,占用的 token 相当可观。如果会话里连续读了好几个大文件,窗口占用会快速逼近上限。这就是为什么长会话后期,Claude Code 的回应质量会下降——不是它变笨了,是白板快写满了。

5. 本篇常见错排查

5.1 改了 CLAUDE.md 但行为没变

最常见的原因是文件没被加载。先跑/memory确认。如果列表里没有你的文件,检查三点:文件名是否严格是CLAUDE.md(大小写敏感)、是否放在项目根目录或当前工作目录、是否在会话启动前就存在。会话中途新建的 CLAUDE.md 不会自动重载,得重开会话。

5.2 MCP 工具报连接失败

先单独测 server 能不能起来:

npx -y @modelcontextprotocol/server-filesystem /path/to/project

如果这条命令本身报错,说明是 server 的问题,跟 Claude Code 无关。如果命令能跑但 Claude Code 里用不了,检查.mcp.json的路径参数是不是绝对路径,相对路径在不同工作目录下会解析失败。

5.3 窗口很快满了,回应变差

跑/context看哪一栏最大。如果是 Messages,说明对话历史太长,用/compact压缩。如果是 Files,说明读进来的文件太多,考虑用子代理去处理调研类任务,让它在独立窗口里读文档,只把摘要带回来。如果是 MCP tools,砍掉不用的 server。

5.4 /compact 之后技能列表丢了

这是预期行为。/compact会把对话历史替换成结构化摘要,并自动重载 CLAUDE.md 和记忆,但技能列表是唯一的例外,不会自动重载。如果你依赖某个技能,压缩后手动重新触发一次。

5.5 子代理的结果没传回主会话

子代理有自己独立的上下文窗口,它读的大量文档不会占用主会话空间,但代价是它只把摘要和少量元数据传回。如果你发现主会话拿不到细节,是因为细节本来就没传回来。需要细节的话,让子代理在摘要里明确列出关键结论和文件路径。

6. 把窗口管起来,比换模型更管用

拆完这一圈,你会发现 Claude Code 的行为其实很好解释:它每次回应,都只基于白板上此刻的内容。CLAUDE.md 和 MCP 描述是常驻底噪,文件读取和对话历史是动态增量,子代理是开了一块独立白板只交回结论,/compact是擦掉旧讨论换成纪要。

想让会话保持高质量,重点不是换更强的模型,而是管好这块白板。我的习惯是:CLAUDE.md 控制在 200 字内,MCP server 按需挂,长会话中途跑一次/context,看到 Messages 涨太快就/compact。调研类任务一律丢给子代理,别让主会话去啃大文档。

如果你还没配好接入层,可以从 API Keys 页面拿一个 Key,按第 2 节的命令写进环境变量就能跑。想先验证模型响应是否正常,用模型对话页面发一条测试消息最快。要是你打算把 Claude Code 长期用在日常编码和 Agent 流程里,Coding Plan 会更省心,不用每次单独管额度。接入过程中遇到报错,接入文档里有各语言的完整示例,对着排查比瞎试快得多。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询