上下文压缩扔得掉对话,扔不掉你的 CLAUDE.md

1 扔不掉,因为它压根不住在对话里

上一篇上下文满了,Claude Code 扔什么、留什么?的四级压缩流水线,收走的是会话历史------你的话、模型的回话、工具回执。可你写进 CLAUDE.md 的那几行------「本项目用 Bun 跑脚本,不要用 npm」「回答一律用中文」------会话开上三小时、压缩跑了好几轮,一条没丢。

为什么? 因为它压根不在这串历史里:CLAUDE.md 在磁盘上,就是一份文本文件。会话开场,harness 把它读出来、拼好;此后每一轮发请求,都把这份内容原样放在最前面。压缩重写的只是历史,够不着它。它连系统提示词都不进,而是作为一条「系统提醒」消息,排在对话最前面发过去。

一句话:存在会话里的东西,会损耗;存在磁盘上的东西,不会。

2 存在哪:全局、项目、本地

CLAUDE.md 这一套,说清楚就三件事:存在哪、怎么写、怎么读进来。一件一件说。

文件不止一个,分三处。说给谁听的,就写到哪个文件:

放在哪 管谁、写什么 进不进 git
全局 ~/.claude/CLAUDE.md,加 ~/.claude/rules/ 整个目录 你这个人:「回答一律用中文」这类个人偏好,到哪个项目都跟着 不进
项目 仓库里的 CLAUDE.md(裸放或收进 .claude/ 都行),加 .claude/rules/ 整个目录 这个仓库:团队约定,比如「本项目用 Bun 跑脚本,不要用 npm」 进------跟着代码走,新同事 clone 下来就有
本地 CLAUDE.local.md 你这台机器:「本地测试库连哪个端口」这类本地配置 不进------加进 .gitignore

分三处不是随手放的:个人偏好、团队约定、本地配置,本来就该各归各------个人的不进仓库,机器的不进 git;本地测试库连哪个端口,不该逼队友照连。

三处要是打架,谁说了算?源码注释写得很直白:加载次序反过来就是优先级,越晚加载的越当回事------全局最早,项目居中,本地最晚。意图就是让具体的压过泛化的:全局写「注释一律中文」,这个项目写「注释一律英文」,后加载的项目那份赢。

注:同类的另一个文件名标准是 AGENTS.md(OpenAI 的 Codex、Google 的 Gemini CLI 等工具读它)。在Claude Code里,加载清单上只有 CLAUDE.md 这一系列,没有 AGENTS.md

3 怎么写:一个文件,还是一个目录

上一节的表里,全局层和项目层都给了两个去处:一个 CLAUDE.md 文件,加一个 rules 目录。它们不是两样东西,是同一批要求的两种写法。

一个文件从头写到尾(CLAUDE.md :所有要求写进一个文件,放在哪就管哪------放仓库根管全仓库;放进 docs/ 就只管 docs,模型真去读那里的文件时,才把它带上。

一个目录,一个主题一个文件(rules/):前端的要求放一个文件,测试的放另一个。文件开头写两行,声明这个文件只管哪类文件:

markdown 复制代码
---
paths:
  - frontend/**/*.vue
---
(Vue 组件的要求......)

声明了管 .vue,这个文件平时不跟着开场发过去,真需要了才带上。

这两种写法,全局层和项目层各有一套;只有本地那份 CLAUDE.local.md,没有目录版。

为什么留两种写法?

要求涨到几十条,麻烦不在字数,在没法分头管:Vue 的要求和 Python 的要求写在一个文件里,没法只给其中几行标「只管 .vue」。拆开,一个主题一个文件,每个文件自己声明管什么。

团队协作上还有个好处:加要求就是加文件,前端认领一个、CI 认领一个,不用几十个人挤一个文件里改。

4 怎么读进来:找齐、写明出处、拼一份

会话开场,harness 把三处翻一遍,三步:

**找齐。**从你启动的目录一层层往上找到磁盘根,每层都认 CLAUDE.md------所以 monorepo 里仓库根一份、子项目一份,两层都生效;rules 目录里每个文件也都算上。

**写明出处。**每份内容的前面,先加一行说明:这份是哪个文件、进没进 git。真发出去长这样(虚构一份示例):

text 复制代码
Contents of ~/.claude/CLAUDE.md (user's private global instructions
for all projects):

回答一律用中文

Contents of ~/shop/CLAUDE.md (project instructions, checked into
the codebase):

- 本项目用 Bun 跑脚本,不要用 npm

Contents of ~/shop/CLAUDE.local.md (user's private project
instructions, not checked in):

- 本地测试库连 localhost:5432

**拼一份发过去。**按次序拼成一份,排在对话最前面;此后每一轮,这份原样跟着,压缩够不着。模型看到每份开头的这行说明,就知道每句要求管多宽。

这一份最外面还包着一句不容商量的话,原文:

text 复制代码
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.

翻译过来:这些要求高于一切默认行为,必须不折不扣执行。你在 CLAUDE.md 里写「不要用 npm」,它就压过系统提示词里关于包管理器的任何通用说法。

把这一路画成一张图:

5 CLAUDE.md 是不是写得越多越好?

压不掉、每轮都在------看着这么好用,那 CLAUDE.md 是不是写得越多越好?

不是。三个问题分开说:为什么不能贪多;那到底写什么;还有什么不该放在claude.md里。

为什么不能贪多?两个原因。

一是占地方。

对话满了,有四级流水线去压;这一份永远原样------你写进去的每一行,从会话第一轮占到最后一轮,谁也压不动。源码里因此写着一条警告线:单份文件四万字符(常量 MAX_MEMORY_CHARACTER_COUNT = 40000)。超了,界面当场亮警告(虚构示例):

text 复制代码
Large CLAUDE.md will impact performance (41,236 chars > 40,000)
· /memory to edit

四万字符折算成 token 一两万------20 万的窗口,一成上下的地方被 CLAUDE.md 常年占着。/doctor 也查这一项。

二是要求一多,会互相打架、互相稀释。

警告里说的 impact performance,除了占地方,这层也是原因:全局写「注释一律中文」,你再往里塞五十条,每条的分量都被摊薄;两条互相矛盾的要求一起发过去,模型听哪条,没有保证。

那到底写什么?

CLAUDE.md 就像给新同事写交接:代码他早会了,缺的只是这个仓库的情况------所以只写他不知道的。

不用写的,例如:

  • 语言标准惯例------模型早就会
  • 「写干净的代码」这类放之四海的话------对任何一个具体决策都不构成约束
  • 逐个文件的目录清单------它自己会读代码

该写的,例如:

  • 跑单个测试要带什么参数
  • 跟语言默认不一样的风格(「用 type,别用 interface」)
  • 仓库的分支和 PR 习惯
  • 不写就会踩的坑

/init命令的做法

/init 命令分三步:先派一个子代理把代码库探索一遍;再问你几个代码里看不出来的问题;最后才动笔。

子代理探索的都是实打实的东西:构建脚本、README、CI 配置,连你从前用 Cursor、Copilot 留下的规则文件,都翻出来迁进去。

动笔守一条硬标准,提示词原文:

text 复制代码
Every line must pass this test: "Would removing this cause Claude
to make mistakes?" If no, cut it.
每一行都要过这一关:删掉这行,Claude 会犯错吗?不会,就删。

还有什么不该放在claude.md里?

大块参考资料。真需要的话,两个办法:

导入:CLAUDE.md 里不整份粘贴 API 文档,只写一行 @docs/api-reference.md,开场拼接时自动带进来(最多套五层,路径写错悄悄跳过)。它省的不是地方------文件照样每轮重发;省的是本体不被撑大,内容永远读源头的最新版。

按需加载:这个才省地方。第 3 节那两条路------放子目录、rules 里写 paths------平时不带上,真需要那些文件了才带上。

6 会话过程中改了Claude.md,什么时候生效?

聊到一半去改 CLAUDE.md,模型手里还是开场那份旧的------不是不听话,是压根没看到。新修改要进会话,只有三个时机:

  • /clear------开新会话,从头再拼;
  • /memory------专门管这些文件,改完当场重读;
  • 压缩刚跑完------四级流水线把历史重写完,顺手把这份缓存也清了,要求从磁盘重新拼。

为什么不盯着文件,一改就重拼?

因为 prompt cache:每轮重发的内容,服务商可以缓存着、按折扣计费;缓存成立有个死条件------前缀一字不变。开场那一份排在每轮请求的最前面,它一动,后面所有内容的缓存全部作废。

说到底,缓存救的是钱,省钱很重要

7 对话会没,CLAUDE.md 常在

会话结束,历史清空,文件还在磁盘上,下个会话开场照拼不误。也正因为扔不掉、压不掉,这一份才是整个窗口里最金贵的地方------每一行都从第一轮占到最后一轮。所以claude.md要精炼,一个小技巧:删掉其中的一行,Claude 会犯错吗?不会,那就删

模型负责读懂要求、照着办;但从哪找、怎么送、怎么在一次次压缩里原样不动,全是 harness 的活。智能在模型,干活在 harness。

不过,这一份终究是你写给它的。它还有一份自己记的笔记------跨会话攒下来的长期记忆,下一篇拆它。


不信?聊到一半往 CLAUDE.md 里加一行「回答开头带一句『收到』」,直接让模型照做------它压根没看到;敲 /memory 再问,就有了。

连载 拆解 Claude Code:Agent Harness 工程实践 关注不迷路

相关推荐
AI编程实验室1 小时前
AI 编程隐私保护清单:API Key、代码上传、Agent 权限与 Git 历史排查
ai编程
Mason_Le1 小时前
OpenSpec迭代开发:基于历史档案的增量变更工作流
ai编程
樊小肆1 小时前
DeepSeeker-Code源码导读09-MCP集成
人工智能·agent
程序员柒叔1 小时前
luna 的内心独白:我把一个本该暂停的任务,跑成了几十轮空转
agent·ai编程·vibecoding
飞哥数智坊1 小时前
难道 AI 真要让程序员三班倒了?
人工智能·ai编程
leeyi1 小时前
Deep Agent 文件系统工具链:ls/read/write/edit/glob/grep/shell 七个工具怎么设计(第94篇-E80)
aigc·agent·ai编程
必须会一定会1 小时前
Agent Handoff M5 发布验收:`CHANGES.md`、`npm pack`、`release:check` 与干净环境安装验证
前端·人工智能·npm·node.js·ai编程
武子康2 小时前
我让 Qwen3.6-27B 真改了一次 Git 仓库:工具调用怎样形成 Agent 闭环
人工智能·后端·agent