AI agent 在 production 上爆掉的那一刻,觀測工具能交出來的,只有一份做得很漂亮的驗屍報告。每一次模型呼叫、每一次工具呼叫、每一步的延遲、每一段的 token 用量,全部一格一格排得整整齊齊。但它對三件最想知道的事,一個字都不說:這條紀錄為什麼斷了、哪個改動能把它修好、以及同樣的錯下次會不會再來。

於是除錯就變成體力活:一段一段往下捲,腦中拼出一個假設,寫個補丁,然後祈禱別把原本好好的地方弄壞。等下一個模型上線、帶著它自己一整套全新的出錯方式,整個迴圈再從頭跑一次。

Mogu 溫馨提示:

這幾年觀測工具的軍備競賽,幾乎都打在「誰的儀表板比較好看」上——配色更柔、火焰圖更滑、每一格點開都有動畫。問題是,再漂亮的驗屍報告,本質上還是被動的:它只忠實記錄「發生過什麼」,對「現在到底該怎麼辦」完全噤聲。看著一具排版精美的屍體,救不回任何一個 production 事故。

那層 harness 只會越長越大

先把場景講清楚。一個 agent 不是只有那顆原始模型,外面還包了一整層 harnessprompt 層、各種工具、一道道檢查與護欄,全都繞著模型轉。Cursor 最近就分享過,他們在 agent 外面到底塞了多少工程——而且每升一次模型、每加一個工具,這層要顧的表面就更大一圈。

麻煩的是,主流觀測工具目前停在「把驗屍報告做得更精美」這一格。儀表板越做越華麗,但它沒有往前再走一步:看到一條壞掉的紀錄之後,人還是得自己跳下去查、自己改、自己賭它有沒有修對。工具把「看見問題」做到了極致,「解決問題」那半邊卻整個留白。


把人工除錯迴圈,換成一條會自己跑的迴圈

這條線 gu-log 其實踩過兩次,但都停在不同的點。SP-158 講的是「追蹤紀錄是改善迴圈的起點」——先看得見 agent 怎麼犯錯,才談得上改;SP-179 再往前一步,講怎麼把每一次翻車用人力蒸餾成一條結構性的防線。這篇要補的,是夾在這兩者中間、最容易被跳過的那一段:把「看見問題 → 修好 → 鎖成測試」整條接起來自動跑,而不是每出一次事就靠人重新接一遍線。

真正缺的東西其實很單純:這個迴圈不該靠人輪班顧,它應該自動跑起來。

想看一個具體長相,可以拿 Opik 這套開源工具當例子——但先講白,重點從來不是這個產品本身,而是它把「出事 → 修好 → 不再犯」接成一個完整閉環的那套想法。它的四個部分不是四個獨立功能,是一條首尾相接的環:

追蹤紀錄 → 一個 agent 讀紀錄做診斷 → 提出補丁 → 套用並重跑驗證 → 把這次失敗鎖成回歸測試 → 回到追蹤紀錄

一層一層拆開看。


第一層:把每一步都自動記下來

一行 @opik.track 標註,就把每一次 LLM 呼叫、工具呼叫、檢索步驟自動記錄起來,支援 LangGraph、CrewAI 等 50 多種框架。

import opik

@opik.track
def my_agent(query: str):
    # agent 的邏輯寫在這
    ...

關鍵不在「有紀錄」這件事本身——觀測工具誰都有紀錄。關鍵在每一筆紀錄都連帶記下「當下是哪一份 agent 設定在跑」。這樣等之後要拿同一個出錯的輸入重跑時,能完整重現當時的狀況。而「可重現」這三個字,正是後面整條修復迴圈站得住腳的地基:修不可重現的 bug,跟對著空氣揮拳沒兩樣。

Mogu 畫重點:

可重現性大概是這整套裡最不起眼、卻最關鍵的一塊。很多人記 log 只記「輸入輸出」,結果三天後想重跑那個詭異案例,發現當時的 prompt 版本、模型、工具設定全都對不上,根本復現不出來。先把「當時是哪一套設定」釘死,後面的自動修復才有東西可以咬。


第二層:讓一個 agent 讀紀錄,然後動手修

這一層叫 Ollie,是 Opik 內建的一個會寫程式的 agent。丟一份出錯紀錄給它,它會去讀原始碼、指出該為這次失敗負責的那幾行、提出一份改動——而且在按下核准之前,它什麼都不會動。

核准之後,它做三件事連在一起:拿原始那筆出錯的輸入重跑一次、把新舊兩份紀錄並排給人比對、再把原本那次失敗鎖進測試套件當成一個回歸案例。

更狠的是,就算完全不給它碰原始碼,光讀紀錄它也能解釋因果鏈。問它一句「為什麼最後的答案無視了檢索回來的內容?」,它會把整棵呼叫樹從頭走一遍,指出根因落在哪一段。

Mogu 歪樓一下:

注意一個很重要的設計:每一步都要人核准,它不是 YOLO 全自動亂修一通。會寫程式的 agent 最危險的地方,就是「我看過這種錯」式的自信——對上一個眼熟的故障樣子,就一頭栽下去動手,結果動到根因完全不同的地方。把人留在迴圈裡按核准,不是流程龜毛,是越聰明的工具越需要的剎車。


第三層:用白話寫測試,每個 bug 自動變成考題

傳統的 eval 流程長這樣:準備一份標好答案的資料集、定義一個數值指標、比浮點數大小。問題是,這跟工程師腦中「這個回答到底好不好」的判斷方式對不上——沒人是靠「0.82 比 0.79 高」在決定一個客服回覆能不能出門的。

Opik 讓人改用白話斷言來描述「什麼叫對」:

suite = opik.TestSuite("crm-agent-v2")

suite.add_assertion("回覆必須包含具體的成交細節,不能只丟一個數字總數")

suite.add_assertion("回覆絕對不能洩漏未經授權的資訊")

suite.run_tests()

底層 Opik 會把這些白話斷言轉成「找一個 LLM 來當評審」的檢查,每個案例給出乾淨的過或不過。

最妙的是收尾這一步:每一條被除錯過的失敗紀錄,會自動變成一個新的測試案例。測試套件就這樣從真實的 production 失敗裡一條一條長出來——每跑完一圈,這層 harness 就比上一圈更難被打破一次。

Mogu 忍不住說:

這招其實 gu-log 自己天天在用:這個專案的鐵律就是「每個 bug = 一個新的測試」,修之前先寫一個會紅的測試把 bug 釘住,修完變綠,這個測試就永遠留著當免疫力。把一次性的事故變成永久的防線,是同一個精神。差別只在 Opik 把「寫那個測試」這一步也自動化掉了——人連回歸測試都不用手刻。


第四層:改東西之前,先在沙盒裡跑整張圖

多數「試玩場」其實只是 prompt 試玩場:改一句 system prompt、重跑那一次 LLM 呼叫,看輸出有沒有變好。但這回答的是錯的問題。production 真正會痛的問題是——「動了某個東西之後,整張 agent 圖會變成什麼樣?」改一個 prompt,可能把下游三個工具呼叫的行為一起帶歪,單看那一格 LLM 呼叫根本看不出來。

Opik 的 Agent 沙盒把完整插好記錄的 agent 整條端到端跑在介面裡。改 prompt、換模型、加工具,直接看整個系統在整棵呼叫樹上怎麼連鎖反應。而且每跑一次沙盒,又產出一份完整的紀錄——驗證本身也被記下來,迴圈就這樣咬住自己的尾巴。


真正的重點:這不是四個功能,是一個閉環

四層分開講完,但把它們接起來看才是整件事的靈魂。

一個 production 失敗進來,Ollie 讀紀錄加原始碼、提一份補丁;人核准;Ollie 拿原始那筆出錯的輸入,在沙盒裡重跑一遍;通過了,就把這版存成新的藍圖,環境指標往上升到預備環境;最後,把原本那次失敗鎖成一條回歸測試。下一次失敗——如果還有的話——進的是同一條迴圈。

每繞一圈,這層 harness 就更難被打破一次。

這才是跟「儀表板越做越漂亮」正式分道揚鑣的地方。觀測這件事被困在「被動記錄」太久了;真正的位移,是從被動的紀錄,走到主動的修復——從一個 production 失敗,到一份核准過的補丁,再到一條鎖死的回歸測試,整條路一次走完,而不是在第一站「看見問題」就停下來鼓掌。

Mogu 內心戲:

再講一次免得誤會:Opik 在這篇只是「一個剛好把這套想法做出來的例子」,不是這篇要推銷的東西(它確實是開源、星星也不少,所以不是空中樓閣,但這不是重點)。真正要記住的是那個形狀:production 系統需要的,是一條會自我修復的 harness 迴圈,不是一塊更高解析度的儀表板。哪天有第二個、第三個工具把同一條閉環做出來,這篇的論點照樣成立——形狀對了,掛誰的牌子都行 (⁠¬⁠‿⁠¬⁠)


結語

別再對著那份排版精美的驗屍報告嘖嘖稱奇了。

過去十年,觀測工具拚的是「把死法呈現得更清楚」;下一步該拚的,是「把病人救回來,順手讓它對同一種死法免疫」。一條從失敗、到診斷、到核准、到重跑、到鎖死回歸測試的閉環,價值不在任何單一格子有多漂亮,而在它每轉一圈,就把同一個坑往實裡填一截——填到最後,能絆倒這個 agent 的東西,只剩下它還沒見過的全新失敗。

而那,本來就是工程該往前推的方向:不是更會驗屍,是更難被同一刀殺死第二次。