AI语音交互算法之自然语言理解与对话管理
系列文章第 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 上联合训练:
联合训练的好处:
-
意图和槽位共享语义表示,学习到的特征更丰富
-
一个模型搞定两个任务,部署成本减半
-
意图分类的梯度信号可以帮助槽位消歧(反之亦然)
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(兜底) |
对于想要深入实践的朋友,建议从 Rasa 或 ConvLab-3 入手——它们提供了 NLU + DST + Policy 的完整 pipeline,可以快速搭建对话系统原型。在此基础上,逐步引入 BERT/LM 替换其中的各个模块,就能形成对 NLU 全链路最扎实的理解。
上一篇:AI语音交互算法之语音识别(ASR)
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐
所有评论(0)