Gary
Hsieh
2026 · taipeiloading
回到文章列表
軟體工程AI 趨勢2026-07-15

怎麼樣驗證你的 LINE 機器人、你的 AI Agent 不會亂講話?

怎麼樣驗證你的 LINE 機器人、你的 AI Agent 不會亂講話?

怎麼樣驗證你的 LINE 機器人、你的 AI Agent 不會亂講話?非決定性的輸出,要怎麼確保它總是符合我們的預期?聊聊 Promptfoo 這套 TDD Regression Suite。

客服機器人本該回答產品問題,結果有人丟了一題數學題目給它,它就開始解了 🫨🫨 再問它某支股票會不會賺,也開始幫人分析起來。

我最近幾乎每個 LINE 討論群都會接一隻 agent,為了驗證他們的回覆會不會亂來,研究了 Promptfoo 一輪,順便把整條路徑實際跑過一次。

一個沒有標準答案的問題:Oracle Problem

寫過測試的人都知道如果輸入 1 + 1 就必須輸出 2 這種東西,輸入固定、輸出固定,對就是對、錯就是錯。但你要怎麼測「這個回覆夠不夠禮貌」?怎麼測「這段摘要有沒有抓到重點」?怎麼測「這個產品的優勢在哪」?

軟體工程裡有名字,而且已經被討論二十幾年 — 叫做 Test Oracle Problem

2015 年《The Oracle Problem in Software Testing: A Survey》,把這個問題定義為:給定一個輸入,要區分「期望的正確行為」與「潛在的錯誤行為」,這個挑戰就叫 test oracle problem。

Oracle 就是那個「權威判定者」,白話說,就是神諭、聖旨。傳統測試裡 oracle 通常很好找 — 規格書、契約、前一版的行為。但有一整類問題,根本指不出那個權威來源在哪。

當 modelling、specification、contract-driven development、metamorphic testing 這些方法都不夠用的時候,test oracle 的最終來源仍然是「人」 — 因為只有人知道那些非正式的規格、期待與領域常識。

2015 年,那時候還沒有 LLM。現在把一個生成式模型放進產品裡,這個問題直接被放大一百倍 🫠

大語言模型當大法官:LLM-as-a-Judge

AI 的整體回答通常沒有唯一正解,所以很難去驗證「這整段回答是對的」。

裡面有些屬性可以直接驗證 — 格式、禁詞、延遲、數值範圍。這些都有精確的判定條件,是可以形式化的,或是量化。剩下「禮貌」「完整」「切題」的語意(semantic)品質,需要用「近似」的方式去評估。

而那部分既然沒有 oracle,最常見的做法就是再找一個 LLM 來當裁判,就是大家講到爛的 LLM-as-a-Judge。

2023 年 EMNLP 的《G-Eval: NLG Evaluation using GPT-4 with Better Human Alignment》,用 chain-of-thought 讓 GPT-4 當裁判去評摘要品質,論文自己說這個方法「大幅超越所有先前方法」。

所以 LLM-as-a-Judge 當成一個 heuristic(探索式的過程),讓另外一個 LLM 來當品質的挑戰者,但他不會是一番兩瞪眼的「你答對了」「你答錯了」的評比,更像是一個評分機制。

先設計「問什麼」

實務上希望 agent 總是輸出你要的東西,第一件事是設計一套「問它問題」的流程,這個流程只有三個問題:

  1. 我會問什麼問題
  2. 我期待的結果是什麼
  3. 我要如何驗證這個結果

以 Promptfoo 為例,這三件事全部寫進一個 promptfooconfig.yaml。最核心的就三個 top-level key:

  • prompts — 你要問什麼
  • providers — 你要問誰,通常是你的 Agent
  • tests — 每個問題配上 assert 陣列,也就是「怎麼算過」

(還有 defaultTestscenariosredteam 之類的,但骨幹是這三個)

好玩的地方是它的執行模型。預設情況下 Promptfoo 會把 providers × prompts × tests 展開成一個矩陣逐格跑,你也可以針對特定 test 限制只跑某個 prompt 或 provider。tests 裡面可以是直接的「字串比對」,也可以是丟給第三方 LLM judge。

對誰測試?

先講怎麼跟 agent 溝通。

Promptfoo 支援的溝通方式很多 — HTTP、WebSocket、各家 SDK、custom script。我自己是用 OpenClaw,OpenClaw 本來就有揭露自己的 ACP 接口,所以我走的是 ACP 這條(ACP 是 Agent Client Protocol,應用場景很多,之後聊)。

provider 設計成這樣:

exec:acpx --cwd /home/garyhsieh/.openclaw/workspace --format quiet --max-turns 4 --timeout 180 openclaw exec

acpx 是一個 headless 的 ACP CLI,他會去 spawn 我的 OpenClaw。

然後我去翻了一下我裝的那版 Promptfoo 原始碼(v0.121 線,src/providers/scriptCompletion.ts),從 exec provider 的角度看,整個框架的核心契約可以簡化成一句話:給它 prompt,最後拿回 output。

就這樣。啪,沒了。(實際上 response 還能帶 token usage、cost、latency 之類的,但主幹就是這個)

底下的 transport 是 HTTP 還是 Python 還是 CLI 還是 ACP,對 evaluator 完全不可見。ACP 的整個 handshake、round-trip 全都發生在 fork 出去的 subprocess 裡面,Promptfoo 只在 process 邊界收 stdout。Promptfoo 其實不知道 ACP 是什麼,它只看到「一條 command、吐 stdout」。

而這樣剛好就夠 — ACP 把一個原本有工具、有檔案、有記憶的 agent,包成一次可以從 CLI 啟動、最後吐 stdout 的介面;而 Promptfoo 的 exec: provider 只要求這個形狀。任何能被塞進「一條 command、吐 stdout」的東西,都同構可測。

再講另一個重點,--cwd

在我的 OpenClaw 設定裡,--cwd 決定它找到哪一個 workspace,進而決定 SOUL.md / USER.md / IDENTITY.md / AGENTS.md / MEMORY.md 這些檔案會不會被載進 context。這是「測我的 agent 本人」,不是「測一個 model」。

同一組 assert、同一個 fail,在這兩種設定下意義完全不同。指錯資料夾,你測的就是別的機器人。

兩種驗法:Deterministic & Non-Deterministic

拿到輸出之後(通常就是一段文字),驗證分成兩種。

Deterministic

就是那些已經很經典的東西 — regular expression、字串比對、JSON schema 檢查、latency 門檻。做法是:先把「哪些可觀察條件一定要成立」寫成 assertion。

但這裡要很小心,assertion 過了,不代表整個回答是對的,只代表那一個條件成立。舉個很賤的例子:

「我不能提供投資建議。不過這支股票基本面很好,可以買,快!。」

因爲 agent 說「不能提供」,好像通過測試了,但… 😂

所以 deterministic 能幫你固定的是格式、禁詞、必要欄位、明確邊界 — 不是整段語意。

我自己這個專案目前 8 條 test 全部落在這一層:icontainscontainsregexnot-icontains-anyicontains-anyjavascript。零 LLM 呼叫、可重現、免 token。

Non-Deterministic

Deterministic 的問題是語意上不夠精準。「不要回答股票問題」你用 regex 擋得掉「股票」兩個字,擋不掉「這檔標的的基本面」。

這時候就換 judge 上場 — llm-rubricg-evalsimilar(similar 是用 embedding 算語意相似度,不是生成式裁判,但還是靠模型跟 threshold,算是介於兩者之間的中間層)。

而這兩層真正的差別在:成本

多數 deterministic assertion 就是本機的字串、結構或數值檢查,便宜、快、可重現。Model-based 每一條都是一次外部 API call,要管 key、管 cache、管 retry、管 rate limit。

所以策略就定了:成本導向。能用 deterministic 構造 oracle 的時候(可枚舉、結構可驗、數值有門檻)就用 deterministic;只有語意層才降級到 judge。

順便講個容易被忽略的:LLM 是機率性的,所以跑一次過了不代表什麼。Promptfoo 有 --repeat 可以每格跑 N 次,我自己還會加 --no-cache 強制每次重打 — agent 是 stateful 又是機率性的,快取會把 regression 蓋掉。要看的是「通過率」,不是單次有沒有通過

最後整條收在 process exit code,non-zero 就接得進 CI。

不只是驗 AI agent

只要是「我給定 context、希望它吞吐特定輸出」的場景,這個概念都能套:

  • 寫 skill — 社群寫手,段落結尾不能有句號、章節要用《》、emoji 控制在 5 到 10 個之間。這些全部都是 regex 跟 javascript assertion,零 judge、零成本
  • 找資料的機器人 — 驗它有沒有引用到指定來源、有沒有編造
  • 輸出文章筆記 — 驗格式、驗結構、驗有沒有把該有的段落寫出來

再往上擴展的話,就是拿不同的 model provider 去做多次詢問然後評分 — 確保在這個 context 之下,配上不同的 model,我都能得到我要的結果。

講到多裁判,2023 年《Judging LLM-as-a-Judge with MT-Bench and Chatbot Arena》整理過 LLM 裁判的幾種系統性偏誤:

  • position bias(選項順序會影響判斷)
  • verbosity bias(偏好長的答案)
  • self-enhancement bias(偏好自己生成的東西)

所以多 model 交叉評分是有道理的,但它不是把偏誤消除,是改用「多個模型的偏誤平均」來優化。

不同等級的測試邊界

繞了一圈,回到最前面那個問題:我們的 AI agent、我們的機器人,要怎麼確保客戶在問它問題、或是我們自己在調整它的時候,它都鎖在我們自己的邊界之內?

邊界的意思很簡單 — 它不會去回答它不該回答的問題。做法就是這三層疊起來:

設計一套可以長大的 evaluation data → 透過 communication protocol 去打它 → 拿到 response → 驗證 → 迭代

「可以長大」是關鍵字。每次你發現機器人講了不該講的話,那就是一條新的 test case。這個 config 會跟著你的產品一起長。

模型會不會亂講,這件事本身是非決定性的,你改不掉。但你可以在外面包一套決定性的執行流程 — 固定測試案例、記錄結果、把已知的錯誤模式變成 regression test。

但是,但是,但是,這不能證明 agent 永遠不會出錯。它只能保證同一種錯,不要默默地回來第二次。

也順便釐清一個詞。前面那個「被問數學題就開始解題」的例子,它其實不是常講的 jailbreak,是 boundary violation — 使用者沒有惡意,只是問到了範圍外,然後 agent 很熱心。

真正的 jailbreak 是:要求忽略 system prompt、套取內部 instructions、誘導洩漏工具結果、間接 prompt injection、編碼或角色扮演繞過。那就是 red team 的流程在做的事(Promptfoo 也有獨立的 redteam workflow)。

這篇講的 regression suite,處理的是前者。你的客服機器人不會一被問數學題就開始解題,也不會被問到股票就自動切換成投資顧問。它就是你的小僕人,focus 在你產品的回覆上。

開始迭代機器人邊界設計

如果今天要開始做機器人,我會這樣排。

第一件事,也是最重要的一件事 — 先把真正的 boundary 設好。 提示層安全、prompt level 只是其中一層,而且是最遜的那一層。

怎麼說?只要你會問問題,你就有辦法跟 agent 來來回回直到他接受「我被妥協了,我給你關鍵檔案」,然後他就給你了 🫣

真正不該讓 agent 看到的東西,不要只靠一句「你不可以說出去」來保護。工具權限、檔案可見範圍、credentials、網路存取、高風險操作要不要 approval — 這些都應該在 runtime 層就先隔離掉(這也是為什麼各家的聊天視窗都把 runtime 隔離得很死)。

agent 拿不到的東西,它就吐不出來。 這比任何 prompt 都可靠。

Promptfoo 在這裡的角色是驗證,不是隔離 — 它負責告訴你「這些規則在我已知的輸入跟攻擊案例下,有沒有真的守住」。它不是那道牆,它是幫你去撞那道牆的工具。牆,還是要自己設計。

第二件事 — 用這套機制持續把你產品或公司的 knowledge base 迭代進去,讓機器人不只知道答案,還遵守回覆的規則。

然後最基本的迭代循環就三步:

  1. 安裝 Promptfoo
  2. 設計自己的 evaluation config
  3. 看 evaluation 報表

Revisit: Test Oracle Problem

2015 年那篇 survey 說,當所有自動化方法都不夠用的時候,test oracle 的最終來源仍然是人。

十一年過去了,仍然適用:LLM-as-a-Judge 幫你近似,deterministic 幫你把關,但「什麼叫做對」,最後還是我們說了算。

我們沒辦法證明 agent 永遠不會亂講,但可以把每一次發現的亂講,都變成一條不准再犯的 regression test。Eval Framework 幫我們把這件事變成每次 commit 都會自動跑一遍驗證的關鍵工具。

Aim for bounded agent!

#Agent#AI#LLM#OpenClaw#測試