当你压缩聊天记录时,聊天机器人会忘掉什么?

当你压缩聊天记录时,聊天机器人会忘掉什么?

等一下,请寄到另一个地址

想象一个帮助安排配送的客服聊天机器人。用户先提供一个地址,几轮之后又更正了地址。对话接着聊了配送时间、包装和收据。最后用户问:“你们会寄到哪里?”

机器人可能记得两个地址,却仍然答错。关键不在旧地址是否还留在记录里,而在它是否知道旧地址已经被替换。

下面是一个简短示例。对话和回复均为说明性内容,并非模型运行结果。我们尚未实际运行本文三种策略的对比。本文是一份调试指南和可复现的测试协议,不是已测量结果的实验报告。

轮次对话
1用户: 把样品包裹寄到浦那市湖路 14 号。助手: 我记录的收货地址是浦那市湖路 14 号。
2用户: 更正一下,请改用浦那市山街 82 号。第一个地址已经过时。助手: 明白了,我会使用浦那市山街 82 号。
3用户: 星期五能送到吗?助手: 我可以帮你查看星期五的配送选项。
4用户: 包裹是一个小盒子。助手: 好的,一个小盒子。
5用户: 请放入一张纸质发票。助手: 我会在配送要求里注明纸质发票。
6用户: 之后我可以追踪吗?助手: 发货后可以提供追踪信息。
7用户: 如果星期五要额外收费,就选普通配送。助手: 我会注明:星期五若需额外收费,就选择普通配送。
8用户: 收件人下午五点后会在家。助手: 我会注明收件人五点后有空。
9用户: 标签上应该写什么?助手: 可以写收件人姓名和收货地址。
10用户: 你能总结一下配送信息吗?助手: 一个小盒子、一张纸质发票;如果星期五额外收费,就选择普通配送。
11用户: 谢谢。助手: 不客气。
12用户: 我们继续吧。助手: 好的。
探测问题用户: 包裹应该寄到哪个地址?助手: 待评估的回复。

预期状态很简单:山街 82 号是当前地址;湖路 14 号已被替代。但如果摘要只说“用户讨论过湖路 14 号和山街 82 号”,它虽然保留了两句话,却丢掉了决定。

这正是本文想探讨的区别:好的记忆不是记得更多,而是记住哪些信息仍然成立。

对话是一连串状态变化

对话记录记下人们说过什么。应用行为依赖的则是一小组不断变化的事实:哪些仍有效、哪些已被替换、哪些是允许的、哪些还在等待处理,以及哪些只是推测。

聊天机器人可能用一段通顺的文字保留了对话主题,却抹去了恰恰决定下一步的区别。“用户讨论了发送订单”无法说明发送是已获批准、暂缓处理,还是已经完成。“用户正在替公司下单”也不同于“助手猜测这可能是公司订单。”

有用的测试不是摘要读起来是否顺畅,而是系统能否用这份摘要回答具体问题,或选择被允许的下一步。记住状态,而不只是那句话。

更正、操作限制和假设需要不同的对话状态

记忆需要保留的六类信息

以下六类适合用来测试,因为它们要求记忆保留信息之间的关系和状态,而不只是关键词。

失败类型对话变化后续回复应如何处理
事实更正“用地址 A。”后来改为“其实用 B。”使用 B,并把 A 视为已替代。
否定指令“准备好订单,但先别寄。”保留这一限制。准备订单不代表获准寄出。
未完成任务用户要求为 25 把椅子起草报价,表示稍后提供木材饰面,之后说“用胡桃木饰面”。将新信息关联到待办报价;收到信息不等于报价已经完成。
事实与假设助手猜订单是替用户公司购买,用户未确认。说明用途尚不清楚,不要把猜测当事实。
偏好改变“选 X。”后来改为“我改变主意了,选 Y。”把 Y 当作当前偏好。
已完成状态可信的订单服务收据确认订单已寄出。识别操作已经完成,不要建议重复寄出。

最后一种情况需要仔细区分。订单已经寄出这一历史记录仍然成立,变化的是“寄出”是否还是待办事项。记忆可以帮助模型理解对话,但不能替代应用的权威交易记录或权限检查。

延续对话的三种方法

若要单独考察记忆表示方式,可以比较三种明确配置。

完整历史会把此前的所有消息和最终探测问题一起提供给模型。模型能看到完整记录,但这不保证它一定会正确理解每次更正。

近期消息窗口只提供最近四组完整的用户与助手对话。更早的内容会被省略。四组只是便于说明的实验设置。四组对话是实验配置,不是生产环境的推荐窗口。 实际应用应根据任务、模型和上下文预算来选择窗口。

结构化滚动摘要会保留较早对话的累计摘要,再附上最近四组对话。旧对话移出近期窗口时,摘要器会将它们合并进已有摘要。

同一段对话分别提供完整历史、近期窗口或结构化滚动摘要

这只是三种具体的参考配置,不代表所有实现方式。近期窗口可以有不同长度;摘要也可以结合数据库、检索或人工维护的状态。比较的重点是:重要信息在对话中前移或后移时,这些具体输入分别保留了什么。

滚动摘要具体应包含什么?

如果系统的任务是保留可用于后续行动的状态,摘要就应当明确呈现状态。下面是一份聚焦于地址的说明性状态快照:

JSON
{
"current_facts": {
"delivery_address": "浦那市山街 82 号"
},
"superseded_facts": [
{
"field": "delivery_address",
"old_value": "浦那市湖路 14 号",
"replaced_by": "浦那市山街 82 号"
}
],
"constraints": [],
"pending_tasks": ["确认配送日期"],
"completed_tasks": [],
"unconfirmed_assumptions": []
}

这六个部分让我们可以提出具体问题:哪个值是当前的?它取代了什么?什么指令限制下一步操作?还有什么问题尚待解决?哪些事情已经完成?哪些细节只是猜测?

这是测试协议的参考设计,不是模型运行结果,也不是 ModelRiver 当前的生产结构。ModelRiver 目前用 summary、facts、actions 和 open_items 表示 session 摘要。这里更细的结构仅用于展示应用可能追踪的区别;单靠 schema 无法保证信息一定被准确保留。

有必要明确测试这一点。Anthropic 关于上下文工程的指南 提醒,过度压缩可能丢失直到后来才显出重要性的细节,并介绍了用结构化笔记追踪长期任务进度和依赖的方法。Anthropic 的 compaction 文档 说明了如何用摘要替换较早的轮次,同时保留近期轮次。这些资料提供了实现参考,但不能证明哪种策略能保留本文六类案例中的状态;这正是下面协议要检查的问题。

一套可用于自己聊天机器人的测试方法

随文提供的测试案例包包含十二段合成对话,覆盖六种失败类型,每类两个版本。每段对话包含十二轮此前的用户与助手交流,以及一个最终探测问题。预期状态和可接受的后续行为也记录在案例中。

每一对案例的内容相同,只调整关键信息出现的位置。早期版本在八轮无关对话之前给出更正或指令;晚期版本则在八轮之后给出。两种版本之后都接两轮中性对话,再回答探测问题。位置信息是刻意测试的变量:近期窗口对早期和晚期信息的访问会不同;滚动摘要是否能保留它们,需要实际检查,不能预设。

对每段对话,准备前面介绍的三种记忆输入。然后查看最终探测问题的实际输入,分别记录以下两项:

  1. 所需状态是否保留? 输入是否区分当前事实和已被替代的事实、是否保留限制、是否说明任务待办还是已完成、是否标记尚未确认的信息?
  2. 回复是否正确处理状态? 回复是否遵循该状态、询问缺失信息,并避免提出被禁止或已经完成的操作?

记录探测时的记忆 token 数量和回复正确性;如果运行实时模型,还应记下模型、设置、延迟、token 用量和估算费用。不同条件要使用相同的模型和设置。如果重复测试,报告案例数量和结果。这个小型协议用于探索,不是正式基准测试。

案例包附有参考 schema、摘要提示词和十二段对话案例,但没有 API 运行器,也没有已完成的实验结果。读者无需先下载文件即可上手:本文地址对话是一份完整的说明示例。下载案例中的地址更正相同,但使用固定的无关对话。

哪些状态保留下来了?

尚未实际运行模型,因此我们不能给策略排名,也不能报告成本、延迟或成功率。运行协议后,可以先填写下面的表格。横线表示尚未测量,不是零。

策略探测时的记忆 token 数状态保留回复正确
完整历史—— / 已评估次数— / 已评估次数
最近四组对话—— / 已评估次数— / 已评估次数
滚动摘要 + 最近四组—— / 已评估次数— / 已评估次数

按失败类型和早期、晚期位置分别报告结果,将部分保留单独记录,并展示两三个失败案例的实际记忆输入和回复。最终探测的成本与延迟应和维护摘要的额外工作分开;最终输入更短,仍可能需要额外的摘要调用。

没有供应商额度也可以开始:对照预期状态,人工检查完整历史和近期窗口的固定输入。手写摘要可以帮助定义目标结构,但不能验证模型的摘要质量。回复正确性和模型生成的滚动摘要,在实际运行前都仍未测量。

如何判断记忆在哪一步出错

以否定指令案例为例,下面是三种假设结果,用来说明如何诊断问题;它们不是实际观察到的模型输出。

指令丢失。 摘要写着“订单 1042 已准备好”,却省略了“获批准之前不要寄出”。回复因此建议寄出。此时应检查摘要环节:后续模型无法遵循从未收到的限制。

指令保留了,但回复没有遵循。 提供的记忆清楚写着 do_not_send_yet,模型却建议寄出。记忆保留了状态,回复却没有尊重它。这与摘要丢失指令属于不同问题。

答案碰巧正确。 摘要漏掉了暂缓指令,但模型刚好回复“我会先等等”。最终答案看起来安全,却不能证明记忆保留了信息;下一段对话中它可能就会出错。

将状态保留和行为正确分开评分。回复正确不能证明记忆质量好;记忆准确也不能保证模型一定遵循它。分别检查两者,才能找到应用中需要关注的环节。

分别检查记忆是否保留了当前状态,以及后续回复是否遵循该状态

先检查记忆,再判断答案为何出错

我们在构建 ModelRiver,所以这个问题也关系到我们的实现。它的 sessions 页面会显示当前滚动摘要,每轮的 Memory snapshot 则在有记录时展示该轮的记忆文本。当回复用了过时的事实时,这让人有材料可查。但这并不能证明摘要一定保留了正确状态。

如需了解 session memory 如何传入并返回,可先查看 session-memory API 文档或 session-memory 聊天机器人模板。要组装记忆,项目必须启用 request-body logging。ModelRiver 的 Test Mode 会返回预先配置的样例数据,无法检测实时模型是否记住或遵循了更正。那需要在自己的评估中调用实际模型。另需注意,ModelRiver 先使用原始历史,达到历史限制后再将其折叠为滚动摘要。其触发条件和结构与本文的四组对话参考配置不同,因此在 ModelRiver 中运行一段会话并不自动等于复现本协议。

在自己的聊天机器人上试试看

找一段包含更正的对话。在最后一个问题处,检查应用实际发送的上下文。它是否保留了哪个值才是当前值?再检查模型回复是否使用了这个值。

如果想尝试更多案例,十二段对话测试协议还包含否定指令、未完成工作、假设、偏好改变和已完成操作。这个方法足够精简,便于改成自己的例子;关键在于确认系统是否保留了下一步判断所依赖的状态。

更多相关案例:备用模型如何改变产品行为以及同一 JSON schema 发给五家供应商后出现了什么问题。