年底很多团队都在做智能客服项目,我最近也帮几个朋友梳理了他们手里的客服意图识别模块,发现大家踩的坑出奇一致:不是模型效果不行,而是根本不清楚意图识别到底该怎么做、怎么评估、怎么迭代。这个标题我一看就觉得该写点什么——大模型干意图识别这事,确实是最容易上手、也最能直观感受到大模型价值的方向之一,但网上能找到的资料要么太学术,要么只给Prompt不给工程。所以这篇我准备从零开始,把"用大模型做智能客服意图识别"这件事拆开揉碎讲清楚,哪怕你之前只调过API,也能照着落地一版能上线的方案。
1. 先定义清楚:意图识别在客服系统里到底是干什么的
1.1 一个典型场景:客服机器人答非所问的尴尬
先看一个非常常见的对话失败场景。用户上来就问"我上周买的手机壳颜色发错了,能换吗",结果机器人回复了一串商品百科——"我们的手机壳采用液态硅胶材质,轻薄防摔,多色可选"。用户当然不满意,后面大概率就是"转人工"三个字。
这出尴尬的根子在于,机器人只做了关键词匹配("手机壳"、"颜色"命中了商品介绍),但是没有识别出用户的真实意图——"售后换货申请"。意图识别干的事情,就是把用户这句口语化表达,映射到业务系统能理解的一个类别标签上,比如售后退换_发起申请,然后路由到对应的处理流程。
1.2 意图识别在整个客服链路中的位置
很多文章一上来就讲Prompt怎么写,但我觉得先看清楚位置更重要。一个完整的智能客服链路通常长这样:
- 输入层:接收用户消息(文本/语音转写),做基础清洗、拼写纠错
- 意图识别层:判断用户想干什么,输出意图类别和关键槽位
- 对话管理/任务编排层:根据意图和槽位决定走什么流程、问什么补全问题
- 知识检索/生成层:从知识库/文档中检索答案,或由大模型组织回复
- 兜底与人工切换:低置信度、敏感词、用户主动要求转人工时切换通道
可以明显看到,意图识别是上游中的上游。意图判错了,后面所有的对话策略、知识检索、答复生成全都会跟着跑偏。说白了,意图识别是客服机器人"听得懂人话"的第一道关卡,做得好直接决定用户的耐性与怒气值。
1.3 大模型做意图识别和传统方案的本质区别
如果是传统方案,我们一般会做意图分类模型。早期用词频、TF-IDF加一个分类器,后来用BERT做文本分类微调,效果都不错,但有几个硬伤:新增一个意图要重新准备几百条标注样本并重训模型;遇到用户口语化的自由表达,比如"我不是特别喜欢这个颜色所以想退",很容易分错;不同业务线之间的意图体系完全隔离,换个场景基本从头再来。
大模型方案直接改变了工作模式。它靠的是自然语言理解能力和Few-shot(少样本)推断能力,你给我几个意图定义和样例,它就能基于对语言的理解把新句子归到正确意图里去。这不是"分类器学了一堆特征",而是模型"读懂"了你的业务意图接着去判断句子。
我的结论是:现在做客服意图识别,优先考虑大模型方案,别再去折腾重新训练BERT分类器。它更适合业务迭代快、意图繁多、表达复杂多变的客服场景,而小样本冷启动、新意图快速上线这些需求,恰好是大模型最擅长的地方。
2. 大模型意图识别的核心工作逻辑:从分类到语义匹配
2.1 为什么大模型在做"分类"时不需要重新训练
先放下API和代码,把原理弄清楚。传统文本分类是把句子映射到一个固定标签集合,本质是"模式匹配"。比如BERT的[CLS]向量过了Softmax函数输出标签分布,这个标签空间是训练时定死的。但大模型做分类更接近"语义相似度匹配加阅读理解":
- 模型在预训练阶段已经见过海量的文本,理解了词的上下文含义
- 我们把意图定义和示例直接拼进Prompt,模型"现看现学"
- 生成时它会根据当前句与给定定义的语义贴合程度,输出对应标签
打个比方,传统分类器像是固定菜谱的厨师,菜系是培训时定死的;大模型是见过各国料理的老厨师,你给他一张写了几句做法的便签,他就能按你的便签临场发挥,做出符合要求的那道菜。
2.2 Few-shot与Zero-shot区别:样例到底给不给
业内经常看到Zero-shot(零样本)和Few-shot(少样本)两个词。Zero-shot就是不提供该意图的任何示例,只给意图名称和一句描述,让模型猜测;Few-shot是在Prompt中给每个意图附上几个典型的说法作为示范。
我个人的体会是,客服场景下务必要用Few-shot。原因很简单:中文客服表达花样太多。同一个"想退款"能说成"钱能退吗"、"我不想要了,怎么弄"、"你们退钱给我吧"、"我要申请售后"。如果没有几个示例在,模型很容易把"钱能退吗"误判为"查询退款政策"。给上三五个例子之后,模型很快就能推出"哦,这类都是用户想发起退款",准确性明显提升。
这里有个实操参考:每个意图的例子至少给3条,5条以上更好,但一个意图给到10条之后边际收益就明显变低了,样本集臃肿还可能拖慢推理速度,成熟项目一般控制在4~6条。
2.3 输出必须是结构化数据,而不是一段自然语言
这是很多第一次做大模型意图识别的人最容易忽略的坑。如果你让模型"请判断用户意图",它给你返回一段文字:"用户想退货,而且询问退货地址,还想知道运费谁出"。好,你接下来在代码里怎么解析?用正则匹配?那和大模型的优雅完全背道而驰了。
正确做法是用约束性Prompt + JSON Schema让模型输出结构化结果。比如规定输出格式为:
{ "intent": "售后退换_发起申请", "confidence": 0.93, "slots": { "order_id": "202412071234", "reason": "发错颜色" }, "needs_human": false }这样,模型返回一个字段,代码拿到intent字段做路由,拿到slots去填充业务系统参数,拿confidence和needs_human做兜底判断。结构化输出的格式要求直接影响整个下游工程链路的顺畅度。
在实际工程里,建议在Prompt里用JSON Schema给出字段类型和枚举范围,同时要求模型只输出JSON、不要额外解释。目前主流的大模型API都支持JSON Mode或Response Format参数,能有效提高JSON格式的稳定性和可解析率。
3. 实战第一步:意图体系设计,这是没有代码但决定成败的一步
3.1 别一上来就列100个意图
我在不少项目里看到过一个非常典型的问题:业务同学一口气列了80个意图,觉得覆盖全面,结果模型上线后怎么调准确率都上不去。为什么?一个是意图之间定义模糊,另一个是各意图的样本严重不均衡,还有的是低频意图太多、根本无法通过少数示例稳定召回。
设计意图体系的第一原则是:能合并的合并,能树形的树形。比如"退款到账时间咨询"、"退款失败原因查询"、"退款进度查询"这三个其实都可以归到一个父意图"退款进度与结果查询"下,再通过槽位(slot)区分具体需要的信息。意图识别跟槽位抽取应该分工:意图识别回答"用户在做什么",槽位抽取回答"这件事的具体细节是什么"。把细节塞进意图名称,只会让分类器越来越难做。
好的意图体系大概长这样(供参考):
| 父意图 | 子意图示例 | 典型用户说法 |
|---|---|---|
| 售后退换咨询 | 申请退货 / 申请换货 / 查询退换进度 | "怎么退货" / "衣服大了能换小一码吗" / "我退的件签收了吗" |
| 订单相关 | 催发货 / 改地址 / 查物流 | "怎么还没发货啊" / "地址帮我改下" / "到哪了,快递" |
| 商品咨询 | 商品参数咨询 / 库存咨询 / 优惠咨询 | "这个支持快充吗" / "还有L码库存吗" / "有优惠券吗" |
| 账户与售后状态 | 修改账号 / 投诉建议 | "手机号停用了怎么登录" / "我要投诉你们门店" |
3.2 每个意图的定义描述比样例更重要
很多教程强调给样例,但我发现意图描述的质量往往更关键。因为大模型理解抽象描述的能力很强,一句清晰的"适用范围、不包含什么"比5个样例还能避免混淆。
我写意图描述有一个固定结构,供参考:
- 意图名称:清晰不歧义的短语,比如"售后退换_发起申请"
- 触发场景:用户在什么情境下会说出这句话
- 包含内容:应该归到这里的典型行为
- 不包含内容:边界情况,明确排除
举个例子:
- intent: 售后退换_发起申请 description: 用户明确表达要退货/换货/退款,需要发起售后处理流程。 example: ["我申请退货", "想换个大一号的", "这个能退吗,刚收到的", "衣服质量问题怎么退"] excluded: 仅询问退换政策或退换流程,未表达发起操作意图的,应归入"售后退换_规则咨询"不加excluded的话,模型很容易把"你们家的退换货政策是什么"这类信息咨询也判成"发起申请"。加上排除说明之后,这类边界句子的误判率可以肉眼可见地下降。
3.3 这个小数据集怎么攒起来
确定了意图体系后,就要准备Few-shot样例了。这个阶段不需要准备成千上万条,通常每个意图几十条候选,最终Prompt里挑4~6条即可。怎么挑?有讲究:
- 覆盖面优先:选择表达方式差异明显的句子,而不是都差不多的句式
- 包含口语化与错别字:客服场景真的会收到"能换个吗?换也行退也行",准备一条这种模糊表达,模型就会知道这属于意图边界或偏推荐意图
- 覆盖真实用户高频说法:从历史客服对话和工单里捞真实句子,比我们自己编的干净话有效得多——真实用户会使用大量口语、省略和语义跳跃,这是任何编写样例都无法替代的。上线后一定要及时沉淀线上badcase并补进样例库,后面我单独讲。
这里有个建议,初始样例如实在没有真实数据,可以结合业务经验先编一些,但上线后一定要用真实线上日志来替换和扩充。虚拟搭建的样本在真实场景面前很容易失真,真实数据的反馈比“看起来合理的样例”可靠得多。
4. 实战第二步:Prompt工程与模型接入,实际操作全步骤
4.1 一个可以直接使用的意图识别Prompt模板
下面是经过多个项目验证的模板,直接可复用。关键点都在注释里:
你是一个智能客服系统的高精度意图分类引擎。 你的任务是读取用户消息,结合给定的意图列表,识别用户本次对话的核心意图并抽取必要槽位。 【意图定义】 - intent: 售后退换_发起申请 description: 用户明确表达要退货/换货/退款,需要发起售后处理流程。 examples: - "我申请退货" - "想换个大一号的" - "这个能退吗,刚收到的" - intent: 售后退换_规则咨询 description: 用户询问退换货政策、流程、时效,但未表达发起退换货操作。 examples: - "你们退换货需要什么条件" - "七天无理由含运费吗" - intent: 转人工 description: 用户要求联系人工客服、投诉、表达强烈不满或明确要求人工处理。 examples: - "转人工" - "叫个人来跟我说" 【输出要求】 严格输出一个JSON对象,格式如下: { "intent": "意图ID,从上面列表中选择;无法确定时输出 unknown", "confidence": 0到1之间的一个数字,表示你对该判断的自信程度, "slots": {"字段名": "从用户消息中抽取的具体字段值"}, "needs_human": true或false,遇到高风险投诉、人身攻击、转人工请求时置为true } 注意:只输出JSON,不要输出任何解释。 【用户消息】 {用户消息}如果项目使用JSON Mode(即API参数中返回结构化格式的功能),建议将以上的"输出要求"部分硬编码在系统提示中,同时打开结构化输出参数。目前主流大模型的相关能力已经比较成熟,一致性和稳定性有保障。
4.2 代码层面如何接入大模型API并解析结果
下面用一个简单的Python接入示意,把关键处理逻辑讲清楚。实际项目中还需要替换为你的API地址和密钥管理方式,这里只做结构示范:
import json from openai import OpenAI client = OpenAI( api_key="你的密钥", base_url="你的API服务地址" ) def intent_recognition(user_message: str): # system是固定模板 system_prompt = load_intent_prompt() # 上一节中的完整模板 # 这里把新用户消息拼接进提示词 user_prompt = f"【用户消息】\n{user_message}" resp = client.chat.completions.create( model="你的模型标识", messages=[ {"role": "system", "content": system_prompt}, {"role": "user", "content": user_prompt} ], temperature=0, response_format={"type": "json_object"} # 强制JSON格式 ) result = json.loads(resp.choices[0].message.content) # 后处理逻辑 if result.get("confidence", 0) < 0.6 or result.get("intent") == "unknown": # 低置信度或未知意图,路由到人工或澄清话术 return route_to_confirmation(result) if result.get("needs_human"): # 高风险/转人工场景 return route_to_human(result) return route_to_workflow(result.get("intent"), result.get("slots"))这里要特别强调的是temperature参数务设置成0(或最小)。意图分类是判别式任务,不需要创造性,温度一旦调高,同一句话可能时而返回这个意图时而返回那个,线上会很不稳定。
4.3 正式环境中Prompt与模型升级的版本管理
一步到位把Prompt写完美?可不现实,一定得迭代。为了支持快速回退与A/B对比,承接团队最好不要把Prompt"裸写"在业务代码里,而是引入提示词版本管理。
实践中可以考虑这样组织:
- 把系统提示词独立为单独的配置文本(
.yaml/.json,或存放在配置平台),存版本号 - 每次修改记录变更原因、影响范围、效果变化
- 通过简单的"版本号 + 输入消息"打进日志,方便事后回溯是哪个Prompt版本产出了这个结果
我见过有的项目直接把几千字的Prompt硬编码在Python文件里,改一个样例要发一次版,实在太痛苦。提示词是要和代码一样做版本管理的,它本身就是一部分"逻辑"。
4.4 响应性能预算:你可不希望用户等5秒才收到机器人回复
除了准确性,响应速度也是一个关键指标。大模型接口的响应时间相比传统分类要高不少,尤其在客服这种对实时性敏感的场景,直接同步调用且不设超时容易带来较差的体验。
方案上通常有两条路可走:
- 首级粗分 + 二级精分:先用一个轻量级分类或关键词匹配把用户问题路由到少数几个可能的意图,再让大模型在这几个候选意图里做精细判断。这样Prompt更短、判断更准,也更快。
- 大模型异步化:先返回正在处理中的话术,后台调用大模型识别后,再将结果推送给用户。适用交互场景允许稍等片刻,可以进行异步预处理。
我的实际建议是:预算充足且意图较少(比如少于30个)时,直接单次调用即可,300ms~800ms都可以接受;意图多(超过50个)时,最好做候选粗筛,把每次Prompt的意图数量控制在10个以内,效果和时延都能显著改善。
5. 实战第三步:兜底策略、置信度与多轮对话状态管理
5.1 置信度阈值与"我不确定"话术
有些做客服系统的同学会忽略一个东西——模型服务的"点是"的能力比"识别错误意图但硬猜"要好得多。当confidence低时,宁可让机器人回一句"抱歉,我还没完全理解你的意思,你是想咨询退换货,还是想查询订单进度?",也不要强行按一个不自信的意图去路由。
阈值怎么定?没有标准答案,但我可以给一个参考范围:confidence < 0.6 时进入澄清流程,0.6~0.8 之间进入人工复核或泛化话术,> 0.8 直接路由对应流程。这个阈值要根据业务可接受的误判成本调整:如果意图路由错了会导致给用户发错优惠券、申请错误售后流程,阈值可适当调高;如果是纯粹的FAQ问答,答案错了伤害不大,阈值可以放宽。
进入澄清流程有一个灵活的做法:把候选的2~3个意图作为多个选项呈现给用户,让用户一键选择,能大幅缓解模型单次判断不够准的问题,而且用户也很习惯这种交互。
5.2 多轮对话中"意图"是会变的,不能每次都从零判断
客服对话很少一句话完事。比如:
- 用户:"我要退货"
- 机器人:"请提供订单号"
- 用户:"等一下,其实我想先问下退货运费谁出"
第二句"退货运费谁出",如果单看字面,很可能被识别为"售后退换_规则咨询",没问题。但如果用户在上一轮已经发起退货,当前轮次实际上是询问当前申请进程的中间问题,意图就属于"上下文中关于运费规则的咨询",而非"规则咨询"这么简单。更严重的情况是,用户第二句直接回答订单号"202412071234",这句话本身根本没有可识别的意图,必须结合上文状态才能理解。
所以在工程实现上,我们不能只做"单句意图识别",还要维护一个对话状态机:包括当前槽位是否齐全、当前处于哪个业务流程阶段、哪些意图在当前阶段有效。大模型可以做到一个很实用的折中方案:
- 将最近2~3轮的对话摘要(或原文截断)一并放到Prompt里作为"对话上文"
- 配合一句明确的指令:"结合上下文,判断用户当前这句的意图,如果用户只是在回答系统提问,则输出对应补充槽位类型"
- prompt里给出当前流程状态,让模型决策"继续当前流程"还是"切换到新意图"
一个可靠的工程建议:不要只靠大模型全权管理状态,最好用代码管理状态机(已经进入售后流程就标记状态),意图识别只负责"当前这句是新增意图还是对当前问题的回答"。
5.3 与客服工作流系统的对接细节
意图识别结果要真正产生价值,必须落到业务动作上。我总结的对接模板如下:
- 直接路由:意图+槽位齐全,直接调用后端API执行(如提交退货申请、变更地址)
- 反问补全:槽位缺失,触发追问子流程(如"请提供订单号")
- 人工切换:
needs_human=true或用户连续2次表达不满,无条件转人工 - 低频/模糊意图:先匹配到知识库FAQ,不触发业务操作
- 日志与监控:所有识别结果都要入库,包含原始消息、Prompt版本、模型返回、最终路由、用户后续反馈,这是优化数据资产的来源
通常客服系统不是只有大模型识别,还会有规则引擎、敏感词过滤、用户画像策略,这些东西配合起来,才是一个完整的客服大脑。
6. 效果评估与线上调优:那些评测数据里看不出来的事
6.1 离线评测与在线指标,两套体系都要有
离线评测,就是在准备一批带标签的测试集(一般300~500条即可覆盖各意图),计算意图准确率和槽位抽取F1。这里强调精度、召回两个维度都要看,尤其要注意**"拒识能力"**,也就是面对没见过的边界表达时,模型有不有底气返回unknown,而不是硬编一个意图。
在线指标主要有三个:
- 意图识别首次命中率:指用户进来的第一句话就被正确理解并路由到正确的处理流程比例
- 澄清话术触发率:模型主动说"没听懂"的比例,过高说明识别能力没有跟上,过低说明模型在"硬猜"误判
- 人工转接率:最终需要人工介入的比例,这是客服团队最关心的核心指标之一
别只盯离线准确率,一个离线90%准确率的系统上线后人工转接率可能非常高,不断有边界情况绕过了评测集——评测集没有覆盖真实用户那些“不太讲道理”的表达。
6.2 高频翻车现场:我见过的典型误判与解法
这里列几个高频误判案例,都是我实际见过的,遇到过的同学应该会很有共鸣:
| 用户原话 | 错误识别 | 正确意图 | 怎么解决 |
|---|---|---|---|
| "你们家退货运费是到付还是先付?" | 售后退换_发起申请 | 售后退换_运费规则咨询 | 在规则咨询的描述中明确提出“未发起操作也适用”,样例增加"运费谁出"类语句 |
| "我不要了" | 售后退换_发起申请 | 需结合上文(可能是在回复是否继续购买) | Prompt引入上文,让模型判断“是否只是在确认取消” |
| "你号多少我加你" | 转人工 | 添加客服微信/企微 | 单独增加意图“联系方式获取”,不与转人工混在一起 |
| "你们是机器人还是真人?" | 转人工/投诉 | 关于服务主体的询问 | 属于特殊意图,单独定义,回复话术可设计为幽默澄清 |
这些误判的共同根源是:我们只在意图定义阶段“脑子里想”用户会怎么说,但真实用户比我们想象得更加多样化。所以从线上捞badcase再补进提示词样例中,是比任何理论优化都更有效的手段。
6.3 从线上数据回流建立"意图样本库",持续迭代
前面说过,大模型Few-shot模式的最大优势是迭代快速,一个坏案例被修正后能立刻生效。我的建议是把样例库建设当作一个持续运作的任务来做:
- 每周从客服日志里抽一波低置信度、转人工前、被用户反复追问的对话
- 人工打标梳理:是什么意图,模型错在什么地方
- 将新典型句子补入对应意图的examples,替换掉表现差的旧样例
- 记录版本变更,跑一遍离线回归测试,再发新版提示词
这个机制一旦跑起来,意图识别就会像滚雪球一样越用越准。很多团队做不好不是技术不够,是没有建立数据回流的闭环机制。
7. 关于成本、规模与大模型选择的一些现实考量
7.1 模型选型:不是越大越快就越好
做意图识别,模型选型也是要动脑筋的。大模型现在确实强,但对意图分类这个相对简单的任务,真不一定非要上最强的大参数模型。我见过不少团队用最大、最贵的模型跑一个只需要判断20个类别的小任务,成本高不说,推理时延还大。
我个人的选型思路是这样的一条判断链:
- 意图类别<20个、表达相对规范:优先本地部署的中等参数开源模型即可,成本低、速度快
- 意图类别20~50个、表达口语化明显:可以考虑中大规模API模型,或者本地部署稍微侧重推理能力的模型
- 意图类别>50个、有大量多轮和多槽位需求:搜索增强与多级分类结构都得上了,模型也要保证较强的推理能力
- 数据隐私要求高、不允许出域:无论如何都得考虑本地部署方案,此时要注重大小合适的模型
成本上也要会算账:意图识别调用量大,一个日活几万的客服机器人,每个月可能产生几百万次请求。按照某些定价来计算,确实是一笔不小的开支。但可以理解的是,我们并不需要每次都让最贵的模型出场,很多简单句子的识别完全可以用低成本方式完成,有必要时再做分级调用。
7.2 分级模型调用策略:省钱又保效果
这里推荐一个我实际用过的分级调用架构,既能控制成本也不牺牲体验:
- 第一级:精确命中知识库或规则推荐时,直接返回答案,不调用大模型
- 第二级:常规语句(比如"订单号查一下我怎么查"),用轻量模型或通用对话快车道处理
- 第三级:复杂、模糊、转人工风险高的语句,才走到更强的大模型来做细粒度意图识别
这种分级机制能让大模型调用量下降一半以上,同时让最重要的疑难句子得到最充分的分析。做客服系统的朋友们可以留意一下:成本优化不是从“少用模型”入手,而是从“让合适的模型处理合适的句子”入手。
7.3 把大模型放进客服体系中:它只是大脑不是全部
最后想强调一个容易被忽视的点:大模型是能做意图识别,而且能做得很好,但它只负责“理解”这一环。一个真正好用的客服系统,还需要业务知识库、订单系统、库存系统、售后系统的流畅联动。意图识别模型准确率提到95%,如果后面接的流程一塌糊涂,用户依然只会觉得“这机器人真蠢”。
所以在做智能客服意图识别这个项目时,早期的重点工作要放在整体链路梳理上:用户在各渠道可能说什么、哪些话需要直接转人工、哪些问题能通过自助方式解决。模型的价值是在这套链路里发挥最大作用,而不是在一个孤立的模块里追求最高score。
8. 最后分享一点个人实战心得
如果你最近正准备在这个方向动手,我的建议是先别急着写代码,找个周末把客服历史对话翻一翻,随便挑500条真实用户消息看一遍,把高频表达和让人看了一愣、不知道该怎么归类的话都记下来。这份语感会直接影响你的意图定义质量和Prompt设计水平。我接手过的项目里,凡是前期没做这步的,后期都花了至少两周在擦屁股。
另外一个小技巧:把Prompt里的意图描述和示例用yaml格式编排,既便于维护,也方便复制到各类API的system消息里。别用一长串纯文本、用意图拼接的方式写,那样后面维护的时候会非常想骂人。
这篇所讲的方案,本质上是用大模型的“理解力”替代了传统“投喂数据+训练”的模式。只要你把意图体系设计清楚、Prompt写得规范、兜底策略做扎实,再配合一套持续捞badcase回流的机制,意图识别这个模块就能稳稳支撑起一个不错的智能客服体验。至少在我经手的项目里,这套玩法比以往微调模型效率高出不少,也更容易让不懂技术的业务同学看懂、参与进来。