你有没有想过,为什么Claude Code能在长达几十轮对话后还记得你最初说的需求?而普通AI聊着聊着就"失忆"了?

秘密在于上下文管理——这不是简单的"能记多少字",而是像专业收纳师整理衣柜一样,在有限空间里最大化有用信息的密度。今天咱们聊聊Claude Code如何把上下文管理变成一门核心能力。

为什么上下文管理是核心能力

想象你的书桌有200厘米宽,看起来够用了吧?但你随手一放就是:咖啡杯、笔记本、参考资料、草稿纸、零食包装…很快就没地方干活了。

AI的上下文窗口(200K token)就像这张书桌。系统提示词占15-20K,每次工具调用返回5-50K,读几个文件、搜几段代码,半壁江山就没了。更糟的是,过期的工具结果、冗余的文件内容、已解决的讨论堆在"桌面"上,AI的注意力被稀释,回答质量直线下降。

上下文管理的核心命题:在有限空间里,最大化信息密度,同时确保关键内容不丢失。

Claude Code用五条原则解决了这个问题。

原则一:为一切设定预算

你有没有做过家庭预算?房租不能超过收入30%,餐饮控制在20%,娱乐最多10%…如果某一项超支,其他就得削减。

Claude Code的上下文管理也是严格的"预算制":

预算体系一览

内容来源预算限制工程理由
单个工具结果50K字符防止单个超大结果占满上下文
单消息中所有工具结果200K字符防止10个并行工具各50K导致500K洪泛
技能列表描述上下文窗口的1%1000个技能也不能喧宾夺主
压缩后恢复文件最多5个文件,单文件5K token,总计50K恢复太多等于没压缩
压缩后恢复技能单技能5K token,总计25K token保持技能系统可用但不臃肿

这些数字不是拍脑袋定的。比如技能列表的1%预算:随着用户安装越来越多技能,如果不加限制,技能描述可能占满整个上下文。Claude Code的解决方案是三级截断级联——先截断描述到250字符,再截断低优先级技能,最后只保留内置技能的名称。哪怕你装1000个技能,技能列表永远不会超过上下文窗口1%的空间。

双重防护的智慧

注意50K和200K这两个数字的设计:

// 单个工具结果不能超过50K
export const DEFAULT_MAX_RESULT_SIZE_CHARS = 50_000

// 但单消息中所有工具结果总和不能超过200K
export const MAX_TOOL_RESULTS_PER_MESSAGE_CHARS = 200_000

这就像:每个抽屉最多放50件东西(合理),但如果你同时打开10个抽屉,总数不能超过200件(防止"合法但危险"的组合)。

反模式:无界内容注入

把工具结果、文件内容不加限制地塞进上下文,就像把超市购物车里的所有东西全堆到桌上——看起来很丰富,实则没地方干活了。

原则二:保留重要内容

搬家时你会怎么做?把所有东西打包,到新地方再全部拆开?那太蠢了。聪明的做法是:大部分装箱,但把最常用的东西(洗漱用品、换洗衣服)放在随身背包里,到新家第一天就能用。

Claude Code的压缩-恢复机制就是这个思路。

压缩会丢失细节

自动压缩(Auto Compact)把整段对话摘要成几句话,释放了上下文空间。但压缩有个副作用:具体的代码内容、文件路径、精确行号都丢失了。如果压缩后模型完全忘记之前读过什么文件,它就得重新读取——浪费工具调用和等待时间。

选择性恢复策略

// 压缩后恢复最近5个文件
export const POST_COMPACT_MAX_FILES_TO_RESTORE = 5

恢复策略的精妙之处:

  1. 压缩前快照:用cacheToObject()记录当前状态
  2. 执行压缩:对话变成摘要
  3. 选择性恢复
    • 最近5个文件(不是全部)
    • 单文件最多5K token(不是完整内容)
    • 总量不超过50K token
    • 已发送的技能不重注入(省4K token)

这就像搬家时的"随身背包"——只带最急用的,而不是把整个家背着走。

关键洞察:恢复太多等于没压缩,恢复太少等于压缩过度。5个文件、5K token、50K总量,是经过工程验证的"甜点"。

反模式:全量压缩或全量保留

要么什么都不恢复(模型被迫从零开始),要么试图保留一切(压缩效果为零)。就像搬家时要么全装箱(第一天没法生活),要么全不装(搬家车装不下)。

原则三:告知而非隐藏

你有没有遇到过这种事:别人给你一份"精简版"资料,但没告诉你删掉了哪些。你基于这个版本做决策,结果关键信息早被删了,你浑然不知。

AI也会遇到同样的问题。如果上下文被截断或压缩了,但模型不知道,它会基于不完整信息做错误决策,甚至"编造"它记不清的内容。

透明截断的四种实现

1. 工具结果截断通知

当工具结果超过50K时,Claude Code不会默默截断。而是:

  • 完整结果写入磁盘
  • 模型收到预览消息,包含"这是截断的,完整版在xxx路径"
  • 模型知道:(1) 当前不是全部,(2) 如何获取全部

2. 缓存微压缩通知

当旧工具结果被清理时,notifyCacheDeletion()明确告知模型"某些旧内容已被删除"。防止模型引用已不存在的内容。

3. 文件读取分页

FileReadTool默认读2000行,但明确告知模型这一点。如果需要后面内容,可以指定offset——模型知道"默认只看到前2000行"。

4. 压缩摘要中的显式声明

压缩提示词要求摘要包含"进行到哪一步了"和"还需要做什么"——压缩后的模型清楚自己处于任务的哪个阶段。

这就像整理书桌时,在收纳箱上贴标签:“这里面是参考资料,需要时可以取出”——而不是直接扔到地下室,假装它不存在。

反模式:静默截断

在模型不知情的情况下截断工具结果或删除上下文。模型可能引用已不存在的内容,做出错误决策。就像你问朋友"那份报告呢",朋友说"我扔了",但你不知道,还在问"报告第三页的数据"——朋友一脸懵。

原则四:熔断失控循环

你有没有见过自动售货机吞了钱不出货,然后你疯狂按退款键,但它就是没反应?如果这是一个AI Agent,它可能会无限重试"退款操作",每次失败都再试一次,直到天荒地老。

在AI系统中,无限重试尤其危险——每次重试都要花钱(API调用),而且失败原因往往是系统性的(比如上下文大到无法压缩),重试不会改变结果。

Claude Code的熔断器设计

// 连续3次压缩失败后停止尝试
// BQ数据:1,279个会话出现过50+次连续失败,最高达3,272次
// 浪费约250K次API调用/天
const MAX_CONSECUTIVE_AUTOCOMPACT_FAILURES = 3

这个数字3来自真实数据:BigQuery显示有1279个会话出现过50次以上连续压缩失败,最高达到3272次。每天浪费约25万次API调用。熔断器把无限循环变成"3次失败后停止"。

熔断器家族

子系统熔断条件熔断行为
自动压缩连续3次失败停止压缩直到会话结束
YOLO分类器连续3次/总计20次拒绝回退到用户手动确认
max_output_tokens恢复最多3次重试停止重试,接受截断输出
Prompt-too-long处理丢弃最旧轮次仍超限丢弃20%,不无限丢弃

每个熔断器遵循相同模式:设定合理重试上限,超过后降级到安全但功能受限的状态,而非崩溃或无限循环

反模式:无限重试

“压缩失败?再试。又失败?换参数再试。“在AI Agent中,这像自动售货机吞钱后疯狂按退款键——机器坏了,按再多次也没用,还浪费你的时间。

原则五:保守估算

你有没有做过预算时发现:计划花1000块,实际花了1200?AI的token估算也一样——低估导致溢出,高估只是略微浪费空间。

Claude Code在每个场景都选择保守估算:

估算策略对照

内容类型估算策略保守程度原因
普通文本4字节/token中等英文实际约3.5-4.5
JSON内容2字节/token高度保守结构字符token化效率低
图片/文档固定2000 token高度保守元数据不可用时用固定值
缓存token从API usage获取精确只有API返回的计数是权威的

JSON按2字节/token估算特别有意思。JSON的结构字符({}[]"":,)token化效率远低于自然语言——100字节的JSON可能消耗40-50个token,而100字节英文只需25-30个。如果用4字节/token的通用估算,JSON密集的工具结果会被严重低估,可能导致上下文溢出。

保守的收益大于成本

高估token消耗的最坏结果:提前触发压缩,用户多等几秒。

低估token消耗的最坏结果:prompt_too_long错误,API调用失败,需要紧急丢弃上下文,可能丢失关键信息。

这就像买保险——宁可多交点保费,也不要出事了发现保额不够。

反模式:精确计数的幻觉

试图在客户端精确计算token数量。只有API服务端的tokenizer才能给出精确值——客户端的任何计数都是估算。既然是估算,就应该向安全方向偏移,而不是追求虚假的"精确”。

五条原则的关系

为一切设定预算
    保留重要内容 ←─┐
        ↓         │
    告知而非隐藏  │
        ↓         │
    熔断失控循环 ──┤
        ↓         │
    保守估算 ──────┘

预算是基础:定义每个内容来源的token上限。

保留与告知是执行:决定压缩后恢复什么,并确保模型知道什么被截断了。

熔断与估算是保障:防止自动化流程超出预算,确保预算不被低估绕过。

这对构建AI Agent的启示

模式1:分层Token预算

  • 解决的问题:多个内容来源竞争有限的上下文空间
  • 核心做法:单项限制(50K)→ 聚合限制(200K/消息)→ 全局限制(上下文窗口-输出预留-缓冲)
  • 代码模板:为每个来源设定独立预算+总量预算,截断级联处理超额

模式2:压缩-恢复循环

  • 解决的问题:压缩丢失关键上下文
  • 核心做法:压缩前快照 → 压缩 → 选择性恢复最近/最重要的内容
  • 前置条件:能追踪哪些内容是"最近使用的”

模式3:熔断器

  • 解决的问题:自动化流程在异常条件下无限循环
  • 核心做法:连续N次失败后停止,降级到安全状态
  • 前置条件:定义"失败"的判定标准和降级后的行为

实战:审计你的Agent

1. 测量上下文消耗

在真实场景中测量每个内容来源占用多少token,找出最大消耗者。是工具结果?是文件读取?还是技能列表?

2. 为工具结果设定大小限制

确保文件读取、数据库查询、API调用的结果有字符/行数上限。不要等到prompt_too_long才想起来限制。

3. 实现压缩后恢复

如果你的Agent使用上下文压缩,设计恢复策略——让压缩后的模型不需要从零开始。最近用过的文件?最近编辑的位置?关键配置信息?

4. 截断时告知模型

告诉模型"这是截断的,完整版在哪里"——比静默截断后模型自己发现信息缺失好得多。

5. 添加熔断器

对任何可能循环执行的自动化流程设定重试上限。宁可降级也不要无限循环。

总结

上下文管理的五条原则:

原则核心做法反模式
为一切设定预算每个来源都有token上限,多级防护无界内容注入
保留重要内容压缩后选择性恢复关键信息全量压缩或全量保留
告知而非隐藏截断/压缩时明确告知模型静默截断
熔断失控循环连续N次失败后停止重试无限重试
保守估算宁可高估token消耗也不要低估追求虚假精确

这就像专业收纳师的工作:

  • 预算:每件物品都有指定的收纳位置,不能乱放
  • 保留:换季衣服装箱,但常用物品放在手边抽屉
  • 告知:收纳箱贴标签,知道什么在哪里
  • 熔断:收纳不了时停止购买,而不是堆到天花板
  • 保守估算:买收纳盒时宁可大一点,不要买小了装不下

理解上下文管理,你就能:

  • 在有限上下文窗口内最大化信息密度
  • 避免"聊着聊着就失忆"的尴尬
  • 在自己的AI Agent中实现专业级的上下文管理

下篇咱们聊聊生产级AI编码模式——从Claude Code学到的工程实践。