A 扁平的日誌可以告訴你有五件事發生了。它通常無法告訴你是哪個操作導致了下一個操作、哪個失敗觸發了回退,或是三次工具呼叫到底是某個規劃步驟的子項,還是彼此無關的工作。

這種區別對 AI 代理很重要,因為路徑本身就是行為的一部分。

我維護 AgentInspect,這是一個用於在本機檢視代理執行流程的開源 TypeScript 工具包。本文說明我為什麼選擇執行樹作為主要除錯模型,並使用經 [email protected] 驗證的合成測試樣板來說明。

把代理執行當成時間線來讀的問題

想像一個支援代理執行了以下操作:

09:00:00.000 plan started
09:00:00.020 inventory request started
09:00:00.060 inventory request failed: 503
09:00:00.061 inventory request started
09:00:00.120 inventory request succeeded
09:00:00.150 answer completed

這足以重建一個簡單故事,但真正的重建其實是在你的腦中完成的。當加入巢狀代理、平行工具、重複使用的操作名稱,以及交錯的應用程式日誌後,時間戳就不再是可靠的因果關係圖像。

執行樹會把關係明確呈現出來:

support-agent
├── plan
├── fetch-inventory (failed: 503)
├── fetch-inventory (success)
└── draft-answer

這個樹狀圖不會取代原始事件資料。它只是針對開發者通常最先會問的問題,對這些資料做出的投影:這次執行走了哪條路徑?

在 TypeScript 中捕捉有意義的邊界

AgentInspect 提供了用於整個執行與命名步驟的包裝器。以下是一個刻意簡化的範例:

import { inspectRun, step } from "agent-inspect";

await inspectRun(
  "travel-planner",
  async () => {
    const plan = await step("plan", async () => ({
      destinations: ["SFO", "SEA"],
    }));

    const [flights, hotels] = await Promise.all([
      step.tool("search-flights", async () => [
        { id: "F-101", price: 220 },
      ]),
      step.tool("search-hotels", async () => [
        { id: "H-202", nightly: 180 },
      ]),
    ]);

    return step.llm("rank-options", async () => ({
      plan,
      flights,
      hotels,
    }));
  },
  { traceDir: "./.agent-inspect" },
);

這是手動加上監測。它並不是在宣稱某個包裝器能自動找出框架內部的每一個操作。其目的,是記錄你在意的邊界:整個執行、規劃步驟、兩個平行的工具呼叫,以及最後面向模型的步驟。

接著就可以在本機檢視這次執行:

npx agent-inspect view travel-planner \
  --dir .agent-inspect \
  --summary

四種形狀,揭露不同類型的 bug

1. 巢狀工作會暴露擁有關係

三層深的合成測試樣板會渲染成這樣:

Execution Tree:
✔ outer (120ms)
  ✔ middle (80ms)
    ✔ inner (50ms)

那兩個空格不是裝飾。它們告訴我們 inner 隸屬於 middle,而 middle 又隸屬於 outer。如果 inner 失敗了,我們就知道是哪個高階操作擁有它。若只看扁平日誌,就得靠匹配 ID 或前後時間戳來推測同樣的結構。

巢狀結構在以下情境特別有用:一個代理委派給另一個代理、一個工具會執行多個子操作,或一個檢索步驟同時擁有查詢重寫與向量搜尋。

2. 回退會暴露復原行為

現在來看一個錯誤復原樣板:

Execution Tree:
✖ tool:primary-search (100ms)
    Error: primary search unavailable
✔ tool:fallback-search (200ms)
✔ handle-recovered-result (50ms)

最終執行可能仍然成功。如果我們只看答案,失敗的主要搜尋可能就會從除錯故事中消失。樹狀圖保留了兩件事:

  • 主要路徑失敗了;
  • 復原路徑完成了。

這個區別可能會改變工程決策。由回退產生的成功答案也許可以接受,但回退使用率突然上升,仍可能表示某個依賴退化,或是路由策略變得昂貴。

3. 重複的兄弟節點會暴露重試

重試也值得有自己清楚可見的形狀:

Execution Tree:
✖ tool:fetch-inventory (40ms)
    Error: synthetic 503 from upstream
✖ tool:fetch-inventory (45ms)
    Error: synthetic 503 from upstream
✔ tool:fetch-inventory (60ms)
✔ handle-recovered-result (30ms)

如果只看最後成功的狀態,就會看不到達成成功所花的成本。重複的工具名稱讓重試序列變得可見。它也讓某個確定性檢查有具體內容可評估,例如 fetch-inventory 是否超過允許的呼叫次數。

樹本身並不能告訴我們重試策略是否正確,但它提供了證據,證明這個策略確實被觸發了。

4. 平行的兄弟節點會暴露並行性

平行樣板會渲染成同層的操作:

Execution Tree:
✔ tool:search-hotels (300ms)
✔ tool:search-flights (200ms)
✔ tool:search-cars (100ms)

這些持續時間不是要相加的。這些步驟是兄弟節點,而且可能彼此重疊。這能避免一個常見的時間線錯誤:以為每個有時間戳的操作都在前一個操作之後才開始。

樹無法證明並行性是否以最佳方式實作,但它能準確保留用來調查並行性的結構關係。

樹是一種視圖,不是全部證據模型

人們很容易想把可讀的樹變成唯一儲存的工件。但我避免這麼做,因為人類可讀的視圖必然會壓縮資訊。

底層追蹤資料可能包含辨識碼、時間戳、狀態、輸入或輸出(依擷取政策而定)、觀察結果,以及中繼資料。不同問題需要不同的投影:

structured trace
├── tree      -> 走了哪條路徑?
├── check     -> 是否滿足不變式?
├── diff      -> 兩次執行之間變了什麼?
├── report    -> 審查者應該讀什麼?
└── bundle    -> 可以分享哪些證據?

執行樹是最快的入口點,但不是取代檢查或分析的東西。

把可疑形狀轉成確定性檢查

假設重試樹顯示某個庫存工具可以執行三次。如果預期政策最多只允許兩次呼叫,就應該把這個預期編碼進去,而不是依賴之後人工目視檢查。

在 CLI 層級,可以用 trajectory 檢查來要求工具並在記錄到觀察結果時失敗:

npx agent-inspect check travel-planner \
  --dir .agent-inspect \
  --preset trajectory \
  --required-tool search-flights \
  --fail-on-observation failed

若需要更豐富的規則,AgentInspect 提供了一個實驗性的 TraceContract API,可表達工具需求、禁止使用的工具、最大呼叫次數、順序、執行狀態、持續時間、模型允許清單,以及 token 上限。由於該 API 在本文引用的版本中仍屬 beta,請先鎖定版本,並在把它當作 CI 閘門前,測試其精確語意。

真正重要的工作流程不只是一個 API:

  1. 檢視樹狀圖;
  2. 找出穩定的行為不變式;
  3. 將其編碼成確定性檢查;
  4. 將人類判斷保留給需要脈絡判讀的問題。

樹無法告訴你的事

一棵乾淨的樹並不能證明答案正確。必要的檢索步驟可能回傳無關文件。模型呼叫可能產生沒有根據的主張。某個工具在技術上成功了,卻可能回傳過時資料。

執行樹最擅長的是結構性問題:

  • 哪些操作有執行?
  • 哪個操作擁有這個失敗?
  • 有沒有使用回退或重試?
  • 哪些工作是平行兄弟節點?
  • 這次執行在哪裡停止?

內容品質則應交給語意評估器、領域測試與人工審查。最可靠的代理除錯流程,是把這些層次結合起來,而不是指望某一種視覺化解答所有問題。

除錯路徑,而不只是答案

最終回應是使用者看得到的東西,但執行路徑才是工程師可以改進的部分。樹把這條路徑從推測出的敘事,變成了具體的工件。

這就是 AgentInspect 本機檢視的設計原則:保留因果結構、即使復原成功也要暴露失敗工作,並讓可疑模式容易轉成可重複的檢查。

你可以在 GitHub 上探索本文使用的確切版本。如果你要嘗試,建議先從一個「失敗與回退」的合成樣板開始。完美的 happy path,是對除錯器最沒意思的測試。


原文出處:https://dev.to/raju_dandigam/execution-trees-not-more-logs-a-better-debugging-model-for-ai-agents-3d4g


精選技術文章翻譯,幫助開發者持續吸收新知。

共有 0 則留言


精選技術文章翻譯,幫助開發者持續吸收新知。
🏆 本月排行榜
🥇
站長阿川
📝20   💬4  
317
🥈
我愛JS
3
評分標準:發文×10 + 留言×3 + 獲讚×5 + 點讚×1 + 瀏覽數÷10
本數據每小時更新一次
📢 贊助商廣告 · 我要刊登