ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

CLAUDE.md拆分实战:用规则地图解决上下文膨胀

CLAUDE.md拆分实战:用规则地图解决上下文膨胀 坦白说我的项目根目录下那份 CLAUDE.md 之前已经到了 1300 行。上周要重构认证模块Claude 明明读到了规则行为却没按最早定的那条数据库变更必须写迁移文件来执行连加粗强调三次都没救回来。这不是第一次了。CLAUDE.md 越长模型越容易把规则当背景噪音。最近我趁着项目迭代把所有规则重新按目录拆了一遍总算把根目录收敛到 200 行左右。这篇就聊聊我在拆分里沉淀下来的判断标准、迁移步骤和坑想给同样被 CLAUDE.md 折磨的朋友一点可参考的思路。我在处理这类问题时最大的体会是规则文件不是不能长而是不能始终加载。Claude Code 本身有按路径加载子目录 CLAUDE.md 的机制很多人没用起来所以只能把所有内容都塞进根目录最后把上下文拖垮。下面按我实际操作的顺序来写。1. CLAUDE.md 膨胀问题出在始终加载上1.1 多层 CLAUDE.md 机制天然就是为拆分准备的Claude Code 的 CLAUDE.md 有多个层级用户目录下的全局文件、项目根目录的文件、各个子目录下的文件。运行时模型会根据当前处理的文件路径决定加载哪些内容。具体说如果模型正在看src/auth/login.go它会同时加载全局配置、项目根目录 CLAUDE.md以及src/auth/下存在的 CLAUDE.md但它不会加载src/payment/CLAUDE.md这种无关目录的规则。换句话说子目录规则是用到才加载根目录规则是每次都会加载。这个机制解决的就是我的痛点规则系统像一个路由表匹配范围越大被无关任务触发的概率就越高把规则下沉到子目录等于把匹配范围收窄到专属目录。这跟规则引擎里的作用域、表单校验里的分组校验是一个逻辑——先定位范围再执行规则。可惜我最初没理解这点。当时觉得项目根目录放一份文件最省事所有规则都往里写最后成了一个大杂烩。1.2 规则全堆在根目录会出现三个典型症状第一个症状是上下文预算被浪费。每次对话都要固定加载全部规则包括那些只跟某个老模块有关的约定。比如我项目里有一条assets 图标必须放 public/icons的规定写代码时几乎每周触发一次但处理后端事务时这条规则完全无关白白占据 token。第二个症状是主旨规则被稀释。规则越多真正刚性的要求就越容易被淹没。这和在表单校验里写了几十条字段规则后必填项这种最基础的校验反而会被忽略是一个道理。CLAUDE.md 的顶部往往是最显眼的区域一旦被一堆低频规则占据模型对中后部指令的重视频率明显下降。第三个症状是维护变得畏首畏尾。上千行的文件删掉任何一行都担心万一之后要用呢于是所有旧规则都躺着不动。新规则不断追加最后没人敢重构这个文件。1.3 我的实测拐点大概在 500 到 800 行之间我没做过严格对照实验但几十个会话实测下来根目录 CLAUDE.md 超过 500 行后模型对后部规则的执行率就开始下滑超过 800 行后即使我在任务描述里特意强调模型也可能忽略某些历史规则。超过 1500 行后规则之间开始互相干扰出现明明写了 A 规则行为却是 B 规则的情况。这不是模型能力问题是上下文聚焦的自然现象。关键结论很简单根目录 CLAUDE.md 尽量控制在一屏能看明白的体量具体操作细节交给子目录。2. 哪些规则该进子目录三条判断标准2.1 范围、频率、粒度三条标准缺一不可判断一条规则该放根目录还是子目录我一般问自己三个问题第一个问题作用范围是不是限定在某个目录或模块是就放子目录是对所有任务都生效的留在根目录。比如src/db 下禁止裸 SQL这种规则只跟数据库模块有关放子目录最合适。第二个问题使用频率是不是每次都高每次都要遵守的规则比如提交前必须跑测试禁止提交 .env 文件这些应该留在根目录因为它们对任意任务都成立反过来发布前需要检查 CHANGELOG这种低频流程就不应该天天加载。第三个问题内容粒度是不是很重如果规则包含大量示例代码、模板、目录结构说明哪怕它全局通用也不该全堆进根目录。根目录只留一句话摘要把模板放到独立文档或子目录让模型按需读取。我把判断逻辑整理成了一张表实际操作时对着看很快判断维度适合留在根目录适合下沉子目录作用范围全局通用、跨模块仅特定目录、服务、模块使用频率每次会话都要遵守特定任务才触发内容粒度简短约束、一句话规则长示例、模板、步骤流程冲突可能性不允许被局部覆盖的红线允许在局部调整的偏好2.2 根目录只留骨架它的核心职责是导航拆分后根目录 CLAUDE.md 的定位变了它不再是唯一规则库而是整个项目的规则入口。我会放这几类内容项目一句话说明和技术栈清单帮模型快速建立背景认知通用命令包括如何安装依赖、如何跑测试、如何 lint统一的提交规范、分支命名、代码评审要求安全红线比如禁止提交密钥、禁止改动迁移文件、禁止绕过审核流程一条规则地图告诉模型更细的规则分别放在哪些子目录遇到什么任务去读哪个文件。最后这条特别重要。它相当于路由系统的索引让模型知道该主动加载什么而不是靠运气瞎猜。否则你拆了子目录模型不知道有这些文件照样按旧习惯处理。2.3 子目录适合装细节越贴近具体代码越好子目录 CLAUDE.md 适合装那些只对特定代码生效的规则。举几个我项目的实际例子src/api/CLAUDE.md里写接口设计约定RESTful 路径风格、错误码格式、分页参数命名src/db/CLAUDE.md里写数据访问约束所有查询必须走 repository 层、禁止批量更新、索引变更要附带评估说明docs/CLAUDE.md里写文档维护约定新增文档必须补目录索引、示例代码要和实际版本号一致scripts/CLAUDE.md里写脚本规范禁止在 shell 脚本里硬编码绝对路径、输出必须带前缀。这类规则有个共同点它们只在处理对应目录时才真正有意义。如果模型在写 API 层代码src/db那套约束就不该被加载进来否则就是纯粹的上下文噪音。2.4 特殊情形全局通用但低频的规则用条件触发处理最难归类的规则是那些全局通用但一个月只触发一两次的流程。比如发布上线流程、批量数据迁移脚本、安全审计检查。它们不是模块专属但塞进根目录会让日常会话变臃肿。我的做法是把完整流程放到独立文档或专有子目录然后在根目录 CLAUDE.md 里留一行触发条件。例如写当任务涉及发布时先阅读 docs/release-check.md 再执行。这相当于给规则加了一个懒加载开关。模型平时不需要加载这堆信息等真正碰到发布任务时它会根据根目录的指令主动去读那份文档。这种条件触发写法在规则系统里很常见和路由规则的懒匹配思路一致关键是触发条件要写得足够明确别让模型猜。3. 实操子目录 CLAUDE.md 怎么建、怎么写、怎么迁移3.1 先设计目录结构再迁移规则拆分前不要直接动手删文件先画出目标结构。下面是我现在用的结构模板可以直接抄repo/ ├── CLAUDE.md # 全局骨架项目概述、通用命令、安全红线、规则地图 ├── src/ │ ├── CLAUDE.md # 后端通用约定代码风格、测试要求、依赖管理 │ ├── auth/ │ │ ├── CLAUDE.md # 认证模块专属JWT 规则、会话过期处理、权限判断 │ │ └── ... │ └── db/ │ ├── CLAUDE.md # 数据库专属SQL 约束、迁移要求、索引规范 │ └── ... ├── docs/ │ ├── CLAUDE.md # 文档维护规则、更新流程 │ └── templates/ │ └── CLAUDE.md # 模板文件相关的边界条件 └── scripts/ ├── CLAUDE.md # 脚本约定、执行环境要求 └── ...这样的结构本质是让每份 CLAUDE.md 只对自己目录负责互不干扰。模型在处理src/auth下的文件时最多加载三层全局、项目根、auth 子目录而不会带上 db、docs、scripts 那些规则。3.2 迁移分成五步不能一步到位第一次迁移我吃过亏一口气把所有规则打散到十个文件结果跑任务时模型根本找不到规则。后来固定成五步走第一步盘点现有规则。把根目录 CLAUDE.md 里所有规则一条条抄进表格列清楚规则内容、作用范围、触发频率、是否包含长示例。这一步是基础不盘点清楚后面的分类都是拍脑袋。第二步分类入桶。分成三桶必须留根目录的、必须下沉到某个子目录的、需要拆出来做独立文档的。分类时严格套用第二章那三条标准拿不准就先放根目录宁少勿滥。第三步建立子目录 CLAUDE.md。把对应规则搬进去同时精简语言。我一般会把规则压缩成短句指令动词的格式例如所有查询必须走 repository 层而不是考虑到代码结构清晰和职责分离建议尝试使用 repository 模式来封装数据访问逻辑。规则文件不是论文不需要解释太多理由。第四步在根目录写导航。每个子目录新增一条摘要让模型知道哪类任务去读哪个文件。比如涉及认证或会话时阅读 src/auth/CLAUDE.md。这一步经常被忽略但没这一步子目录规则就像图书馆里没编目的书没人找得到。第五步开新会话验证。CLAUDE.md 通常在会话启动时加载所以改完文件后一定要新开会话验证别在旧会话里继续测试。我会构造一个典型任务比如给 auth 模块增加一个刷新令牌接口然后看模型有没有实际遵守子目录规则。3.3 嵌套优先级与冲突仲裁写清楚比赌模型聪明靠谱子目录规则和根目录规则冲突时模型怎么选我的习惯是在子目录 CLAUDE.md 头部显式写一句声明本文件是该目录下的最高优先级规则若与根目录 CLAUDE.md 冲突以本文件为准但提交信息里需要注明本次偏离。这比赌模型自行判断要可靠得多。规则系统里最怕的就是优先级模糊CLAUDE.md 也一样。冲突仲裁不能靠模型临场发挥你要给它一个简单的裁决原则。如果存在子目录里再套子目录的情况还可以加一句本规则仅适用本层目录不向下传递防止某个深层目录被祖先规则意外约束。这种局部覆盖全局、底层覆盖顶层的设计和表单校验里的分组覆盖规则以及路由系统的优先级策略是一回事。3.4 写规则时的格式建议短句、一事一条、留更新记录经过多次重建我现在写子目录 CLAUDE.md 会遵循几个格式习惯每条规则都限定适用路径比如本规则仅适用于 src/api 目录;用祈使句少用可能应该尽量这类模糊词一条规则只讲一件事不要在一个条目里塞三个要求文件顶部写明更新日期和改动原因方便三个月后回看需要长示例时单独开一个示例片段不要混进规则正文。格式清晰直接影响模型的执行率。规则文件不该追求文学性它更像一份配置清单清晰、简短、无歧义才是核心。提示如果规则里出现可能或许看情况这类词大概率后面会失效。要把它们改成明确的触发条件和动作模型才不会犹豫。4. 案例拆解一个 1000 行的 CLAUDE.md 怎么瘦身4.1 瘦身前所有规则混在一个大文件里我用实际项目的结构来说话。瘦身前根目录 CLAUDE.md 大概有上千行内容大致是这样分布的项目概述和技术栈约 50 行通用命令约 80 行后端编码规范约 200 行前端命名规范约 150 行数据库操作注意事项约 300 行部署和发布流程约 120 行各种历史遗留的临时规则约 200 行。每次处理 API 任务时前端命名规范、数据库注意事项、部署流程全都跟着加载。有一次我让模型帮我改前端组件它居然把数据库索引规则也读进来了浪费了大量上下文不算还差点因为那条禁止裸 SQL误解了前端请求代码。这类高耦合低相关的加载就是规则全堆根目录的必然结果。4.2 瘦身后根目录只留骨架细节全部下沉拆分后的目标结构如下根目录 CLAUDE.md 保留约 200 行内容是项目概述、通用命令、编码红线比如统一用 error 包装、禁止 console.log 提交、以及规则地图src/api/CLAUDE.md放接口约定约 80 行src/db/CLAUDE.md放数据库规范约 120 行src/frontend/CLAUDE.md放组件和样式规范约 100 行docs/CLAUDE.md放文档规范约 60 行scripts/CLAUDE.md放脚本和发布相关流程约 90 行。根目录里的规则地图长这样- 涉及 API 接口设计阅读 src/api/CLAUDE.md - 涉及数据库查询或迁移阅读 src/db/CLAUDE.md - 涉及前端组件和样式阅读 src/frontend/CLAUDE.md - 涉及文档更新阅读 docs/CLAUDE.md - 涉及发布或批量脚本阅读 scripts/CLAUDE.md有了这张地图模型在遇到具体任务时会主动去读对应文件而不是把所有细节都提前加载到上下文里。4.3 效果对比token 成本大约省一半以上做一个粗算就能看出差距。按中文场景粗略估计一行规则大约对应 20 到 40 个 token。假设原文件 1000 行平均每行 30 token那就是 3 万 token 起步。每次会话固定加载这 3 万 token不管有没有用。拆分后根目录 200 行约 6000 token某个子目录 100 到 150 行约 3000 到 4500 token加起来日常会话差不多只加载 1 万 token 左右。相比原来省了一半以上而且模型只需要聚焦真正相关的规则执行准确率也会更高。不同项目差异很大但趋势是一致的拆完后的加载量远小于全量堆积。4.4 一个可以直接抄的小技巧规则地图就是规则系统的索引规则地图是我这次拆分里收获最大的一个小设计。它和数据库索引一个思路不提前把所有数据加载进来而是先看索引确定要读取哪一部分再去取数据。写规则地图有个细节触发词要具体别写涉及后端时阅读 src/api/CLAUDE.md这种模糊表述而是写涉及接口、路由、状态码、参数校验时阅读 src/api/CLAUDE.md。触发词越具体模型越容易命中正确文件。5. 拆完之后的问题规则不生效、冲突、加载过多怎么排查5.1 规则不生效先从这三方面排查拆完子目录后最容易遇到的问题就是规则不生效。我的排查顺序是固定的先查文件路径和命名。CLAUDE.md 必须精确叫这个名字位置必须放在对应目录根部放错一层都可能不被加载。还要检查大小写很多系统是区分大小写的claude.md和CLAUDE.md不是同一个文件。再查该规则是否真的适用于当前目录。子目录规则只在该子目录被访问时生效如果模型在处理根目录下某个通用文件它不会加载任何子目录规则。遇到这种情况要么把规则提到根目录要么在规则地图里显式说明处理这类任务时主动读取 xxx 文件。最后直接问模型。开一个带上下文的会话问一句你现在读取了哪些 CLAUDE.md关于某个目录的规则是哪条它会告诉你实际加载了哪些文件。这个办法最直接比反复猜测快得多。还有一点改完 CLAUDE.md 后一定新开会话。模型不会在旧会话中途自动重读文件旧会话里测不出新规则。5.2 规则重复和冲突需要一份规则裁决表多个子目录出现重复规则很常见比如src/api/CLAUDE.md和src/db/CLAUDE.md里都写了错误信息不能直接暴露给用户这类安全规则。重复本身问题不大但两份规则表述不一致时模型就不知道该听谁的。我的做法是建一份规则裁决表统一维护所有涉及相同诉求但表述不同的规则。表头是规则主题、根目录写法、子目录写法、最终生效版本、判定原因。一旦发现冲突以最深目录且最新更新的一份为准并把其他位置改成引述式写法比如安全相关规则见 src/api/CLAUDE.md 第 2 节。注意不要用 grep 找到重复就盲目删除。先确认重复的两份规则是否面向同一个任务有些重复是刻意为之比如根目录红线是禁止提交密钥子目录可能细化成禁止把 token 写进日志两者是层级关系不是冗余。5.3 跨目录任务导致加载过多又变回了大文件拆分后还有一个副作用一个任务如果横跨多个子目录模型可能会把所有相关子目录的 CLAUDE.md 都读一遍加载量又涨上去了。比如给认证模块加一个刷新令牌接口同时涉及src/auth、src/api、src/db模型一上来全读token 又爆了。我的应对办法有两个。一个是在规则地图里给每个子目录设置触发条件让模型先读最相关的不够再读其他不要一次全加载。另一个是把跨目录通用的规则上浮到根目录避免同一个认知分散在多个文件里。比如全局都适用的错误处理风格直接放根目录不需要每个子目录重复写。5.4 历史遗留规则怎么清理三个月没触发的基本可以归档拆完文件后那些已经失效的历史规则仍然躺在子目录里。我的判断方法是用 git log 或 git blame 看每条规则的更新时间如果三个月内没有相关任务触发过它也没有对应的 issue 或 commit 关联就先移到归档文档区而不是直接删除。直接删除的风险在于你可能遗漏某个低频流程。归档后如果两个月内依然没人提及再彻底删除也不迟。实际清理下来我项目里至少三分之一的历史规则属于当初为了某个一次性任务顺手加的归档后整个文件清爽不少。5.5 编辑 CLAUDE.md 的规范每次改动都留痕最后一个小习惯每次给 CLAUDE.md 增删规则都在 git commit message 里说明改了什么、为什么改。比如docs/CLAUDE.md增加文档索引强制要求原因是上周发布时发现目录缺失。这样以后回看文件历史时能理解每条规则是怎么来的、还剩多少价值。CLAUDE.md 本身就是一个需要持续维护的工程文件不是一次写完就拉倒的备注。6. 把 CLAUDE.md 当成规则系统来设计6.1 规则分层的思想可以迁移到任何规则场景拆完 CLAUDE.md 后我才意识到这套思路其实到处都是。路由规则讲匹配范围表单校验讲分组校验订阅规则讲优先级和兜底规则引擎讲条件触发。它们的核心就三件事匹配范围、优先级、降级策略。CLAUDE.md 的组织也一样。根目录是兜底规则对所有任务生效子目录是局部规则只对特定路径生效会话里临时给的偏好是最顶层规则针对本次任务生效。这三层形成清晰的梯度模型在具体任务里就知道该以哪层为准。6.2 简单规则也能涌现复杂行为不靠堆量有个挺有名的鸟群模型里面每只鸟只遵循三条简单规则靠近同伴、对齐方向、避免碰撞就能模拟出壮观的群体舞蹈。CLAUDE.md 其实同理——真正有效的往往是最顶上那几条核心准则而不是一千条细枝末节的指令。我最后把根目录的规则收敛到几个核心原则安全红线永远第一有全局约定先在全局找冲突时局部优先但必须说明。剩下的细节全部交给子目录按需加载。结果是模型表现稳定维护成本也降下来了。6.3 给每次新增规则做一个入口体检踩过几次坑之后我总结出一个新增规则的体检清单。每次想往 CLAUDE.md 里加一条规则前先过四关第一这条规则会不会每月至少触发一次不会的话别放根目录。第二它是否只服务于某个目录或模块是直接去对应子目录写。第三仓库里有没有已经相似的规则有去合并而不是新增。第四能不能用一段简短原则替代三条细则能就用原则说话把细则留给文档。过了这四关的规则才值得写进文件。如果过不了大概率又是躺着吃灰的历史规则。项目到目前为止根目录的 CLAUDE.md 一直稳定在 200 行上下各子目录按需加载。我最大的体会是规则文件的管理其实和代码重构一样关键在于让每条规则出现在它该出现的位置而不是把责任全压在模型的理解能力上。每次想新增规则时先搜一遍已有的再去判断该放哪个目录长期下来这个习惯能省掉大量维护成本。
返回列表