3. 意图识别入门:意图识别的定义、基于规则的方法、基于统计的方法
好,咱们今天聊聊意图识别。说白了,就是让机器猜你心里想干嘛。
你对着智能音箱说“帮我关灯”,它得知道你的意图是“控制设备”,而不是“闲聊”或者“问天气”。我刚开始做对话系统那会儿,觉得这事儿挺简单的——不就是匹配关键词嘛?后来被现实狠狠教育了一顿。嗯,咱们一步步来。
3.1 意图识别的定义
意图识别,是自然语言理解(NLU)里的核心任务之一。它的目标很明确:给定一段用户输入,判断用户想干什么。
举个例子:
- “今天天气怎么样?” → 意图:查询天气
- “帮我订一张去北京的机票” → 意图:预订机票
- “你叫什么名字?” → 意图:闲聊/询问身份
你想想看,如果连用户想干嘛都搞不清楚,后面的对话管理、动作执行就全乱套了。所以意图识别是对话系统的第一道关卡,也是我最重视的一环。
核心要点:意图识别本质上是一个分类问题。我们把用户输入映射到预定义的意图类别上。类别数量从几个到几百个不等,取决于你的业务场景。
3.2 基于规则的方法
这是最古老、也最直观的方法。说白了,就是写一堆“如果...就...”的逻辑。
3.2.1 关键词匹配
最简单的规则:用户说了“天气”,就认为是查询天气意图。
if "天气" in user_input:
intent = "query_weather"
elif "订票" in user_input or "机票" in user_input:
intent = "book_ticket"
else:
intent = "unknown"
我在项目中遇到过一个问题:用户说“今天天气不错,我想出去走走”,结果触发了“天气”关键词,被识别成查询天气。其实人家只是想闲聊。这就是关键词匹配的硬伤——没有上下文理解。
3.2.2 正则表达式
比关键词稍微灵活一点。可以用正则匹配更复杂的模式。
import re
patterns = {
"query_weather": r"(今天|明天|后天).*天气",
"book_ticket": r"订.*(票|机票|火车票)",
"set_alarm": r"设.*闹钟|提醒我.*[点时分]"
}
def rule_based_intent(text):
for intent, pattern in patterns.items():
if re.search(pattern, text):
return intent
return "unknown"
正则的好处是能处理一些变体。比如“帮我订一张机票”和“订票”都能匹配到。但缺点也很明显:写规则的人得把所有可能说法都想全了。我曾经维护过一个规则系统,光“查询天气”就写了40多条正则,还是漏了不少情况。
我的经验:规则方法适合意图数量少(比如5-10个)、用户输入比较固定的场景。比如语音助手里的“打开/关闭”类指令,用规则又快又准。
3.2.3 规则方法的优缺点
| 优点 | 缺点 |
|---|---|
| 实现简单,不需要训练数据 | 覆盖不全,容易漏掉新说法 |
| 可解释性强,出问题好排查 | 规则维护成本高,越写越多 |
| 响应速度快,延迟低 | 无法处理模糊或复杂的表达 |
避坑指南:我曾经接手过一个项目,规则文件有3000多行。每次新增意图都要小心翼翼,生怕跟旧规则冲突。后来我彻底重构了——把规则拆成模块,每个意图一个文件,才勉强能维护。所以,如果你发现规则超过100条,就该考虑换方法了。
3.3 基于统计的方法
规则方法搞不定怎么办?上统计方法。说白了,就是让机器从数据里自己学规律。
3.3.1 朴素贝叶斯
这是最经典的统计分类方法之一。原理很简单:计算每个意图在给定输入下的概率,选概率最大的那个。
from sklearn.naive_bayes import MultinomialNB
from sklearn.feature_extraction.text import CountVectorizer
# 假设我们有训练数据
train_texts = ["今天天气怎么样", "帮我订机票", "设个闹钟"]
train_labels = ["query_weather", "book_ticket", "set_alarm"]
# 特征提取
vectorizer = CountVectorizer()
X_train = vectorizer.fit_transform(train_texts)
# 训练模型
model = MultinomialNB()
model.fit(X_train, train_labels)
# 预测
test_text = "明天会下雨吗"
X_test = vectorizer.transform([test_text])
predicted = model.predict(X_test)[0]
print(predicted) # 输出: query_weather
朴素贝叶斯的好处是训练快、数据量要求不高。我早期做一个小型客服系统时就用它,几百条标注数据就能跑起来。但它的假设太强了——认为每个词之间相互独立。你想想看,“不”和“好”放在一起是“不好”,但朴素贝叶斯会当成两个独立特征,这就出问题了。
3.3.2 支持向量机(SVM)
SVM比朴素贝叶斯强一些。它试图找到一个超平面,把不同意图的数据点分开。
from sklearn.svm import SVC
# 用同样的数据
model_svm = SVC(kernel='linear')
model_svm.fit(X_train, train_labels)
predicted_svm = model_svm.predict(X_test)[0]
我在项目中对比过,SVM在意图数量20-30个时效果明显优于朴素贝叶斯。但训练时间也长一些,而且对特征工程要求高。说白了,你得把文本转换成好的特征向量,不然SVM也白搭。
3.3.3 统计方法的通用流程
- 数据收集:收集用户真实输入,标注好意图标签
- 文本预处理:分词、去停用词、小写化等
- 特征提取:把文本转成数值向量(如TF-IDF、词袋模型)
- 模型训练:选择分类算法,训练模型
- 评估与调优:用测试集评估准确率,调整参数
关键点:统计方法的效果高度依赖数据质量。我见过太多团队花大量时间调模型参数,结果发现是标注数据有大量错误。所以我的建议是:先把数据质量搞上去,模型自然就变好了。
3.4 规则 vs 统计:怎么选?
这个问题我经常被问到。我的回答是:看场景。
| 场景 | 推荐方法 | 原因 |
|---|---|---|
| 意图少(<10),输入固定 | 规则方法 | 简单、快速、可解释 |
| 意图多(>20),表达多样 | 统计方法 | 覆盖广、泛化能力强 |
| 没有标注数据 | 规则方法 | 不需要训练数据 |
| 有大量历史对话数据 | 统计方法 | 数据驱动,效果更好 |
其实在实际项目中,我经常把两者结合起来。先用规则处理那些明确、简单的输入,剩下的交给统计模型。这样既保证了核心场景的准确率,又覆盖了长尾情况。
一个小技巧:你可以给规则方法设置一个置信度阈值。比如正则匹配上了,直接输出结果。如果没匹配上,或者匹配结果置信度低于0.8,就交给统计模型做二次判断。这种混合方案我在好几个项目里都用过,效果不错。
3.5 小结
意图识别是对话系统的第一道门槛。规则方法简单直接,适合小规模场景;统计方法灵活强大,适合复杂场景。我个人建议初学者先从规则入手,理解清楚意图识别的本质,再逐步过渡到统计方法。
下一章咱们聊聊实体识别——光知道用户想干嘛还不够,还得知道具体细节。比如“订机票”这个意图,你得知道出发地、目的地、时间这些信息。嗯,到时候细说。