内容来源:alexop.dev。https://alexop.dev/posts/stop-bloating-your-claude-md-progressive-disclosure-ai-coding-tools/
原题:Stop Bloating Your CLAUDE.md: Progressive Disclosure for AI Coding Tools
原发布时间:2026-01-18

AI 编程工具没有状态,每个会话都要重新开始。解决办法不是把一切都塞进 CLAUDE.md,而是构建分层上下文系统:让经验沉淀在文档里,由专业智能体按需加载。

兼容性说明(核对日期:2026-07-20):原文早于 Claude Code 当前的 Auto Memory 功能,因此,它所说的“每次会话都没有隐藏记忆”,如今指的是全新的对话上下文,而非不存在任何跨会话持久化。当前文档还说明,Claude 读取的是 CLAUDE.md,不是 AGENTS.md;如需共享指令,建议使用 @AGENTS.mdln -s AGENTS.md CLAUDE.md。下文保留原文措辞及小写的 agents.md 命令。使用 context: fork 的 Skills 仍受支持。

文章社交分享卡片

昨天,我花了一个小时和 Claude 一起排查 Nuxt Content 的一个坑。我们共同找到了答案:查询页面集合时必须使用 stem,而不是 slug。到了今天呢?Claude 又犯了同一个错误。昨天的会话已经消失了。

本文示例来自我的 Second Brain——一个使用 Nuxt 和 Nuxt Content 构建的个人 Wiki,通过卡片盒笔记法式 Wiki 链接管理知识。你可以在 GitHub 上查看真实的 CLAUDE.md 文件

这就是限制所在。你的上下文不过是一组 Token——一个滑动窗口,对话结束的那一刻就会忘掉所有内容。1

交互式上下文窗口可视化工具的静态截图

这些可视化图中显示的百分比只是示意,并非真实测量结果。系统提示词的实际开销会随工具版本和配置而变化。重点在于相对比例,而不是精确数值。

没有隐藏记忆,也没有保存过往对话的数据库。只有这组 Token,并且每次会话都会从头重建。

Dex Horthy 把这称为“上下文工程”:LLM 没有状态,因此,改进输出的唯一方法就是优化输入。2 你拥有的只有这组 Token;不在其中的任何内容,对模型来说都不存在。

然而,这个数组有容量上限。如果用噪声把它填满,就会进入 Dex 所说的“低智区”:无关上下文会争夺注意力,导致性能下降。

大多数开发者的应对方式,是把学到的每一条经验都写进 CLAUDE.md。我见过膨胀到 2,000 行的文件:样式指南、架构决策,以及某个花了三天才修好的 Bug 背后的血泪史,全都塞在里面。

这只会让情况变得更糟。

膨胀的 CLAUDE.md 会让问题恶化

Claude 一旦犯错,我们的本能反应就是加一条规则:“查询页面集合时绝不能使用 slug,要改用 stem。”

接着又犯一个错,再添一条规则。然后继续重复。

用不了多久,你的 CLAUDE.md 就会变成这样:

# CLAUDE.md

## 项目概述
……50 行……

## 代码风格
……200 行格式规则……

## 架构决策
……150 行历史背景……

## 易踩的坑
……300 行边界情况……

## 测试约定
……100 行……

工作还没开始,上下文预算就已经损失了一半。

交互式 Token 预算计量器的静态截图

HumanLayer 把自己的 CLAUDE.md 控制在 60 行以内。3 前沿 LLM 能够可靠遵循 150~200 条指令,而 Claude Code 的系统提示词本身就已经占用了约 50 条。3

怎么算都不够用。你不可能把一切都塞进一个文件。

别再用自然语言描述 Lint 规则

一行配置就能处理的事情,为什么要写两百行代码风格说明?凡是工具能够强制执行的内容,我都不再放入 CLAUDE.md。

不要用自然语言描述样式规则:

## 代码风格
- 使用两个空格缩进
- 优先使用单引号
- 始终添加末尾逗号
- 每行最多 100 个字符

交给 ESLint 处理:

{
  "extends": ["@nuxt/eslint-config"]
}

规则本来就在配置中,不必再用自然语言重复:

// @nuxt/eslint-config 中包含的内容:
{
  rules: {
    'indent': ['error', 2],
    'quotes': ['error', 'single'],
    'comma-dangle': ['error', 'always-multiline'],
    'max-len': ['error', { code: 100 }]
  }
}

AI 可以运行 pnpm lint:fix && pnpm typecheck,立即知道自己是否违反规则。无需解释,也不存在歧义。

如果工具能够强制执行,就不要再用自然语言描述。 样式交给 ESLint,类型交给 TypeScript,格式交给 Prettier。这些规则可以验证,而不必依靠理解。

Moss 把这称为反向压力(backpressure)——一种让智能体自我纠正的自动反馈机制。4 没有 Linter,你就要浪费时间输入“你忘了添加导入”或者“这里应该用 const,不是 let”。有了反向压力,智能体会运行构建、读取错误并自行修复。你可以摆脱琐碎纠错,把注意力集中到更高层的决策。

现在,我的 CLAUDE.md 只写了:

修改代码后,运行 `pnpm lint:fix && pnpm typecheck`。

用一行取代两百行。甚至连这一行都可以省掉——使用 Husky,在提交时自动运行检查。这对 Ralph 之类的技术尤其有用:AI 会自主处理任务队列中的工作。5

ESLint 抓不到的坑

ESLint 抓不到这个问题:

“Nuxt Content v3 会在 .data/ 中进行强缓存。修改 Hook 中的转换逻辑后,必须清除缓存才能测试变更。”

也抓不到这个:

也抓不到这个:

“指向数据集合的 Wiki 链接需要路径前缀。应使用 [[authors/john-doe]],而不是 [[john-doe]]。”

这些都是——那些并不明显、却会让你栽一次跟头的行为,就像新成员入职第一天时你会特意告诉他的事情。它们需要记录,但不应该放进 CLAUDE.md。

核心洞见是:CLAUDE.md 存放通用上下文,而这些坑只与特定场景有关。

你不需要在每次对话中都加载 Wiki 链接前缀规则;只有编写带作者链接的内容时才需要。每次都加载只会浪费 Token。

那么,这些坑该放在哪里?又该怎样在不中断工作流的情况下记录下来?

我的 /learn Skill

我的方法是:当我发现 Claude 正在为一个我们过去已经解决的问题苦苦挣扎时,就运行 /learn

这是我自己构建的一项 Claude Code Skill(查看完整提示词)。它会:

1、分析对话,找出可复用且不明显的洞见
2、在 /docs 中找到合适的保存位置(或者建议新建文件)
3、保存之前征求我的批准

最终,我会在 docs 目录里得到一个不断增长的知识库:

docs/
├── nuxt-content-gotchas.md    # 15 条来之不易的经验
├── nuxt-component-gotchas.md  # Vue 特有的坑
├── testing-strategy.md        # 何时使用哪类测试
└── SYSTEM_KNOWLEDGE_MAP.md    # 架构概览

CLAUDE.md 始终保持稳定。 它只告诉 Claude 去哪里查:

## 延伸阅读

**重要:** 开始任何任务之前,先判断下面哪些文档与任务相关,并首先阅读。进行修改前,加载完整上下文。

- `docs/nuxt-content-gotchas.md` - Nuxt Content v3 易踩的坑
- `docs/testing-strategy.md` - 测试层级及其适用时机

其中,重要这条指令至关重要——没有它,Claude 不会自动阅读这些文档。有了它,Claude 会在开始工作前识别相关文档:内容查询会触发易踩坑文档,测试任务会触发测试策略。这就是渐进式披露:在正确的时间加载正确的上下文。3

另一种方法,是构建能够自动加载特定领域易踩坑内容的 Skills。比如创建一项 nuxt-content Skill,只要处理内容查询,就自动注入易踩坑文档。理论上,这样更加整洁:你不必操心,上下文就会自动加载。但在实践中,我发现 Skills 并不总会按预期激活。触发条件可能很模糊,有时 Claude 就是不会调用。Vercel 的智能体评测也证实了这一点:在 56% 的测试用例中,Skills 从未被调用,相比基准线没有带来任何改进。6 基于文档的方案更可预测:我知道 Claude 一定会阅读我指向的内容。

每个领域配一个智能体

我还会用自定义智能体把这种方法更进一步。每个智能体都有自己的文档文件,只在需要时加载。如果你还不熟悉这些定制层如何协同工作,我写过一篇 CLAUDE.md、Skills 与子智能体的详细对比

.claude/agents/
├── nuxt-content-specialist.md   # 内容查询、MDC、搜索
├── nuxt-ui-specialist.md        # 组件样式、主题
├── vue-specialist.md            # 响应式机制、Composables
└── nuxt-specialist.md           # 路由、配置、部署

调试内容查询时,Claude 会加载 nuxt-content-specialist;设置组件样式时,它会加载 nuxt-ui-specialist。这些专业智能体知道应当从官方来源获取最新文档,而不是依赖过时的训练数据。

这就是我不使用 Context7 之类的 MCP 查阅文档的原因。智能体可以直接从官方文档网站获取 llms.txt,并找到自己需要的内容。没有工具定义膨胀,也没有中间过程占用 Token——只是在自己的上下文窗口中完成一项聚焦的调研任务。我还详细写过为什么我使用自定义调研智能体,而不是 MCP

Skills 的工作方式与之类似:设置 context:fork 后,它们会在隔离上下文中运行,不会污染主对话。智能体既有能力,也有动力阅读真实文档。无需 Context7,也没有 MCP 开销。

交互式渐进式披露探索工具的静态截图

复利效应

这套系统会形成一个反馈循环:

交互式反馈循环动画的静态截图

随着时间推移,我的 /docs 目录会成为一个经过整理的知识库,里面保存的恰恰是 AI 编程工具在我的代码库中容易出错的内容。这就像微调,只不过一切都在我的掌控之下。

这个思路来自一种自我改进 Skills 模式:由智能体自动分析会话并更新自身。7 我对它做了调整,改用 Markdown 文档和 /learn 命令,从而明确控制要记录哪些内容,以及保存到哪里。

下面是我的 nuxt-content-gotchas.md 中一条真实记录:

## 页面集合查询:使用 `stem`,不要使用 `slug`

页面类型集合中不存在 `slug` 字段。
请改用 `stem`(不含扩展名的文件路径):

// ❌ 失败:"no such column: slug"
queryCollection('content').select('slug', 'title').all()

// ✅ 有效
queryCollection('content').select('stem', 'title').all()

Claude 在我的项目中永远不会再犯这个错误。不是因为我把它写进了 CLAUDE.md,而是因为 Claude 处理内容查询时,会先阅读易踩坑文档。

我的 50 行 CLAUDE.md

它的结构如下:

# CLAUDE.md

Second Brain 是一个个人知识库,使用
卡片盒笔记法式 Wiki 链接。

## 命令
pnpm dev          # 启动开发服务器
pnpm lint:fix     # 自动修复 Lint 问题
pnpm typecheck    # 验证类型安全

修改代码后,运行 `pnpm lint:fix && pnpm typecheck`。

## 技术栈
- Nuxt 4、@nuxt/content v3、@nuxt/ui v3

## 目录结构
- `app/` - Vue 应用程序
- `content/` - Markdown 文件
- `content.config.ts` - 集合 Schema

## 延伸阅读

**重要:** 开始任何任务之前,先阅读下列相关文档。

- `docs/nuxt-content-gotchas.md`
- `docs/testing-strategy.md`
- `docs/SYSTEM_KNOWLEDGE_MAP.md`

就这些,只保留通用上下文。其余内容全部放在文档、智能体或工具中。

跨工具兼容

如果同时使用多种 AI 编程工具,不需要分别准备配置文件。VS Code Copilot 和 Cursor 都支持用 agents.md 存放项目级指令。你可以用符号链接共享同一份配置:

# 创建符号链接,让所有工具读取同一个文件
ln -s CLAUDE.md agents.md

这样一来,这套精简、聚焦的指令就可以同时用于 Claude Code、Copilot 和 Cursor。只有一个信息源,不会在工具之间发生漂移。

上周的真实效果

上周,我在实现语义搜索。Claude 开始处理内容查询时,先按 CLAUDE.md 的指示阅读了 nuxt-content-gotchas.md,其中已经记录了 stem/slug 这个坑。

没有出错,也无需纠正。

不过,在那次会话中,我们又有了新发现:queryCollectionSearchSections 返回的 ID 已经带有前导斜杠。构造 URL 时不要再添加一条斜杠。

我运行了 /learn,Claude 建议添加:

## 搜索区段 ID

返回的 ID 带有前导斜杠(`/slug#section`)。
构造 URL 时不要再添加一条斜杠。

添加完成。下次处理搜索时,Claude 就会知道。


AI 工具没有状态,并不是一个需要对抗的 Bug,而是一项设计约束——就像有限的屏幕空间或缓慢的网络连接。接受这一点,就能构建顺应这种约束的系统。

让 CLAUDE.md 保持精简;把能够强制执行的内容交给工具;边工作边沉淀经验;按需加载上下文。

还有一点需要注意:你永远无法百分之百确定,智能体遇到问题时一定会阅读文档。对于 Nuxt Content 这类棘手领域——相关训练数据稀少或已经过时——我学会了在提示词中明确说明。如果知道当前工作属于训练覆盖较差的领域,我会在计划中加入:“如果遇到 Nuxt Content API 问题,先阅读 docs/nuxt-content-gotchas.md。”这句提醒会产生关键差异:智能体究竟是根据过时模式猜答案,还是认真查阅当前知识。

AI 会忘记,你的文档不会。


脚注

1、LLM 不会在不同会话之间保留记忆——上下文只是滑动窗口中的 Token。参见 Factory 的分析文章 The Context Window Problem
2、Dex Horthy,No Vibes Allowed: Solving Hard Problems in Complex Codebases。Dex 是 HumanLayer 的创始人,也是自主 AI 编程方法 Ralph 的创造者。他的 12 Factor Agents 宣言把“让智能体成为无状态归约器”列为第十二项原则。
3、HumanLayer 的 Writing a Good CLAUDE.md 指南建议将文件控制在 60 行以内,并通过渐进式披露提供详细指令。 ↩2 ↩3
4、Moss,Don’t Waste Your Back Pressure。反向压力——来自类型系统、Linter 和构建工具的自动反馈——让智能体能够处理时间跨度更长的任务,而无需人类持续干预。
5、Geoffrey Huntley,Ralph。Ralph 是一种自主 AI 编程技术:任务进入队列后,无需人类干预即可执行,因此,在提交时自动检查至关重要。
6、Jude Gao,AGENTS.md outperforms skills in our agent evals。Vercel 的评测发现,把经过压缩的文档索引直接嵌入 AGENTS.md 可以达到 100% 通过率;即使有明确指令,Skills 最高也只有 79%,而让它们自然触发时,表现并不优于基准线。
7、Developers Digest,Self-Improving Skills in Claude Code。一种自动沉淀经验的模式:由 Skills 分析会话、提取修正内容,再更新自身。