昨天開始幫 AI 系統留下 Log 之後,至少出問題時已經可以往回查。
我知道這次使用哪一版 Prompt、Retrieval 找到哪些文件、模型最後拿到什麼 Context,也可以看到整個 Request 花了多少時間。
但 Log 做完之後,很快又遇到下一個問題。
我知道系統「發生了什麼」,卻還是不知道這次修改到底有沒有讓它變好。
這件事在調 Prompt 的時候特別明顯。
假設今天改了一版 Prompt,我以前最常做的測試方法就是自己輸入幾個問題。
第一題回答得不錯。
第二題也正常。
第三題格式比上一版漂亮。
然後我就會覺得:
嗯,這版好像比較好。
接著直接把新的 Prompt 留下來。
問題是隔天再換幾個問題測,可能又突然發現舊版反而比較正常。
因為我每次測的問題不同,判斷標準也沒有固定,有時候覺得回答完整比較重要,有時候又覺得太長不好,最後其實很難知道 Prompt 到底是真的改善,還是剛好這幾題表現比較好。
所以今天開始碰 AI Engineering 裡一個我以前很少認真做的東西:Evaluation。
一開始看到 Evaluation,我腦中其實馬上想到一堆指標。
Accuracy、Precision、Recall、Faithfulness、Context Relevance,甚至還可以再用另一個 LLM 當 Judge。
但如果現在全部一起做,我大概又會卡在「到底要選哪個指標」。
所以今天先從最簡單的事情開始。
固定一組問題。
例如先準備 20 題:
Q1
Q2
Q3
...
Q20
這些題目不全部都是簡單題,我刻意混進幾種情況:
文件裡可以直接找到答案
需要整合兩段資訊
文件裡沒有答案
問題本身很模糊
容易產生幻覺的問題
接著每次修改 Prompt,都重新跑同一組。
光做到這一步,就已經比我以前隨手問三題可靠很多。
至少不同版本是在回答同一份考卷。
有固定題目之後,下一個問題馬上出現。
LLM 的回答不像選擇題,很難直接用對或錯處理。
例如:
參考答案:
系統支援 PDF、DOCX 與 TXT。
模型回答 A:
目前支援 PDF、DOCX、TXT。
模型回答 B:
系統目前可處理 PDF、Word 文件以及純文字檔案。
兩個其實都可以算對。
如果只是做字串比對,B 反而可能被判錯。
所以我先沒有追求一個很漂亮的總分,而是把判斷拆成幾個比較容易理解的問題:
答案有沒有回答問題?
有沒有使用正確資訊?
有沒有加入 Context 裡不存在的內容?
資料不足時有沒有承認不知道?
輸出格式有沒有符合要求?
這樣人工看的時候至少比較有一致標準。
不然今天覺得這句「寫得很好」,明天又覺得另一版「比較自然」,最後根本不是在測系統,只是在測我當下喜歡哪種文字。
昨天 Logging 做完之後,這件事變得更明顯。
如果最後答案錯,我現在可以先看 Retrieval。
假設正確文件根本沒有出現在 Top K 裡,那就算模型再強,也很難回答正確。
所以 Evaluation 其實不能只看最後 Response。
至少 RAG 流程裡,我會想分成:
Retrieval Evaluation
↓
Generation Evaluation
前面先問:
正確文件有沒有被找回來?
相關 Chunk 排得夠不夠前面?
後面才看:
模型有沒有根據 Context 回答?
有沒有亂補資訊?
答案是否真的解決使用者問題?
這樣出問題時才知道要改哪裡。
不然 Retrieval 明明一直拿錯資料,我卻連續改十版 Prompt,最後可能只是讓模型更會把錯誤資料講得很有說服力。
人工看 20 題還可以,如果之後變成 100 題、500 題,每次改 Prompt 都自己看一定撐不住。
所以今天也順便試了一個很常看到的方法:LLM as a Judge。
概念很直覺,把:
問題
參考答案
模型回答
評分規則
一起交給另一個模型,讓它判斷這次回答好不好。
例如要求輸出:
{
"correct": true,
"grounded": true,
"complete": false,
"score": 4,
"reason": "..."
}
這樣一次跑很多測試就方便很多。
但做到這裡又出現一個很好笑的問題。
我原本就是因為不完全相信 LLM 的回答才想做 Evaluation,現在結果變成找另一個 LLM 告訴我第一個 LLM 有沒有答對。
所以 Judge 本身也不能直接當真。
至少現在我的做法會保留一小部分人工檢查,看看 Judge 的判斷跟我自己的判斷差多少,如果連很明顯的錯誤它都一直放過,那這套評分方式就要重新調整。
把這些東西串起來之後,我終於可以做以前一直很想做,但其實沒有認真做過的比較。
Prompt v1
↓
固定 Evaluation Dataset
↓
Results
Prompt v2
↓
同一份 Evaluation Dataset
↓
Results
然後比較兩版。
可能 v2 的正確率比較高,但回答時間變長;也可能格式穩定很多,卻在「資料不足」的題目更容易亂猜。
這時候就不再只是「新版看起來比較聰明」。
我開始可以看到它到底改善在哪裡,又犧牲了什麼。
這可能是今天最意外的感覺。
以前 Prompt 想改就改,反正改完問幾題,覺得不錯就留下。
現在有固定測試集之後,每次修改反而會開始想:
這個改動真的有必要嗎?
因為一跑 Evaluation,很可能原本想改善某一種回答,結果另外五題一起退步。
這跟寫一般程式突然有點像。
程式改完會跑 Test,Prompt 改完也應該有東西告訴我,有沒有把原本正常的行為一起弄壞。
昨天我開始替 AI 系統留下過程,今天則開始替它建立一份可以重複考的考卷。
至少從現在開始,「這版 Prompt 好像比較好」這句話,我希望自己可以少講一點。
明天準備繼續往 Production 靠近,因為現在有 Log、有 Evaluation 之後,還有一個問題一直沒有處理。
在我電腦上測得很好,不代表真的有人開始使用之後還會一樣。
所以接下來要開始看 Monitoring,看看一個已經跑起來的 AI 系統,到底有哪些東西是需要一直盯著的。