多轮对话中用户意图演化,大模型迷失根因与应对方案

多轮对话意图演化大模型
于 2026-08-29 04:22:35 修改
·本内容遵循CC 4.0 BY-SA版权协议

LLM 在用户意图不断演化时确实会“迷失”,这是我在多轮对话评测里反复验证过的真问题。用户说第一句时,需求往往只是模糊方向;随着对话推进,他才慢慢补充时间、地点、对象和偏好,甚至中途推翻前面的设定。模型如果只对着最近一条消息生成答案,很容易给出通顺但完全对不上需求的结果。这篇文章不讨论大模型“聪明不聪明”,而是拆解意图演化场景下 LLM 丢信息的根因,以及从提示词、历史摘要、对话状态追踪到批量评测的落地方案。适合正在做客服机器人、Agent 应用、AI 助手或任何需要多轮对话的产品开发。

1. 当用户意图反复变化时,LLM 为什么容易“迷失”

1.1 一个典型的多轮对话场景:从查天气到订行程

先看一个非常常见的对话演变链路。用户一开始只问天气,中间插入出行查询,最后又追加酒店需求:

  • 用户:杭州这周天气怎么样?
  • 助手:这周杭州以多云和阴天为主,周三可能有小雨。
  • 用户:那周三上午从杭州去上海的高铁有票吗?
  • 助手:查询到周三上午有多趟高铁,最早一班是 G7302,8:15 发车。
  • 用户:帮我选一个发车早一点的,到了之后再找一家离虹桥站近的酒店。

如果把这个对话交给一个只做单轮指令的 LLM 应用,没有额外的历史管理,它看到最后一条消息时,上下文可能是最近两三轮的简单拼接。模型有可能理解“要选一辆早班高铁”,也可能理解“要订酒店”,但未必能同时保留“周三上午”“杭州到上海”“虹桥站近”三个约束。用户没有重复这些约束,因为他默认助手记得。这就是演化型意图和普通多轮问答的差别:不是每一轮都从零提问,而是在前一意图上不断增删改查。

这种场景在真实业务里非常普遍。客服系统里,用户先问“退款多久到账”,然后补一句“我是用信用卡付的”,再改成“那我还能换货吗”。这三个请求共享同一个订单对象,但语义目标完全不同。如果产品只做一个“大模型聊天框”,没有状态管理,LLM 很容易把退款历史和换货意图搅在一起。

1.2 模型“跟着最近消息走”的两个后果

我在实测时发现,模型处理这种连续演变时,最容易出现两种后果。

第一种是“局部最优”。模型把最近一条用户消息当成完整指令,生成一个局部通顺的回复。单独看这条回复没有任何问题,但放到真实对话链路里就是答非所问。比如最后一步,模型直接输出虹桥站附近的酒店列表,却忘了用户还要“早一点的高铁”这个前置需求。

第二种是“上下文冲突被掩盖”。用户说“把时间改成后天”,模型可能知道这是对时间约束的修改,但如果不清楚“哪个任务的时间”被修改,就会把时间槽改到整个对话的最新主题上。表面看回复合理,实际上约束被错误迁移。这个问题比“答非所问”更难发现,因为普通审核很难看出来模型是不是搞错了对象。

造成这两种后果的根源,不是模型的句子生成能力,而是应用层没有建立“当前意图状态”的概念。模型可以流畅地组织文字,却缺少一个显式的状态变量来记录:用户之前确认过什么、最近改了什么、哪些约束仍然有效。这个判断在单轮对话里不重要,在多轮演化场景里就是决定成败的一环。

2. 根因剖析:不是模型笨,而是上下文建模方式有缺口

2.1 相关性衰减:旧信息被新信息淹没

先做一个简单的思想实验。你给模型 5000 个字的历史记录,然后在末尾问“所以我的预算上限是多少”。模型在生成回答时,注意力机制会自动分配权重:和“预算上限”直接相关的片段权重高,和当前问题关系不大的片段权重低。问题是,用户在前几轮提到的预算,可能不像表面看起来那样和当前问题无关。

意图演化场景里,“旧约束”不是无用背景,它必须和“新指令”合并才能得到正确答案。比如前面例子里的“周三上午”是最早出现的约束,但在回答最后一条消息时,它必须继续生效。模型在长上下文里更关注新出现的“酒店”“虹桥站”,于是“周三上午”“高铁”这些较早的信息被当成低权重历史,最终没有参与生成。

这不是模型“记忆容量不够”,而是相关性计算让旧信息在局部任务里被稀释。上下文窗口越长,这种稀释不一定会消失,反而可能因为中间夹杂大量无关内容而更严重。

2.2 缺少显式的“当前目标”状态

任务型对话系统里通常有一个概念叫“对话状态”,也就是当前这一轮系统认为用户想要什么、已经提供哪些参数、还缺哪些参数。LLM 单轮模型默认没有这个状态变量,它只能从上下文里“重新推断”当前目标。每次推断都有概率损失,随着轮数增加,损失会累积。

你可以把 LLM 想象成一位内容生成专家,但旁边没有专人记录会议结论。每轮对话都需要它自己回忆“刚才说了什么、现在要做什么”。对话短时问题不大,一旦出现“我改了三次日期、换了两个目的地、又增加一个新需求”这种复杂链路,单靠隐层记忆根本扛不住。

解决方向不是在模型里加记忆,而是在应用层增加一个显式的状态管理模块。这个模块负责记录意图和槽位的每一次变化,并把最新状态注入提示词。模型还是那个模型,但输入信息被整理过,输出自然更稳。

2.3 指令遵循能力强,不代表历史建模能力强

现在的主流 LLM 做单轮指令遵循已经很强。给它一个明确的 prompt,按照步骤执行,结果通常不错。但多轮对话不是多个单轮请求的简单拼接,而是带有状态约束的序列决策任务。

一个模型可以在“请列出杭州到上海的高铁”这种清晰请求上表现很好,但当你给它一段包含历史、摘要、用户最新消息、以及各种业务规则的复杂上下文时,它可能不知道该优先遵循哪一部分。指令越长、约束越多,模型越容易在生成时走偏。

所以当意图追踪出现问题时,不要立刻怀疑模型“能力不够”。很可能是上下文组织方式没有给模型提供足够清晰的优先级。比如,系统提示词里写了“要保留用户历史约束”,但历史约束分散在 8 轮对话里,模型在解码时很难每一轮都去核对。更好的做法是把“当前有效约束”单独拉出来,放到靠近用户消息的位置,并且用结构化格式表示,让模型一眼看到重点。

3. 给 LLM 装上“意图方向盘”:工程化处理方案

3.1 方案一:对话状态追踪,显式记录槽位和意图

对话状态追踪(Dialog State Tracking,简称 DST)是传统任务型对话系统里最核心的模块之一。它的思路很直接:定义一组业务槽位,每轮用户消息进入后,先提取槽位更新,再维护一份“当前状态”,最后用这份状态去生成回复。

一个出行场景的状态示例:

JSON
{
"current_task": "book_hotel_and_train",
"origin": "hangzhou",
"destination": "shanghai",
"departure_time": "2025-01-08 morning",
"transport": "high_speed_rail",
"hotel_preference": "near_hongqiao",
"hotel_status": "pending"
}

每一轮用户说“改成中午出发”,状态管理器把 departure_time 从 morning 改成 noon,并保留其他槽位不变。生成回复时,系统把这份状态注入 prompt,模型只需要基于状态输出自然语言。

这种方式的缺点是槽位需要业务人员预先设计。对于开放域聊天,很难用槽位穷举所有意图。所以比较推荐用在业务边界清晰的任务型场景里,比如订票、退款、售后、预约。

3.2 方案二:意图重写,每轮都生成一条自包含的当前问题

如果你不想维护复杂的槽位,可以走“意图重写”路线。核心逻辑是:在把用户最新消息交给业务 LLM 之前,先用一个重写步骤,把“历史摘要 + 最新消息”合并成一条自包含的完整问题。

示例重写输入:

TEXT
用户历史意图:周三上午从杭州到上海,坐高铁,发车要早。
用户最新消息:到了之后帮我找一家离虹桥站近的酒店。

示例重写输出:

TEXT
当前用户完整需求:我需要先预订周三上午从杭州出发到上海虹桥的早班高铁,然后找一家离虹桥站尽可能近的酒店。请同时处理两个任务,不要忽略高铁时间约束。

这个重写结果再交给主 LLM,模型就不需要从长历史里自己找线索。重写方案的优点是不需要业务槽位,实现成本低,适合需求变化灵活的对话场景。缺点是重写本身有概率出错,而且如果历史摘要里已经丢了信息,重写再努力也补不回来。所以在实践里,我一般会把摘要和重写放在一起用。

流程可以简化为:

TEXT
1. 取最近 N 轮历史或历史摘要
2. 调用重写模型,得到自包含的当前意图
3. 把当前意图和系统 prompt 一起发送给业务 LLM
4. 返回最终回复,并更新历史摘要

3.3 方案三:用历史摘要替代原始上下文

长对话如果总是把全部历史塞进上下文,有两个问题:一是 token 成本高,二是旧信息被稀释。历史摘要是更工程化的做法。

摘要在每轮结束后由 LLM 生成,也可以每 N 轮更新一次。它的内容要围绕“可用状态”而不是“发生了什么”。什么意思?不要只写“用户问了天气”,而要写“用户预定出发时间:周三上午;出发地:杭州;目的地:上海;当前待办:高铁票+酒店”。因为后者才是后续生成真正需要的状态信息。

JSON
{
"goal": "完成从杭州到上海的高铁预订,并订一处近虹桥站的酒店",
"constraints": {
"date": "2025-01-08",
"time_of_day": "morning",
"departure": "hangzhou",
"arrival": "shanghai_hongqiao",
"hotel_near": "hongqiao_station"
},
"confirmed": ["早班高铁"],
"pending": ["选择车次", "预订酒店"]
}

摘要要简洁、结构化、可覆盖。如果业务模型是直接读 JSON 的,摘要就按 JSON 传;如果是自然语言生成,摘要可以写成一句完整的话。关键是“可覆盖”,也就是后续轮次可以基于它更新,而不是每次从零重建。

3.4 方案四:轻量规则做意图漂移检测

不是所有应用都需要引入大模型做状态管理。如果业务固定,可以用规则先做一层意图漂移检测。

当用户消息中出现“不过”“改成”“换”“不是”“算了”“其实”“还是”这类词时,触发一个标记:当前轮可能存在意图变更。此时应用可以优先重写对应槽位,或者要求用户确认,而不是直接把整段历史扔给模型。

规则层的好处是快、可解释、方便上线。坏处是覆盖有限。例如用户不说“换成”,只说“那酒店不要了”,规则未必能判断出这是“撤销酒店意图”。所以规则层更适合做“第一层闸门”,更复杂的语义变化仍然要用 LLM 判断。

4. 落地方案:先跑通单条对话,再做批量验证

4.1 最小可运行流程设计

我第一次接触这类问题时,习惯先把流程拆成四步,避免一上来就搞一个复杂系统。

第一步,准备一组带意图演化的对话样例。不需要太多,20 到 30 组足够。每组至少包含三轮:初始意图、约束细化、目标变更。样例里要明确标注“哪一轮发生了变化、变化后哪些约束仍然有效”。

第二步,实现一个最基础的版本:只把最近三轮对话拼起来,直接发给 LLM。跑一遍,记录结果。这一步是基线。

第三步,加一层摘要或意图重写,再跑同一组样例。把两步结果放在一起对比。

第四步,记录每一轮的成功、失败、原因,然后针对失败样本优化提示词或状态更新逻辑。

为什么要先做基线?因为你不做基线,就分不清多轮表现差是因为模型本身,还是因为你的摘要或重写逻辑引入了错误。我踩过几次的教训是:新模块加得越多,越难定位问题。有一版系统加了摘要、缓存、槽位三个模块,某一天多轮意图突然全断,最后发现是摘要里的 JSON 字段被截断,根本不是模型问题。

4.2 核心处理逻辑示例

下面是一个带意图重写的处理流程伪代码。它不绑定具体框架,重点是展示顺序。

PYTHON
def handle_turn(history, user_message):
# 1. 从历史中提取或更新摘要,摘要保存当前目标、已确认约束、待办项
summary = get_or_update_summary(history, user_message)
 
# 2. 用摘要和最新消息生成一个自包含的完整意图
rewritten_intent = rewrite_intent(summary, user_message)
 
# 3. 用完整意图调用业务 LLM,生成回复
reply = call_business_llm(rewritten_intent)
 
# 4. 把本轮消息和回复写回历史,并准备下一轮摘要更新
history.append({"user": user_message, "assistant": reply})
 
return reply, history

第 2 步非常关键。如果重写出来的是一个缺约束的问题,后面 LLM 再强也答不对。所以实际验证时,我会先单独检查 rewritten_intent 是否正确,再看最终 reply。不要一上来就把整条链路都当成黑盒。

4.3 成功标准和失败判断

测试时一般用三个判断点:

  • 重写后的意图是否保留所有有效约束。
  • 最终回复是否和重写意图一致。
  • 多轮之后,摘要里是否还保留最初的关键条件。

第二个判断点失败,问题通常在生成环节。第一个判断点失败,问题通常在历史摘要或重写 prompt。第三个判断点失败,说明摘要更新策略需要调整。

每次只锁定一个环节去查。先看重写结果,再看最终输出,最后看摘要。这比直接改 temperature 或换模型高效得多。

4.4 批量验证时,如何设计任务和日志

单条对话能跑通后,就需要批量验证。比如 30 组对话样例,每组 5 轮,一共 150 次调用。这里有几个容易被忽略的工程点。

第一,任务编号和输出命名要统一。每一组样例要有唯一 ID,每一轮输出也要有轮次号。否则结果一混,你不知道哪条对话出现了意图丢失。

第二,失败重试策略要明确。LLM 接口偶尔会超时或返回异常,简单重试可以,但要设置重试次数上限,并且记录重试原因。

第三,日志一定要保存“实际发送给模型的 prompt”。这是排查看不到数据时最重要的依据。很多多轮问题,日志里存的只是用户和助手文字,看不到系统提示词、摘要 JSON、重写结果,事后排查非常被动。

第四,并发数不要一开始就拉满。如果目的是验证意图丢失比例,并发太高会导致接口限流,反而把问题复杂化。先低并发跑一轮,确认日志结构没问题,再逐步提高。

5. 从原型到生产:评估、日志、部署和常见坑

5.1 多轮意图演化场景的评测指标

单轮准确率覆盖不了意图演化问题。实际评估时我会增加几个更贴合场景的指标。

指标 含义 怎么判断
约束保留率 最终回复里是否包含已确认的约束 人工或规则检查回复中的日期、地点、对象等
意图变更检测准确率 模型是否正确识别用户在某轮发生了意图变化 对比标注好的意图变化点和模型输出
状态更新准确率 槽位值是否正确更新 检查 DST 模块输出的 state 与标准答案是否一致
指代消解成功率 代词是否指向正确实体 用标注样本统计“它”“那家”等指代对象
重写一致性 重写后的意图和原始历史语义是否一致 人工评分或对比关键实体

这些指标不需要一开始全上。可以先选约束保留率和重写一致性,这两个最贴近“意图演变过程中信息不丢失”的核心目标。等系统稳定了,再补状态更新和指代消解。

评测集是关键。建议维护一份“意图演化评测集”,里面分三类:

  • 细化型:在原意图上增加约束。
  • 替换型:推翻部分约束,换成新值。
  • 撤销型:取消某个意图或某个前置条件。

每一类至少 10 个样例,模型每次改动后都跑一遍。没有评测集,你很难判断“这次改动是变好了还是变差了”。

5.2 排查链路:先看日志,再看输入,最后调参数

多轮对话表现变差时的排查顺序,我一般固定为五步。

第一步,看日志里实际发给业务 LLM 的 prompt 是什么。这一步能判断输入是否完整、摘要是否过期、重写是否丢失约束。

第二步,看历史摘要。确认它是否更新到了最新状态,有没有把“周三上午”错误地改成“周四”或直接删掉。

第三步,看意图重写结果。确认重写后的自包含问题是否覆盖了所有仍然有效的约束。

第四步,看用户原始消息和上一轮回复。排除是不是用户表达本身有歧义。

第五步,确认以上都没问题,才去调整模型参数,比如 temperature、top_p、最大 token 或者切换更合适的模型。

为什么要坚持这个顺序?因为大多数“模型不听话”都发生在输入构造阶段。如果 prompt 里根本没有正确信息,调温度、换模型都是浪费。

5.3 框架和部署环境怎么选,不一定要全装在同一台机器

处理意图演化时,你可能需要用到 LLM 推理框架、对话状态管理模块、历史数据库和业务服务。初学者容易产生一个错觉:这些模块必须装在同一台电脑上,或者必须用同一个框架。实际不是这样。

是否放在同一台机器,取决于延迟要求、数据隐私和资源占用。

如果只是一个学习 Demo,全装在同一台机器上没问题。但一旦要接真实对话或批量任务,就要单独看每个服务的资源曲线。比如本地跑一个大模型做推理,显存和内存占用很高,再让同一个进程处理复杂的对话状态管理和日志写入,很可能拖慢响应速度。

有些项目把 LLM、向量库、Agent 编排全部塞在一台机器上,小规模没问题,并发一上来就容易出现“某个服务把资源吃满,其他服务全部排队”的现象。更稳妥的做法是先明确模型服务是单独部署还是内网共享,再决定业务服务放在哪里。并没有“必须同机”的规定,只有“当前场景是否合适”的取舍。

如果你在本地机器上跑推理,同时想接一个外部工具做状态管理,完全可以通过接口调用。配置时重点关注网络延迟、超时时间和调用频率。不要因为教程里写了 A 和 B 装在一起,就认为你的环境也必须这么装。

5.4 个人建议:先用增量改造,不要一次堆满组件

最后说下我自己的偏好。每次接到“LLM 多轮对话意图老跑偏”这类需求时,我不会第一步就上复杂的 DST 加槽位管理。我会从增量改造开始。

第一版只做意图重写,配合最近 N 轮历史。 第二版加历史摘要,把长对话压成结构化状态。 第三版再根据业务引入规则检测或真正的 DST。 第四版再看是否需要独立部署模型服务或接框架。

每一步都留评测记录。每加一个组件,都拿同一份意图演化评测集跑一遍。这样既能规避“组件太多导致问题难以定位”,也能持续对比收益。如果重写和摘要已经能解决 90% 的问题,就不必急着做完整 DST。

回到标题的问题:LLMs Get Lost in Evolving User Intent,与其说是模型能力短板,不如说是应用层对“用户当前完整意图”的管理不到位。用户在线下聊需求时,天然会不断细化、替换、撤销;可很多产品只是把它当成一个普通聊天框,把最近几句话丢给模型,剩下的就看运气。把意图重写、历史摘要和必要的状态追踪补上之后,模型的表现通常会明显稳定下来。这是我在多轮对话项目里最深刻的体会:不是先换更大的模型,而是先让模型每次都能看到一份整理好的“当前完整需求”。

AI对齐监控:为何OpenAI投入20%算力,以及开发者如何应对
OpenAI将20%算力投入AI对齐监控,标志着从静态对齐向动态行为校准的范式转变。该监控涵盖输出、行为内部表征三层,依赖对抗性评估、可扩展监督、沙盒仿真等高算力技术。其核心挑战在于平衡能力迭代安全成本,并推动MLOps中嵌入分层监控、红队测试可观测性集成。行业正转向能力安全协同进化的治理新范式。
weixin_30851867
398
构建高可靠AI智能体系统:从架构设计到评估体系的工程实践
本文聚焦AI智能体从单点演示到生产级系统的关键跃迁,系统阐述面向可靠性的架构设计(含组件解耦、图状决策循环、安全气囊机制)、多维评估体系(功能性、非功能性、长期演化指标)及可观测性落地方法。强调将智能体视为软件系统,需具备容错、降级、回滚、监控告警混沌测试能力,并指出评估基准缺失、长记忆工程、复杂规划不确定性、多智能体协作对抗安全等深水区挑战。
weixin_34413103
309
Gemini为何比GPT更顺?拆解AI协作文档的交互设计本质
本文深入拆解Gemini相比GPT更流畅的底层原因,指出差异核心在于交互设计而非模型能力。重点分析三大技术支柱:上下文保真度(智能分层语义锚点)、响应延迟感知(神经科学级节奏控制)、多模态对齐一致性(端到端联合建模)。同时揭示错误恢复三级熔断、视觉微动效、协作文档范式等工程细节,强调其在真实知识工作流中的体验优势。
weixin_30920513
352