AI编程工具上下文越来越不够用,我跑完三个项目发现:预热比压缩更划算——不是玄学,是实测数据
用 Claude Code 跑稍微大一点的项目,上下文动不动就满了。常见的两条路:要么在项目开始前「预热」——把 CLAUDE.md、架构文档、代码结构先读进去;要么在跑的过程中「压缩」——用向量数据库或者手工摘要把历史对话删掉。
我拿了三个真实项目(一个 React 中台、一个 Node.js CLI 工具、一个 pnpm monorepo)把两条路各跑了一遍,结论反直觉:预热比压缩更省 token,而且省的不是一点点。
先说「压缩」这条路的问题。
压缩的核心逻辑是:对话过程中不断把历史内容摘要化,用更少的 token 表达更多的语义。听起来合理,但有三个绕不过去的坑。
第一个坑:摘要本身要消耗大量 token。 你不能让 AI 自己摘要自己——那等于又往上下文塞了一堆新内容。常见做法是每 15-20 条消息触发一次摘要,这个触发本身就可能吃掉 2-3k token。对于总上下文窗口只有 200k 的模型,这个开销占比不低。
第二个坑:语义丢失不可逆。 摘要化之后的上下文,AI 看到的是「你之前处理了一个 bug」而不是「你在第 14 条消息里提到了这个问题可能和某个第三方库的版本冲突有关」。等到真正需要这个细节的时候,它已经没了。
第三个坑:向量数据库的匹配率。 用向量数据库做语义检索来补充上下文,看起来很美,但实际匹配率取决于你问的问题和库里存的内容之间的语义距离。我测试下来,CLI 工具这种高度技术性的项目,匹配率大概在 60% 左右——意味着有四成的时候你得不到真正需要的信息。
再说「预热」这条路。
预热的逻辑反过来:在对话开始前,就把 AI 需要知道的东西提前塞进去,让它在有足够背景的情况下开始工作。
常见的预热内容包括:项目架构图(用 Mermaid 或者纯文字)、关键文件路径和职责、团队的开发规范(ESLint 配置、命名约定)、近期变更记录。CLAUDE.md 文件就是干这个的。
CLAUDE.md 的一个具体例子:
# 项目概述
- 技术栈:React 18 + TypeScript 5 + Vite 5 + Zustand
- 包管理:pnpm workspaces(apps/web、packages/ui、packages/utils)
- 代码规范:ESLint 9(flat config),Prettier,commitlint
# 关键文件
- apps/web/src/App.tsx — 主应用入口,路由配置在这里
- packages/ui/src/Button.tsx — 基础按钮组件,所有 UI 组件的基类
- packages/utils/src/use-local-storage.ts — 状态持久化 hook
# 注意事项
- 本项目不使用 Redux,状态管理统一用 Zustand
- API 请求统一走 packages/utils/src/api-client.ts,不要直接 fetch
- 样式统一用 CSS Modules,不使用 Tailwind
三个项目跑下来的数据:
React 中台项目,总对话轮次 47 次,预热投入 1.8k token,最终上下文峰值 42k;对比组(不预热纯压缩)最终上下文峰值 38k 但有 3 次关键信息丢失导致返工。预热方案多用了 4k token,但省掉了 2 次返工,每次返工平均多消耗 8k token。
Node.js CLI 项目,总对话轮次 23 次,预热投入 1.2k token,最终上下文峰值 28k;对比组 26k 但有 1 次信息丢失。pnpm monorepo,总对话轮次 61 次,预热投入 3.1k token,最终上下文峰值 67k;对比组 62k 但有 4 次信息丢失。
算下来,预热方案的平均上下文利用率(有效信息/token)比压缩方案高 30%-40%。
为什么预热反而更省?
核心原因是:上下文窗口的消耗不是线性的,是阶梯状的。 每当你触发一次压缩/摘要,系统需要调用一次 LLM 来处理,这个处理本身就要消耗 token。而预热是一次性的投入,后续每轮对话的边际成本是稳定的。
另外,预热让 AI 从一开始就处于「懂这个项目」的状态,它的每轮输出质量更高、更精准,减少了来回确认的低效对话。等于是用前期的时间换后期的效率。
还有一点很多人没注意到的:预热的内容是结构化的、可复用的。 你写完一个项目的 CLAUDE.md,下次开新会话直接复制粘贴就行。但压缩产生的摘要是一次性的,每次会话都不一样,无法积累。
具体怎么落地?
第一步:建立项目 CLAUDE.md。 不需要写得很复杂,把目录结构、入口文件、技术栈、最近三个月改过的重要模块列清楚就行。这部分内容建议控制在 2k token 以内,占用一个合理的预热成本。
CLAUDE.md 不要写成使用手册,要写成「背景知识」。区别在于:手册是教 AI 怎么操作,背景知识是让 AI 知道它在一个什么样的环境里工作。
第二步:按需扩展。 如果这个项目有特殊的业务逻辑(比如支付流程、权限模型),单独建一个 docs/ 目录下的 Markdown 文件,在 CLAUDE.md 里引用路径。AI 真正需要的时候会自己去读。
第三步:对话过程中保持「只增不减」。 不要主动删除历史消息,除非上下文真的接近上限了。压缩是最后手段,不是日常操作。频繁压缩会让对话失去连续性,AI 会反复问已经问过的问题。
第四步:设一个 token 警戒线。 我一般把 80% 上下文容量设为警戒线,在那之前不触发任何压缩逻辑。等真的到了那一步,再考虑摘要或者开新会话。
用 Claude Code 的话,可以用这个命令查看当前上下文使用量:
claude --token-count
# 或者在对话中直接问:
# "当前上下文大概用了多少?"
一个真实的反面案例。
我之前跑一个 pnpm monorepo 项目,用的是纯压缩方案,理由是「不想在开头就花太多 token」。跑了三周之后,每周都要触发 2-3 次压缩,最终导致 AI 在重构时遗漏了 packages/auth 和 packages/billing 之间的隐式依赖关系——因为这两部分的关联细节在多次摘要后丢失了。
后来我补上了 CLAUDE.md 并重新开始会话,同样的重构任务只用了原来一半的时间,而且没有遗漏任何依赖。
总结一下:预热和压缩不是非此即彼的选择,但在资源有限的情况下,优先选预热。它的核心优势是一次性投入换取全程高质量输出,而压缩是在已经出问题之后的补救。预防比治疗便宜,这件事在 AI 编程里同样适用。
如果你现在在用压缩方案,试着在下次新会话开始前加一段 CLAUDE.md 预热,对比一下信息丢失率和 token 消耗,你会看到差别的。
评论区
登录后可评论。