iT邦幫忙

2026 iThome 鐵人賽

DAY 7
0

前言

前六天,我們從一個最小可用的 Agent Runner 開始,逐步替它加上工具呼叫、Trace 資料模型、SQLite 儲存,以及簡單的 Trace Viewer。

第一週不是要讓 Agent 變得很聰明,而是先解決一個更基礎的問題:

當 Agent 執行任務時,我們能不能看見它中間做了什麼?

如果只能看到 final answer,Agent 就很像黑盒。

現在我們已經做到:

User Task
  -> LLM Response
  -> Tool Call
  -> Tool Result
  -> Final Answer
  -> Save Trace
  -> Trace Viewer

也就是說,Agent 的執行過程已經可以被記錄、保存與查看。

今天是第一週回顧。我會整理目前系統架構、展示一筆完整 trace,並說明第二週為什麼要進入 Eval。


今天要完成什麼?

Day 7 是回顧篇,不會新增大型功能。

會完成:

  1. 回顧 Day 2 到 Day 6 完成的模組。
  2. 整理目前的專案結構。
  3. 展示一次完整 Agent 執行流程。
  4. 說明目前系統限制。
  5. 銜接第二週的 Evaluation。

今天先不做:

  • 新增工具。
  • 建立 eval dataset。
  • 實作 evaluator。
  • 製作成功率 dashboard。

這些從 Day 8 開始處理。


第一週完成了什麼?

第一週主要完成五個基礎模組。

天數 主題 完成內容
Day 2 Agent Runner 建立 SimpleAgent,讓系統可以接收任務並回傳答案
Day 3 Tool Calling 加入 calculator tool,讓 Agent 可以使用工具
Day 4 Trace Model 設計 TraceStepAgentTrace
Day 5 Trace Storage 使用 SQLite 保存 trace
Day 6 Trace Viewer 使用 Streamlit 查看歷史 session 與 steps

這些模組串起來後,Agent 不再只是:

Input -> Output

而是變成:

Input
  -> LLM Response
  -> Tool Call
  -> Tool Result
  -> Final Answer
  -> Trace Storage
  -> Trace Viewer

這就是本系列標題中「從黑盒到可驗證」的第一步。


目前的專案結構

第一週結束後,專案大致會長這樣:

agent-testing-platform/
  app.py
  trace_viewer_app.py
  agents/
    __init__.py
    simple_agent.py
    prompts.py
    fake_llm.py
  tools/
    __init__.py
    calculator.py
  tracing/
    __init__.py
    models.py
  storage/
    __init__.py
    database.py
    schema.sql
  ui/
    __init__.py
    trace_viewer.py
  data/
    agent_traces.db

每個資料夾的責任如下:

資料夾或檔案 責任
app.py 命令列入口,負責執行 Agent 並保存 trace
trace_viewer_app.py Streamlit 入口,負責開啟 Trace Viewer
agents/ Agent Runner、prompt、LLM client
tools/ Agent 可以使用的工具
tracing/ Trace 資料模型
storage/ SQLite 初始化、儲存與查詢
ui/ Streamlit UI
data/ SQLite database 檔案

這個結構目前還很小,但已經先把責任切開。

第二週開始會加入 Eval。如果前面全部都寫在同一個檔案,後面會很難維護。


回顧 Agent Runner

Day 2 建立的主要介面是:

SimpleAgent.run(user_task) -> AgentResult

SimpleAgent 的責任是:

  • 接收 user task。
  • 組合 messages。
  • 呼叫 LLM client。
  • 回傳 AgentResult。

後來 Day 3 和 Day 4 又逐步把 AgentResult 擴充成可以包含:

  • final answer
  • tool calls
  • trace

這個設計讓後面的模組可以用一致的方式取得 Agent 執行結果。

例如 Day 5 儲存 trace 時,只需要做:

save_trace(result.trace)

這表示 Agent Runner 和 Storage 之間的界線是清楚的。


回顧 Tool Calling

Day 3 加入了第一個工具:calculator

新增的工具放在 tools/calculator.py

它的用途很單純:

輸入算式 -> 回傳計算結果

例如:

135 * 28 -> 3780

這個工具本身不複雜,但它帶出一個重要概念:

Agent 不應該把所有事情都交給 LLM 猜,而是應該在適合的時候使用可靠工具。

目前我們用 FakeLLMClient 模擬工具呼叫。

也就是說,現在還不是使用真正 LLM API 的 function calling,而是先用可控方式建立 Agent 內部流程:

LLM Client 回傳 tool_call request
  -> SimpleAgent 查找 tool registry
  -> 執行 calculator
  -> 回傳 final answer

這樣一來,初期不會被不同模型供應商的 API 格式綁住,可以先把 Agent 架構設計清楚。


回顧 Trace Model

Day 4 設計了兩個資料模型:

AgentTrace
TraceStep

AgentTrace 代表一次 Agent 執行。

它包含:

  • session_id
  • steps

TraceStep 代表一次執行中的其中一個步驟。

它包含:

  • step_type
  • name
  • input_data
  • output_data
  • error
  • timestamp

也就是說,一次任務不再只有最後答案,而是可以被拆成多個 step。

例如:

0. user_input
1. llm_response
2. tool_call
3. tool_result
4. final_answer

這個設計是後面 Eval 和 Failure Analysis 的基礎。

如果沒有 trace,我們即使知道 Agent 答錯,也很難知道錯在哪一步。


回顧 Trace Storage

Day 5 把 trace 寫進 SQLite。

新增的資料表是:

sessions
steps

sessions 負責記錄一次 Agent 執行。

steps 負責記錄該 session 裡面的每個 step。

兩者的關係是:

sessions 1 -> many steps

這個設計讓我們可以查詢:

  • 有哪些歷史 session?
  • 某次 session 有幾個 steps?
  • 某次執行是否有 tool call?
  • 哪些 step 發生錯誤?

雖然目前還沒有做複雜查詢,但資料結構已經先準備好。


回顧 Trace Viewer

Day 6 使用 Streamlit 建立了簡單 Trace Viewer。

目前 Trace Viewer 可以做到:

  • 顯示 session list。
  • 選擇某一次 session。
  • 顯示該 session 的 step timeline。
  • 顯示每個 step 的 input。
  • 顯示每個 step 的 output。
  • 顯示已經被記錄的 error。

啟動方式是:

streamlit run trace_viewer_app.py

如果資料庫中已經有 trace,就可以從下拉選單選擇 session,查看該次 Agent 執行過程。

這讓 trace 從「資料庫裡的資料」變成「人看得懂的紀錄」。


展示一筆完整 Trace

先在專案根目錄執行:

python3 app.py

輸入:

請計算 135 * 28

Agent 會回傳:

Answer:
The result is 3780

同時,trace 裡會記錄類似這樣的 steps:

{
  "session_id": "8a2b2f21-d1a4-4d8d-9a57-0db43a4e9d23",
  "steps": [
    {
      "step_type": "user_input",
      "name": "User Task",
      "input_data": {
        "content": "請計算 135 * 28"
      },
      "output_data": {},
      "error": null
    },
    {
      "step_type": "llm_response",
      "name": "LLM Response",
      "input_data": {
        "messages": [
          {
            "role": "system",
            "content": "..."
          },
          {
            "role": "user",
            "content": "請計算 135 * 28"
          }
        ]
      },
      "output_data": {
        "response": {
          "type": "tool_call",
          "tool_name": "calculator",
          "tool_input": "135 * 28"
        }
      },
      "error": null
    },
    {
      "step_type": "tool_call",
      "name": "Tool Call",
      "input_data": {
        "tool_name": "calculator",
        "tool_input": "135 * 28"
      },
      "output_data": {},
      "error": null
    },
    {
      "step_type": "tool_result",
      "name": "Tool Result",
      "input_data": {
        "tool_name": "calculator"
      },
      "output_data": {
        "tool_output": "3780"
      },
      "error": null
    },
    {
      "step_type": "final_answer",
      "name": "Final Answer",
      "input_data": {},
      "output_data": {
        "answer": "The result is 3780"
      },
      "error": null
    }
  ]
}

這筆 trace 可以回答幾個問題。

第一,使用者輸入是什麼?

請計算 135 * 28

第二,Agent 為什麼會用工具?

因為 llm_response 回傳了:

{
  "type": "tool_call",
  "tool_name": "calculator",
  "tool_input": "135 * 28"
}

第三,工具實際收到什麼輸入?

135 * 28

第四,工具實際回傳什麼?

3780

第五,最後答案如何產生?

The result is 3780

這就是 Trace 的用處:不是只知道答案,而是知道答案背後的執行路徑。


用 Trace Viewer 查看同一筆紀錄

接著啟動 Trace Viewer:

streamlit run trace_viewer_app.py

在瀏覽器中,選擇剛剛產生的 session。

畫面上應該會看到:

  • user_input - User Task
  • llm_response - LLM Response
  • tool_call - Tool Call
  • tool_result - Tool Result
  • final_answer - Final Answer

每個 step 都可以展開查看 input 和 output。

這表示我們已經可以用 UI 回放一次 Agent 執行。

雖然目前 UI 很簡單,但對除錯已經有幫助。


第一週系統目前可以回答的問題

第一週完成後,平台已經能回答:

1. Agent 收到什麼任務?

這由 user_input step 記錄。

2. Agent 產生了什麼中間決策?

這由 llm_response step 記錄。

目前我們使用 FakeLLMClient,所以這個決策是規則模擬出來的。未來換成真正 LLM API 後,這個 step 會更重要。

3. Agent 呼叫了哪些工具?

這由 tool_call step 記錄。

4. 工具回傳了什麼?

這由 tool_result step 記錄。

5. Agent 最後回答什麼?

這由 final_answer step 記錄。

6. 執行紀錄能不能保存?

Day 5 已經把 trace 存進 SQLite。

7. 執行紀錄能不能被查看?

Day 6 已經用 Streamlit 做出簡單 Trace Viewer。

這些能力讓 Agent 從原本的黑盒,變成至少可以被觀察的系統。


目前系統限制

第一週完成的是基礎,不是完整平台。

目前仍有幾個限制。

1. 還沒有接真正的 LLM API

目前使用的是 FakeLLMClient

這讓我們可以穩定測試流程,但也表示目前的 Agent 還不是由真實模型做決策。

後續可以把 FakeLLMClient 換成 OpenAI、Claude 或 Gemini client。

2. Tool Calling 還是簡化版本

目前工具呼叫是透過 fake client 回傳固定格式:

{
  "type": "tool_call",
  "tool_name": "calculator",
  "tool_input": "135 * 28"
}

這還不是正式的 function calling。

不過它已經足夠讓我們先建立工具執行、工具紀錄與 trace 儲存流程。

3. 錯誤處理還不完整

如果輸入:

請計算 135 28

目前程式仍可能因為找不到算式而拋出 exception。

理想狀態應該是:

錯誤被捕捉
  -> 寫入 trace
  -> 回傳可讀的錯誤訊息
  -> 後續分類成 failure type

這會在後面的 Failure Analysis 和 Guardrails 階段再處理。

4. 還不能判斷答案對不對

目前平台能回答:

Agent 做了什麼?

但還不能回答:

Agent 做得對不對?

這就是第二週要處理的 Eval。


為什麼下一步是 Eval?

Trace 解決的是可觀測性問題。

也就是:

我們能不能看見 Agent 做了什麼?

但 Agent Testing Platform 不能只停在「看見」。

接下來還要能回答:

Agent 有沒有完成任務?

假設我們有一個任務:

請計算 135 * 28

Agent 回答:

The result is 3780

人可以看出這是對的。

但平台要能自動判斷:

expected: 3780
actual: The result is 3780
result: pass

這就需要 Evaluation。


第二週會做什麼?

第二週的主軸是 Eval。

預計會完成:

天數 主題 內容
Day 8 什麼是 Agent Evaluation? 定義 eval dataset、success rate、format accuracy
Day 9 設計 Test Case 格式 定義 input、expected、grading_method
Day 10 建立第一組 Eval Dataset 建立 10 到 20 筆測試案例
Day 11 Batch Evaluation Runner 讓 Agent 一次跑完整組測試
Day 12 最簡單的自動評分 實作 exact match 和 keyword match
Day 13 JSON 格式驗證 檢查 structured output 是否符合格式
Day 14 第二週回顧 產出第一份 baseline evaluation report

第二週結束後,平台就不只會記錄 Agent 做了什麼,也會開始評估 Agent 是否完成任務。


今天的重點整理

第一週最主要的成果是:

讓 Agent 從黑盒變成可觀察。

目前我們已經完成:

  • Agent Runner。
  • Calculator tool。
  • Trace model。
  • SQLite trace storage。
  • Streamlit Trace Viewer。

這些功能讓我們可以看到一次 Agent 執行中的關鍵步驟:

user_input
llm_response
tool_call
tool_result
final_answer

但這還只是 Agent Testing Platform 的第一層。

接下來第二週要開始建立 Eval,讓平台不只會看過程,也能判斷結果是否正確。


下一步

Day 8 會進入 Agent Evaluation。

下一篇會先不急著寫 evaluator,而是先定義幾個基本問題:

  • 什麼是 eval dataset?
  • 什麼是 test case?
  • Agent 的 success rate 要怎麼算?
  • 格式正確率和答案正確率有什麼不同?
  • 為什麼要用固定測試集,而不是每次手動測幾題?

從 Day 8 開始,我們會讓這個平台從「看得到 Agent 過程」,進一步走向「測得出 Agent 表現」。


上一篇
Day 6|建立簡單 Trace Viewer
下一篇
Day 8|什麼是 Agent Evaluation?
系列文
從黑盒到可驗證:30 天打造 AI Agent 的 Trace、Eval 與 Guardrails 系統8
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言