多轮对话不要靠”把所有历史塞进提示词”硬撑。可落地的做法是把对话拆成两层:任务态(当前在办什么事、还差哪些必填字段)用结构化数据单独存储并显式驱动澄清,过程态(历史消息与工具结果)按轮次裁剪与压缩。每轮开始时把两者合并成模型输入,结束后只回写任务态。这样无论对话走多少轮,模型看到的输入规模都是可控的。
多轮对话为什么会越聊越糟
把历史全量塞进上下文的写法,通常在第 10 轮之后出现三个典型症状:
- 目标漂移:用户中途换话题,模型仍按旧目标执行,因为旧指令还在上下文里且位置靠前。
- 反复确认:已确认过的信息被重复追问——模型在长上下文里”找不到”自己问过什么。
- 成本与延迟飙升:每一轮都重发全部历史,token 消耗随轮次线性甚至超线性增长。
根因是同一个:把”对话状态”和”对话记录”混为一谈。前者是结构化的、应该被覆盖更新的;后者是流水式的、应该被裁剪的。
落地框架:任务态 + 过程态双层
| 层 | 存什么 | 更新方式 | 是否进提示词 |
|---|---|---|---|
| 任务态 | 意图、槽位(必填字段)、已确认值、待澄清项、当前步骤 | 每轮覆盖更新 | 每轮完整注入(体积小) |
| 过程态 | 最近 N 轮消息、工具调用结果 | 追加 + 超限裁剪 | 只注入最近若干轮 |
| 长期记忆 | 跨会话的用户偏好、历史结论 | 按需检索 | 命中时才注入 |
槽位用 schema 定义,不要用自然语言描述
把”要收集什么”写成结构化定义,模型才知道自己还差什么:
{
"intent": "book_meeting",
"required": ["date", "time_range", "attendees"],
"slots": {
"date": { "value": "2026-10-20", "source": "user", "confidence": 0.95 },
"time_range": { "value": null, "source": null, "confidence": 0 },
"attendees": { "value": ["张三"], "source": "inferred", "confidence": 0.6 }
},
"missing": ["time_range"],
"needs_confirm": ["attendees"]
}
注意 source 和 confidence 两个字段:区分”用户明确说的”和”模型推断的”是澄清策略能否做对的前提。推断值必须回问确认,用户原话不需要。
{"raw":"下周三下午","value":"2026-10-21T14:00"}。回显时用原始表述,执行时用归一化值,可以避免一轮一轮的转述误差。澄清策略:什么时候必须问
澄清问得太多用户会烦,问得太少会办错事。可用四条规则约束:
- 必填缺失 → 必问:
required里没有值就问,不做默认假设。 - 推断值低于阈值 → 回问确认:例如置信度 < 0.8 的参会人,回问一句”包括张三,对吗?”。
- 一轮只问一个:同时缺三项时按影响面排序问最关键的,不要甩一串问题给用户。
- 给备选而不是开放提问:「下周三下午 2 点还是 4 点?」的完成率远高于「您希望几点?」。
missing_slots = [s for s in required if not slots[s]["value"]]
if missing_slots:
ask_one(missing_slots[0]) # 只问第一个,问完再评估
elif low_confidence:
confirm(low_confidence[0]) # 确认推断值
else:
execute(intent, slots) # 槽位齐了才执行
过程态怎么裁:三档策略
Anthropic 在 Claude 开发者平台上给出的思路有实测数据支撑:上下文编辑(自动清理陈旧的工具调用与结果)单独使用带来 29% 的性能提升,与记忆工具组合使用提升 39%;在 100 轮的网络搜索评测里,上下文编辑让原本会因上下文耗尽而失败的任务得以完成,同时 token 消耗降低 84%。对应到自建智能体,可以拆成三档:
过程态裁剪三档(点击展开)
- 第一档:硬截断。只保留最近 6–10 轮完整消息,更早的压缩成一段摘要。实现成本最低,先上这一档。
- 第二档:工具结果单独裁剪。工具返回往往占大头,只保留结论字段,把原始 JSON 换成”调用了 X,返回 3 条,关键字段为……”,并在需要时保留一个可再次获取的引用 ID 。
- 第三档:分层摘要。每满 N 轮生成一次滚动摘要,摘要里强制保留:当前目标、验收标准、已做决策及理由、失败过的尝试。这四项丢了,压缩后就会重复踩坑。
话题切换与目标漂移怎么处理
用户中途改主意是常态,靠”最近消息优先”自然覆盖是不稳的。做法是在每轮开局先做一次意图判定:
- 新意图与当前意图同类(如改会议时间)→ 更新槽位,保留任务上下文。
- 新意图不同类(如从订会议室跳到查天气)→ 把当前任务态压栈,新建任务态;用户说”刚才那个继续”时再弹栈恢复。
- 判定为闲聊或不确定 → 不改动任务态,避免污染。
如果业务流程本身步骤固定、分支明确,那么更稳妥的做法是把流转写死,不要让模型每轮决定下一步,这一点在智能体编排什么时候该用状态机里有更详细的讨论。
和其他能力怎么衔接
对话管理的三个邻居经常被混淆,边界是这样的:
- 长期记忆:跨会话保存用户偏好与历史结论,属于”记住这个人”,不是”记住这轮对话”。三层拆分方式见智能体长期记忆的实现。
- 断点续跑:把任务态持久化到外部存储,进程重启后能恢复,属于”可恢复性”。与裁剪互补而非重复,可参考智能体断点续跑与中断恢复。
- 结构化输出:槽位的抽取结果必须由 schema 约束并做校验重试,否则”看起来填上了”的槽位可能是半截值,做法见智能体结构化输出的三道关。
历史消息保留多少轮合适?
槽位抽取不准怎么办?
压缩历史会不会丢掉关键信息?
用户中途换话题,原来的信息还要留着吗?
澄清问太多导致流失,有折中办法吗?
一句话收尾:多轮对话的稳定性来自”状态结构化”,而不是”上下文变大”。把任务态抽出来单独管,过程态按档裁剪,剩下的交给模型即可。










评论 (0)