意图识别是构建可靠人机交互系统的核心技术,其意义在于通过精准判断用户需求,为后续处理提供确定性基础。
尽管大型语言模型(LLM)具备强大的生成能力,但其输出可能生成错误、矛盾甚至违规信息。在金融、医疗、法律等监管严格领域,直接使用 LLM 结果可能引发合规风险,甚至导致重大经济损失或法律纠纷。
因此,多数严谨系统仍采用传统分层架构:首先通过意图识别技术解析用户输入的核心诉求(例如判断用户是查询账户余额、还是咨询理财问题);随后根据预设规则执行对应业务流程,调用专门的数据接口或知识库进行响应。
这种架构的优势在于:意图识别环节可过滤无效请求并拦截高风险输入,处理环节则通过结构化流程确保合规性与结果可靠性,既发挥人工智能的辅助作用,又通过分层设计规避技术不确定性带来的潜在危害。
因此,意图识别仍然是构建智能系统非常重要的一环。
意图识别的技术选择
BERT 类模型
意图识别是一个典型的文本分类问题。在 LLM 之前,广泛采用的是基于 BERT 类或预训练 BERT 类模型进行训练或微调的方法。这类方法通过大量语料训练,能够较好地理解语义,准确识别用户意图。
但是这类方法也存在明显的局限性。因为为了构建这样的模型,我们不得不:
- 花时间搜集准备大量语料,并进行标注
- 在有 GPU 的专用训练设备上面训练
- 部署在有 GPU 的专用推理设备上
这些步骤都将花费大量的时间,并且,由于模型是专用的,线上推理时也容易引起资源浪费问题。
基于 LLM 技术
在 LLM 的时代,意图识别有没有什么更好的做法呢?
LLM 能被广泛接受的原因之一是其强大的通用性。通过将任务描述成提示词,理论上同一个 LLM 能处理任何的问题。因此,LLM 的使用门槛极低,无需收集和标注数据,无需训练和部署模型,只需要将任务描述成提示词即可。
意图识别任务当然也可以用 LLM 提示词来表示。看起来,用 LLM 来识别意图可能是 LLM 时代一个相当不错的选择。准备语料、训练、部署这些繁琐的步骤全部被编写提示词替代了。
基于 RAG 技术
除了上述两种常见的技术之外,还有什么其他方法吗?
LLM 时代另一个被广泛使用的 RAG 技术(Retrieval Augmented Generation)事实上也可以用于处理分类问题。RAG 中的一个关键技术点是基于语义计算相关性。
一个直接的想法是,是不是可以:1. 搜集所有分类的真实文本,组织成一个文本库;2. 在文本库中检索待预测的文本;3. 找到结果中最高相关性的文本对应的分类作为预测分类。
看起来也是可行的,而且它也具备很多优势:
- 利用通用模型的能力,无需重头开始训练模型
- 结果具备可解释性
- 具备很强的可工程优化性,在发现预测不好的文本时,直接将此文本放入文本库即可提升下次预测的准确度
基于 Embedding+MLP 小模型方案
事实上,完全基于相关度的分类也有其问题,其中比较严重的可能是泛化能力偏弱。即,如果文本库中没有相似的说法,则很难正确分类。
有什么办法可以提升泛化能力呢?
我们注意到 RAG 的相关性计算过程是:
- 预先将文本库中的所有文本全部编码为向量存储起来
- 在预测时,先用同样的模型将待预测文本编码为一个向量,然后再用此和向量和文本库中的全部向量计算相似度
文本的向量化是 RAG 中的关键一环,事实上,生成的文本向量(也称做文本嵌入,即 Embedding)不仅可以用于计算相似度,还可以用来进行分类。
我们可以设计一个简单的 MLP 模型(Multi-Layer Perceptron,即多层感知器模型,是一个简单的多层全连接的神经网络模型),输入为文本向量,输出为分类标签。
这样,我们就可以在预测时,先将文本编码为向量,然后用 MLP 模型进行分类。
这个方案的优势在于:
- 依然可以利用通用模型的能力,无需重头开始训练模型
- 泛化能力更强,即使文本库中没有相似的说法,也可以通过 MLP 模型进行分类
- 由于利用了大部分的通用文本向量模型的能力,MLP 模型的规模可以做得比较小,从而使得 MLP 模型的训练和推理都非常快
集成的意图识别方案
上面介绍了常用的意图识别技术,可以看到有很多各有优劣的技术。那么,在实践时要怎么选择呢?
一般而言,可以综合这些技术,设计一个优势互补的集成的意图识别方案,以便满足实际产品运营过程中的多种不同的诉求,比如:
- 如何快速(如分钟级)而稳定地解决某些特定情况(如某些 ML 模型表现不太好的例子)的表现
- 在达到较高准确度的同时提升响应速度
- 在分布外(不同于预先识别到的场景及语料)的场景下表现也要相对较好
在真实场景中落地时,可以如下结合这些技术:
1 | flowchart TB |
由于 BERT 类模型可以被更简单通用的基于 Embedding+MLP 的技术替代,所以,这里就可以不考虑选择 BERT 类模型了。
这样的方案的优势在于:
- 通过基于 RAG 的相似度查找,可以快速(响应时间约在 300ms 左右)定位到与用户输入高度相似的历史文本,从而提高意图识别的准确性和效率。
- 在基于 Embedding+MLP 进行意图识别时,可复用上一步生成的文本向量,提高泛化性的同时,满足效率要求(10ms 左右)
- 通过上述两个步骤,希望能处理掉 80%以上的请求,即,可将 80%以上的使用场景响应时间都控制在 300ms 左右
- 对于另外的约 20%比较难的用户输入,则采用基于 LLM 进行意图识别,可以利用 LLM 的推理能力输出更准确的结果。这一步耗时通常较长,一般在 1~2s,但是由于只处理 20%的请求,对整体的响应时间影响较小。
- 对于整体上表现都不够好的用户输入,可以及时补充到 RAG 的文本库中,如果标注及时,可完成分钟级的意图识别准确度更新
可见,上述方案综合了各类技术的优劣,形成了一个具备高工程落地可行性的方案。
方案的实现
上述集成方案中的基于 RAG 的相似度查找和基于 LLM 进行意图识别两个步骤看起来难度都不算高。具备一定的调用通用大模型能力的背景即可快速完成。
下面主要分享一下工程实现过程中常常会碰到的几个问题。
语料准备
不管是在基于 RAG 的相似度查找,还是在基于 Embedding+MLP 小模型的步骤中都需要用到语料。
- 基于 RAG 的相似度查找需要预先构建一个文本语料库
- 基于 Embedding+MLP 小模型则需要构建训练语料及验证语料数据集
事实上基于 LLM 的技术也至少需要一个用于评估的数据集语料。
所以,语料的准备常常是意图识别中最重要也是最复杂的一部分内容。那么,在 LLM 的时代,有没有什么更高效的方法来准备语料呢?
我们当然可以利用 LLM 强大的文本生成能力来辅助快速构建语料了!
具体来说,我们可以先给出一些分类的标签及其说明,然后让 LLM 根据这些标签生成对应的语料。
例如,假设我们有一个“交易查询”的意图,我们可以使用提示词:
用户想要在系统中查询订单详情。假设你是这样的用户,有哪些可能的消息发送到智能客服?以列表的形式返回,列举20个,尽可能包含可能的各种句式、表达方式。可能涉及时间范围、金额范围、商家等。在每一行输出一个,除了消息之外,不要输出任何其他字符
把这样的消息发送给 GPT,看看其生成的语料质量如何,如果不满意则调整一下提示词继续。
在优化好提示词之后,就可以使用 API 调用 LLM 的接口来批量生成语料了。
除此之外,还可以针对搜集到的真实语料用 LLM 进行扩展,可以采用类似这样的提示词:
“{input}”在这一句话里面,{intent_def}。生成10个意思相近的表达。只需输出十行,不要输出任何额外的字符
使用这样的方法,可以快速得到成千上万的语料,然后就可以在此基础上训练模型了。
当然,LLM 生成的语料还是有偏的(跟真实语料不一致),准备一份真实语料用于验证模型表现还是很有必要的。这类语料可以不用太多,因此也相对容易搜集。
持续的语料优化
在模型上线之后,可以通过收集用户与智能客服的交互数据,不断优化语料库和模型。
例如,可以将用户输入的语句进行人工标注,然后与模型预测的结果进行对比,如果预测结果不准确,则可以将这些语句加入到 RAG 语料库中,并可以重新训练 MLP 模型。
当然,也可以用 LLM 自动改写这些识别不好的用户输入,在扩大语料范围和适用性后,再加入 RAG 语料库或重训 MLP。
同时,更进一步,可以识别这些语句的语言模式,然后利用 LLM 参考此模式去生成语料。
比如用户可能不想继续上一个意图,而提出了新意图。典型的输入比如“算了,我不想处理交易了,帮我查询一下如何申购理财产品吧”。
则可以编写提示词:
用户之前在操作功能“{last_function}”,现在办完了或者不想办理这个了,改为想要办理另一个功能“{function}”。假设你是这样的用户,有哪些可能的消息发送到智能客服?以列表的形式返回,列举10个,尽可能包含可能的各种句式、表达方式。在每一行输出一个,除了消息之外,不要输出任何其他字符
利用上述提示词可以让 LLM 批量生成此类的语料,从而处理掉一类的问题。
辅助意图的设计
由于意图识别常常基于单轮的用户输入来实现,而用户的对话具有持续性。因此,很多时候常常不能根据单轮的用户输入推断出有目的性的意图。
比如,用户想要补充信息,输入“日期就用上个月的吧”,此时是无法将输入映射到一个确定的目的性特别强的意图上去。
但是,如果结合上下文,我们就可以知道用户这是在补充信息,而当前的目的性意图与上一轮的是一致的。
因此,在设计意图时,除了设计那些目的性很强的意图之外,还需要设计一些辅助意图,用来描述用户可能的对话行为。在模型识别到此类意图时,可以通过对话的状态保持找到当前的真实意图。
此类辅助意图可以有:
- 提供信息
- 表达感谢
- 确认信息
- 否认信息
- 转人工
- …
MLP 小模型的训练和部署
MLP 模型的代码实现、训练和评估,可能相对有一定门槛。
这里也可以借助 LLM 强大的代码能力辅助我们完成工作。
编写如下提示词发给 LLM,可以帮我们自动完成大部分的 MLP 编码工作:
帮我生成代码完成功能:
1. 从一系列文本文件中读取文本,文件名为分类名,文件内容每一行为改分类对应的语料
2. 调用bge模型对这些文本生成embedding,并将embedding缓存到一个指定的文件中
3. 构建一个mlp模型,利用embedding的结果构建一个分类器,实现多分类任务,并考虑样本在多个分类中不平衡的情况
4. 实现训练和eval代码
在得到代码之后,可能需要将调用 bge 模型的过程改成调用通用的模型 API。由于 MLP 模型很小,可以在普通的开发机器上完成模型的训练。
在我的场景中,训练一个包含 12w 左右训练数据的模型,采用三层隐层维度 256 的 MLP 模型,只需要 7 分钟左右即可训练完成,准确率可以达到 97%左右(取决于语料质量),而模型大小只有 1.5MB 左右。
模型训练完成之后,如何部署到应用中呢?
模型训练的代码一般使用PyTorch或者Tensorflow这类框架编写完成。但是在部署这类小模型时如果也依赖这类框架执行推理计算,则显得大材小用了。
事实上,对于这类简单的 MLP 模型,我们可以直接用如numpy这类向量计算库完成推理。
将以下提示词发送给 LLM,就可以得到numpy版本的推理代码:
我有一个MLP模型代码如下:
...
请编写一个函数将模型参数保存为numpy格式,然后再编写另一个函数使用numpy加载这个模型的参数进行推理预测
得到的代码稍加改动就可集成到模型意图识别的流程中了。
总结
本文介绍了在 LLM 时代如何搭建一个实用的集成意图识别系统。
通过对常用的意图识别技术手段的分析,结合各种技术的优势,取长补短,分享了一个实用的设计。以最大范围使用通用模型的能力为原则,在落地实现时,可以有效降低工作量。
另外,使用 LLM 生成训练数据和模型代码,我们大大简化了开发过程,并对系统持续演进和优化提供了思路。