多輪對話的狀態管理:什麼該留、什麼該丟
對話越長品質越差,是因為上下文管理沒有設計。這是可落地的策略。
多輪對話的常見退化:第十輪之後模型開始忘記早期的設定、重複問已經回答過的問題、或把不同話題混在一起。原因幾乎都是上下文管理不當。
正確的心智模型是:每一輪送出的上下文都是你主動組裝的,不是「把歷史全部附上」。你要決定留什麼。
三層結構
- 固定層:系統提示、工具定義、角色設定。永遠在最前面,永不變動(讓前綴快取能命中)。
- 事實層:對話中確立的結構化事實,例如使用者身分、已選方案、已確認的參數。用結構化格式維護,而非自然語言。
- 近期層:最近 N 輪的原始對話。
def build_context(state, history, n_recent=6):
facts = '\n'.join(f'- {k}:{v}' for k, v in state['facts'].items())
msgs = [
{'role': 'system', 'content': SYSTEM}, # 固定層
{'role': 'system', 'content': f'目前已確認的事實:\n{facts}'}, # 事實層
]
msgs += history[-n_recent:] # 近期層
return msgs事實層怎麼維護
每輪結束後,用一次額外呼叫抽取本輪新確立的事實並合併進狀態。這次呼叫可以用小模型,成本很低。
EXTRACT = '''從本輪對話中抽取新確立的事實,只輸出 JSON。
只抽取「使用者明確說出或確認」的資訊,不要推測。
已知事實:{known}
本輪對話:{turn}
輸出:{{"add": {{...}}, "update": {{...}}, "remove": [...]}}'''remove 欄位很重要:使用者說「不對,我要改成月繳」時,舊的事實必須被移除,否則兩個矛盾的事實會同時留在上下文裡。
什麼時候該截斷、什麼時候該摘要
- 直接截斷:閒聊、寒暄、已被事實層取代的內容。
- 摘要保留:包含推理過程或使用者偏好的段落。
- 永不丟棄:使用者明確的約束(「我只要繁體中文」「預算兩萬以內」)——這類應該升級到事實層。
話題切換的偵測
使用者換話題時,近期層的內容反而是干擾。可以用一個輕量分類判斷本輪是否延續前一輪,若否則縮小 n_recent,只保留事實層。
把組裝好的上下文長度做成監控指標。長度隨輪數線性成長,就代表你的管理策略沒有生效。
訂閱後繼續閱讀全文
本篇為訂閱者專屬內容。訂閱後可取得下列權限:
- 解鎖全部內容權限
- 閱讀不限篇數
- 全站移除廣告
月卡
NT$240
開通 30 天
一次付清,開通 30 天
季卡
NT$620
開通 90 天
一次付清,開通 90 天,每天約 NT$7
年卡
NT$2,160
開通 365 天
一次付清,開通 365 天,每天約 NT$6
一次性付款,付款成功後立即開通,到期自動結束,不會再次扣款,也不需要取消訂閱。
立即訂閱
金額均為新臺幣(TWD),即實際扣款金額,不另收手續費
支援信用卡 · Apple Pay · Google Pay · WebATM · ATM 轉帳
購買須知與退款政策