一个用户在同一句话里说出两个互相矛盾的需求,或者连续几轮对话中的意图发生了转变,这时系统该听谁的?这是对话系统和智能助手在真实业务中最常遇到的难题之一。意图冲突并不可怕,可怕的是系统没有一套明确的裁决机制,导致随机响应、答非所问。本文围绕意图过滤和承诺策略两个核心手段,聊聊如何把冲突处理从玄学变成工程。

意图冲突是怎么产生的
先弄清楚冲突的来源,才能对症下药。第一类冲突是句内冲突,也就是用户在一条话术中同时表达了多个意图。比如用户说:帮我订明天去北京的机票,顺便把上周那个订单退了。这句话里既有订票意图,又有退单意图,如果意图识别模块只输出一个最高分结果,另一个意图就被粗暴丢弃了,用户会觉得系统没听懂后半句话。
第二类冲突是跨轮次冲突,即多轮对话中前后意图发生了变化。用户第一轮说要查询账单,第二轮突然改口说不用查了,直接帮我缴费。如果系统还在沿着查询账单的流程走,就会出现驴唇不对马嘴的回复。这种冲突的本质是上下文状态没有及时更新,旧意图没有被新的表达覆盖。
第三类冲突是系统级冲突,来自多个业务模块或多个识别模型对同一句话给出了不同判断。比如规则引擎认为这是投诉意图,分类模型认为这是咨询意图,两边分数还不相上下。这类冲突在系统逐渐复杂、多模型并存的项目里非常普遍,也是最难处理的一种,因为它涉及架构层面的裁决权分配。
意图过滤:把无效和低质意图挡在门外
意图过滤的第一道关卡是置信度阈值。识别模型通常会给每个候选意图打分,低于阈值的意图直接过滤掉。但固定阈值有明显缺陷:闲聊类意图天然分数偏低,业务类意图分数偏高,用同一把尺子量所有意图必然误伤。更合理的做法是按意图类别分别设置阈值,或者引入相对差距判断——只有当第一名分数超过第二名一定幅度时才认为是明确意图,否则进入待定状态。
第二道关卡是优先级仲裁。当多个意图同时通过置信度筛选时,需要按业务优先级排序。常见的设计是给每个意图配置优先级字段,高危操作(如转账、退款)优先级最高,查询类次之,闲聊类最低。下面的伪代码展示了这种过滤逻辑:
def filter_intents(candidates, context):
# 第一步:按类别阈值过滤低置信度意图
valid = [c for c in candidates
if c.score >= THRESHOLDS.get(c.name, 0.6)]
if not valid:
return None # 全部低于阈值,进入澄清流程
# 第二步:检查意图之间的相对差距
valid.sort(key=lambda c: c.score, reverse=True)
if len(valid) > 1 and valid[0].score - valid[1].score < 0.15:
return None # 分数接近,无法明确裁决
# 第三步:同分情况下按业务优先级仲裁
return max(valid, key=lambda c: (c.score, c.priority))第三道关卡是上下文一致性过滤。有些意图单独看分数很高,但放进当前对话上下文就显得不合理。比如用户正在退款流程的第三步,此时识别出一个订餐意图,即使分数不错也应该被降权或挂起。上下文过滤的核心是维护一个会话状态栈,只有与当前状态兼容的意图才有资格胜出。这层过滤能拦截大量误识别,是实际项目里性价比最高的手段。
承诺策略:何时拍板、能否反悔
过滤解决的是谁有资格胜出,承诺策略解决的是什么时候确认、确认之后还能不能改。过早承诺的风险是误判后难以挽回,过晚承诺则让用户重复表达、体验拖沓。工程上通常把承诺分为三个等级:立即承诺、延迟承诺和试探承诺。
立即承诺适用于高置信度、低风险的场景,分数高且操作可逆就直接执行。延迟承诺适用于低置信度或高风险场景,系统先挂起决策,通过一轮澄清话术向用户确认:您是想退款还是想咨询退款进度?试探承诺则介于两者之间,系统按最可能的意图推进流程,但在关键节点留出纠偏窗口,比如我已为您查询账单,如需缴费请说缴费。
承诺之后还必须有撤销机制,否则一次误判就会让用户陷入流程死胡同。撤销设计有两个要点:一是定义清晰的撤销触发条件,包括用户显式说不要了、改口了,或者识别到与当前承诺意图冲突的新意图;二是定义回滚深度,简单的场景只需终止当前流程,复杂的场景要恢复到之前的会话状态快照。
class CommitStrategy:
def decide(self, intent, context):
if intent.score > 0.85 and intent.risk == "low":
return self.commit(intent) # 立即承诺
if intent.score < 0.55 or intent.risk == "high":
return self.clarify(intent) # 发起澄清
return self.soft_commit(intent, context) # 试探推进
def on_new_intent(self, new_intent, committed):
# 新意图与已承诺意图冲突且优先级更高时触发撤销
if new_intent.name != committed.name \
and new_intent.score > committed.score \
and new_intent.priority >= committed.priority:
self.rollback(committed)
return self.clarify(new_intent)
return committed落地建议与常见误区
把过滤和承诺组合起来看,一个健壮的意图冲突处理管线应该是:识别输出多个候选、置信度与相对差距双重过滤、上下文一致性校验、优先级仲裁、按风险等级选择承诺等级、配套撤销与澄清机制。每一层都不要省,很多团队只在置信度上做文章,结果线上还是频繁出现答非所问,问题往往出在缺了上下文校验和撤销机制。
几个常见误区值得提醒。第一,不要追求一次识别就百分百正确,澄清话术不是失败而是正常交互手段,设计得好反而能提升用户信任。第二,优先级表不要写死在代码里,业务方会频繁调整规则,配置化是基本要求。第三,日志要记录每次冲突的完整候选列表和裁决依据,否则线上问题排查会变成猜谜游戏。冲突处理没有银弹,但它非常吃数据反馈——把每次澄清和撤销都回流成标注样本,识别准确率会进入良性循环,系统也会越用越聪明。