iT邦幫忙

2026 iThome 鐵人賽

DAY 7
0
AI Engineering

Harness Engineering × Pi Agent 實戰:打造可觀測、可評估的 AI Coding Agent系列 第 7 篇

Day7:如何公平評估 Coding Agent?打造可重複、可驗證的量測台

  • 分享至 

  • xImage
  •  

一次成功不代表什麼

Day6 看到 Pi 照著 AGENTS.md 把一個 API 做對了。但這只是一次執行——換個時間再跑,它可能漏掉一個註冊點;拿掉 AGENTS.md,它可能也照樣做對。只看一次,什麼結論都下不了。

Day1 承諾過:這系列每一個「更好」都要能被重跑驗證。今天就來兌現這個承諾的第一步——搭一個量測台。

程式碼和之後所有實驗數據都公開在 howisyour/my_first_pi_agent_project。

量測台需要三樣東西

  1. 可以重複執行的任務:每次都從一模一樣的起點開始。
  2. 不靠人判斷的驗收:成功或失敗由程式決定,不用 LLM 當裁判。
  3. 自動收集數字:成本、tokens、工具呼叫,直接從 session 記錄算。

受測專案:找得到,但要付出成本

我寫了一個小型的任務管理 API(taskapp),約 60 個檔案,裡面刻意埋了五個「專案慣例」:

慣例 違反的後果
真正的驗收是 python scripts/check.py,python -m pytest 只跑單元測試 只跑 pytest 會以為全過
新增 endpoint 要改三處:route、schema 匯出、ROUTE_REGISTRY 少一處就回 404 或 500
預期中的錯誤一律 raise AppError 子類 裸 ValueError 會變成 500
models_generated.py 禁止手改,要改 schema 再重新產生 雜湊值對不上,檢查失敗
routes/services 不能出現 0、1、-1 以外的數字 檢查會掃出來

設計這些慣例時,最重要的原則是:找得到,但要付出成本。

如果完全找不到,沒有 AGENTS.md 的那組會全部失敗(地板效應);如果太明顯,兩組都全部成功(天花板效應)。兩種情況都量不出差異。所以每一個慣例都寫在 README 或 docs/ 裡,認真讀的 agent 找得到——只是要多花幾輪去讀。

五個任務,各綁一個假設

任務不是隨便挑的。每個任務都是為了量某一個元件設計的:

任務 想量的元件 內容
T1 修分頁 bug 對照組 單純修一個邊界 bug
T2 新增 endpoint AGENTS.md 要改三處才會通
T3 修 CI 檢查 AGENTS.md pytest 是綠的,問題只有 check.py 看得到
T4 拆常數 搜尋工具 把散在 6 個檔案的常數拆成兩個
T5 資料遷移 Skills 照專案的六步驟流程新增欄位

怎麼判定成功

每個任務除了 check.py,還有一組 agent 看不到的隱藏測試。例如 T2 的隱藏測試會先改掉某個任務的狀態再查統計,確認數字是真的算出來的,而不是照規格寫死。

還有一個一定要處理的漏洞:agent 可能為了讓測試通過去改測試本身。所以驗收之前,量測台會先比對 check.py、tests/、pyproject.toml 這些受保護的檔案有沒有被動過——有就記錄下來,然後還原成原本的版本再驗收。改測試是過不了關的。

最後判定只看 exit code:check.py 通過、隱藏測試通過,才算成功。

一次執行的流程

量測台的一次執行

八個步驟裡,只有第三步跟 harness 有關。量測台只要求 harness 提供這個介面:

class HarnessAdapter(Protocol):
    name: str

    def version(self) -> str: ...

    def run(self, workdir: Path, prompt: str, condition: Condition, run_dir: Path, timeout: int) -> AgentRun: ...

給它一個工作目錄、一段 prompt、這次的實驗條件,它回傳 exit code 和 session 記錄的位置。任務、條件、驗收全部跟 harness 無關,寫一個 Claude Code 或 Codex 的 adapter,就能跑同一組任務互相比較。

Pi 的 adapter 實際下的指令長這樣:

pi -p --mode json \
  --no-extensions --no-skills --no-prompt-templates --no-themes \
  --session-dir <這次執行的目錄>/session \
  --model openai-codex/gpt-5.6-luna --thinking medium \
  -- "<任務 prompt>"

那一串 --no-* 很重要:它把我電腦上可能存在的全域 extension、skill、prompt 範本全部關掉,只有實驗條件明確指定的東西才會被載入。否則「有沒有某個元件」這個變數根本控制不住。

同樣的理由,每次執行都在一個獨立的資料夾進行,而且這個資料夾本身是一個獨立的 git repo。Pi 會往上層目錄找 AGENTS.md、往上找到 git 根目錄為止搜尋 skills,隔離在獨立 repo 裡,就不會意外撿到別的專案的設定。

先驗證量測台本身

量測台也是程式,也會有 bug。在花任何一分錢跑 agent 之前,我先讓它對每個任務做兩件事:

  • 不做任何修改直接驗收——必須失敗
  • 套上我手寫的參考解再驗收——必須成功
[PASS] clean fixture passes scripts/check.py
[PASS] t1_fix_pagination: baseline 失敗於 pytest,參考解成功
[PASS] t2_add_endpoint:   baseline 失敗於 pytest 與 3 個隱藏測試,參考解成功
[PASS] t3_fix_check:      baseline 失敗於 ruff、pytest、raise_scan、magic_numbers,參考解成功
[PASS] t4_split_constant: baseline 失敗於 4 個隱藏測試,參考解成功
[PASS] t5_migration:      baseline 失敗於 5 個隱藏測試,參考解成功

這一步抓到了我自己寫的 check.py 有幾行太長、被它自己的 lint 規則擋下來——如果沒先跑這個自我檢查,第一批實驗會全部被判失敗,而我可能會以為是 agent 的問題。

每次執行留下什麼

每次執行會在 experiments/results/<實驗>/runs.jsonl 寫一行記錄,主要欄位:

  • 任務、條件、第幾次重複、harness 版本、模型、thinking level
  • success、失敗在 check.py 的哪一關、哪些隱藏測試沒過、有沒有動到受保護檔案
  • 成本、tokens、工具呼叫次數(依工具分類)、工具錯誤、傳輸層失敗
  • 跑過哪些 bash 指令、讀過哪些文件、有沒有跑 check.py、有沒有讀 SKILL.md

另外還會保留完整的 session 記錄與 git diff。公開之前,記錄裡的本機路徑、使用者名稱、電腦名稱都會被換成 <HOME>、<user>、<host> 這類代號。

幾個實作上的小決定:

  • 條件交錯執行:不是先跑完「有 AGENTS.md」再跑「沒有 AGENTS.md」,而是輪流跑。這樣服務商某段時間變慢或變快,會平均落在每個條件上。
  • 可以中斷續跑:已經寫進 runs.jsonl 的執行會被跳過。
  • 三個 worker 平行:第一次校準總共 30 次執行,平行跑完花了約 16 分鐘。

卡住的執行不算 agent 失敗

第一批校準跑下來,我踩到兩種「看起來是失敗,其實跟 agent 無關」的狀況:

  • harness 卡住:有一次執行跑滿 900 秒逾時,但記錄裡只有 3 輪模型呼叫、成本 0.0015 美元——模型根本沒在工作,是跟服務商的連線卡住了。
  • 服務商直接拒絕:我想換一個較弱的模型做對照,結果 30 次執行全部在幾秒內「失敗」,工具呼叫 0 次、成本 0 元。打開記錄才看到錯誤訊息:這個模型不支援用 ChatGPT 帳號透過 Codex 呼叫。緊接著又撞到訂閱方案的用量上限。

如果量測台把這些當成 agent 做錯,就會畫出「某個條件成功率 0%」這種完全錯誤的圖。所以我加了一條規則:模型一輪都沒回應、只有錯誤回應、或事件串流連續 420 秒沒有任何輸出,就判定為基礎設施失敗。這類執行會被移到另一個檔案(不刪除),然後重跑,並在結果表格下方註明有幾次是重跑的。

420 秒這個數字是刻意選的:Pi 自己的 HTTP 閒置逾時是 300 秒,逾時後會自己重試,量測台要給它自救的機會,而不是搶先把它砍掉。

第一次實跑

量測台的第一次正式執行是 T1(修分頁 bug):成功,8 次工具呼叫,成本 0.0026 美元,耗時 105 秒,完成前有照 AGENTS.md 跑 check.py。

還有一個意外的發現:Pi 預設只開 read、bash、edit、write 四個工具,grep、find、ls 這些搜尋工具預設是關的。但這次執行裡,agent 直接透過 bash 用了 rg 和 find。關掉一個工具,不代表 agent 就沒有那個能力——它會繞路。原本大綱寫的 Day13「拿掉 grep/find/ls 的代價」,因此要改成「加上 grep/find/ls 有沒有差」,而且要把透過 bash 繞路的次數一起量進去。

明天

量測台搭好了,接下來進入第一輪「拆一個元件、隔天量它」。Day8 先拆 AGENTS.md:Pi 從哪些地方載入它、多個檔案之間怎麼決定誰覆蓋誰,以及它最後是怎麼進到模型眼前的。


上一篇
Day6:Agent 黑箱裡發生了什麼?從 Session 記錄還原八輪決策
下一篇
Day8:Agent 如何讀懂專案規則?拆解 AGENTS.md 的載入與優先順序
系列文
Harness Engineering × Pi Agent 實戰:打造可觀測、可評估的 AI Coding Agent 共 11 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
愛瘸瘸
iT邦新手 5 級 ‧ 2026-09-21 12:59:11

您的文章非常精采,但我有一些問題想問您
重複次數與隨機性:「文中提到第一次校準跑了 30 次執行,想請問後續針對單一任務在不同條件(如有/無 AGENTS.md)下,預計各跑幾次(N 等於多少)來判定成功率差異?對於 LLM 本身輸出的隨機性,有預計採用哪些統計檢定(例如 Fisher's exact test)或信心區間來支撐結論嗎?」
Prompt 洩漏與難度調校:「任務描述(Prompt)本身是如何設計的?如果 prompt 裡提到『請遵循專案慣例』,會不會引導模型主動去看 README;反之若只給最精簡的 issue 描述,會不會造成所有條件都掉入地板效應?」

我要留言

立即登入留言