如何使用大模型实现意图识别

前文介绍了如何使用 LangChain 简化大模型接口调用,并实现了一个智能聊天机器人例子。想实现更复杂的智能应用,我们往往需要识别用户的意图,并根据意图采取不同的行动。

本文将介绍如何使用大模型分析对话上下文,并识别用户的意图。

意图识别

意图识别,顾名思义,就是识别用户的意图。用户输入一句话,系统需要结合对话历史,从中识别出这句话的意图,并给出相应的回复。

假设我们想实现一个智能客服系统,为用户查询相关数据,比如:

  • 查询订单
  • 查询物流
  • 查询账户余额
  • 查询积分
  • 查询优惠券
  • 查询商品
  • 查询商品

系统需要根据用户提问,识别出用户意图,再调用对应工作流来查询数据。在这个过程中,用户意图识别是关键。由于用户提问千变万化,传统基于固定规则的意图识别方法,很难满足需求。

以最简单的积分查询为例,用户可能的提问方式包括:

block-beta
  columns 2
    U1(["👤 user"]) UM1("我的积分还有多少?")
    A1(["🤖 assistant"]) AM1("查询积分")
    space space
    U2(["👤 user"]) UM2("我还有积分没兑换吗?")
    A2(["🤖 assistant"]) AM2("查询积分")
    space space
    U3(["👤 user"]) UM3("我的积分会过期吗?")
    A3(["🤖 assistant"]) AM3("查询积分")

显然,这种基于自然语言的提问方式,很难用固定规则来识别,只能借助大模型来分析对话上下文。

提示词

想用大模型识别用户意图,提示词的设计是关键。我们需要设计一个提示词模板,并根据对话历史,生成提示词。以最简单的角色设定为例,我们可以通过 system 消息,对大模型进行提示:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
你是一个用户意图识别专家,擅长分析用户对话,并识别出用户的意图。作为一个智能客户系统的关键组件,你的工作是:

1. 分析用户对话,识别出用户的意图。
2. 根据用户的意图,准确输出对应的意图标签。

客服系统支持以下意图:

- 查询订单
- 查询物流
- 查询账户余额
- 查询积分
- 查询优惠券
- 查询商品

## 限制

- 只输出意图标签,不要输出任何解释。
- 不要输出意图标签之外的任何内容。
- 如果无法识别出意图,请输出 `unknown`。

这是一份典型的角色设定提示词,系统通过这份提示词,告诉大模型:

  • 角色,即大模型在对话中的身份
  • 任务,即大模型需要完成的任务
  • 限制,即大模型需要遵守的规则,比如输出格式约定等

接下来,我们写一些代码,来实现意图识别功能,看看这份提示词的效果。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
from langchain_openai import ChatOpenAI

# 设置接口地址常量,这里使用的是阿里云的接口地址
OPENAI_BASE_URL = "https://dashscope.aliyuncs.com/compatible-mode/v1"

# 设置 API Key 常量(注意保密)
OPENAI_API_KEY = "sk-..."

llm = ChatOpenAI(
    base_url=OPENAI_BASE_URL,
    api_key=OPENAI_API_KEY,
    model="deepseek-v3",
)

prompt = """
你是一个用户意图识别专家,擅长分析用户对话,并识别出用户的意图。作为一个智能客户系统的关键组件,你的工作是:

1. 分析用户对话,识别出用户的意图。
2. 根据用户的意图,准确输出对应的意图标签。

客服系统支持以下意图:

- 查询订单
- 查询物流
- 查询账户余额
- 查询积分
- 查询优惠券
- 查询商品

## 限制

- 只输出意图标签,不要输出任何解释。
- 不要输出意图标签之外的任何内容。
- 如果无法识别出意图,请输出 `unknown`。
"""

systemPrompts = [
  ("system", prompt),
]

history = []

while True:
    # 获取用户输入
    user_input = input("你:")

    # 调用大模型接口
    result = llm.invoke(systemPrompts + history + [("user", user_input)])

    # 输出大模型接口的返回结果
    print("AI:", result.content)

    # 更新对话历史(只保留最后10条,即5轮对话历史)
    history.extend([
      ("user", user_input),
      ("assistant", result.content),
    ])

这个例子很简单,只是在前面聊天机器人的基础上,优化了 system 角色设定提示词而已。虽然代码很简单,但实际测试的效果还可以:

block-beta
  columns 2
    U1(["👤 user"]) UM1("积分什么时候过期?")
    A1(["🤖 assistant"]) AM1("查询积分")
    space space
    U2(["👤 user"]) UM2("我有订单没收到?")
    A2(["🤖 assistant"]) AM2("查询物流")
    space space
    U3(["👤 user"]) UM3("我的积分会过期吗?")
    A3(["🤖 assistant"]) AM3("查询积分")
    space space
    U4(["👤 user"]) UM4("我的生日是?")
    A4(["🤖 assistant"]) AM4("unknown")
    space space
    U5(["👤 user"]) UM5("查询")
    A5(["🤖 assistant"]) AM5("unknown")
    space space
    U6(["👤 user"]) UM6("积分怎么兑换?")
    A6(["🤖 assistant"]) AM6("查询积分")

基本上,我们定义的几种预设意图,都能识别出来;对于不明确或者预设以外的情况,都能稳定输出 unknown 。注意到最后一个场景可能不太准确,系统没有提供兑换积分的预设,被误识别为查询积分了。不过不要紧,接下来我们为其加上一些样本提示,进一步提升它的准确性。

少样本提示

为提高大模型输出结果的准确性,我们可以为其提供一些样本提示,这就是所谓的 少样本提示(Few-shot Prompting)。 提示样本的格式很简单,只需要提供用户输入和意图标签即可,结构如下:

block-beta
  columns 2
    U1(["👤 user"]) UM1("用户输入")
    A1(["🤖 assistant"]) AM1("意图标签")

如果用户意图需要根据多轮对话来判断,则可以提供包含多轮对话的样本,例如:

block-beta
  columns 2
    U1(["👤 user"]) UM1("用户输入①")
    A1(["🤖 assistant"]) AM1("大模型提示")
    U2(["👤 user"]) UM2("用户输入②")
    A2(["🤖 assistant"]) AM2("意图标签")

设计好的提示样本,同样作为 messages 数组的一部分,提供给大模型即可:

block-beta
  columns 2
    S1(["👤 system"]) SM1("系统提示")
    space space
    U1(["👤 user"]) UM1("用户输入①")
    A1(["🤖 assistant"]) AM1("意图标签①")
    U2(["👤 user"]) UM2("用户输入②")
    A2(["🤖 assistant"]) AM2("意图标签②")
    U3(["👤 user"]) UM3("用户输入n")
    A3(["🤖 assistant"]) AM3("意图标签n")
    space space
    U4(["👤 user"]) UM4("对话输入①")
    A4(["🤖 assistant"]) AM4("大模型回答①")
    U5(["👤 user"]) UM5("对话输入n")
    A5(["🤖 assistant"]) AM5("大模型回答n")
    U6(["👤 user"]) UM6("用户输入")
    space Arrow<["LLM"]>(down)
    A6(["🤖 assistant"]) AM6("意图标签")

如上图,整个 messages 数组包含三部分,从上到下依次是:

  • 系统提示
  • 样本提示
  • 用户输入(包含对话历史及当前输入)

接下来,我们写一些代码,来实现意图识别功能,验证少样本提示的效果。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
from langchain_openai import ChatOpenAI

# 设置接口地址常量,这里使用的是阿里云的接口地址
OPENAI_BASE_URL = "https://dashscope.aliyuncs.com/compatible-mode/v1"

# 设置 API Key 常量(注意保密)
OPENAI_API_KEY = "sk-..."

llm = ChatOpenAI(
    base_url=OPENAI_BASE_URL,
    api_key=OPENAI_API_KEY,
    model="deepseek-v3",
)

prompt = """
你是一个用户意图识别专家,擅长分析用户对话,并识别出用户的意图。作为一个智能客户系统的关键组件,你的工作是:

1. 分析用户对话,识别出用户的意图。
2. 根据用户的意图,准确输出对应的意图标签。

客服系统支持以下意图:

- 查询订单
- 查询物流
- 查询账户余额
- 查询积分
- 查询优惠券
- 查询商品

## 限制

- 只输出意图标签,不要输出任何解释。
- 不要输出意图标签之外的任何内容。
- 如果无法识别出意图,请输出 `unknown`。
"""

systemPrompts = [
  ("system", prompt),
]

samples = [
  # 积分兑换不支持
  ("user", "积分怎么兑换?"),
  ("assistant", "unknown"),

  # 积分查询
  ("user", "积分什么时候过期?"),
  ("assistant", "查询积分"),

  # 还可以在这继续将样本
  # 大模型会从样本中总结出规律,并应用到新对话中
]

history = []

while True:
    # 获取用户输入
    user_input = input("你:")

    # 调用大模型接口
    result = llm.invoke(systemPrompts + samples + history + [("user", user_input)])

    # 输出大模型接口的返回结果
    print("AI:", result.content)

    # 更新对话历史(只保留最后10条,即5轮对话历史)
    history.extend([
      ("user", user_input),
      ("assistant", result.content),
    ])

执行程序,可以看到大模型输出的意图标签,准确率比之前高了不少。起码,对于积分兑换的场景,大模型已经能正确识别成 unknown 了:

block-beta
  columns 2
    U1(["👤 user"]) UM1("积分怎么兑换?")
    A1(["🤖 assistant"]) AM1("unknown")
    space space
    U2(["👤 user"]) UM2("积分兑换商城在哪?")
    A2(["🤖 assistant"]) AM2("unknown")

后续,我们还可以继续增加和优化样本提示,进一步提升大模型的准确性。

总结

本文介绍了如何使用大模型识别用户意图,并给出了一个简单的例子。通过少样本提示,我们可以显著提升大模型的准确性。

【小菜学AI】系列文章首发于公众号【小菜学编程】,敬请关注:

【小菜学AI】系列文章首发于公众号【小菜学编程】,敬请关注: