如何用 Harbor 在真實任務上測試你的代理——Arize AI 的 Xander Song
如何用 Harbor 在真實任務上測試你的代理——Arize AI 的 Xander Song
Arize AI 的 Xander Song 介紹 Harbor,這是一套開源框架,可在擬真的沙箱任務上評估代理;他說明如何以驗證器為基礎的獎勵機制與軌跡追蹤,驗證了一項提示詞變更,讓代理從 REST 分頁查詢改走 SQL,並指出最難的部分在於擬真資料。
Podcast 專家音訊節目
收錄於 888news Podcast 智庫專區,包含精華摘要與上市公司即時行情
Arize AI 的工程師 Xander Song 任職於 Phoenix 可觀測性平臺團隊,他主張代理團隊應根據實測證據、而非直覺來發布變更,並以開源框架 Harbor,在隔離的 Docker 沙箱中讓代理執行貼近真實的任務。這場演講大部分時間著墨於 Harbor 的架構——任務(task)、環境(environment)、驗證器(verifier)、預言機(oracle)、試驗(trial)與軌跡(trajectory)——接著說明他自己的團隊如何將這套框架套用到一套混合系統上:Claude Code、自製的 MCP 伺服器、一支 CLI,以及一個名為 Pixie 的伺服器端代理。標題承諾的「用真實資料跑真實任務」確實做到了,但這一集同時也是 Phoenix 的產品導覽,並且坦率交代了這套做法仍不成熟之處:回歸測試覆蓋率仍處於「早期階段」,而最難的部分在於取得貼近真實的資料。
Song 自稱是 Harbor 的「重度使用者」而非維護者,同時也是 Phoenix 與 OpenInference 的維護者,這讓他在這個故事的兩半都有份。讀者讀完應該能建立一套可運作的心智模型,理解 Harbor 的各項基本元件如何拼在一起;看到一個具體案例,說明一次提示詞調整如何透過工具呼叫指標獲得驗證;並清楚看見這套框架的極限——尤其是對那些系統無法塞進單一 Docker 映像的團隊而言。
Harbor 的核心迴圈:固定任務與驗證器,替換代理
核心主張是:只要任務、其資料與驗證器都夠真實且準確,你就能更換代理的實作、重跑整條流程,快速取得這次變更讓該任務進步還是退步的訊號。Song 把另一種做法稱為「只憑感覺發布」。一個任務是一份 Markdown 指令檔,加上一個預先灌入相關資料的 Docker 環境(例如一個 SQLite 檔、某個特定 commit 的 Git 儲存庫,或任何其他東西);驗證器則是代理執行完畢後才跑的指令碼,用來檢查預期的副作用是否發生,並把 0/1 通過或失敗這類獎勵寫進 reward.txt。每個任務可設定重複試驗次數,以吸收 LLM 的隨機性;而整趟執行——所有任務、所有試驗、所有驗證器、所有軌跡——稱為一個 job。
flowchart TD
A["任務:指令 Markdown + 內含資料的 Docker 環境"] --> B["每次試驗使用全新容器"]
B --> C["代理或預言機執行任務"]
C --> D["代理在環境中留下副作用"]
D --> E["代理結束後掛載驗證器並執行檢查"]
E --> F["獎勵寫入 reward.txt(例如 0 或 1)"]
C --> G["可選的 ATIF 軌跡,供除錯使用"]
F --> H["彙總跨試驗與資料集的指標"]
G --> H
關鍵的架構特性在於:驗證器對代理的實作一無所知——它們只評分代理留下的東西,就像寫得好的整合測試對 API 背後的實作一無所知一樣。Song 把這稱為「在綠燈下重構」的能力:固定任務不變,徹底換掉代理,然後發動整條流程,看一切是否照常運作。驗證器可以選擇性檢視 ATIF 軌跡,但這不是標準做法。
預言機讓你在花掉任何一個 Token 之前先除錯整條流程
Harbor 讓你不只能放入代理,還能放入「預言機」——一支真正解掉該任務的指令碼。Song 認為這是這套框架最實用的功能之一:它讓你在任何代理執行之前,先驗證資料是否正確、環境是否設定妥當、驗證器行為是否符合預期。在「修好一個失敗的資料庫遷移」這個實作範例中,預言機就是真正修好該遷移的指令碼;驗證器會執行 up-migration、檢查結束碼,並確認預期的欄位與索引存在。由於驗證器對預言機都能通過,Song 說他因此有足夠信心「更大膽地憑感覺放手做」,不必逐行審查每個驗證器。
每次試驗彼此獨立,讓整條流程可水平擴充套件
每個任務與每次試驗都在各自全新的 Docker 容器中執行,起始狀態完全相同,因此整條流程可水平擴充套件,也能搭配 Daytona、Modal、E2B 等沙箱供應商。Song 的團隊使用 Daytona,約有 200 個並行 worker,即使測試套件很大也能「快速掃完」。他們從個別試驗計算出 pass@k 這類彙總指標——例如 Claude Code 是否在三次嘗試內修好該遷移。示意圖中,資料集裡的四個任務分別對 Claude Code(搭配 Opus 5)與 Codex(搭配 GPT-5)執行,各三次試驗,並依任務及整體資料集計算 pass@3。
| 基本元件 | 內容 | 範例 |
|---|---|---|
| 任務(Task) | Markdown 指令 + Docker 環境 | 「修好這個失敗的遷移」 |
| 環境(Environment) | Dockerfile 加上預先灌入的資料 | SQL 檔、DDL、含壞掉 up-migration 的原始碼 |
| 驗證器(Verifier) | 檢查副作用、輸出獎勵的指令碼 | 執行 up-migration、斷言結束碼為 0、檢查資料表與索引 |
| 預言機(Oracle) | 解掉任務的指令碼 | 該遷移的實際修法 |
| 試驗(Trial) | 一次獨立執行 | 同一任務、同一代理、全新容器 |
| Job | 完整執行:所有任務 × 試驗 × 驗證器 | 全資料集的 pass@k 與各項指標 |
| 軌跡(Trajectory) | 代理各步驟的 ATIF JSON 紀錄 | 供除錯用的 LLM 呼叫與工具呼叫 |
Harbor 是主機端的協調器;契約就是「指令碼放在對的位置」
觀眾提問後,Song 特別強調一個細節:Harbor 本身是一支在主機上執行的命令列程式——本機時跑在筆電上,CI 時跑在 GitHub Actions runner 上——而不是跑在 Docker 環境裡。它負責協調:啟動代理、執行驗證器、執行預言機,全都由必須放在 Docker 映像內預期位置的指令碼驅動。指令碼放哪裡,基本上就是全部的契約。實際後果是極大的彈性:Song 的團隊把一整套單節點 Phoenix 伺服器、它的 API、一支 CLI、一批放在檔案系統上的 skill,以及一個 SQLite 檔,全部塞進同一個映像。「基本上,只要塞得進 Docker 映像,Harbor 就能讓它跑起來。」反過來,有觀眾指出,牽涉 S3 等相依元件的分散式系統就難得多——Song 的建議是為代理切出一個穩定的介面,但他也承認,用 mock 模擬 S3 呼叫等於又回到 Harbor 原本想擺脫的 mock 世界。他提到 Harbor 可以執行多個 Docker 映像,或許有幫助,但他自己沒深入處理過這個問題。
一次提示詞調整,用工具呼叫次數而非正確性來驗證
具體案例是這樣:Phoenix 的 MCP 伺服器與 CLI 原本同時提供 REST 與 GraphQL,但使用者問的是彙總型問題——最近幾個月最忙的一天、trace 數量、各模型的支出——這些問題迫使代理在客戶端分頁與彙總,產生大量工具呼叫。團隊於是新增一個工具,讓代理對資料庫寫唯讀 SQL 查詢。新的問題是工具選擇:同時有 REST、GraphQL 與 SQL 可用時,代理不知道該用哪一個。解法是一次小幅的提示詞調整——原本只提到 GraphQL;現在提示詞寫明,遇到計數、分組這類彙總,要用 SQL 工具,而不是先去找 GraphQL。
Song 請 Claude 針對 Phoenix 的各個領域(traces、spans、datasets、experiments)腦力激盪使用者可能問的問題,有些是彙總型、有些不是,並為每一題寫出預言機解法——一次 REST 呼叫或一句資料庫查詢——藉此生成一份合成資料集。他抽查了這些問題。部分驗證器採用 LLM-as-judge,其他則是 SQL 查詢或 REST 呼叫本身。調整後的結果:SQL 使用量上升、GraphQL 使用量下降、平均工具呼叫次數減少,代理輪次也變少,因為多輪分頁被壓縮成單一 SQL 輪次。獎勵值從頭到尾都維持高檔,因為系統原本就能答對——這是最佳化,不是修正確性。Song 指出,這些降幅看起來不大,是因為測試資料量不夠大。
Phoenix 補上資料集版本控管、實驗比較與軌跡檢視
Harbor 有自己的開源本機 UI 與託管網路服務,所以 Phoenix 是可選的。Song 說,Phoenix 補上的是把 Harbor 的基本元件對應到自己的概念:資料集對資料集、job 對實驗、試驗對 run、獎勵對評估。它也會把 ATIF 軌跡轉成 OpenInference——一套建構在 OpenTelemetry 之上的語意慣例開放標準,由 Song 共同維護,最近捐給了 CNCF 與 OpenTelemetry 工作小組。這層轉換帶來幾個好處:可渲染 LLM 與工具步驟的專屬 UI、資料集版本控管(讓你確切知道某個 job 是對哪個版本的任務跑的),以及長期的實驗追蹤。
示範中,Song 在任務層級比較兩個 job——提示詞調整前後的 Opus 5。頂層指標顯示 GraphQL 工具呼叫下降、SQL 呼叫上升、工具次數下降、輪次下降,獎勵不變。逐任務表格列出每個 job 的預期答案與實際答案。還有一個自然語言篩選器(在瀏覽器裡跑本機模型,把文字轉成查詢 DSL),讓他能篩出第二個實驗工具次數較少的那些列;示範時第一次嘗試沒命中,他手動貼上正確的表示式。深入軌跡可以看到,調整前是呼叫 bash,底層再透過 bash 模擬器呼叫 GraphQL;調整後則直接發出 SQL 查詢。他甚至請代理自己去檢視實驗並解釋發生了什麼事——團隊會用代理來迭代代理本身。
會偷看軌跡的驗證器沒問題,只是沒那麼穩健
有觀眾質疑那個 SQL 使用量的驗證器:如果驗證器應該與實作無關,那檢查代理有沒有用 SQL,不就是作弊?Song 回答「是」,並說這取決於你在測什麼。以正確性為主的回歸測試,他的驗證器「相當純」——只檢查代理有沒有得到正確答案,不理會軌跡。至於像減少工具呼叫這類最佳化工作,偷看軌跡換來的資訊值得犧牲穩健性。他把 Harbor 放在一條從完全解耦到與實作耦合的光譜上,並主張:只要耦合測試能回答你在意的問題,就沒有理由不寫。同樣的邏輯也適用於測試某個 skill 有沒有被觸發:你可以檢查軌跡裡有沒有該 skill 的呼叫,只是把 skill 改名就會讓測試不穩。
難解之處:資料來源、回歸成熟度與 skill 衝突
Song 坦然說明哪些問題還沒解決。對這類任務來說,資料就是「最難的部分」,資料越真實,訊號越好。他的團隊蒐集了一批半真實的 SQLite 檔,都是 dogfooding 時順手留下的;有合適的就重複使用,並請 Claude 裁掉不需要的資料、推上雲端儲存——這是臨時性的流程,不是自動化管線。他們目前沒有對大型資料集做評估,不過他認為這沒問題,而且如果要測代理在完整資料庫上的表現,這就會很重要。回歸測試方面,他們「真的還在很早期」,目前聚焦在把最重要的幾個 skill 在他們支援的眾多模型與供應商上的 happy path 做扎實;他把它類比為 Playwright 端對端測試,只是迴路裡多了代理與 LLM 呼叫。至於 skill 衝突——某個 skill 的 front matter 踩到另一個 skill、導致某個 skill 不再被觸發——他提出兩種做法:靠端對端測試在 skill 沒觸發時失敗,或直接在軌跡裡檢查該 skill 的呼叫。談到團隊如何整理與共享資料集,他說團隊很小(「真的就只有我和幾個人」),無法代表大型組織的做法,不過 Phoenix 的共享、整理與從外部檔案 upsert 等功能就是為此設計的。
Harbor 在這裡評估的其實是一套混合系統,不是編碼代理
Song 最後區分了他的使用情境與 Harbor 的典型用途。Harbor 典型上是用來評估編碼代理,但他的團隊並不是在做 Claude Code 或 Codex——他們改不動那些東西。他們最佳化的是那套混合系統:Claude Code 加上自家 MCP 伺服器、自家 skill、自家 CLI、自家 API。正因為是混合系統,所有東西才被塞進同一個環境、當成一個單位來評估。走到這個結論花了不少時間,而 Phoenix 單節點、類 Grafana 的架構很容易 Docker 化,幫了大忙。他也點出一個實務上的摩擦:因為 Harbor 的契約是「指令碼放在哪些目錄」,沒有 linter 能讓編碼代理依靠來做對;目前最好的輔助是下載 Harbor 的 skill,用它引導專案設定。
整場演講的主軸是:唯有產生證據的成本低到能經常做,證據才可能勝過直覺——而 Harbor 的「每次試驗彼此獨立」設計、預言機優先的除錯方式,以及以指令碼為基礎的契約,正是讓成本變低的關鍵。尚未化解的張力在於:讓驗證器穩健的那份解耦,同時也讓它們看不見團隊常想最佳化的東西,例如哪個工具或哪個 skill 被觸發,於是在可維護性與敏感度之間被迫取捨。有兩項發展值得關注:OpenInference 捐給 CNCF 與 OpenTelemetry 工作小組之後,是否會把軌跡格式推向共同標準;以及團隊在 skill 上仍屬早期的回歸工作,是否會成熟到 Song 所說、相當於 Playwright 的覆蓋水準。