وقتی کاربر در چند پیام پیاپی نظرش را تغییر میدهد («یه رستوران ارزون میخوام... نه در واقع متوسط باشه و پیتزا هم داشته باشه»)، چتباتهای متنی ساده معمولاً گیج میشوند یا پارامترهای قبلی را فراموش میکنند. سیستمهای گفتگوی وظیفهمحور برای فراخوانی API و ثبت سفارش، نمیتوانند به خروجیهای متنی غیرقطعی تکیه کنند؛ آنها نیاز دارند تا وضعیت خواستههای کاربر در قالب یک دیکشنری ساختاریافته از اسلاتها و مقادیر (Slot-Value) همیشه بهروز و دقیق باقی بماند.
ردیابی وضعیت گفتگو (Dialogue State Tracking یا DST) دقیقاً همین پل میان کلمات کاربر و ورودی قطعی بکاند است. این مفهوم حتی در دوران مدلهای زبانی پیشرفته نقشی کلیدی دارد؛ زیرا ایجنتها برای کار با ابزارها نیازمند آرگومانهای بدون ابهام هستند و ارزیابی کیفیت آنها معیاری مشخص میطلبد.
در این درس، با بررسی الگوهای کلاسیک و خطاهای رایج مانند بازنویسی اسلاتها و ارجاعات متنی، یاد میگیرید چطور یک پایپلاین مطمئن با رجکس و ترکیب مدلهای زبانی به همراه خروجیهای ساختاریافته Pydantic پیادهسازی کنید.
«یه رستوران ارزون میخوام تو شمال شهر... در واقع قیمتش متوسط باشه... غذای ایتالیایی هم داشته باشه.» سه دور گفتگو (Turn)، سه بار بهروزرسانی وضعیت. وظیفهی ردیابی وضعیت گفتگو (Dialogue State Tracking یا DST) این است که دیکشنری اسلات-مقدار (Slot-Value) را همگام نگه دارد تا رزرو بهدرستی انجام شود.
صورت مسئله
در سیستمهای گفتگوی وظیفهمحور (Task-Oriented Dialogue)، هدف کاربر در قالب مجموعهای از جفتهای اسلات-مقدار کدگذاری میشود: {cuisine: italian, area: north, price: moderate}. کاربر در هر دور از گفتگو میتواند اسلاتی اضافه کند، تغییر دهد یا حذف کند. سیستم باید کل گفتگو را بخواند و وضعیت فعلی را دقیق خروجی دهد.
کافی است فقط یک اسلات اشتباه استخراج شود تا سیستم رستوران اشتباهی را رزرو کند، پرواز دیگری را زمانبندی کند یا مبلغ را از کارت اشتباهی کسر کند. DST حلقهی وصل میان حرفهای کاربر و عملیاتی است که در بکاند اجرا میشود.
چرا در سال 2026 با وجود مدلهای زبانی بزرگ (LLM) هنوز این موضوع اهمیت دارد:
- حوزههای حساس به انطباق و مقررات (بانکداری، سلامت، رزرو پرواز) نیازمند مقادیر اسلات قطعی هستند، نه تولید متن آزاد و مهارنشده.
- ایجنتهای ابزارمحور (Tool-Use Agents) قبل از فراخوانی APIها همچنان به تفکیک و تعیین دقیق اسلاتها نیاز دارند.
- اصلاح حرفهای قبلی در گفتگوهای چندمرحلهای سختتر از چیزی است که به نظر میرسد: «راستی نه، بذارش برای پنجشنبه.»
پایپلاین امروزی: مفاهیم کلاسیک DST + مدلهای زبانی استخراجگر + چارچوبهای خروجی ساختاریافته (Structured-Output Guardrails).
مفاهیم پایه
ساختار وظیفه. یک شِما (Schema) دامنهها (رستوران، هتل، تاکسی) و اسلاتهای آنها (نوع غذا، منطقه، قیمت، تعداد نفرات) را تعریف میکند. هر اسلات میتواند خالی باشد، با مقداری از یک مجموعهی بسته پر شود (قیمت: {cheap, moderate, expensive})، یا مقداری آزاد و متنی بگیرد (نام: "The Copper Kettle").
دو فرمولبندی برای DST.
- دستهبندی (Classification). برای هر جفت (اسلات، مقدار_کاندید)، یک پیشبینی بله/خیر انجام میدهد. مناسب برای اسلاتهایی با واژگان بسته. روش استاندارد پیش از سال 2020.
- تولید متن (Generation). با دریافت گفتگو، مقادیر اسلاتها را به صورت متن آزاد تولید میکند. مناسب برای اسلاتهایی با واژگان باز. رویکرد پیشفرض امروزی.
معیار ارزیابی. دقت هدف مشترک (Joint Goal Accuracy یا JGA) — یعنی نسبت دورهایی از گفتگو که در آنها همهی اسلاتها کاملاً درست باشند؛ قانونی با منطق صفر و یک. در سال 2026، صدر جدول رتبهبندی MultiWOZ 2.4 حدود 83% است.
معماریها.
- قاعدهمحور (رجکس اسلات + کلمات کلیدی). بیسلاینی بسیار قوی برای دامنههای محدود. دیباگ کردن آن ساده است.
- TripPy / BERT-DST. روش تولید مبتنی بر کپی (Copy-Based) با انکودر BERT. استاندارد دوران پیش از LLMها.
- LDST (مدل LLaMA + LoRA). مدل زبانی آموزشدیده با دستورالعمل (Instruction-Tuned) همراه با پرامپتهای دامنه-اسلات. روی MultiWOZ 2.4 به کیفیتی در سطح ChatGPT میرسد.
- بدون هستیشناسی (Ontology-Free، سالهای 2024–2026). شِما را کنار میگذارد؛ نامها و مقادیر اسلاتها را مستقیماً تولید میکند و از پس دامنههای باز برمیآید.
- پرامپت + خروجی ساختاریافته (2024–2026). مدل زبانی در ترکیب با شمای Pydantic و دیکودینگ مقید (Constrained Decoding). با 5 خط کد آمادهی استفاده در پروداکشن میشود.
الگوهای شکست کلاسیک
- ارجاع به گزینههای قبلی (Co-reference) در طول گفتگو. «بریم همون گزینهی اول.» سیستم باید تشخیص دهد منظور دقیقاً کدام گزینه است.
- بازنویسی در برابر الحاق (Over-write vs Append). کاربر میگوید: «ایتالیایی رو هم اضافه کن.» آیا باید نوع غذا جایگزین شود یا به فهرست قبلی اضافه گردد؟
- تأییدهای ضمنی. «اوکی عالیه» — آیا این یعنی پیشنهاد رزرو قبول شد؟
- اصلاح حرفهای قبلی (Correction). «راستی، ساعتش رو بکن 7 عصر.» باید بدون پاک شدن بقیهی اسلاتها، فقط زمان بهروزرسانی شود.
- ارجاع به گفتههای قبلی خودِ سیستم. «آره، همونی که گفتی.» کدام مورد؟
پیادهسازی
مرحلهی 1: استخراجکنندهی قاعدهمحور اسلات
کد را در code/main.py ببینید. عبارات باقاعده (Regex) به همراه دیکشنری کلمات هممعنی، 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
این رویکرد خارج از واژگان استاندارد شکننده است؛ اما برای تأییدهای قطعی اسلاتها بهخوبی کار میکند.
مرحلهی 2: حلقهی بهروزرسانی وضعیت
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
سه اصل پایدار که باید رعایت شوند:
- هیچوقت اسلاتی را که کاربر دست نزده ریست نکنید.
- رد صریح («اصلاً نوع غذا مهم نیست») باید اسلات را پاک کند.
- اصلاح از طرف کاربر («راستی...») باید مقدار قبلی را بازنویسی کند، نه اینکه به آن اضافه شود.
مرحلهی 3: ردیابی وضعیت با LLM و خروجی ساختاریافته
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 بازگرداندن یک آبجکت وضعیت معتبر را تضمین میکند. بدون دردسرهای رجکس، بدون ناهماهنگی با شِما و بدون اسلاتهای توهمشده.
مرحلهی 4: ارزیابی با معیار JGA
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 جلوتر از شما خواهد بود.
مرحلهی 5: مدیریت اصلاحات کاربر
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 کل وضعیت را بر اساس تاریخچه از نو بسازد، نه اینکه آن را بهصورت افزایشی آپدیت کند — این کار اصلاحات را بهطور طبیعی مدیریت میکند.
دامهای رایج
- هزینهی بازتولید کل تاریخچه. اگر به LLM بسپارید که در هر دور کل وضعیت را دوباره تولید کند، در مجموع توکن مصرف خواهد شد. طول تاریخچه را محدود کنید یا دورهای قدیمیتر را خلاصه کنید.
- تغییر تدریجی شِما (Schema Drift). اضافه کردن اسلاتهای جدید پس از اتمام کار، دادههای آموزشی قبلی را نامعتبر میکند. برای شمای خود حتماً نسخهبندی داشته باشید.
- حساسیت به بزرگی و کوچکی حروف. تفاوت میان "Italian" و "italian" و "ITALIAN" — همهجا مقادیر را نرمالسازی کنید.
- ارثبری ضمنی (Implicit Inheritance). اگر کاربر در دورهای قبلی گفته باشد «برای 4 نفر»، درخواست جدید برای ساعتی دیگر نباید تعداد نفرات را پاک کند. همیشه تاریخچهی کامل را به سیستم بفرستید.
- اسلاتهای متنی آزاد در برابر مجموعههای بسته. نامها، زمانها و آدرسها به اسلاتهای متن آزاد نیاز دارند؛ اما نوع غذا و منطقه مجموعههای بستهای هستند. در شِما هر دو نوع را ترکیب کنید.
استفادهی کاربردی
استک سال 2026:
| موقعیت | رویکرد |
|---|---|
| دامنهی محدود (یک یا دو قصد) | قاعدهمحور + رجکس |
| دامنهی گسترده، همراه با دادههای برچسبدار | مدل LDST (ترکیب LLaMA + LoRA روی دادههای مشابه MultiWOZ) |
| دامنهی گسترده، بدون دادهی برچسبدار، آمادهی پروداکشن | ترکیب LLM + کتابخانهی Instructor + شمای Pydantic |
| گفتاری / صوتی | سیستم ASR + نرمالساز + LLM-DST |
| جریان رزرو چنددامنهای | مدل زبانی هدایتشده با شِما همراه با مدلهای مجزای 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 را بسنجید. - متوسط. همان دیتاست را با Instructor + Pydantic و یک LLM کوچک پیاده کنید. JGA را مقایسه کرده و سختترین دورهای گفتگو را بررسی کنید.
- سخت. هر دو روش را پیادهسازی و مسیریابی کنید: در حالت پیشفرض از روش قاعدهمحور استفاده کنید و اگر با اطمینان کمتر از 2 اسلات استخراج کرد، به سراغ LLM بروید. مقدار JGA ترکیبی و هزینهی استنتاج به ازای هر دور گفتگو را بسنجید.
اصطلاحات کلیدی
| اصطلاح | در گفتار عامیانه | معنای دقیق فنی |
|---|---|---|
| DST | ردیابی وضعیت گفتگو | نگهداری دیکشنری اسلات-مقدار در طول دورهای گفتگو. |
| Slot | واحد نیت کاربر | پارامتر نامگذاریشدهای که بکاند به آن نیاز دارد (مانند cuisine یا date). |
| Domain | حوزهی وظیفه | رستوران، هتل، تاکسی — مجموعهای از اسلاتها. |
| JGA | دقت هدف مشترک | نسبتی از دورهای گفتگو که همهی اسلاتها در آن درست هستند؛ قانونی با منطق صفر و یک. |
| MultiWOZ | بنچمارک مرجع | دیتاست چنددامنهای WOZ؛ معیار استاندارد ارزیابی DST. |
| Ontology-free DST | بدون شِما | تولید مستقیم نامها و مقادیر اسلاتها بدون فهرستی ثابت. |
| Correction | «راستی...» | دوری از گفتگو که در آن کاربر مقدار اسلاتی را که قبلاً پر شده بود بازنویسی میکند. |
برای مطالعهی بیشتر
- مقاله Budzianowski و همکاران (2018): MultiWOZ — یک Wizard-of-Oz چنددامنهای در مقیاس بزرگ — بنچمارک مرجع و استاندارد.
- مقاله Feng و همکاران (2023): بهسوی ردیابی وضعیت گفتگو بر پایهی مدلهای زبانی بزرگ (LDST) — آموزش دستوری LLaMA با LoRA برای وظیفهی DST.
- مقاله Heck و همکاران (2020): مدل TripPy — استراتژی کپی سهگانه برای DST مستقل از مقدار در شبکههای عصبی — ابزار اصلی و استاندارد DST بر پایهی کپی.
- مقاله King و Flanigan (2024): گفتگوی وظیفهمحور سرتاسری و بدون نظارت با LLMها — سیستم TOD بدون نظارت مبتنی بر EM.
- جدول رتبهبندی MultiWOZ — نتایج رسمی و استاندارد DST.