iT邦幫忙

2026 iThome 鐵人賽

DAY 13
0
AI Engineering

現代化的 AI 系統設計系列 第 13

[Day 13] - Agent = Model + Harness:建造Agent 之前先建立一個會失敗的 Agent Baseline

  • 分享至 

  • xImage
  •  

Model 取得下一步的決策權,然後呢?

前面我們把 Agent 的邊界放在「誰決定下一步」。但 Model 取得動態決策權之後,不會自動知道怎麼呼叫 Tool、把結果放回下一輪,也不會自己管理執行上限與 Trace。所以進入 Agent 篇,我們還是從 Baseline 開始:先用 Model 加上最小 Harness,讓第一個動態 Loop 真的跑起來,再看它怎麼失敗。

這篇會讓一個最小 Agent 執行「幫我退掉 order 123」,並故意注入一次回應遺失的 Timeout。它最後會說退款完成,系統裡卻留下兩筆退款紀錄。這個失敗,正好能讓我們看見 Model 之外,Harness 還缺了什麼。

看到 Agent,很容易立刻把 Planning、Memory、Guardrails 與 Multi-agent 全部塞進架構圖。但如果沒有最小版本,就無法知道每個元件解決了什麼問題。因此在拆解 Agent Loop 前,我們先建立一個可比較的起點。

先建立一個能執行、能觀察,也能暴露失敗的 Agent Baseline。後續每加入一個元件,都必須說清楚它修掉了哪一種失敗。


這篇會討論到

  • 為什麼可以用 Agent = Model + Harness 作為操作性模型
  • 第一個 Agent Baseline 最少需要哪些能力
  • 如何用 Trace 與最終狀態,區分「Agent 停了」和「任務完成」

Agent 由負責推理的 Model 與負責執行的 Harness 組成,並透過 Action 與 Observation 和提供事實的 Environment 互動


先給一個操作性定義:Agent = Model + Harness

先說清楚:Agent = Model + Harness 不是業界共同制定的正式定義,而是本文用來拆解 Agent System 的操作性模型。

同一個 Model 放在 Chat UI 裡,通常只會接收訊息並產生回答;放進 Coding Agent,卻能讀檔案、執行指令、觀察錯誤,再繼續修改。差別不只是 Prompt,而是 Model 外面多了一套負責驅動執行的系統。

OpenAI 在拆解 Codex agent loop 的工程文章中,將 Harness 描述為 Codex 背後的核心 Agent Loop 與 Execution Logic,負責協調 User、Model 與 Tools。AWS AgentCore 也把 Harness 描述為會執行 Model、System Prompt、Tools、Memory 與 Limits 的受管 Orchestration Loop。

不過,各家的詞彙並不一致。Anthropic 使用的是 Augmented LLM:在 LLM 周圍加入 Retrieval、Tools 與 Memory,再依需求演進成 Workflow 或 Agent。因此這裡的公式不是要重新發明定義,而是要把兩種責任分開:

部分 主要責任
Model 理解模糊目標、根據 Observation 推理、提出下一步或產生回答
Harness 組裝 Context、提供 Tool、執行 Tool Call、回填結果、驅動 Loop、限制輪數並留下 Trace

Model 產生的 Tool Call,本質上仍是一個「我想執行這個動作」的 Intent。它不會自己連上訂單系統,也不會在 Process Crash 後自動記得進行到哪裡。真正把 Intent 轉成執行、再把結果帶回下一輪的是 Harness。

而 Agent 之外還有另一個重要角色:Environment。

Agent(Model + Harness)↔ Environment

Order Service、Payment Service、Browser、檔案系統與使用者都位於 Agent 外部。Model 可以判斷下一步,Harness 可以驅動互動,但真實世界究竟有沒有改變,最後仍由 Environment 決定。

這也讓我們得到第一個設計原則:

Model 負責處理不確定性;Harness 負責管理執行;Environment 負責提供事實。


Harness 的第一版,只需要把 Loop 跑起來

最小 Agent Loop 其實不複雜:

User Goal
   ↓
Build Context → Model
                  ├─ Final Output → Stop
                  └─ Tool Call
                         ↓
                    Tool Executor
                         ↓
                    Observation
                         └──────→ 回到 Model

OpenAI Agents SDK 的 Runner 就呈現了這個基本骨架:呼叫 Model;若得到 Final Output 就結束;若得到 Tool Call,就執行 Tool、把結果放回 Context,再進入下一輪;超過 max_turns 則以錯誤終止。

把它整理成 Baseline,第一版只需要完成五個動作:

動作 Baseline 現在要做什麼?
準備 保存 Goal 與 Run ID,組裝 Instructions、對話和 Tool Schema
決定 讓 Model 依目前 Observation 產生 Final Output 或 Tool Call
執行 驗證參數並執行 Tool,將成功或錯誤包成 Observation
繼續或結束 回填結果後進入下一輪;遇 Final Output、Error 或 Max Turns 時停止
留下證據 記錄每輪決策、Tool Result、Latency、Token 與 Termination Reason

LangGraph 的官方文件 特別區分 Explicit Termination Condition 與 Recursion Limit:前者說明任務為何應該結束,後者只是防止 Loop 失控的 Safety Net。

但在這個 Baseline,我們刻意先接受一個簡化:Model 產生 Final Output 時,Harness 就結束這次 Run。稍後再用 Evaluation 判斷,這次結束究竟是不是真的成功。

最小 Agent Loop 會在 Final Output 時正常停止,超過 Max Turns 則以安全錯誤終止,兩者都不直接證明任務完成


讓 order 123 先跑一次

現在給 Baseline 一個任務:

User:「幫我退掉 order 123。」

測試環境只提供三個 Tool:

get_order(order_id)
get_refund_policy(order_id)
issue_refund(order_id, amount)

Harness 把目標、對話紀錄與 Tool Schema 交給 Model。Model 依序查詢訂單與退款政策,再呼叫 issue_refund。沿用前面的退款事故,我們在 Sandbox 注入一次「服務端完成退款,但回應遺失」的 Timeout。Baseline 沒有 Reconciliation,因此 Model 直接重試,最後回答退款完成。

這裡的重點不是再次解釋 Timeout,而是把這次執行存成可比較的 Baseline Record:

run_id: run_order_123_001
goal: "幫我退掉 order 123"
turns:
  - model: {decision: tool_call, tool: get_order}
    tool:  {arguments_valid: true, status: success}
  - model: {decision: tool_call, tool: get_refund_policy}
    tool:  {status: success}
  - model: {decision: tool_call, tool: issue_refund}
    tool:  {arguments_valid: true, status: timeout, error_class: network_timeout, result: unknown}
  - model: {decision: tool_call, tool: issue_refund}
    tool:  {status: success}
  - model: {decision: final_output}
termination_reason: final_output
metrics:
  turn_count: 5
  tool_call_count: 4
  wall_latency_ms: 8420
  total_tokens: 6810
evaluation:
  task_success: false
  final_state: {refund_records: 2}
  duplicate_actions: 1
  production_ready: false

這份 Record 同時保留 Model Decision、Tool Observation、Loop Termination 與 Environment Evaluation。它不是 Production Trace Schema 的標準答案,而是 Baseline 的實驗契約:未來加入任何能力後,都用同一組欄位重跑,才能知道結果究竟有沒有改善。

第一版刻意不加入完整的 Planning、Memory、Checkpoint、Human Approval 與 Multi-agent,否則還沒看到問題,就已經把答案塞進系統。但有一條安全邊界不能退讓:這個缺少 Permission 與 Idempotency 的 Baseline,只能連接 Fixture、Sandbox 或模擬後端,不能取得 Production 退款權限。

order 123 的 Trace 最終產生 Final Output 並正常停止,但 Environment 留下兩筆退款紀錄,因此任務結果仍然失敗


Agent 停了,不代表任務成功

前面建立的 Evaluation 與 Trace,在這裡開始有了新的用途:它們要替 Agent Baseline 留下可以重跑與比較的執行證據,而不是重新建立另一套觀測系統。

這個對照組至少要保留五類訊號:任務結果與最終狀態、Tool 選擇與錯誤分類、Turn 與停止原因、Latency 與 Token,以及人工介入或重複副作用。YAML 中不一定要採用同一套欄位名稱,但每次實驗必須能回答相同問題。

OpenAI Agents SDK 能以 Span 記錄 LLM Call、Tool Execution、Handoff 與 Agent Run;Anthropic 對 Agent Evaluation 的整理 也將完整 Trial 視為包含 Tool Calls、Intermediate Results 與其他互動的 Transcript/Trace/Trajectory。

但 Trace 只告訴我們發生了什麼,成功條件仍要回到 Environment。τ-bench 評估客服 Agent 時,不是只看最後一句回答,而是比較對話結束後的資料庫狀態與目標狀態。

因此至少要分開三件事:

判斷 order 123 的結果
Protocol Termination final_output,Runner 正常停止
Task Outcome 退款發生兩次,任務失敗
Production Readiness 缺少 Approval、Idempotency 與 Recovery,不可上線

只看第一層,幾乎每個 Demo 都會成功;開始看第二、第三層,才真正進入 System Design。


Baseline 失敗的地方,就是後續 Harness 的地圖

order 123 只證明了其中一種失敗。接著應該固定同一套 Baseline 與紀錄格式,替它準備一組 Failure Catalog:不同 Fixture 分別注入重複 Observation、錯誤使用者狀態、程序中斷、缺少核准、結果未知與無進展循環。這不是聲稱單一 Trace 發生了所有問題,而是建立後續元件必須通過的測試地圖。

問題群 Baseline 暴露的失敗 後續設計方向
不知道下一步 重複查詢、沒有新資訊、遇到變化仍沿用舊路徑 Planning、Replanning、Progress Detection
不知道現在在哪裡 混用文字中的狀態;中斷後必須重頭開始 Typed State、Memory、Checkpoint、Resume
不知道動作是否安全完成 未經核准就執行;結果未知時直接 Retry Permission、Human Approval、Idempotency、Reconciliation
不知道是否該結束 Model 自稱完成但外部狀態不正確;不斷循環直到 Max Turns Success Assertion、Stop Condition、Budget、Handoff

這裡最容易犯的錯,是看到 Agent 表現不好就直接換更大的 Model。但很多失敗根本不屬於 Model:結果未知時如何確認副作用、誰能批准退款、程序崩潰後如何恢復,以及什麼才算任務成功,都是 Harness 與外部系統的責任。

也因此,Agent = Model + Harness 最有價值的地方不是公式本身,而是它逼我們問:

這次失敗應該改善 Model,還是改善 Harness?

Baseline 的四類失敗分別導向 Planning、State、Recovery、Safety 與 Stop 等後續 Harness 設計方向


先讓 Agent 能被比較,再讓它變得複雜

這篇沒有做出一套 Production-ready Agent,只建立了第一個可觀測的對照組:Model 能根據 Observation 動態選擇下一步,Harness 能執行 Tool、回填結果、限制 Loop,並留下足以重建過程的 Trace。

它仍然會犯很多錯,而這正是我們需要的結果。

因為從下一天開始,每加一個元件都要回答同一個問題:

它修掉了哪一種可以被重現、被量測的 Baseline Failure?

有了這個 Baseline,下一步就能重跑同一組 Failure Catalog,比較不同 Loop 設計如何讓 Agent 判斷進展、修正下一步,並在正確的時候停下來。之後才是 State 與 Memory、Checkpoint 與 Resume、Tool Safety 與 Human-in-the-loop。如果單一 Agent 最後真的出現能力或 Context 過載,再討論是否需要 Multi-agent。

複雜度不應該來自 Framework 的功能選單,而應該來自 Baseline 已經證明存在的能力缺口。


AI 你怎麼看?

Agent 開心宣布退款完成,但 Environment 指出同一筆退款其實被執行了兩次

如果你現在有一套 Agent,它最常出現哪一種問題?

  • A:一直重複嘗試,卻沒有更接近目標
  • B:會使用 Tool,但經常選錯或傳錯參數
  • C:說自己完成了,外部狀態卻沒有改變
  • D:流程太複雜,出了問題很難重建

留下一個字母與情境。下一篇,我們會用同一套 Baseline,實際比較 Agent Loop、Planning、Progress 與 Stop Condition 如何改變執行結果。


上一篇
[Day12] - RAG 已經會找資料了,為什麼還需要 Agent?從固定流程到動態決策
下一篇
[Day 14] - Agent 一直在跑,為什麼任務沒有前進?從 Progress 到正確停止
系列文
現代化的 AI 系統設計19
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言