LLM意图漂移:多轮对话中如何应对用户临时变卦
2026/9/9 10:36:09 网站建设 项目流程

聊天机器人也好,Agent 工具也好,很多人第一次用 LLM 时都有一种“这玩意儿真聪明”的感觉。可一旦进入真实业务场景,比如让模型充当客服机器人、售前导购、技术助理,你会发现一个非常隐蔽、又特别致命的问题:用户聊着聊着就变卦了。

比如用户先说“我想查一下上个月的订单记录”,等模型把订单数据调出来后,用户紧接着说“算了,不查了,帮我退掉其中那笔 499 的订单”。如果你只是机械地执行“查询订单”这个动作,模型大概率会把两句话当成两个独立任务来处理,甚至可能因为上下文窗口里的旧意图权重太高,继续围绕“查订单”展开,而非识别出用户已经切换到“退款”这个新目标。

这不是模型笨,也不是 API 调用写错了。这是 LLM 在“演变中的用户意图”面前的典型困境。本文不准备复述那些宣传稿式的“大模型很强大”的套话,而是想从原理、现象、工程应对三个层面,把这件很多人踩过坑、又说不清楚的事讲透。

这篇文章适合正在做对话系统、Agent 应用、客服机器人,或者准备把 LLM 接入真实业务流的开发者。读完你会明白:LLM 为什么会在意图演变时掉链子;从工程角度看,该怎么设计上下文、记忆和任务分发;以及哪些坑是你无论换多少个 Prompt 模板都躲不掉的。

1. 这篇文章真正要解决的问题

不知道你有没有遇到过这样的对话场景:

用户输入:“帮我看看北京明天到上海的高铁。”

模型给出了车次列表。用户紧接着输入:“算了,还是帮我看看机票吧。”

很多简单的 LLM 对话应用,到这里就开始出问题了。有的模型会把“机票”理解成“高铁”的补充条件,继续查高铁;有的模型干脆宕机式的回复“您说的是高铁还是机票?”,把已经明确表达的新意图又打回原地;还有的模型给出机票结果后,又额外附带了一句“顺便提醒您,高铁票也可以预订哦”。

这不是个别模型的 bug,而是所有基于固定上下文窗口做意图理解的模型面对“意图漂移”时的通病。所谓“意图漂移”,是用户在实际对话中的目标不总是一成不变,会随着信息反馈、情绪变化或新想法的出现而转向新的任务方向。如果系统把“用户意图”理解成“用户第一句话里提取出的任务标签”,那后面的对话一旦转向,系统就会在旧意图和新意图之间迷失。

这篇文章要解决的核心问题有三个:

第一,理解 LLM 在意图演变中失败的深层原因,不是“模型不行”这么简单,而是训练目标和推理机制共同造成的结构性缺陷。

第二,识别哪些场景最容易触发意图漂移,以及为什么 Prompt 工程只能缓解、不能根治。

第三,给出工程可落地的应对策略,包括状态管理、意图确认、上下文摘要和任务回退机制。

如果你正在用 LangChain、LlamaIndex 或自研 Agent 框架搭建对话系统,这篇文章里的大部分方案都可以直接借鉴,并不限定具体框架。

2. LLM 意图理解的基本原理与局限性

2.1 什么是“用户意图”

在传统对话系统里,“用户意图”通常指用户通过自然语言表达的、希望系统完成的具体目标。工程上会把它建模成一个分类标签,比如“查询订单”“申请退款”“修改地址”“取消订阅”。

传统的意图识别方法是训练一个文本分类模型,输入一句话,输出一个意图标签和对应置信度。例如输入“我要退掉那件 499 的外套”,分类器会输出“退款意图,置信度 0.92”,然后对话管理器根据这个标签触发对应的业务流程。

LLM 问世后,意图识别不再被显式建模为分类问题。模型通过海量语料学习到的语义理解能力,可以直接从对话文本中推断用户想干什么。你不需要定义固定的意图标签集,模型也能理解“帮我把那单 499 的门票处理了”是在说退款。

但这里有一个非常容易被忽略的问题:LLM 的意图理解天然偏向“即时性”。也就是说,模型倾向于从最近的输入、最近的上下文窗口里推断当前意图,而不是从整个对话历史中的“用户目标轨迹”来推断。这就像一个记忆力很好但注意力有限的人,能记住你说的每句话,但判断你当下意图时,总是被最后一句话带跑。

2.2 上下文窗口不是“记忆”

很多人以为,把对话历史全部塞进 LLM 的上下文窗口,就等于给了模型“记忆”。这句判断在短对话里勉强成立,在长对话和意图演变场景里完全不成立。

上下文窗口本质上是模型处理输入时的“可视区域”,它不像人类记忆那样有主次之分、有遗忘曲线。窗口里的每个 token 对模型来说是平等计算的(尽管注意力权重有差异,但模型并不会主动区分“这是旧意图”“这是新意图”)。当旧意图的表述数量多、细节丰富,而新意图只有一句话时,模型很容易把新意图当作旧意图的补充或修正,而不是一个全新的任务方向。

这就解释了为什么用户连续追问了很多轮高铁信息后,突然说“算了,查机票吧”,模型经常会傻掉。因为前面 10 轮高铁细节已经在上下文里占据了绝对的信息量,新输入“机票”这个 token 虽然语义明确,但在注意力分布上并不一定压得过前面累计的“高铁”相关信息。

2.3 核心局限:缺乏“意图生命周期”建模

传统对话系统里有一套成熟的理论框架叫“对话状态跟踪”,系统会维护一个状态变量,比如current_intent=query_order,并根据每轮用户输入更新这个状态。这就是“意图生命周期”的工程化体现:意图有开始、有持续、有切换、有结束。

LLM 的对话架构里,意图并没有被显式建模为可跟踪的状态。它的存在形式是“上下文中的语义指向”。模型阅读全部对话历史,自己决定当前应该做什么。这种设计的好处是灵活、不需要定义固定状态机,坏处是当用户意图切换时,模型没有机制去“重置”旧意图,只能靠语义推理硬扛。

这就是“LLMs Get Lost in Evolving User Intent”这个标题背后真正的技术痛点:模型擅长理解“当前这一句话”的意图,却不擅长驾驭“一段对话里不断演变”的意图流。

3. 哪些场景最容易触发意图漂移

并不是所有对话场景都会出现意图漂移问题。理解哪些场景高发,能帮助你在设计阶段就做好预案。

3.1 多轮任务型对话

用户与系统交互多轮,且每一轮都有可能修正、扩展或完全改变目标。典型场景是客服系统:用户先问“发票怎么开”,得到答复后又问“那你们发货用什么快递”,这两个问题看似相关,但意图已经从“发票办理”跳到了“物流查询”。

3.2 信息探索型对话

用户在探索过程中逐渐明确自己的真实需求。例如用户问“有什么适合送女朋友的礼物”,系统推荐了项链,用户说“她不喜欢戴首饰,换个别的”,系统推荐了香水,用户又说“她对香味敏感”。这个过程中,用户的意图在一步步收敛,同时也在一层层否定前序意图。如果系统死守第一次推荐时建立的“首饰偏好”上下文,后面就会越推越偏。

3.3 混合多意图对话

一句话里包含多个意图,或者一句话随着条件变化从意图 A 转向意图 B。比如“这个商品还有库存吗?算了不用看了,直接下单吧”。如果没有识别出“库存查询”已经结束、“下单”已经开启,系统很可能会把“直接下单”当作库存查询的附加条件。

3.4 长会话中的意图回归

用户在最开始问了一个问题,中间聊了别的话题,最后又绕回第一个问题。这种“意图回归”场景下,如果系统没有把第一个问题的目标状态保存好,很容易在用户绕回来时表现得像失忆了一样。

4. 核心原因拆解:LLM 为什么会在意图演变中丢失方向

这个现象的技术原因可以拆成五层,每一层都有对应的工程解决方案。

4.1 上下文中的信息优先级混乱

Transformer 的注意力机制会让模型根据所有历史 token 与当前 token 的相关性动态分配注意力权重。看似合理的设计,真实场景里却有一个问题:用户意图的优先级是由“对话目标的当前相关性”决定的,而不是由“token 语义相似度”决定的。

举个例子,用户前 20 轮都在讨论“退货退款流程”,最后突然说“那顺便帮我把会员续费取消掉”。从语义相似度看,“退货退款”与“会员续费”都是用户账号相关的服务,注意力机制很可能会把新意图归入旧意图的语义场,而不是判定为“这是一个全新的任务”。用户转向的其实是完全不同的一条业务线,但模型感知不到这种“业务边界”。

工程上的应对思路是:不要把所有历史无差别地塞进上下文,而是对历史做结构化摘要,把“已完成的任务”和“当前活跃任务”分开存储。

4.2 指令遵循强于状态跟踪

LLM 经过指令微调后,非常擅长“遵循指令”。但“遵循指令”和“跟踪状态”是两回事。

假设系统 Prompt 里写着“你是一个电商助手,负责处理用户订单相关问题”,用户说“帮我查订单”,模型遵循了“查订单”的指令。当用户说“我改主意了,不查了,我要投诉快递”,模型仍然在“订单助手”这个角色设定下工作,它很难意识到:用户已经从“查询任务”切换到“投诉任务”,这不仅是意图变化,更是服务流程的变化。

这其实暴露了 Prompt 设计的一个盲区:Prompt 定义了模型的身份和能力边界,却没有定义“当用户意图变化时,如何跨越这个边界”。

4.3 训练目标的先天缺失

从训练角度看,LLM 的核心训练目标是“根据前文预测下一个 token”。这种训练方式让模型具备强大的文本连贯性能力,但并没有专门针对“用户目标轨迹追踪”进行优化。

通俗地说,模型学会了“顺着说”,但没有学会“记住目标”和“感知目标变化”。它能把对话续得通顺漂亮,但用户心底里真正想完成的任务是否变了,模型没有内建机制去判断。

4.4 对话历史的等权处理

在多数 LLM 对话应用里,对话历史就是一个字符串列表,按时间顺序拼接到 Prompt 中。每一轮对话在模型看来都是线性排列的 token,没有“这一轮很重要”和“这一轮可以忽略”的区分。

当你把 30 轮对话全部塞进上下文,里面可能包含 10 轮已经完成的任务、5 轮闲聊、3 轮用户情绪表达,最后 2 轮才是真正的当前意图。模型要从这些混乱的信息中准确提取当前意图,难度可想而知。

4.5 缺少“确认机制”

人类对话中,当听者不确定对方是否转换话题时,会自然地问一句“你是说……吗?”“你要的是这个吗?”。但 LLM 应用普遍没有这种机制。模型倾向于直接回答或直接执行,而不是在关键节点做意图确认。

在工程上,训练一个“是否发生意图切换”的二分类器,或者在检测到高风险意图漂移时强制模型生成澄清问题,都是可行的补救措施。

5. 一个容易复现的示例场景

为了让你对这个现象有体感,我写了一个最小 Python 示例,用 OpenAI API 模拟一个“高铁查询”对话。这个演示不依赖复杂框架,核心是展示“意图漂移”如何发生。

import openai client = openai.OpenAI(api_key="YOUR_API_KEY") messages = [ {"role": "system", "content": "你是一个高铁票务助手,只能处理高铁相关的查询。"}, {"role": "user", "content": "帮我查一下明天北京到上海的高铁。"}, {"role": "assistant", "content": "好的,为您查询到以下车次:G1、G3、G5。请问需要预订哪一趟?"}, {"role": "user", "content": "G1 几点出发?"}, {"role": "assistant", "content": "G1 次列车早上 7:00 从北京南站出发。"}, {"role": "user", "content": "算了,高铁太慢了,帮我看看有没有合适的航班。"}, ] response = client.chat.completions.create( model="gpt-4o-mini", messages=messages, temperature=0.7, ) print(response.choices[0].message.content)

用户最后一句“算了,高铁太慢了”已经把意图从“高铁查询”切换到了“机票查询”,但我们之前设置的系统限定是“只能处理高铁相关的查询”。在这个设定下,模型很可能给出类似这样的回复:“很抱歉,目前我只能为您提供高铁查询服务,机票查询暂不支持。”从流程逻辑上它没有错,但从用户角度看,这个回答是相当僵硬的。

更现实的情况是:系统 Prompt 里没有限定业务范围,模型会直接开始列航班信息。听起来不错对吗?但它没有意识到,这个“航班查询”背后需要的流程、数据接口、权限体系,和“高铁查询”完全不是一套。如果代码里没有对“意图切换”做识别和路由,即使模型生成了航班信息,也只是“幻觉式回答”——它并不知道自己调用的接口并不存在。

这个例子的价值在于它揭示了意图漂移的一体两面:对纯文本生成来说,模型表面聪明的应对掩盖了系统对意图演变的“无知”;对真实业务系统来说,这种无知会导致接口调用错误、流程断裂甚至用户数据安全问题。

6. 实战策略:用“意图状态机 + 上下文摘要”让 LLM 找回方向

仅仅意识到问题,不能解决问题。工程上真正有效的是:不要把所有认知负担都丢给 LLM,而是用外部结构帮模型管理意图生命周期。

6.1 维护一张“意图状态表”

在 LLM 应用的内存或 Redis 里维护当前会话的意图状态,包含以下字段:

conversation_state = { "session_id": "session_001", "current_intent": "query_flight", "previous_intent": "query_train", "intent_history": [ {"intent": "query_train", "status": "completed"}, {"intent": "query_flight", "status": "active"}, ], "task_params": { "from_city": "北京", "to_city": "上海", "date": "明天", }, "needs_confirmation": False, }

每一轮用户输入到达后,不要直接拼进 Prompt 发给模型,而是先做一个轻量级的“意图识别”步骤。这一步可以用小模型、规则分类器,也可以再调一次 LLM。识别结果与当前状态比较,如果发现意图改变,就更新状态表,并决定是否需要在回复前向用户确认。

6.2 用“意图漂移检测器”做闸门

简单方案:维护一个高优先级的意图切换检测函数,只对用户最新输入做判断。

def detect_intent_shift(new_user_input: str, current_intent: str) -> bool: # 使用轻量分类器或 LLM 调用,判断新输入是否与当前意图一致 # 返回 True 表示意图已切换,False 表示延续当前意图 prompt = f""" 当前用户意图:{current_intent} 用户最新输入:{new_user_input} 请判断用户是否发起了新的、与当前意图不同的任务请求。 如果用户只是补充当前任务的信息,回答 False。 如果用户切换到了新任务,回答 True。 只输出 True 或 False。 """ result = call_llm(prompt) return result.strip() == "True"

这个检测器不需要很复杂。它的价值在于把“意图是否切换”的判断从“让模型在全量上下文中自行体会”变成“一个明确的二分类问题”。后者的准确率远高于前者。

6.3 意图确认:不确定时就先问

检测到意图切换后,不要急着执行新意图。先向用户确认一次,能避免大量无效调用。

def confirm_with_user(previous_intent: str, new_intent: str) -> str: confirm_prompt = f""" 用户之前正在处理:{previous_intent},现在提到:{new_intent}。 请生成一句友好的询问,向用户确认是否要切换到新的任务。 不要假设用户一定想切换,只是确认。 """ return call_llm(confirm_prompt)

这个设计看起来会多一次交互,但对用户体验的伤害远小于“自作主张”执行错误任务。特别是涉及支付、取消订单、修改数据这类高风险的业务操作时,意图确认是必须的。

6.4 上下文归档与摘要

当意图完成切换后,把旧意图相关的完整对话内容“归档”——从主上下文里移除,替换成一句摘要,给模型保留一个粗粒度的背景印象。这样可以显著降低旧意图对新意图的干扰。

def archive_context(session, completed_intent: str): # 获取该意图相关的全部消息 intent_messages = session.get_messages_by_intent(completed_intent) summary = summarize_messages(intent_messages) # 调用 LLM 生成摘要 session.remove_messages(completed_intent) session.add_system_message(f"之前用户曾处理过:{summary},但该任务已完成,请勿再主动提及。")

这么做的好处,用一句大白话说就是:当用户已经决定“不查高铁了”,你就别再把 20 轮高铁信息摆在桌面上了。让新意图得到干净的上下文环境,LLM 才能专注地发挥能力。

7. 评估意图跟踪能力:如何验证你的系统是否真的解决了问题

工程改进不能靠感觉。对于“意图演变”这一能力维度,建议针对性设计测试集和评估指标。

7.1 构建意图演变测试集

不能用普通的单轮问答测试集来验证这个能力。你需要构造“演变式”对话样本,每条样本应该包含:

  • 初始意图
  • 若干轮意图延续
  • 一次明确的意图切换
  • 切换后的新任务指令
  • 期望的系统行为

例如:

[ { "id": "case_001", "scenario": "用户先查天气,后转为订餐厅", "dialogue": [ {"role": "user", "content": "明天上海天气怎么样?"}, {"role": "assistant", "content": "明天上海多云,24-28 度。"}, {"role": "user", "content": "那帮我订一间明天晚上两人位的餐厅,推荐一下。"} ], "expected_behavior": "检测到意图从查询天气切换到预订餐厅,向用户确认餐厅需求,不继续输出天气信息" } ]

这种测试集的价值在于,它把意图漂移从“偶发现象”变成“可回归测试的既定场景”。每次修改系统 Prompt 或上下文策略后,跑一遍测试集,就知道改动是变好了还是变坏了。

7.2 评估指标

推荐三个指标:

意图切换检测准确率:系统是否正确判断了“何时发生了意图切换”。注意不要只算准确率,要重点看召回率——用户切换了意图但系统没发现,是危害最大的错误。

任务状态更新正确率:系统在意图切换后是否正确更新了内部状态表。这个指标决定了后续业务调用是否准确。

用户确认有效率:系统发出确认询问后,用户确认“是的,我要切换”的比例。如果这个比例很低,说明系统在不需要确认时反复打断用户,很影响体验。

8. 常见问题与排查思路

问题现象可能原因排查方式解决方案
用户切换意图后,系统仍按旧意图回答旧意图的上下文信息量过大,压过了新意图的语义权重检查发送给模型的完整 Prompt,观察历史消息拼接顺序引入意图状态机,切换后归档旧上下文
系统频繁打断用户确认“你是不是要说X”意图切换检测过于敏感,把补充说明误判为新意图查看意图检测日志,分析误判样本提高切换判定阈值,或要求检测器同时输出置信度
新意图执行时引用了旧意图的参数任务参数没有随意图切换而重置检查状态管理代码,看切换意图时参数是否被清空在意图切换逻辑中增加参数重置步骤
系统对长对话早期的意图“失忆”上下文窗口被后期对话占满,早期信息被截断查看 Token 使用量和对话历史保留策略引入摘要机制,将早期信息压缩后保留
模型在意图切换后仍然补充旧意图的建议Prompt 中没有明确“旧任务已完成”的指令检查系统 Prompt 和归档后的消息内容在切换完成后显式添加“旧任务已结束”的系统消息
有时切换检测失败,有时又能成功使用了温度较高的采样参数,导致判断不稳定检查意图检测调用的 temperature 设置将意图检测的 temperature 设置为 0 或极低值

9. 工程最佳实践:意图管理设计的五个建议

9.1 把“意图状态”当作一等公民

很多 LLM 应用的状态管理只有“消息列表”和“API Key”,没有显式的意图字段。这是导致意图漂移失控的根本原因。建议在会话数据结构中,把当前意图、意图历史、任务参数作为独立字段管理,而不是让模型从消息列表里自行推断。

9.2 用两层架构:规则层 + 模型层

纯靠 LLM 做意图识别,成本高且不稳定。纯靠规则做意图识别,又不够灵活。推荐做法是:用规则处理高确定性的意图切换(比如用户输入里包含“算了”“换个”“改成”“不要了”这些转折词),用 LLM 处理低确定性的语义意图切换。两层结合,既保证响应速度,又保证理解深度。

9.3 明确“意图确认”的业务规则

不是所有意图切换都要确认。给一个参考规则:

低风险意图切换(查询 A 变成查询 B,比如查天气变成查高铁):直接切换,不用确认。

中风险意图切换(查询变成预订类操作):快速确认一次,用轻量话术。

高风险意图切换(涉及支付、取消、修改、删除):必须确认,最好让用户完整口述一遍新意图,避免歧义。

9.4 记录意图切换的完整链路

不要把“意图切换”只当作运行时的临时状态,建议把它写入日志系统。至少记录:切换前意图、切换后意图、切换触发的那条用户输入、系统是否做了确认、用户最终是否确认了切换。这套日志对后续优化意图检测准确率,价值极大。你会发现,很多时候模型判断错误的模式,在日志里是有迹可循的。

9.5 避免过度依赖大模型做所有事

对话系统里最容易被忽略的,是那些“看起来很简单、不需要模型”的活。意图状态维护就是典型例子。让 LLM 只负责语义理解,让代码负责状态变更和流程控制,这个边界划得越清晰,系统就越稳定。

10. 技术选型参考:LangChain 与自研方案的取舍

如果你正在考虑用 LangChain 这类框架来构建对话系统,需要知道它对意图演变问题的支持程度。

LangChain 的核心抽象包括ConversationBufferMemoryConversationSummaryMemory等,它们解决的是“对话历史怎么保存、怎么压缩”的问题,而不是“意图状态怎么跟踪”的问题。这意味着你必须在其上自行实现意图切换检测和状态维护。

比如,使用 LangChain 时,可以在回调链中插入意图判断步骤:

from langchain.memory import ConversationSummaryMemory from langchain.chains import ConversationChain memory = ConversationSummaryMemory(llm=llm) conversation = ConversationChain(llm=llm, memory=memory) while True: user_input = input("用户:") if detect_intent_shift(user_input, current_intent): # 在切换意图时清空或归档 memory memory.clear() current_intent = extract_new_intent(user_input) response = conversation.predict(input=user_input) print("助手:", response)

这个示例展示的是“在 LangChain 基础上补一层意图状态管理”的思路。核心观点是:像 LangChain 这样的框架提供的是对话编排能力,而不是对话认知能力。意图跟踪需要你自己注入。

自研方案的优势在于你可以完全控制状态转换逻辑,适合业务复杂度高、意图类型有限的场景。LangChain 等框架的优势在于快速搭建和生态组件丰富,适合原型验证和轻量场景。

从我的经验看,一个生产级的对话系统,最终都会在状态管理上走向自研或深度定制。框架解决的是 70% 的通用问题,剩下 30% 的业务特异性,必须掌握在自己手里。

11. 从问题到实践:今天就可以开始的三个动作

如果你正在做一个真实的 LLM 对话应用,不必等系统推倒重来,下面三个动作今天就可以做。

第一步:检查你自己的会话状态设计。打开代码,找一下messages列表是在哪里维护的。如果整个会话只有一个字符串数组,没有任何对话状态字段,恭喜你,你找到了最需要改的地方。

第二步:给代码加一个简单的意图切换检测函数。不需要很精确,先用if判断用户输入中是否包含“算了”“改”“换”“不要了”这些触发词。把这些触发词作为意图切换的强信号。哪怕只覆盖 30% 的场景,也能立刻提升体验。

第三步:在系统 Prompt 中加一条限制:当检测到新意图后,系统消息中要追加“之前的任务已结束,请开始处理新的任务”。这个简单的提醒,能在很大概率上减少模型继续纠结旧意图的问题。

这三个动作的成本极低,都不需要改架构、不需要重新训练模型,但对真实对话体验的提升立竿见影。而当你把这三个动作都做完,再回来看“LLMs Get Lost in Evolving User Intent”这个话题,就会理解:模型的“迷失”,本质上是工程设计的“缺位”。大模型不是万能钥匙,它是一把性能优越、却需要导航系统的引擎。你要做的,不是在原地抱怨引擎不识路,而是开始给它装上传感器和地图。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询