AI 编程与智能体

[AI 上下文 #4] CLAUDE.md 为什么应该简短:AI 代理始终加载上下文的设计方法

第 3 篇介绍了如何使用 /clear 清除对话历史。但在 /clear 后立即查看剩余上下文,会发现它并不是 100%。在 Claude Code 中执行 /context,原因就很清楚了:系统提示、工具定义、CLAUDE.md,以及 MCP 服务器注册的工具,早已占用数万个令牌…

5 分钟阅读
[AI 上下文 #4] CLAUDE.md 为什么应该简短:AI 代理始终加载上下文的设计方法 封面图

第 3 篇介绍了如何使用 /clear 清除对话历史。但在 /clear 后立即查看剩余上下文,会发现它并不是 100%。在 Claude Code 中执行 /context,原因就很清楚了。系统提示、工具定义、CLAUDE.md,以及 MCP 服务器注册的工具,早已占用数万个令牌。甚至在对话开始之前。

本篇讨论“始终加载的上下文”。如果对话历史是可变成本,那么这一部分就是固定成本。它在每轮都会被完整带上,使用 /clear 也不会消失,并在整个会话期间占用模型的一部分注意力。固定成本设计不佳,就意味着每个会话从一开始就处于劣势,因此它应该优先于对话管理进行改进。

会话开始前就已经加载的内容

代理的上下文窗口并不是从一张白纸开始的。第一条用户输入到达之前,里面就已经铺好了几层内容。

最底层是系统提示。代理运行框架(例如 Claude Code)注入基本指令,其中包含工具使用规则、响应格式等内容,规模达到数千个令牌。这是用户无法修改的区域。

其上是工具定义。模型要使用工具,就必须知道每个工具的名称、说明和参数模式,而这些内容都会以文本形式进入上下文。只有基本工具时负担不大,但连接 MCP 服务器后情况就不同了。一个服务器注册几十个工具很常见,连接几个服务器后,光工具定义就会消耗数万个令牌。从未使用的工具也会在每轮中来回传输。

最后一层是 CLAUDE.md 之类的项目指令文件。全局设置、项目设置和子目录设置都会自动加载,而这一层是用户唯一可以直接设计的层。

CLAUDE.md 的原则:只简短保留始终成立的内容

决定 CLAUDE.md 中该放什么,只有一个标准:“这项内容是否对该项目的所有任务始终成立?”这个文件会随每轮和每项任务一起加载,因此只在部分任务中适用的内容不值得占用空间。

构建和测试命令、代码库的整体结构,以及少数不可违反的规则,符合要求。相反,某个功能的详细规格、完整的库使用说明、过去工作的记录,都只在特定任务中需要,因此不应放进去。

长度存在一个悖论。看起来指令写得越多,越容易被遵守,但实际往往接近相反。正如第 2 篇所见,上下文变长后,分配给单个条目的注意力会变少;在数百行的指令文件中,真正重要的规则会被埋在 lost in the middle 中。写 50 条规则,50 条都会被模糊地遵守;写 10 条,则更接近清晰地遵守这 10 条。如果代理总是违反 CLAUDE.md 的规则,那么在增加规则之前,先缩短文件可能才是正确的顺序。

在始终加载的三层中,只有 CLAUDE.md 可以直接设计
在始终加载的三层中,只有 CLAUDE.md 可以直接设计

不要全部加载,只加载指针

那么,未通过筛选的信息,也就是偶尔需要的详细文档,应该放在哪里?答案是:“放在上下文之外,只告知位置。”

不要把完整的数据库迁移流程放进 CLAUDE.md,而只写一行:“迁移流程请参考 docs/migration.md”。代理只有在执行迁移任务时才会读取该文件。详细内容只会进入需要它的会话上下文;无关会话只需承担一行指针的成本。

Claude Code 的 skill 将同一原则系统化。skill 是特定任务的流程文档,平时只有名称和一行说明进入上下文,任务开始时才加载正文。与其把“部署流程”常驻在 CLAUDE.md 中,不如将它做成 skill,这样在不进行部署的 99% 会话轮次中都能节省这些令牌。

工具本身也需要整理。如果连接了不用的 MCP 服务器,只要关闭它,就能消除数万个令牌的固定成本。现在越来越多的运行框架支持延迟加载:平时只保留工具名称,需要时才加载完整模式。方向是一致的:不要始终加载所有内容,而是在需要时加载需要的内容。

墙上只放几条始终成立的规则;详细手册放在架子上,需要时再取出
墙上只放几条始终成立的规则;详细手册放在架子上,需要时再取出

固定成本检查流程

始终加载的上下文一旦膨胀,就很难察觉。因为每个会话产生的成本都一样,没有可比较的对象。因此,偶尔有意识地检查很有价值。

在 Claude Code 中,可以通过 /context 分解查看当前上下文在何处、使用了多少内容。它会显示系统提示、工具、MCP 和记忆文件各自占用的令牌数;如果工具定义异常地比对话还大,就先整理 MCP 服务器。每季度打开一次 CLAUDE.md,并以“上个月这一行真的帮上忙了吗?”为标准删除内容。指令文件放任不管只会不断增长,因此必须把修剪变成例行工作,才能保持简短。

总结

  • 系统提示、工具定义和 CLAUDE.md 是每轮都会加载的固定成本。它们不会因 /clear 消失,因此必须在对话管理之前完成设计。
  • CLAUDE.md 的标准是“是否对所有任务始终成立?”文件越长,单条规则就越模糊;如果规则没有被遵守,应先缩短文件。
  • 用指针代替完整的详细文档,将重复流程拆分为 skill,并关闭不用的 MCP 服务器。原则是只在需要时加载需要的内容。

做到这里,一个会话的上下文就会相当干净。但即使再怎么节省,也总会遇到某个大型任务无法放进一个会话的时刻。下一篇将介绍此时使用的结构化解决方案:子代理。我们会看看让另一个上下文负责探索、只返回结论的隔离模式,如何保护上下文。

延伸阅读