一位用户询问我们的支持智能体:“为什么发票 INV-2025-08-44719 在 4 月 3 日被扣了两次款?”45 分钟和 18 次工具调用之后,智能体自信地回复道:该账户在该季度没有任何重复计费的证据。用户理所当然地投诉了。当我们回放追踪记录(trace)时,答案变得显而易见。智能体在第九轮对话时对内容进行了压缩(compacted)。摘要显示用户“在询问 4 月初的一笔重复收费”。其中并不包含字符串 “INV-2025-08-44719”。随后的每一次工具调用——账本查询、退款 API 查询、审计日志扫描——都是针对转述后的意图发出的,而不是用户输入的字面意义上的发票编号。
Bug 不在工具里,也不在模型的推理中。问题在于我们的上下文管理器(context manager)与每个下游组件之间都有一个契约,但没有人把它写下来。契约写着:“我会保留语义。”而组件需要的是:“我会保留字符串。”
这是自动摘要在生产环境智能体中不断产生的失效模式,它比那些更出名的压缩失败案例更具隐蔽性。我们经常听到摘要丢失了重要事实或压缩掉了推理步骤。我们较少听到的是,摘要保留了所有事实,完美地维持了对话脉络,却悄悄地改变了确定性下游查询所依赖的精确表述。智能体并不会感到困惑,它只是充满自信地搜索了错误的字符串。
压缩悄然破坏的两个契约
大多数压缩策略都是隐含地围绕一个假设设计的:在智能体上下文中流动的是语义,而语义是需要保留的东西。摘要捕捉意图,智能体根据意图进行推理,工具为推理服务。压缩语义,不会丢失任何重要的东西。当上下文管理器下游的每个组件本身都是 LLM 时,这个模型运作良好,因为 LLM 对转述(paraphrase)具有鲁棒性。模型可以读取“询问 4 月初的重复收费”并生成一个形状大致正确的查询。
但只要管道中的任何组件执行字面查询——例如 SQL 的 WHERE invoice_id =、哈希表查找、正则表达式匹配、针对 BM25 索引的精确字符串向量检索、Webhook 签名验证、幂等键(idempotency-key)检查——该组件与上下文之间就有了不同的契约。它不需要语义,它需要用户输入的精确字符。而在摘要提示词中,没有任何内容告诉摘要生成器哪些字符串是承载关键信息的。
这里实际上有两种契约在起作用,而且它们通常是未说明的:
语义契约 (Semantic contract) 。“我需要知道用户想要什么。”由规划器(planner)、路由逻辑、语气匹配以及任何消耗意图的组件持有。对转述具有鲁棒性。对摘要具有鲁棒性。
词法契约 (Lexical contract) 。“我需要用户提供的精确字节。”由每一个数据库查询、每一个具有固定 schema 的 API 调用、每一个缓存键、每一个指纹、每一个审计标识符持有。对转述非常脆弱。会被摘要摧毁。
灾难在于,词法契约在设计阶段是不可见的。绘制智能体架构图的架构师看到标有“摘要生成器”和“工具执行器”的方框,并假设摘要对两者来说都是足够好的输入。他们在后者上错了,而且只有当用户追问“你真的查看了发票 INV-2025-08-44719 吗?”时,他们才会发现问题——而由于发票编号仍不在上下文窗口中,智能体现在也无法回答这个问题。
为什么 Claude Code 和 Codex 在这里分道扬镳
这并不是一个假设性的区别。两个部署最广泛的编程智能体以截然相反的方式处理它,这种分歧很有启发性。Codex 在压缩过程中逐字保留了每一条用户消息。它会删除助手回复和工具消息,并用摘要替换它们,但原始的人类对话轮次被物理地保留在提示词(prompt)中。Claude Code 的 /compact 指令以及更广泛的 Anthropic 压缩 Beta 版默认会摘要化所有内容,包括用户轮次,并要求开发者传递明确的 instructions(指令)来保护特定类型的内容——如代码片段、文件路径、标识符。
Codex 的设计隐式地承认了词法契约:它假设用户输入的任何内容都可能对未来的工具调用具有承载作用,因此从不转述它。代价是 Token 效率。与爱聊天的用户进行的长时间对话会无限期地为每条原始消息付费。Anthropic 的设计则朝另一个方向优化:它假设开发者知道哪些字符串是神圣不可侵犯的,并会告知系统。这在表达能力上更强,但给可能尚未意识到这一负担的团队增加了配置负担。
两者都是合理的工程选择。但对于一个不是你自己构建的智能体来说,哪一个作为默认设置都不是完全正确的。如果你正在使用托管的压缩 API,并且拥有任何针对用户提供的值进行字面查询的工具,你需要假设摘要不会保留这些值,并且你需要设计一个单独的机制来处理。
真正能经受实战考验的模式 解决办法不是让摘要变得更聪明,而是意识到摘要对于字面量内容(lexical content)来说并非合适的载体,并为这些内容开辟一条不受压缩影响的独立通道。在生产环境中行之有效的模式如下:
在触发任何压缩之前,尽早提取标识符。 当用户消息到达时,运行一个快速提取器 —— 可以是小型模型、正则表达式流水线,或者是针对同一模型的结构化输出调用 —— 提取出所有潜在的标识符:发票号码、订单 ID、文件路径、账户参考、SKU、错误代码、时间戳,以及任何可能需要通过字面量查询进行往返匹配的内容。在摄入(ingest)时就执行此操作,而不是在需要时才执行,因为当你需要它们时,摘要可能已经发生了。
将标识符存储在绕过上下文管理器的边车(sidecar)中。 将它们放入会话作用域的键值存储、智能体状态中的结构化插槽,或是一个被钉选(pinned)且排除在压缩之外的专用消息中。重点在于,它们存在于摘要器无法触及的地方。许多生产级智能体框架现在正是为了这个原因而提供了“请勿压缩(do not compact)”的注解;如果你的框架没有提供,你可以通过在每一轮对话中将标识符块重新注入到系统提示词(system prompt)中来模拟这一功能。
让工具从边车中获取信息,而不是从对话中。 重构工具描述,使其期望从注册的插槽中接收作为参数的标识符,而不是从自由格式的规划中获取。这虽然只是对工具签名的一个微小改动,但对智能体的可靠性却是巨大的提升:规划器现在必须从边车中获取数据,而不是从摘要中猜测,这使得一整类由“意译”引起的 Bug 在语法层面变得不可能发生。
审核摘要提示词中的逐字记录指令,但不要依赖它们。 大多数托管压缩 API 都允许你指定要保留的内容。利用这一点 —— 告诉它保留标识符、代码块和准确的错误消息。但请将其视为深度防御措施,而不是主要机制。摘要提示词会发生漂移,在长度压力下被截断,并在边缘情况下悄无声息地失效。边车是承重墙,而提示词指令只是纱门。
这种模式的轮廓揭示了一个更深层的认知:智能体的上下文并非单一实体。它至少包含两部分 —— 模型赖以推理的叙事载体(narrative substrate),以及工具执行所需的字面量载体(lexical substrate)。如果压缩策略只顾及前者,就会在无形中破坏后者。
“摘要损失”揭示了智能体架构的什么问题 正确的切入点是,“摘要损失”(summary-loss)并非摘要质量的问题,而是接口缺失的问题。上下文管理器一直被视为一个摄入轮次并输出轮次的黑盒,其他所有组件都假设输出的内容至少与原始内容一样好,足以满足其需求。对于以语义(semantic)为目的的组件,这个假设是成立的;但对于以字面量(lexical)为目的的组件,这个假设并不成立。由于架构从未明确区分这两者,失败只会在运行时、在难以复现的特定条件下显现。
当你开始针对这种失效模式审计你的智能体时,你会惊讶地发现,有多少组件其实有着从未被声明的字面量契约。带有 BM25 组件的向量搜索?字面量的。使用倒排排名融合(RRF)的 RAG 检索?在关键词阶段是字面量的。通过查询字符串缓存工具结果?字面量的,而且现在当摘要改变了查询语句时,你还会面临缓存未命中雪崩。根据从原始用户消息中提取的关联 ID 进行操作的 Webhook 处理器?字面量的,而你的压缩策略正在悄悄破坏观测栈中的因果关系。这些问题单独看都是微小的 Bug,但加在一起就构成了一类 Bug。这类 Bug 的规模如此之大,以至于“压缩破坏了下游环节”现在已成为任何运行长期智能体的团队必须预留预算处理的类别。
表现最好的团队是那些开始将上下文管理器视为具有公开接口的组件,而不仅仅是一段管道的团队。他们的压缩策略有一个版本化的规范(spec)。规范说明了哪些内容会被保留,哪些不会,以及文档记录的逃生舱口(escape hatches)是什么。工具是根据规范编写的,而不是为了贪图一时的方便。当摘要模型发生变化时 —— 这在提供商迭代压缩 API 时每隔几个月就会发生一次 —— 规范就是保护他们免受回归影响的屏障,因为规范正是他们测试所检查的对象。
周一该做点什么 如果你现在正在生产环境中运行智能体,并且上述情况听起来很有可能但尚未证实,这里有一个为期一周的调查方案,可以告诉你是否存在这个问题。
获取一周的智能体追踪记录。筛选出那些跨越了压缩边界的记录。对于每一条记录,提取用户的原始消息和压缩边界后发出的工具调用参数。运行字符串匹配检查:用户输入中每一个呈现标识符形态的标记(token),是否都逐字出现在压缩后的工具调用中?绘制比例图。如果该比例未接近 100%,那么你就存在这个 Bug。
挑选一个使用用户提供的标识符的工具并添加一个防御机制:在执行之前,要求标识符必须来自会话边车,而不是推断出的参数。记录每一次边车查询失败的情况。日志量就是你的 Bug 暴露面。
审计你的压缩提示词或提供商的默认设置。明确记录哪些内容类别被文档标注为保留,哪些没有。任何在第二份清单中的内容,你都绝对不能依赖,就这么简单。
更深层的转变是,停止将上下文窗口视为智能体拥有的单一资源,而是将其视为两个耦合的存储库 —— 一个用于叙事,一个用于事实 —— 它们恰好共享同一个预算。一旦你以这种方式审视系统,那种“把用户原始问题摘要掉”的压缩策略就不再是神秘的意外,而是将两个本应分开的契约混为一谈的架构所导致的必然结果。
智能体会变得越来越长,对话会一直需要被压缩,而摘要将始终是提供商首选的手段。在未来一年里,能够交付可靠智能体的团队,将是那些提前决定哪些字符串是工具无法承受丢失的,并将这些字符串绕过摘要器进行路由,而不是让它们穿过摘要器的团队。
会员专享
余下内容仅对会员开放。 会员可读完整内容 —— 每一个公开发布的观点背后,那些框架、决策与推理的全貌。
— 完整文章,包含未公开存档的部分 — 可落地的工作框架,附带权衡与决策依据 — 新文章抢先看,先于公开发布 登录以继续阅读→ 随时取消 · 一次订阅,畅读全部