AI Agent 時代,Trace 才是你的 source of truth
最近看了 LangChain 幾篇關於 agent tracing 和 eval 的文章(1 2 3 4),加上他們最近出的一篇 conceptual guide 把整個觀點串起來,覺得裡面有一個核心命題講得蠻到位的: 在傳統軟體裡,code 記錄了你的 app 在做什麼;在 AI agent 裡,trace 才是。
這不只是 observability 工具的行銷話術,而是一個根本性的範式轉移。以下整理一些我覺得有啟發的觀點,以及 LangChain 團隊實際上怎麼設計工具來解決這些問題。
Code 不再記錄你的應用邏輯
傳統軟體裡,你想知道表單送出後發生什麼事,打開 handleSubmit() 就看到了: 驗證輸入、檢查權限、呼叫 API、處理錯誤。邏輯就寫在 code 裡,同樣的輸入走同樣的路徑、產生同樣的結果。
但 AI agent 的 code 長這樣:
agent = Agent(
model="gpt-4",
tools=[search_tool, analysis_tool],
system_prompt="You are a helpful data analyst..."
)
result = agent.run(user_query)
你定義了零件(哪個 model、哪些 tools、什麼 prompt),但實際的決策邏輯不在你的 code 裡。要呼叫哪個 tool、怎麼推理、什麼時候停下來 — 全部發生在 model 的 runtime 裡。
所以你可以 debug 你的 orchestration code(tool calling 有沒有壞、parsing 對不對),但你沒辦法 debug「智慧」— agent 做的決策好不好、推理有沒有效,這些邏輯活在 model 裡面,不在你的 codebase。
而且這個不確定性是層層加深的: 從傳統軟體(確定性)→ LLM 應用(單次呼叫,引入自然語言的模糊性)→ Agent(多步驟迴圈,在幾十甚至幾百步中持續推理、呼叫工具、維護狀態)。每一層都讓行為更難預測,也讓 code 離「真相」更遠。
Trace 就是 agent 的「原始碼」
那實際的行為記錄在哪裡? 在 trace 裡。
不過要理解 agent 的 observability,需要先認識三個核心原語(primitives):
🔹 Run: 單一執行步驟 — 一次 LLM 呼叫,包含完整的 prompt、可用工具、輸入輸出。這是最小的觀測單位,讓你看到 agent 在某個特定時間點「在想什麼」
🔹 Trace: 一次完整的 agent 執行,把所有 run 串在一起,記錄完整的步驟序列、每一步的推理、呼叫了什麼 tool、為什麼呼叫、結果是什麼、花了多少時間。這才是你的 app 邏輯的真正文件
🔹 Thread: 把多次 agent 執行(多個 trace)群組成一個對話 session。因為真實場景裡,agent 和用戶的互動可能橫跨好幾輪、甚至好幾天
這三個原語用的是跟傳統 observability 類似的概念(trace、span),但它們捕捉的不是 service call 和 timing,而是推理的上下文。而且 agent trace 的規模跟傳統 distributed trace 完全不是一個量級 — 傳統 trace 可能幾百 bytes,複雜 agent 的 trace 可以到幾百 MB。
為什麼 thread 很重要? 舉個例子: 一個 coding agent 在前 10 輪都運作正常,到第 11 輪開始出錯。如果你只看第 11 輪的 trace,agent 呼叫的 tool 看起來都很合理。但把整個 thread 拉出來看,你會發現第 6 輪時 agent 把一個錯誤的假設寫進了 memory,到第 11 輪時這個壞的 context 已經 compound 成嚴重的問題了。沒有 thread 層級的視角,這種跨輪次的 regression 根本抓不到。
理解了這三個原語後,你在傳統軟體世界對 code 做的所有操作,現在都要對應到這些 observability 資料上:
🔹 Debugging → Trace 分析: 用戶回報 agent 失敗了,你不是打開 code 找 bug,而是打開 trace 看推理哪裡出錯了。「Bug」不是你 code 裡的邏輯錯誤,而是 agent 實際行為中的推理錯誤。一個實際的例子: agent 對同一個失敗的 API call 重試了五次才放棄。你的 retry 邏輯沒壞,但 agent 沒有從錯誤訊息中學到東西 — 同樣的 tool call、同樣的參數、同樣的失敗。這只有看 trace 才看得出來
🔹 Breakpoint → Playground: 傳統 debug 你在 code 上設斷點,但你沒辦法在「推理」上設斷點。替代方案是: 打開 trace 找到 agent 做出壞決策的那個時間點,把當時的完整狀態(也就是那個 run 的 context)載入 playground(context、memory、available tools、prompt),然後在那個點上迭代測試不同的 prompt 和 context
🔹 Testing → Eval-driven: 因為 agent 是非確定性的,你需要在 production 持續跑 eval 來抓品質下降和 drift,不能像傳統軟體一樣部署前測完就好
🔹 Performance profiling → 決策分析: 傳統軟體 profile hot loops 和演算法,agent 則要 profile 決策模式 — 不必要的 tool calls、冗餘的推理、低效的路徑。LangChain 提到一個真實案例: 他們用 AI 輔助分析 150 步的 trace,發現 agent 對同一個檔案重複呼叫了好幾次 read_file,而不是把內容存在 context 裡。修復只是一個簡單的 prompt 調整,但靠人工看 trace 要花好幾個小時才可能發現這種 pattern
🔹 Monitoring → 品質監控: Agent 可以 0 error、100% uptime 但表現超爛 — 做錯事但沒報錯、用 10 倍成本做完、答案正確但沒用。你需要監控的是決策品質,不只是系統健康
為什麼 Agent 的行為不可預測
這是傳統軟體工程師轉做 agent 開發最需要適應的一點。三個關鍵差異:
| 傳統軟體 | AI Agent | |
|---|---|---|
| 確定性 | ✅ 同輸入同輸出 | ❌ 每次都可能不同 |
| 對輸入變化的穩健性 | ✅ 小改動不會劇變 | ❌ Prompt sensitivity |
| 輸入空間 | ✅ UI 限定範圍 | ❌ 自然語言,無邊界 |
因為 agent 是非確定性的、對小變化敏感、接受無限制的輸入,你根本無法在上線前預測它會做什麼。大部分的失敗模式是在 production 才浮現的,跟傳統軟體正好相反。
這也帶出一個根本性的轉變: production 不再只是「抓漏掉的 bug」的地方,而是「發現該測什麼」的地方。 傳統軟體裡,你在 staging 寫好測試、上線後只是確認沒有 edge case。但 agent 的每個自然語言輸入都是獨特的,你無法事先預測用戶會怎麼措辭、會觸發什麼邊界情況。Production trace 揭示的失敗模式,往往是你根本想不到要測的東西。這意味著你的 eval suite 應該持續從 production 的真實案例中成長,而不是只靠工程師事先設計的場景。
Deep Agent 讓問題更嚴重
當 agent 變得更複雜(所謂的 “deep agent” — 跑幾分鐘、幾十到幾百步、多輪互動),trace 分析的挑戰更大:
- 更長的 prompt: 動輒幾百甚至幾千行的 system prompt(persona + tool instructions + guidelines + few-shot examples)。行為出問題時,很難知道是哪個部分造成的
- 更長的 trace: 幾十到幾百步的執行紀錄,人類根本看不完。傳統的 tracing 工具只記錄 service call 和 latency,根本不捕捉每一步的推理 context,面對這種規模的 trace 完全不夠用
- 多輪互動: Human-in-the-loop 的對話可能橫跨好幾個 session,甚至好幾天。要理解完整行為軌跡需要跨多次互動來看 — 這就是為什麼需要 thread 層級的觀測
Deep Agent 怎麼測? 三種 Eval 粒度
前面提到 agent 的 testing 變成 eval-driven,但到了 deep agent 的層級,eval 本身也變得更複雜。LangChain 最近分享了他們在四個 deep agent 產品上學到的 eval 經驗(DeepAgents CLI、LangSmith Assist、Personal Email Assistant、Agent Builder),我覺得蠻有實戰參考價值的。
第一個認知轉變: 每個 test case 都需要不同的判斷邏輯
傳統 LLM eval 很簡單: 建一個 dataset,寫一個 evaluator,每筆資料跑同樣的流程、用同樣的標準打分。
Deep agent 打破了這個假設。因為每個 test case 的「成功」長得不一樣:
例如測試一個日曆排程 agent 的「記住偏好」功能,你需要驗證:
- Agent 有沒有呼叫
edit_file去改memories.md(trajectory 檢查) - Agent 有沒有跟用戶確認它記住了(final response 檢查)
memories.md裡面真的有寫「不要排 9 點以前的會」(state 檢查)
這三個檢查是這個 test case 獨有的。換一個 test case(例如「幫我找下週三下午的空檔」),成功標準又完全不同。所以 deep agent 的 eval 不是寫一個通用 evaluator 然後批次跑,而是每個 test case 都有自己的 assertion 邏輯。
三種 Agent 執行粒度
這三種 eval 粒度剛好對應到前面提的三個 observability 原語 — single step 驗證的是 run,full turn 驗證的是 trace,multi-turn 驗證的是 thread:
Single Step(單步): Agent 的 Unit Test
只跑一步 — 給 agent 當前狀態,看它下一個動作是什麼。不跑完整個流程。
這是他們大約一半的 test case 用的方式。原因很實際: regression 通常發生在單一決策點,不是整個執行序列。而且只跑一步省 token、跑得快。
例如: 給 agent 一個「幫我找會議時間」的 context,驗證它第一步是不是呼叫了 search_calendar 而不是 send_email。如果用 LangGraph,可以用 interrupt_before 在 tool node 前暫停,拿到 agent 的決策結果做 assertion。
為什麼這跟 observability 有關? 因為這些 single step test case 通常來自 production — 用戶回報了一個問題,你打開那個 run,看到 agent 在那個時間點的完整狀態(prompt、context、tools),然後直接把它轉成 test case。沒有詳細的 run 紀錄,你根本無法重建那個決策時刻。
Full Turn(完整回合): Agent 的 Integration Test
讓 agent 跑完一整輪(可能包含多次 tool call),看最終結果。三種東西可以檢查:
- Trajectory: 某個 tool 有沒有在過程中被呼叫(不管順序)。例如日曆 agent 可能需要多次 tool call 才能找到所有人都有空的時段
- Final Response: 最終回覆的品質。對 open-ended 任務(coding、research)特別重要,因為路徑可能很多,但最終產出才是重點
- Other State: Agent 產出的 artifact — coding agent 寫的檔案、research agent 找到的 sources。直接檢查這些 artifact 是否正確
Multiple Turns(多輪): 模擬真實用戶互動
模擬用戶跟 agent 的多輪對話。挑戰是: 如果你寫死一連串 user input,但 agent 在第一輪就偏離預期,後面的 input 就不 make sense 了。
LangChain 的做法是加 conditional logic: 跑完每一輪後檢查 agent output,符合預期才繼續下一輪,不符合就直接 fail。如果只想測第二輪或第三輪的行為,直接從那個狀態開始測,不用每次都從頭跑。
Multi-turn eval 是最難做好的一種,也是最少團隊真正落實的。但對有狀態互動的 agent 來說又最接近真實使用情境。
怎麼選擇 eval 粒度?
實務上的考量:
- Full turn 最容易想到 input: 就是你 agent 的輸入嘛,很直覺。但要定義「正確的 output」和自動化評分比較難,所以有些團隊一開始會先自動跑 agent、手動看結果
- Single step 最容易自動化評分: 就是檢查呼叫了哪個 tool,很明確。但要注意: 如果你的 agent 架構還在頻繁調整(哪些 tool 可用、呼叫順序),這些測試會很快過期
- Multi-turn 最難做好: 要設計合理的對話序列,還要處理 agent 偏離預期的情況。最少見但對 stateful 場景最重要
大部分 production agent 的做法是混搭: full turn 測核心流程、single step 測已知的 failure mode、multi-turn 測有狀態的互動場景。
環境設定是隱藏的大坑
Deep agent 是 stateful 的,eval 環境必須每次測試都重置,否則結果不可重現。
Coding agent 最明顯 — 你需要一個乾淨的目錄或 sandbox 來跑每個 test case。LangChain 的 DeepAgents CLI 用輕量做法: 每個 test case 建一個 temp directory,測完刪掉。
另一個實用技巧: Mock 外部 API。LangSmith Assist 需要連真的 LangSmith API,但跑 eval 打真的 API 太慢太貴。他們的做法是把 HTTP request 錄下來,eval 時 replay。Python 可以用 vcr,JS 可以用 Hono app 做 proxy。
小結: Deep Agent Eval 的心智模型
| 粒度 | 類比 | 適合測什麼 | 佔比 |
|---|---|---|---|
| Single Step | Unit test | 單一決策點的正確性 | ~50% |
| Full Turn | Integration test | 端到端結果 + trajectory | ~35% |
| Multiple Turns | E2E test | 真實多輪對話場景 | ~15% |
重點不是每種都用,而是根據你的 agent 特性混搭。但幾乎所有 deep agent 都需要 bespoke test logic — 那種「一個 evaluator 跑全部」的做法在 deep agent 上不 work。
從開發到 Production: Trace 驅動的觀測與 Eval 體系
上面講的 eval 模式解決的是開發階段的問題 — 你知道要測什麼、寫好 test case、跑 CI。但上線之後呢? Production 每天幾千幾萬筆 trace,你不可能為每一筆都量身寫檢查邏輯。
這裡有一個很重要的認知: observability 和 evaluation 不是兩件獨立的事。你為了觀測而產生的 trace,正是驅動 eval 的燃料。LangChain 的 conceptual guide 把這個關係講得很清楚。從 production 的角度來看,可以分成三層逐步加深,每一層都建立在 trace 之上:
第一層: Traditional Product Analytics
就是你在傳統軟體已經在做的事 — 追蹤 metrics。對 agent 來說,大多數 production 團隊會追蹤:
- End user feedback(thumbs up/down)
- Latency
- Token usage / cost
- Error rates
- Tool call 頻率
這些 metrics 能告訴你「出了什麼事」— 成功率下降了、latency 變高了、某個 tool 報錯率增加了。但 metrics 只能 surface 問題,不能告訴你 why。
不過在 agent 的世界裡,trace 讓這些 metrics 有了更深的用途。當你發現某個 metric 異常時,下一步就是打開對應的 trace 往下挖。而且 production trace 本身也能自動變成你的 eval dataset — 一個典型的工作流:
- 用戶回報 agent 行為不對
- 找到 production trace
- 定位到出錯的那一步,提取當時的完整狀態(run 的 context)
- 直接從這個狀態建立 test case
- 修復後驗證
這意味著你的 offline eval suite 是從真實的 production 資料長出來的,不是工程師憑空想像的場景。每一個 production 問題都可以變成一個新的 test case,你的測試覆蓋率會隨著時間自然增長。
第二層: Online Evals
在 production trace 上跑 evaluator,對已知的維度打分 — 用戶有沒有感到挫折、agent 有沒有完成任務、回答有沒有 grounded in facts。
具體來說,你可以在每筆 trace(或抽樣)上跑各種檢查:
- Trajectory 檢查: 偵測異常的 tool call pattern
- 效率監控: 抓到效能退化的趨勢
- 品質評分: 用 LLM-as-judge 對 production output 打分
- 失敗告警: 在用戶回報之前就發現問題
Online eval 的限制是: 你需要事先知道要找什麼。你可以 score 已知的問題,但沒辦法發現未知的 pattern。
第三層: Agent Analytics(探索性分析)
這是 LangChain 最新做的 LangSmith Insights Agent,我覺得設計思路蠻有意思的。
核心問題是: 當你每天有幾千甚至幾萬筆 trace,那些探索性的問題怎麼回答?「用戶到底怎麼用我的 agent?」「存在什麼我還不知道的失敗模式?」你沒辦法為還沒發現的 pattern 寫 evaluator。
有人提到他們每天記錄 10 萬筆以上的 trace,但「什麼都沒做」,因為靠人力根本不可能消化這個量。
LangSmith Insights Agent 的做法是用 clustering 來自動發現 pattern:
- 對大量 trace 做自動分群,產出多層級的 cluster hierarchy(頂層 cluster → 更細的分組 → 個別 trace),讓你可以 zoom in/out 到適當的粒度
- 預設提供兩種分析角度:「用戶怎麼使用我的 agent」和「agent 可能在哪些地方失敗」,但也可以自訂 prompt 來找任意 pattern(例如 compliance、tone、domain-specific 問題)
- 可以跟前面兩層結合 — 例如先用 metrics 過濾出所有 thumbs down 的 trace,再對這個子集做 clustering 分析。把定量信號(thumbs down)和定性分析(這些 thumbs down 裡有什麼 pattern)結合
- 可以 on-the-fly 計算還不存在的屬性。例如你問「為什麼用戶感到挫折」,它可以即時在 trace 上判定「用戶是否挫折」,然後基於這個新屬性做過濾和分群
這個設計思路我覺得蠻好的,因為它正好補上了傳統 product analytics 和 online eval 之間的 gap — 傳統 analytics 是為離散結構化事件(click、page view)設計的,面對非結構化的自然語言對話就不夠用了;online eval 需要你事先知道要找什麼。Clustering-based 的探索性分析剛好填了這個洞。
協作方式也會改變
在傳統軟體裡,協作發生在 GitHub — review code、在 PR 上留言。但 agent 的邏輯不在 code 裡而在 trace 裡,所以協作也得跟著 trace 走。你需要分享 trace、在特定決策點上加註解、討論 agent 為什麼選了這條路。Observability 平台不再只是監控工具,而是變成協作工具。
Product analytics 和 debugging 也會合併。你看到「30% 用戶感到挫折」後,下一步就是打開那些對話的 trace 看 agent 做錯了什麼。用戶體驗就是 agent 的決策,而決策記錄在 trace 裡。
以上,這幾篇文章加在一起,核心訊息很清楚: 在 AI agent 時代,trace 的地位就像傳統軟體裡的 source code。 Debugging、testing、profiling、monitoring、協作 — 所有你以前對 code 做的事,現在都要對 trace 做。而且 observability 和 evaluation 不是兩件獨立的事 — trace 同時是你觀測的媒介和驅動 eval 的燃料,兩者密不可分。
對做 agent 產品的團隊來說,我覺得實務上的建議是:
- 最基本: 先把 tracing 做好,確保每個 agent 執行都有完整紀錄(包含 run 層級的推理 context)
- 建立 production → test case 的循環: 每個 production 問題都轉成 offline test case,讓 eval suite 持續成長
- 追蹤基本 metrics: feedback、latency、error rate、cost — 這是你的 dashboard
- 跑 online eval: 對已知的品質維度持續打分
- 探索性分析: 定期對 trace 做 clustering,發現你不知道的 pattern
不是「有 tracing 比較好」,而是「沒有 tracing 你根本不知道你的產品在做什麼」。
原文: