对话状态跟踪 本节摘要:「我要一家北边便宜的餐厅……改成中等价位吧……再加意大利菜。」三轮、三次状态更新,对话状态跟踪(DST)让槽位-值字典保持同步,预订才能成。在任务型对话系统里,用户的目标被编码为一组槽位-值对 ,每一轮用户发言都可能新增、修改或清除一个槽位,系统必须读完整个对话并正确输出当前状态。错一个槽位,系统就订错餐厅、排错航班、扣错卡——DST 是「用户说了什么」与「后端执行什么」之间的铰链。2026 年尽管有了 LLM,它依然要紧:银行、医疗、航司等合规敏感领域需要确定性的槽位值而非自由生成;工具型智能体调 API 前仍需解析槽位;多轮纠正(「其实改成周四」)比看上去难。现代流水线是经典 DST 概念 + LLM 抽取器 + 结构化输出护栏。
本节摘要:「我要一家北边便宜的餐厅……改成中等价位吧……再加意大利菜。」三轮、三次状态更新,对话状态跟踪(DST)让槽位-值字典保持同步,预订才能成。在任务型对话系统里,用户的目标被编码为一组槽位-值对
{cuisine: italian, area: north, price: moderate},每一轮用户发言都可能新增、修改或清除一个槽位,系统必须读完整个对话并正确输出当前状态。错一个槽位,系统就订错餐厅、排错航班、扣错卡——DST 是「用户说了什么」与「后端执行什么」之间的铰链。2026 年尽管有了 LLM,它依然要紧:银行、医疗、航司等合规敏感领域需要确定性的槽位值而非自由生成;工具型智能体调 API 前仍需解析槽位;多轮纠正(「其实改成周四」)比看上去难。现代流水线是经典 DST 概念 + LLM 抽取器 + 结构化输出护栏。本节从规则式槽位抽取、状态更新循环、LLM + Pydantic 的 DST,讲到联合目标准确率(JGA)评估与纠正处理,点明跨轮共指、覆盖 vs 追加、隐式确认等经典失败模式,以及全历史重生成能自然处理纠正却带来 O(n²) token 成本的取舍。
对应原课程:Phase 5 · Lesson 29 ·
dialogue-state-tracking(原英文phases/05-nlp-foundations-to-advanced/29-dialogue-state-tracking/docs/en.md)。前置依赖:第 17 节(聊天机器人)、第 20 节(结构化输出)。
阅读完本节,你应当能够:
在任务型对话系统里,用户的目标被编码为一组槽位-值对:{cuisine: italian, area: north, price: moderate}。每一轮用户发言都可能新增、修改或清除一个槽位。系统必须读完整个对话并正确输出当前状态。
错一个槽位,系统就订错餐厅、排错航班、扣错卡。DST 是「用户说了什么」与「后端执行什么」之间的铰链。
2026 年尽管有了 LLM,它依然要紧:
现代流水线:经典 DST 概念 + LLM 抽取器 + 结构化输出护栏。
任务结构。 一个 schema 定义领域(餐厅、酒店、出租)及其槽位(cuisine、area、price、people)。每个槽位可为空、填入闭集值(price: {cheap, moderate, expensive})或自由值(name: "The Copper Kettle")。
两种 DST 表述:
💡 指标:联合目标准确率(JGA)——每一轮所有槽位都对的比例。全有或全无。MultiWOZ 2.4 排行榜 2026 顶部约 83%。
架构演进:
见 code/main.py。正则 + 同义词词典在窄领域覆盖 70% 的规范话术:
CUISINE_SYNONYMS = { "italian": ["italian", "pasta", "pizza", "italy"], "chinese": ["chinese", "chow mein", "noodles"], } def extract_cuisine(utterance): for canonical, synonyms in CUISINE_SYNONYMS.items(): if any(syn in utterance.lower() for syn in synonyms): return canonical return None
在规范词表之外脆弱。适合确定性槽位确认。
def update_state(state, utterance): new_state = dict(state) for slot, extractor in SLOT_EXTRACTORS.items(): value = extractor(utterance) if value is not None: new_state[slot] = value for slot in NEGATION_CLEARS: if is_negated(utterance, slot): new_state[slot] = None return new_state
三条不变式:
from pydantic import BaseModel from typing import Literal, Optional import instructor class RestaurantState(BaseModel): cuisine: Optional[Literal["italian", "chinese", "indian", "thai", "any"]] = None area: Optional[Literal["north", "south", "east", "west", "center"]] = None price: Optional[Literal["cheap", "moderate", "expensive"]] = None people: Optional[int] = None day: Optional[str] = None def llm_dst(history, llm): prompt = f"""You track the slot values of a restaurant booking across turns. Dialogue so far: {render(history)} Update the state based on the latest user turn. Output only the JSON state.""" return llm(prompt, response_model=RestaurantState)
Instructor + Pydantic 保证返回合法状态对象。没有正则、没有 schema 不匹配、没有幻觉槽位。
def joint_goal_accuracy(predicted_states, gold_states): correct = sum(1 for p, g in zip(predicted_states, gold_states) if p == g) return correct / len(predicted_states)
校准:系统在多少比例的轮次上把所有槽位弄对?MultiWOZ 2.4 上的 2026 顶级系统:80~83%。你领域内的系统应在你的窄词表上超过它,否则 LLM 基线就胜过你。
CORRECTION_CUES = {"actually", "no wait", "on second thought", "change that to"} def is_correction(utterance): return any(cue in utterance.lower() for cue in CORRECTION_CUES)
检测到纠正时,覆盖最近更新的槽位而非追加。没有 LLM 帮助很难做对。现代模式:总让 LLM 从历史重新生成整个状态,而非增量更新——这能自然处理纠正。
2026 的栈:
| 情形 | 方法 |
|---|---|
| 窄领域(一两种意图) | 规则 + 正则 |
| 宽领域,有标注数据 | LDST(LLaMA + LoRA 在 MultiWOZ 式数据上) |
| 宽领域,无标注,要生产就绪 | LLM + Instructor + Pydantic schema |
| 语音 / 语音 | ASR + 归一化器 + LLM-DST |
| 多领域预订流程 | schema 引导的 LLM,每领域一个 Pydantic 模型 |
| 合规敏感 | 规则主路径,LLM 兜底配确认流程 |
保存为 outputs/skill-dst-designer.md:
--- name: dst-designer description: Design a dialogue state tracker — schema, extractor, update policy, evaluation. version: 1.0.0 phase: 5 lesson: 29 tags: [nlp, dialogue, task-oriented] --- Given a use case (domain, languages, vocab openness, compliance needs), output: 1. Schema. Domain list, slots per domain, open vs closed vocabulary per slot. 2. Extractor. Rule-based / seq2seq / LLM-with-Pydantic. Reason. 3. Update policy. Regenerate-whole-state / incremental; correction handling; negation handling. 4. Evaluation. Joint Goal Accuracy on a held-out dialogue set, slot-level precision/recall, confusion on the hardest slot. 5. Confirmation flow. When to explicitly ask the user to confirm (destructive actions, low-confidence extractions). Refuse LLM-only DST for compliance-sensitive slots without a rule-based secondary check. Refuse any DST that cannot roll back a slot on user correction. Flag schemas without version tags.
code/main.py 里为 3 个槽位(cuisine、area、price)搭规则式状态跟踪器,在 10 段手工对话上测,报 JGA。至此,我们走完了「自然语言处理」这一章的全部 29 节。回望来路:从第 01 节的 token 化与词形还原、第 03 节的 Word2Vec,到第 10 节的注意力与第 13 节的问答;从第 14 节的混合检索、第 22 节的嵌入深潜、第 23 节的分块策略,到第 27、28 节的评估框架与长上下文;最后落到本节的对话状态跟踪——把语言从「理解」推到「行动」。本章的一条主线是:文本如何变成向量,就理解了 LLM 之前的一切 NLP;另一条主线是:每一项能力都有「从零实现 → 框架对比 → 可复用产物」的工程闭环。带上这套底座,你已为后续「LLM 工程化」「RAG 与智能体」等章节做好了准备——下一章见。