嵌入向量给用户问题做意图分类路由实操

发布时间:2026/6/29 20:53:37
嵌入向量给用户问题做意图分类路由实操 先说结论一个入口要应付好几类问题别再堆 if-else 关键词了。把用户那句话先转成嵌入向量跟你预设的几个意图样本算余弦相似度谁近就路由到谁的处理链——退款走退款链查物流走物流链闲聊扔给兜底。我上个月给一个内部客服机器人这么改完误分类肉眼可见地少了一截。我踩到的那个问题背景是这样。我们组维护一个给运营同学用的小工具入口就一个输入框啥都能问。一开始我图省事用关键词匹配做分流句子里有退就当退款有到哪了就当查物流。跑了两周运营群里炸了。有人问这单为啥退不了——里面有退路由到退款链结果人家是想查物流状态卡在哪。还有人打错字把物流写成无流直接掉进兜底回了句没听懂。关键词这玩意儿对语义一点感知都没有换个说法就抓瞎。我盯着日志看了半天决定换嵌入。分类路由怎么做分四步思路不复杂核心就是把匹配字面换成匹配语义。第一步给每个意图准备几条样本句。别只写一条。比如查物流我写了我的包裹到哪了快递怎么还没动单号查一下到哪这么三四条覆盖不同说法。第二步把这些样本句全部过一遍嵌入模型存成向量。这步离线做一次就行结果缓存起来。我直接存内存里了几十条向量而已没必要上向量库。第三步用户问题进来实时转成向量跟每个意图的样本向量算余弦相似度。取每个意图里最高的那条当该意图得分。第四步谁分高走谁但要卡个阈值。最高分低于 0.75 我就判定没匹配上扔兜底链让大模型自由发挥别硬塞。一段能跑的核心代码import numpy as np # 意图样本离线先转成向量缓存好 INTENTS { refund: [我要退款, 这单想退掉, 钱怎么退回来], logistics:[包裹到哪了, 快递还没动, 查下物流到哪], } def cos(a, b): return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b)) def route(query_vec, intent_vecs, threshold0.75): best_intent, best_score None, -1 for name, vecs in intent_vecs.items(): score max(cos(query_vec, v) for v in vecs) # 取该意图最近的一条 if score best_score: best_intent, best_score name, score return best_intent if best_score threshold else fallback # route(embed(我这单为啥退不了), intent_vecs) - refundembed()就是调嵌入接口拿向量剩下全是 numpy。真没多少行。一个真把我坑住的地方阈值这事我栽过。一开始我把 threshold 设成 0.6想着宽松点别漏。结果闲聊和正经问题全被归到最近的业务意图去了——有人发了句在吗居然被判成查物流因为跟某条样本沾了点边。后来调到 0.78 又太严正常的问句被踢进兜底。来回试了大半天最后落在 0.75并且发现一个细节阈值跟你用的嵌入模型强相关换个模型这数得重调。不同模型出来的向量分布不一样余弦值的高低刻度根本不通用。所以别抄别人的阈值自己拿一两百条真实日志跑一遍分布看错分都卡在哪个值再定。另外多嘴一句脏细节样本句别写得太书面。我最早样本全是请问我的订单物流信息如何查询这种端着的句子结果用户大白话东西到哪了反而匹配不上。后来把样本改成跟用户一样的口气准确率立马上去了。写在后面整套搭下来其实最花时间的不是代码是攒样本句和调阈值。代码两小时调参两天。搭这个分类器的时候我没自己撸服务是在一个零代码就能配智能体的平台上拖出来的——意图分类、知识库、几条处理链拉一拉就连上了省了我搭框架的功夫。当然它也就帮你把杂活串起来真正的业务逻辑和样本还是得自己抠指望它一键生产可用机器人是不现实的第一版出来照样干巴巴。你们做多意图路由是怎么定阈值的还在用关键词的评论区聊聊我挺好奇有没有更省事的招。嵌入和大模型我走的讯飞星辰 MaaS现成 API 调没自己部署算力。