跳到主要内容

那个把用户的字面问题“改写”没了的摘要器

· 阅读需 9 分钟
Tian Pan
Software Engineer

一个用户问:“这是否符合第 28 条规定的‘转移’(transfer)?”四十轮对话后,模型给出了一个针对不同问题的答案。对话记录显示,模型回答了它收到的问题。用户正在阅读一份看起来像幻觉的投诉。两者都对。模型从未看到用户的提问——它看到的是你的摘要生成器对其进行的礼貌改写:“用户询问了第 28 条的适用性。”

“转移”一词就是问题所在。摘要生成器把它丢弃了,因为摘要生成器的损失函数被调优为保留事实而非措辞,而且评估准则从未学会区分改写主题和改写约束。主题被保留了。约束变成了迷雾。

这种失效模式是结构性的,而非偶发性的。任何通过模型生成的摘要来压缩长对话的应用,在关键路径上都有第二个模型——其质量契约通常被视为 Token 预算旋钮,而非一段产品逻辑。这种不对称性正是 Bug 所在。

摘要是损失函数错误的算法有损压缩

教科书上对对话摘要的描述听起来人畜无害:丢弃较旧的轮次,生成发生过的内容的简短摘要,将摘要置于实时上下文之前,这样第四十一轮的模型实际上是通过一层薄薄的改写看到了第一轮的内容。压缩率是真实的——四十轮对话坍缩为几百个 Token——且延迟惩罚是有界的。大多数生产环境中的“长上下文”策略都是这种方式的变体。

教科书遗漏的是,摘要生成器被要求优化一个应用程序从未指定的损失函数。默认的摘要提示词奖励简洁性、事实覆盖率和主题忠实度。它并不奖励对命名实体、问题中起承重作用的特定动词或约束条件的确切表述的逐字保留。最近关于长篇摘要的研究记录了一条“U 型”忠实度曲线——模型能忠实地总结文档的开头和结尾,却忽略了中间部分,而这种偏见会随着每一次传递而复合。到第四十一轮时,字面上的第一轮已经历了一次或多次重写,每一次重写都旨在听起来自然且信息丰富,但没有一次被训练成一份契约。

出现故障的地方不是“模型是否检索到了第一轮”。模型检索到的是它的替代品。摘要生成器将一个取决于动词法律解释的“是/否”问题改写为一个没有约束的主题指针,而下游模型回答了那个指针。

约束是问题;主题只是标签

一个有用处的心智模型:大多数用户轮次同时携带一个主题(“法规第 28 条”)和一个约束(“我们刚刚描述的具体行为是否符合‘转移’”)。主题是搜索引擎会索引的内容。约束是请求中起承重作用的逻辑。

摘要生成器,尤其是运行在诸如“用一句话保留每轮的关键事实”之类的简短指令下时,几乎普遍偏向于主题。主题是通用的,更容易改写,并且能产生让内部人工评估员看起来连贯的输出。约束是具体的,通常取决于单个动词或单个限定词,并且是改写首先会破坏的东西。摘要生成器正在履行它的职责。它的职责是错误的。

这种情况在非法律领域不断出现。医疗用户询问某种药物是否对特定的既往病症有禁忌;摘要记录为“用户询问了药物相互作用”。金融用户询问某种特定结构是否构成洗售(wash sale);摘要记录为“用户讨论了一笔交易的税务处理”。支持用户询问退款是否包含运费;摘要记录为“用户询问了退款政策”。在每种情况下,对主题改写的回答都与原始问题的回答不同,而模型被迫回答改写后的内容,因为除此之外没有其他信息存活下来。

你无法总结的东西:用户的原话

弥补这一差距的模式简单得令人惊讶:原始用户查询必须逐字保留,不进行摘要。它被视为上下文中的一个结构化插槽,与滚动摘要并列,并在会话生命周期内保持存在。

最近一些关于智能体(Agent)上下文压缩的研究将其正式确定为“幸存词汇原则”(surviving vocabulary principle)——当压缩器必须改写时,它被约束为重复使用参与者的实际措辞,而不是发明自己的措辞。一种更激进的变体是删除低信号内容,同时保持每个幸存的 Token 与输入完全相同,因此压缩后的记录是原件的严格子集而非重写。无论哪种方法都剥夺了摘要生成器用自己的词替换用户词汇的自由。这种剥夺正是重点所在。

在聊天应用中,这转化为三个具体的行为。首先,最近的 K 轮保持逐字记录——不可商量。其次,任何被识别为主要意图的用户轮次——提问、请求、约束陈述——无论存在多久,都会被逐字固定,即使其周围的轮次被压缩。第三,摘要生成器的提示词明确指示它,命名实体、情态动词、限定词和引用短语必须原封不动地保留,或者标记为缺失,而不是被改写。

第三点很重要,因为应用层的指令如果不反映在提示词和评估中,就无法触达摘要生成器的行为。“保留关键事实”和“保留关键事实(包括约束条件的字面表述)”是产生不同摘要的不同提示词。

像评估模型一样评估总结器

总结器(Summarizer)不是一个工具函数。它是滑动窗口填满后,每一个对话轮次关键路径上的一个模型。它有自己的失效模式、漂移面以及与应用程序之间的契约。大多数团队为他们的主模型准备了评估套件,却完全没有为总结器准备评估套件。这种不对称性正是导致“因改写而丢失问题”的 bug 在未被察觉的情况下发布到生产环境的原因。

一个有用的评估是由输入和答案对组成的,其中答案会随着常见的改写而改变。选取一个带有核心动词或限定词的真实用户问题,编写基于准确表述的答案,再编写一个基于主题改写的第二个答案,然后衡量总结器生成的结果导致下游模型产生错误答案的频率。如果一个总结器始终将“符合转让资格”(qualify as a transfer)映射为“第 28 条的适用性”(applicability of article 28),那么从设计上讲,它就未能通过此项评估;如果这项评估不存在,这种失败就是不可见的。

第二个指标是实体覆盖率。对于原始记录中的每一个命名实体、限定词和引用短语,有多少比例在总结中保留了下来?抽象式总结(abstractive summarization)的忠实度研究表明,实体覆盖率与答案依赖于该实体的下游任务准确性强相关。总结器的提示词(prompt)和总结器的评估都应该明确奖励实体覆盖。

第三个指标是跨轮次的漂移。渐进式总结——随着对话变长,对总结的总结再进行总结——会以单次总结所没有的方式积累改写错误。在每一轮都针对原始记录运行全新的总结会消耗更多 token;但假装这不重要则会付出更多线上故障的代价。

总结器是产品功能面,而非 token 预算调节钮

解决这类 bug 的架构共识是:总结器是一个用户能感知其行为的模型,它应该像管理主模型一样被管理。这意味着:提示词需要有版本控制并经过代码审查;拥有一套在实体丢失和约束改写时会报错的回归测试套件;提示词或模型变更需有发布流程;并且要有一个负责人,其职责包括思考“总结器是否针对我们最难对付的用户群体做出了正确的权衡”。

同时也意味着要认识到,选择压缩策略是一个产品决策。纯粹逐字保留用户的核心意图会持续消耗 token;纯粹的总结则会损失用户的精确提问;结构化提取到内存对象中——这里是核心意图,这里是约束,这里是命名实体——增加了实现复杂度,但让应用程序能够控制哪些维度被保留。这些都不是免费的,也不是默认提供的。默认行为取决于总结器的提示词恰好奖励什么,而大多数团队的提示词是“简洁且听起来自然”——这恰恰是会导致约束被改写掉的提示词。

询问其行为是否符合“转让”资格的用户,从未授权将其替换为“适用性”。默默执行这种替换的总结器并不是在为用户优化;它是在为自己的损失函数优化,并将用户的问题强行塑造成它喜欢的形状。解决方案不是寻找更聪明的总结器。解决方案是停止让总结器去做本属于应用程序的决策:对话中哪些词是用户原话,哪些词是可以协商修改的。

保留用户的原话。围绕它们进行总结。像评估关键路径上的模型一样评估总结器,因为它本质上就是。这样,第四十一轮对话才能回答你真正提出的问题。

References:Let's stay in touch and Follow me for more thoughts and updates