上下文压缩:为何编程Agent容易失控,聊天Agent却能聊几小时?
最近在做 Agent 相关开发时,发现一个很有意思的现象:同样是上下文压缩,在不同业务场景下的影响天差地别。
用 Claude Code、Codex、Cursor、Trae这类编程工具写代码,对话压缩个两三次,你就会明显感觉到它 “变笨了”—— 找不到工具、记不住文件路径、忘记之前定好的约束,甚至开始重复做已经完成的事。而日常聊天类产品,比如你跟豆包聊一下午,天南海北扯几十轮,上下文不知道被压缩了多少轮,你却几乎感觉不到明显的质量下降。
这背后不是模型能力的差距,而是两类业务对上下文信息的要求,本质上就不在一个维度上。
一、先搞清楚:上下文压缩到底在做什么
上下文压缩不是简单的 “删除旧消息”。目前主流的压缩方式大致分三层:
微观清理层(Micro-compact):每次 API 调用前,静默清理过期的工具返回结果、冗余的日志输出、重复的状态信息。这一层几乎无损,成本极低。
摘要压缩层(Auto-compact):当上下文接近窗口阈值时,调用模型把历史对话重写为一段摘要,用几十到几百 token 替代几千 token 的原始对话。这是真正有损的一步。
KV Cache 层:推理引擎层面做的 token 合并、低秩压缩、量化,例如 DeepSeek 采用的 MLA(多头潜在注意力)/ HCA 机制,通过对 KV 进行低秩压缩,大幅减少了显存占用。这一层对语义损伤较小,但对精细符号有影响。
以 Claude Code 为例,它有完整的 5-7 层渐进式压缩流水线,从工具结果落盘、历史裁剪、微压缩,到最后的全量摘要,是一套 “不到万不得已不动用有损压缩” 的防御体系。但只要触发了摘要式压缩,信息损耗就不可逆转。
二、核心差异一:符号精确性 vs 语义连续性
这是最本质的区别。
编程类业务是典型的高信息密度 + 零容错符号系统。代码世界里,差一个字符就是天壤之别:
文件名 userService.ts 和 UserService.ts 是两个文件
变量名 userId 和 user_id 差一个下划线,就是完全不同的标识符
函数参数从 (id: string) 变成 (userId: string),调用方全崩
文件路径 src/api/v2/handler.ts 记错一级目录,工具直接找不到文件
缩进、括号层级错一处,整个代码的语法结构直接失效
摘要式压缩的本质是语义蒸馏—— 它的底层逻辑是「丢弃细节、保留大意」,擅长留住 “这段代码在做用户鉴权” 这种宏观描述,但不擅长精确保留 validateToken(payload: JwtPayload): boolean 这种精确符号。可在代码世界里,”大意” 几乎没有实用价值:只知道 “这里有个处理用户数据的函数”,却记不住具体函数名和参数列表,Agent 根本无法完成调用。
每压缩一次,符号精度就衰减一次;多轮压缩后,具体的标识符就模糊成了 “某个验证函数”。一次关键的符号丢失,就可能直接造成语法错误或逻辑断裂,让 Agent 直接失控。
而聊天类业务是低信息密度 + 高容错的语义系统。人类日常对话本身就充满语义冗余:同一件事往往会反复表述,核心信息包裹在大量寒暄、铺垫和修饰里。你和豆包聊旅行、聊美食、聊电影,压缩后只要还能记住 “用户想去日本、喜欢吃拉面、上周刚看过某部电影” 这些语义要点,对话就能继续顺畅进行。
记错几个细节?漏掉一两句无关紧要的寒暄?没关系,自然语言的模糊性天然提供了极高的容错空间,用户甚至根本察觉不到。
打个比方:压缩就像把一张高清图转成缩略图。聊天场景下,你只需要认出 “这是一只猫”,缩略图足够了;编程场景下,你需要数清猫身上有几根毛、每根毛的精确角度 —— 缩略图完全不够用。
三、核心差异二:链式推理的误差放大效应
编程 Agent 的工作方式是多步链式推理:读文件 → 分析问题 → 制定方案 → 修改代码 → 运行测试 → 修复错误 → 再测试…… 每一步都依赖前一步的精确结果。从本质上看,这是一个严密的离散状态机:Agent 需要在内存中持续维护一组精确的 “状态变量”—— 当前修改的文件路径、当前的变量作用域、上一步工具返回的报错信息、待完成的任务清单。这些状态是非此即彼的,不存在中间地带。
这就形成了一个误差放大器:
第一次压缩:记错了一个变量名 → 写出来的代码有 bug
第二次压缩:忘记了之前发现的某个边界条件 → 修复方向跑偏
第三次压缩:连已经改了哪些文件都记不清了 → 开始重复劳动、陷入循环
每一轮压缩引入的微小误差,都会在后续的推理链条中被放大。到第三四轮压缩时,Agent 的内部状态已经和真实状态严重偏离,表现出来就是 “失控”—— 工具乱调、逻辑混乱、忘记任务目标。
更麻烦的是 Agent 的隐性状态维护。Claude Code 会维护 todo list、已完成项、已知错误列表这些隐性状态,这些状态不会每次都显式说出来,而是存在对话的隐含逻辑里。上下文压缩最容易抹掉这些离散的状态节点,相当于状态机丢失了当前的状态指针,直接导致 Agent”失忆”,忘了自己做到哪一步。
聊天业务完全没有这个负担。对话更像是连续的语义流,核心是主题和情感的延续,不存在严格的前后依赖链条。每一轮对话相对独立,用户说一句、AI 答一句,话题跳了、偏了、忘了某个细节,都不影响对话的整体体验。这种语义层面的抽象与泛化,恰恰是大模型最擅长的能力,也是聊天场景不怕压缩的核心原因之一。
四、核心差异三:结构化数据的脆弱性
编程 Agent 重度依赖结构化的工具调用协议。每一次工具调用在消息序列里都是严格配对的:Assistant 发出一个 tool_use(带 ID),User 回复对应的 tool_result(带相同 ID)。
上下文压缩时,这个配对关系非常容易被破坏。比如:
裁剪历史时,切点落在 tool_use 和 tool_result 之间,产生 “孤儿消息”
摘要重写时,把结构化的 tool_use 块写成了自然语言描述
多轮并行工具调用的顺序被打乱,导致状态错乱
除此之外,工具调用本身有严格的 JSON 格式约束,工具定义的 Schema、参数结构都必须完整保留才能被正确解析。但当前的压缩技术很难完美保障结构化数据的完整性:无论是语义摘要还是 Token 裁剪,都可能破坏 JSON 的闭合结构、截断字段定义。一旦解析器无法识别工具调用格式,Agent 的整个执行循环就会直接崩溃。
这就是为什么很多人遇到 “Claude Code 突然不调用工具了,开始用嘴说命令”—— 不是它不想调用,是压缩后的上下文里,工具调用的结构化边界已经模糊了,模型把它当成了普通文本。
而聊天业务几乎没有结构化数据。整条对话就是纯文本消息,压缩前后都是纯文本,不存在结构破坏的问题,自然也不会遇到 “格式解析失败” 这类硬阻断故障。
五、核心差异四:任务闭环 vs 开放交互
还有一个容易被忽略的视角:谁在驱动对话前进。
编程 Agent 是自主闭环执行的。你说一句 “帮我重构这个模块”,接下来的十几轮可能都是 Agent 自己在驱动:读文件、改代码、跑命令、查错误…… 用户可能全程只看着。这意味着 Agent 必须自己维护完整的任务状态,一旦压缩导致状态丢失,没有人来帮它纠正。
聊天产品是用户驱动每一轮的。每一轮对话都是用户发起、用户掌舵。如果 AI 记错了什么,用户自然会提醒;如果话题跑偏了,用户会拉回来。用户本身就是上下文质量的校正器。
换句话说:聊天场景下,用户的每一次输入都在“隐式的”重新锚定上下文;编程场景下,Agent 自己在黑盒里跑,压缩跑偏了也没人拉一把。
六、核心差异五:深度推理模式 vs 直觉联想模式
除了业务场景的客观差异,模型本身的设计取向也放大了这种感受差。
像 Claude 这类主打长上下文深度推理的模型,在 Agent 工作流中实际上是在运行系统 2 思维模式:慢速、严谨、步步为营,每一步推导都严格依赖前面的结论和信息。这种模式对上下文的连贯性和完整性要求极高,上下文压缩就像在一个人演算数学题时突然抽走半页草稿纸,哪怕只丢失少量信息,也可能让后续的推理完全跑偏。
而聊天场景下的模型更多运行在系统 1 模式:快速、直觉、联想式生成。它不需要严密的逻辑链条,只需要顺着语义和情绪自然延续即可,本身就不要求强逻辑连贯性,因此对压缩带来的信息损耗抗干扰能力要强得多。
七、结语
总结一下,五类差异层层叠加:
| 维度 | 编程类业务 | 聊天类业务 |
|---|---|---|
| 信息类型 | 精确符号系统,差一字符即错 | 模糊语义系统,容错率极高 |
| 推理结构 | 严格链式状态机,误差逐级放大 | 发散式语义流,误差相互独立 |
| 数据结构 | 结构化工具调用,边界脆弱 | 纯自然语言,结构简单 |
| 驱动方式 | Agent 自主闭环,无人校正 | 用户驱动每轮,自然校正 |
| 思维模式 | 深度逻辑推理,对连贯性要求高 | 直觉联想生成,抗干扰能力强 |
这也是为什么做 Agent 框架的团队,永远在和上下文管理死磕 —— 因为你面对的不是 “聊天记不记得住” 的体验问题,而是 “符号系统能不能保真” 的工程问题。聊天场景 80 分的压缩算法,放到编程场景可能连及格线都到不了。
从另一个角度说,这也解释了为什么 “无限上下文” 至今都是伪命题。不是技术做不到更长的窗口,而是当任务本身要求符号级精确时,窗口再大也没用 —— 注意力稀释、位置编码失真、压缩损耗,这些问题不会因为窗口变大就消失。
对编程 Agent 来说,真正的解法从来不是 “把窗口做更大”,而是:结构化外部记忆、状态显式化、可验证的任务边界,以及 —— 承认压缩必然有损,在工程上设计好熔断和重置机制。长远来看,核心思路是将关键状态与工具定义从易受压缩的对话上下文中剥离,为 Agent 设计独立的、不受压缩影响的外部记忆体与草稿板,用结构化存储保障核心信息的绝对保真。
而在日常使用中,最直接有效的办法也很简单:当发现编程 Agent 的对话已经过长、即将触发多次压缩时,及时开启新会话,重新明确当前的核心状态与目标,往往是防止 Agent”失控” 最具性价比的方案。毕竟,人类程序员写代码也会记不住,还不是靠注释、文档和 Git 吗?