不只是「沒當機」:用另一顆 Claude 評分聊天機器人真正說了什麼

· 中文 · Claude Sonnet 5 代筆

articleaiclaudetesting

這個網站上的 AI 助理(樂樂)已經有四層測試在保護她:單元測試用假造的 Claude 回應驗證邏輯分支,整合測試對著真實 Redis 驗證交接狀態機,端對端測試確認整條加密送出管線不會半路崩潰,另外還有幾支手動腳本,在改動行為規則之後打一次真實 API 確認沒有走鐘。這四層加起來能保證的是「這支程式不會壞掉」——沒有一層真正回答一個更根本的問題:訪客實際收到的那句回覆,內容夠不夠完整、語氣夠不夠專業?

機制:找另一顆 Claude 當裁判

答案是補上第五層測試,直接繞過整條 Action 管線,對著聊天機器人的核心邏輯打一次真實請求——不是假造的 API 回應,是真的送出去、真的等模型回來。拿到回覆之後,交給第二顆獨立的 Claude(一顆比聊天機器人自己用的 model 更強的版本)當裁判評分,對照的不是我手寫、也不是請 AI 生成的一份「標準答案」,而是程式碼直接從聊天機器人自己會用的同一份真實資料(履歷內容、安全架構說明、部落格文章本體)現場撈出來的結果。裁判打分數時,逼它輸出固定格式的結構化 JSON,而不是自己在一段文字裡寫「大概 85 分」再從裡面挖數字出來——這樣拿到的分數才不會被裁判自己的文字風格干擾。

情境:模擬訪客訊息 + 對話狀態

真實呼叫聊天機器人

真實回覆

程式化萃取真實資料

裁判 Claude 評分

結構化分數 (0-100)

這個「找一顆 AI 來評分另一顆 AI」的做法,業界通稱 LLM-as-a-judge,是目前評測聊天機器人品質最常見的手法之一——比起純靠人工看過每一句回覆,它能自動、持續地重跑;比起死板的關鍵字比對斷言,它抓得住「這句話有沒有硬掰」這種語意層次的問題。唯一要留意的是裁判本身也有取樣變異,所以同一個情境會連續問裁判三次取平均,而不是信任單一次評分。

抓到的東西

第一次真的跑起來,這套機制自己先抓到了幾個技術上的小問題——結構化輸出的 schema 不支援數字範圍限制、忘記把某個假物件傳進交接情境,結果真的去連了一次只有生產環境才存在的 Redis 主機名稱。這些修完之後,比較有意思的發現才開始浮現。

其中一個問題出在對話記憶裡已知的訪客資訊。如果一位訪客上次留過姓名、公司、跟需求,AI 理論上不該再問一次——這條規則本身沒有被違反,AI 確實沒有重問姓名或聯絡方式。但裁判抓到一句話:AI 開場說「我目前沒有看到我們之前完整的對話紀錄」。這句話技術上是對的(這次對話真的是空的,已知資訊是從上一次造訪帶過來的),但訪客聽起來會覺得矛盾——你明明知道我是誰,怎麼又說不記得。第一輪修正明確禁止了這句話的字面內容,重新驗證卻發現 AI 換了個說法達到一樣的效果——「我看不到我們討論過的具體細節」。真正有效的修正,是把規則從「禁止一句話」改成「禁止一整類自白式開場白」,同時給一個正面替代方案:需要更多細節,直接接著問就好,不用先聲明自己缺什麼。

另一個問題出在真人交接的開場應對。訪客一表明想外包一個專案,AI 一開始的回覆用編號清單列了三個問題——公司名稱、專案性質、聯絡方式——讀起來像一張表單,而不是自然對話。修掉編號清單之後分數只往上動了一點點,裁判又指出更細的問題:AI 在同一則回覆裡,除了問問題之外,還先講了一句「我來幫你確認一下 Joey 現在是否有空」——訪客都還沒回答、都還沒被問「要不要試試看」,AI 就已經在講「我會去確認」了。這條規則本來就要求「先問、對方說要試才去確認」,但沒人明確禁止把兩件事寫進同一則回覆——補上這一句之後,分數才真正穩定往上移動。

這兩個發現有一個共通點:純粹靠人工讀 prompt,或是只靠字串比對的 mock 測試,都不會抓到——AI 沒有違反任何寫死的規則,問題出在語氣跟時機這種只有真的讀一遍完整回覆才感覺得出來的地方。

分數不是一翻兩瞪眼

不是每一次都乾脆俐落。裁判評分本身有變異,同一個情境重跑,有時候會落在及格線之上,有時候會差個幾分掉到及格線之下——尤其是那些原本就落在灰色地帶的情境。與其為了讓每一次執行都 100% 綠燈,把 prompt 文字繼續無止盡地碰運氣式微調,這套機制刻意留了一個緩衝帶:90 分以上算通過,85 到 90 分之間標記成「需要人工複查」而不是直接判定失敗。分數該不該完全乾淨,跟修正到底有沒有生效,是兩件不同的事——後者看的是分數有沒有明顯往上移動、原本抓到的具體問題模式有沒有真的消失,不是死盯著單次執行是不是滿分。

這套機制目前只覆蓋了聊天機器人功能的一小部分情境,之後每次改一條行為規則、加一個新工具,都值得順手多寫一個情境進去——它已經證明了自己的價值:不只是抓問題,修完之後也能直接拿它重新驗證修正是否真的有效,不用再臨時寫一次性的驗證腳本。