系列文章第 4 篇 · 让机器“听懂”意图,记住上下文


一、从“听到”到“听懂”的关键一跃

ASR 把声音变成了文字,但这只是万里长征的第一步。接下来的问题更难:

  • “帮我订一张明天去北京的机票” —— 机器需要知道:你要做什么(订机票),以及关键细节是什么(目的地=北京,时间=明天)

  • 如果紧接着说“算了,改成上海吧” —— 机器还需要记得上一轮对话的内容,知道“改成”是针对订票这件事,“上海”是替换目的地

这两个任务分别对应自然语言理解(NLU)对话状态跟踪(DST),它们构成了语音交互的“大脑”。本文的焦点是:在语音交互场景下,这些任务的特殊性是什么,以及有哪些主流算法。


二、口语 NLU 的特殊挑战

语音交互中的 NLU 比纯文本 NLU 多了几层额外挑战:

挑战 说明 示例
ASR 误差传播 ASR 的识别错误会直接传递给 NLU “订一张去北极的机票” → ASR 识别成“订一张去北京的机票”
口语化表达 口语中有大量重复、修正、语气词 “那个那个,帮我,嗯,查一下明天的天气”
碎片化输入 用户边说边想,产生不完整句子 “上海…不对,深圳的”
多意图混合 一句话包含多个意图 “现在几点了顺便帮我设个闹钟”
语境依赖性 理解依赖上文 “查天气” → “那上海呢?”

因此,语音 NLU 不能照搬文本 NLU 的方案,需要有针对性地处理这些特殊性。


三、NLU 两大核心任务

3.1 意图识别(Intent Classification)

定义:判断用户说话的目的是什么。属于多分类问题。

典型意图体系示例:

领域(Domain) 意图(Intent) 示例
天气 query_weather “今天北京天气怎么样”
音乐 play_music “放首周杰伦的歌”
导航 navigate_to “导航到最近的加油站”
闹钟 set_alarm “设一个明早7点的闹钟”
闲聊 chitchat “你叫什么名字”
否定 cancel “算了不要了”

算法演进:

阶段 方法 典型 F1
传统 关键词匹配 + 规则 ~85%
传统 ML TF-IDF + SVM / FastText ~88-90%
深度学习 TextCNN / BiLSTM + Attention ~92-94%
预训练模型 BERT / RoBERTa 微调 ~95-97%
大模型 GPT-4 / Claude few-shot 或 zero-shot ~96-99%(含模糊意图)

3.2 槽位填充(Slot Filling)

定义:从用户的语句中提取出关键信息片段。属于序列标注问题(对每个 token 打 BIO 标签)。

示例:

用户:帮我订一张明天从深圳飞北京的商务舱机票

BIO 标注:
帮  O
我  O
订  O
一  O
张  O
明天 B-DATE
从  O
深圳 B-DEP_CITY
     I-DEP_CITY
飞  O
北京 B-DEST_CITY
     I-DEST_CITY
的  O
商务舱 B-CLASS
     I-CLASS
机票 O

主流算法:

方法 特点
BiLSTM-CRF 经典的深度序列标注基线,CRF 层保证标签转移合理性
BERT + CRF 用预训练 BERT 替换 LSTM,效果显著提升
Joint BERT 意图分类和槽位填充共享 BERT 编码器,联合训练,相互促进
Global-Locally Self-Attention 引入槽位之间的全局依赖(如 DEP_CITY 和 DEST_CITY 不应相同)
LLM 结构化输出 用 GPT-4 等直接输出 JSON 格式的意图 + 槽位

中文槽位的特殊难点:

  • 中文无自然分词边界,槽位边界与 BERT tokenizer 的子词切分不一致

  • 数字和时间表达多样:“下周三”、“后天”、“7月8号”等归一化复杂

  • 同义词和简称:“深航” vs “深圳航空” vs “ZH”


四、从单轮到多轮:对话状态跟踪(DST)

单轮 NLU 只解决“这句话什么意思”。但在真实对话中,用户会通过多轮交互逐步澄清需求:

用户:帮我查一下天气
  → 意图: query_weather, 槽位: {}
系统:请问您想查哪个城市的天气?
用户:深圳的
  → 意图: query_weather, 槽位: {city: 深圳} (继承自上一轮)
用户:明天呢?
  → 意图: query_weather, 槽位: {city: 深圳, date: 明天} (进一步叠加)

4.1 对话状态的形式化定义

对话状态(Dialogue State)是对话中所有“已知信息”的结构化快照:

Dialogue State = {
    domain: "weather",
    intent: "query_weather",
    slots: {
        city: "深圳",
        date: "2026-07-07",
        time: null
    },
    turn_count: 3,
    user_emotion: "neutral"
}

4.2 DST 的核心逻辑

槽位的三种更新方式:

方式 说明 示例
CARRYOVER 未提及的槽位保持原值 上轮 city=深圳,本轮未提 city → 保持深圳
UPDATE 新信息覆盖旧值 “改成上海吧” → city 从深圳更新为上海
DELETE 用户否定后清除 “不用查天气了” → 清除天气域的所有槽位
DONTCARE 用户表示无所谓 “随便哪家餐厅都行” → restaurant 域标记为 don’t care

4.3 DST 算法方法

(1)基于规则的 DST

适合槽位数量有限的垂直场景。维护一个槽位-值字典,用规则匹配更新:

# 伪代码示例
if "明天" in utterance:
    state["date"] = resolve_date("tomorrow")
if "改成" in utterance or "换成" in utterance:
    # 后面紧跟的是新的槽位值
    state["last_mentioned_slot"] = extract_new_value(utterance)

(2)基于分类的 DST

将每个槽位当作一个多分类问题:给定对话历史,预测槽位应该取候选值列表中的哪一个。通常用 BERT 等模型对 (context, candidate_value) 做二分类。

代表方法:TRADE(Transferable Dialogue State Generator)用 copy mechanism 从上下文中直接复制槽位值。

(3)基于生成的 DST

将整个对话状态表示为 JSON 或特殊格式文本,用 seq2seq 模型直接生成。这更灵活,但可控性稍弱。

代表方法:SOM-DST(State Operation Memory-based DST),将 DST 建模为一系列 state operation(CARRYOVER, UPDATE, DELETE, DONTCARE)。

(4)基于 LLM 的 DST

直接将对话历史 + Schema 描述输入 LLM,要求输出结构化的对话状态:

Prompt:
你是一个对话状态跟踪器。当前对话状态:
{"city": "深圳"}
用户说:"那上海呢?"
请输出更新后的对话状态。

LLM 输出:
{"city": "上海"}  // DST 操作:UPDATE city

在一些评测中,GPT-4 的 DST 联合准确率(Joint Goal Accuracy)已超过 90%,远超专用 DST 模型。


五、对话策略(Dialogue Policy)

知道状态后,系统需要决定“下一步该说什么”。这就是对话策略模块。

5.1 策略的四种模式

模式 描述 适用场景
填槽式(Slot-Filling) 逐个询问缺失的必要槽位,直到信息完整 查天气、订票等
FAQ 式 用户问 → 系统匹配最佳答案 → 返回 客服、知识问答
流程式(Flow-based) 预定义对话流程图,按节点跳转 银行业务办理、预约
开放域 无预定义结构,完全由模型驱动 AI 陪伴、闲聊

5.2 策略学习方法

方法 说明
规则/状态机 最可控、最可解释,适合流程确定的业务场景
监督学习 从人-人对话日志中学习策略(行为克隆)
强化学习(RL) 定义奖励函数(任务成功率 - 对话轮次),让 agent 自己探索
LLM-as-Policy 对话状态 + 业务规则 → LLM 直接生成系统回复

实际工程中,最常见的是「规则/状态机 + LLM 兜底」的混合方案

  • 核心业务路径(如预定流程)用确定性状态机确保可靠

  • 边界情况、闲聊用 LLM 灵活处理


六、统一 NLU:BERT 时代的联合建模

2018 年后,BERT 的出现催生了 NLU 任务的联合建模范式。

6.1 JointBERT

意图分类槽位填充这两个任务在同一个 BERT 上联合训练:

[CLS] 帮 我 订 明天 去 北京 的 机票 [SEP]

预训练 BERT

[CLS] token 的 hidden state

各 token 的 hidden states

意图分类头
Softmax over intents

槽位标注头
CRF / Softmax over BIO tags

联合损失
L = L_intent + λ * L_slot

联合训练的好处:

  • 意图和槽位共享语义表示,学习到的特征更丰富

  • 一个模型搞定两个任务,部署成本减半

  • 意图分类的梯度信号可以帮助槽位消歧(反之亦然)

6.2 从 BERT 到 LLM:范式转换

LLM 的出现让 NLU 的建模方式发生了根本性变化:

维度 BERT 微调范式 LLM 范式
输入 单句 + 标签 Prompt + 上下文 + 工具/Schema 描述
输出 分类标签 / BIO 序列 自然语言 + 结构化 JSON
开发成本 标注数据 + 训练 Prompt 工程 + 少量 few-shot 样例
灵活性 固定意图/槽位体系 可动态调整 Schema
推理延迟 低(模型小) 较高(模型大,但可通过蒸馏优化)

当前趋势:对于意图明确的垂直场景,BERT 微调在延迟和成本上仍有优势;而复杂语义理解、开放域对话,以及在意图/Schema 频繁变化的场景下,LLM 正在成为首选。


七、语音场景下的 NLU 特殊优化

7.1 ASR 容错

ASR 一定会出错,与其追求 100% 的识别准确率,不如让 NLU 学会容忍 ASR 错误。

方法:

  • 音近字纠错:在槽位填充时,对候选值做拼音归一化。ASR 将“福田”识别成“福天”,NLU 通过拼音 “futian” 模糊匹配到正确的地名

  • ASR N-best 输入:不只输入 ASR 的 1-best,而是输入 N-best(前 N 个候选),让 NLU 综合利用

  • ASR 置信度加权:对低置信度的词降低其 NLU 特征权重

  • 端到端抗噪训练:在 ASR 输出 + 噪声(随机替换/删除)上训练 NLU

7.2 口语化处理

口语中有大量书面语中不存在的模式:

口语现象 示例 处理方式
重复/修正 “那个…深圳,不对,上海” 识别“不对/不是”等修正标记,撤销前面的槽位值
语气词 “嗯,帮我,那个,查一下天气” NER/槽位填充前的文本清洗
省略 “(查)明天的(天气)” 用对话上下文补全缺省信息(DST 的 CARRYOVER)
倒装 “深圳天气,明天” 排序不敏感的精简语义理解

7.3 On-device vs Cloud

维度 端侧 NLU 云端 NLU
模型规模 < 50M 参数 不限
典型方案 MobileBERT / TinyBERT 微调 LLM / 大型 BERT
延迟 < 10ms 50-500ms
能力范围 固定领域,有限意图 开放域,复杂推理
隐私 数据不出设备 需上传语音/文本到云端

很多智能音箱采用端云协同:端侧做高频简单意图(开灯、设闹钟),云端处理复杂请求(查百科、多轮对话)。


八、总结

NLU 和对话管理是语音交互的“智能中枢”。它的核心任务包括:

任务 技术路线
意图识别 BERT 微调 → LLM Prompt(趋势)
槽位填充 BiLSTM-CRF → BERT+CRF → JointBERT 联合建模
对话状态跟踪 规则 → 分类 → 生成式 → LLM-based
对话策略 状态机(核心路径)+ LLM(兜底)

对于想要深入实践的朋友,建议从 RasaConvLab-3 入手——它们提供了 NLU + DST + Policy 的完整 pipeline,可以快速搭建对话系统原型。在此基础上,逐步引入 BERT/LM 替换其中的各个模块,就能形成对 NLU 全链路最扎实的理解。


上一篇:AI语音交互算法之语音识别(ASR)

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐