模型成功回傳文字,畫面就能顯示了嗎?在目前的對話管線裡,有一種結果會同時留下兩個紀錄:provider_succeeded = True,以及 fallback_used = True。前者表示模型供應端已完成回傳,後者表示最後交出去的內容改用了固定備援文字。這兩件事可以同時成立。
今天重新檢查測試時,這個組合讓 Safety Policy Engine 的問題變得很具體。測試替身送回一段帶有診斷與用藥指示的合成文字,程式確實收到了,接著卻把它拒絕。呼叫完成,只回答「有沒有拿到輸出」;能否讓輸出離開系統,還需要另一個判斷。
昨天整理風險分類時,我把未知保留為一種獨立結果。今天接著往下看:分類器把結果交出來後,誰決定是否呼叫模型?模型回覆之後,又由誰決定是否採用?如果這兩個決定都只寫在提示詞裡,程式最後仍只能期待模型遵守。
我想釐清的政策引擎,必須能在執行流程中改變結果:限制生成、拒絕輸出、選擇備援,並留下理由。現有程式已經有其中幾個關卡,但要把它們稱為完整引擎,還有一段距離。
目前的回應規劃先看風險分類,再看使用者意圖。落在未知時,規劃會選擇澄清;高度困擾與危機相關標籤則走向另外的固定回應。傾聽、探索或簡單下一步等一般意圖,要等前面的分支都沒有命中,才有機會參與選擇。
這個順序有實際意義。如果一則訊息被規則分到需要限制的路徑,即使意圖分析認為使用者「只想說說」,也不能靠這個意圖把一般生成重新打開。現有測試包含這種優先序的檢查;它驗證指定案例的程式行為,並不代表分類器已能理解所有表達。
真正阻止模型呼叫的地方,在 src/psychological_support/conversation/pipeline.py。以下節錄保留了原本分支:
fixed_only = risk.risk_level in {
RiskLevel.UNKNOWN,
RiskLevel.HIGH_DISTRESS,
RiskLevel.POTENTIAL_CRISIS,
RiskLevel.IMMEDIATE_DANGER,
}
if fixed_only:
response = fixed_response(plan)
這幾種情況直接取用固定文字,不會先請模型生成,再期待它自行收斂。未知分支仍會提供澄清,因此「限制」不必等於把使用者留在空白畫面;被限制的是當次任意生成的空間。
但固定回應也只是在程式內選擇文字。計畫裡即使附有尋求人類支持的動作名稱,也不表示已通知任何人、完成轉介,或有人在現實世界接手。這條管線沒有執行那些外部行動。
能進入一般生成的路徑,仍會收到系統安全要求與回應計畫。使用者文字放在獨立的使用者訊息裡,沒有被提升成系統規則。這是提示內容的分隔方式;相關測試確認了訊息角色與排列,不能據此宣稱所有提示注入都會失敗。
模型回傳後,validate_response() 會檢查文字形狀與一組有限的禁止模式。空值、過長內容、某些不接受的字元,以及命中診斷、用藥指示、依賴操控等規則的文字,都有對應的拒絕路徑。若檢查產生旗標,管線捨棄那份輸出,改用固定備援,沒有再請模型把原文修飾一次。
這就是開頭那組看似矛盾的紀錄。供應端成功回傳,仍可能因內容檢查而被替換。這時失敗分類可以保持空值,因為沒有發生供應端錯誤;拒絕原因應由安全旗標表達。把所有狀況壓成一個「成功/失敗」,就會失去這個差別。
反過來,供應端不可用、拋出例外或逾時時,也會進入固定備援,但留下的是相應的失敗分類。已有測試檢查例外訊息不會直接混進回覆或追蹤資料。連固定模板在交出前,也會再經過輸出檢查,避免讓模板因為寫在程式裡就自動獲得豁免。
今天執行的 46 項本地合成測試通過,涵蓋分流、規劃、輸出檢查、供應端失敗與部分權限不變量。這些證據來自固定案例與測試替身,沒有呼叫真實模型,也沒有真人或臨床驗證。有限模式能拒絕列出的句型,仍無法證明所有換句話說、暗示或跨輪語境都被涵蓋。
往下追程式時,我看到另一個值得停下來的地方:管線會呼叫 authority_for() 計算回應權限,但是否呼叫模型,實際上由前面的 fixed_only 集合判斷。算出的權限值會寫入追蹤紀錄,卻不是這個分支直接讀取的開關。
兩邊目前針對未知與高風險採取相容的限制方向,但這種相容需要持續維護。若將來政策函式新增條件,管線沒有同步更新,就可能出現「紀錄說受限,實際流程仍允許生成」的落差。這是從程式結構看到的維護風險,今天沒有把它當成已發生的產品事件。
不確定性的處理也有同樣邊界。基礎政策函式會把缺少或無效的不確定性視為高度不確定,並對較高的不確定性縮減一般支持權限。但這條對話管線傳入的是二選一的值:未知時傳入 1.0,其餘傳入 0.0。它沒有接收一個經過校準的模型信心分數,更不能把這兩個數字解釋成人的風險機率。
因此,後續設計需要一份由政策評估產生、並且由執行端確實遵守的決策結果。它應交代能否生成、採用哪種固定回應,以及限制的原因;遇到缺值或規則衝突時,也要有明確結果。這仍是待實作與驗證的方向,今天沒有修改產品管線。
目前的追蹤結構會記錄風險標籤、回應模式、權限、分流原因碼、供應端結果與安全旗標,也帶有政策版本欄位。這些資料讓「為什麼改用備援」有跡可循,同時不必在這份結構裡放入原始對話與模型全文。
不過,一個固定的版本字串還不能證明整套規則已受到版本治理。管線建立並回傳追蹤資料,也不等於已有持久保存、完整重播或不可竄改的稽核紀錄。今天能確認的是局部決策資訊存在;完整政策引擎仍需補上規則版本與決策的綁定、衝突處理,以及執行端不能繞過限制的驗證。
本日尚未完成此部分,以下先整理目前設計與下一步。接下來要收斂的是政策與執行之間的契約:同一份輸入與規則版本應能得到可解釋的決策,受限結果必須實際關閉對應能力,缺少必要資料也不能偷偷回到一般生成。
今天留下的問題因此很明確:當政策已經說「不允許」,程式裡究竟哪一道邊界,能讓其他元件無法把這個決定改回來?