AI 開發

AI Coding Agent 的 Agent Harness 是什麼?從 Model、Harness、Tools 到 JSON State 深入解析 2026 Agent 架構

閱讀約 16 分鐘

DeepSeek 專篇寫過一家產品的宿主。本篇只拆通用四層:Model、Harness、Tools、JSON State。模型填參數。宿主跑循環。工具過 Schema。狀態能回放。

閱讀前速覽

層 鎖什麼 誰執行
Model tool_use / arguments 模型填 JSON,不跑副作用
Harness 循環 / 權限 / 壓縮 宿主裝配上下文再執行
Tools inputSchema Schema 過門,宿主再調
State session / turn / JSONL 能重建,才算有狀態

四層都是物件。Prompt 不是架構。

Harness 是環,不是模型

2026 的 Coding Agent 看起來像「一個模型在改倉庫」。拆開以後是四張物件。模型只產出下一次動作的 JSON。真正裝上下文、過 Schema、評權限、跑工具、寫回結果、在視窗將滿時壓縮歷史的,是 Harness。沒有這一環,模型只是聊天。Claude Code 官方把同一件事寫成循環:收提示,評估,執行工具,再評估,直到沒有工具呼叫。Codex 把連續性寫進 Thread 和會話記錄。Cursor 同樣是宿主循環,不是模型自己碰磁碟。

  • Model:只填 lookup_order 和 A-1042。看不見套接字,也不 spawn 行程。
  • Harness:系統提示、工具表、權限、壓縮、預算、max_turns。這些是宿主狀態,不是模型權重。
  • Tools 與 State:工具有 Schema。會話有可檢查的 JSON。聊天文字不是狀態。

內建工具怎麼填 JSON,見 AI Coding Agent 與 JSON 工具呼叫。MCP 那一跳,見 Coding Agent 如何呼叫 MCP。Schema 為什麼是門,見 AI 為什麼需要 JSON Schema。某一家產品的外掛宿主,見 DeepSeek Harness 專篇。本篇不再講那一家,只寫四層怎麼疊。

第一層:Model 只填 JSON

模型看見的是宿主給的工具表和到目前為止的訊息。它的輸出是文字,或一段工具呼叫,或兩者。虛構查單,不要貼真實金鑰:

{
  "type": "tool_use",
  "id": "call_3c91",
  "name": "lookup_order",
  "input": { "order_id": "A-1042" }
}

這一段不是 HTTP,也不是 MCP 的 tools/call。它是模型對宿主說「請查 A-1042」。宿主校驗形狀,再決定執行還是攔住。把模型當成執行器,會漏掉中間那一跳。

第二層:Harness 跑循環

一次會話是狀態機,不是單次補全。官方循環可以收成一張物件:不可變的是模型名和工具表;可變的是訊息數、待執行工具、預算。輪次從 2 走到 8,是宿主在計數,不是模型在記日記:

{
  "session_id": "sess_7f2a",
  "turn": 2,
  "max_turns": 8,
  "immutable": {
    "model": "coding-agent",
    "tools": ["lookup_order", "Read", "Bash"]
  },
  "mutable": {
    "messages": 6,
    "pending_tool": "lookup_order",
    "budget_tokens": 128000
  }
}

Claude Code 的一輪:模型產出帶工具的回覆,宿主執行,把 tool_result 寫回,再問模型。沒有工具呼叫時循環結束,並交出用量和 session_id。鉤子可以在執行前攔截。Codex 在審批之後選沙箱,再執行。權限怎麼寫成規則,見 Coding Agent 權限模型。Harness 呼叫權限,並不等於權限。

第三層:Tools 過 Schema

工具表是模型的選單。每一行必須有名字、說明、一份 JSON Schema。寬 object 等於請模型發明鍵。查單不要帶退款欄位:

{
  "name": "lookup_order",
  "description": "Look up an order by ID. Confirm before any refund.",
  "inputSchema": {
    "type": "object",
    "properties": {
      "order_id": { "type": "string", "pattern": "^[A-Z]-\\d{4}$" }
    },
    "required": ["order_id"],
    "additionalProperties": false
  }
}

過門之後,宿主執行,再把結果寫成物件餵回去。模型讀的是回寫,不是終端機捲動條。失敗也要是物件,不要只丟一句散文:

{
  "type": "tool_result",
  "tool_use_id": "call_3c91",
  "content": "{\"order_id\":\"A-1042\",\"status\":\"paid\"}"
}

第四層:JSON State 能回放

狀態不是「剛才聊了什麼」。狀態是訊息、工具結果、會話編號、壓縮邊界。Codex 把會話追加進 JSONL,resume 從記錄重建。一行就該能指出是哪一次查單:

{"ts":"2026-09-28T01:12:04.221Z","type":"tool_result","id":"call_3c91","name":"lookup_order","ok":true,"order_id":"A-1042"}

上下文會滿。Claude Code 在接近上限時自動壓縮,流裡會出現 compact_boundary。早期細節可能被摘要吃掉。專案根的 CLAUDE.md 會再注入,所以穩定規則寫進檔案,不要只寫在第一輪提示裡。壓縮是狀態變遷,不是靜默丟記憶:

{
  "type": "system",
  "subtype": "compact_boundary",
  "session_id": "sess_7f2a"
}

五步把 Harness 收成物件

不要從「換一個更強的模型」開始。按物件寫:

  1. 先列工具表。每條工具有 Schema。additionalProperties: false。沒有 Schema 的工具不要交給模型。
  2. 寫出循環的停止條件。max_turns 或預算。開口徑任務不要裸跑。
  3. 權限寫成規則。唯讀查單 allow。寫盤 ask。退款 deny。不要把「請自動批准」當預設。
  4. 狀態落成 JSON。至少留下 tool_use、tool_result、session_id。能按 id 對上,才算接通。
  5. 壓縮當事件。看到 compact 就知道摘要替換了舊訊息。必須留下的規則放磁碟檔案。

Schema 怎麼當門,見 Agents API + JSON Schema。本篇只要求:四層都有物件,而且由宿主執行副作用。

復盤 Agent,先攤開四份 JSON

一次翻車,多半是工具表、權限、狀態沒對齊,不是模型「不夠聰明」。

  • 把 inputSchema 和 input 格式化,看缺欄位和多餘鍵。
  • 用 JSONPath 提取 抽出 $.name、$.input.order_id、$.session_id。
  • 一次成功回寫和一次被拒 JSON Diff。先改 Schema 和規則,再改提示。
  • 核對 call_3c91 在 tool_use 和 tool_result 是否同一 id。
  • 會話 JSONL、權杖、倉庫路徑不要貼進公共格式化站。JSONSort 在瀏覽器本地跑。

四份物件都能按 Schema 重建,你才是在收架構,不是在收「它好像會改檔案」。

常見誤區

  • 把 Harness 當成新模型。模型換代。環、門、狀態應該先穩定。評測錯位從這裡開始。
  • 以為更長的 system prompt 就是架構。提示會被壓縮吃掉。工具表、權限、會話記錄不會。
  • 跳過 Schema,直接執行。Harness 管循環,不替你免除二次校驗。寬 object 會把發明鍵送進副作用。
  • 把聊天視窗當成狀態。視窗是渲染。狀態是 JSON。resume 讀的是記錄,不是截圖。
  • 壓縮當無事發生。官方會發邊界事件。巢狀規則可能要重新讀檔才會回來。
  • 用某一家產品的外掛詞當通用詞。dsh、Capability Seam 是專篇物件。通用四層是 Model / Harness / Tools / State。

FAQ

Harness 和 Agent Framework 是一回事嗎?

不是同一層。Framework 常在業務倉庫裡編排節點。Harness 是宿主循環:裝上下文、過門、執行、落狀態。你可以在 Harness 上寫業務 Agent,不要把兩層糊在一起。

模型會自己改檔案嗎?

不會。模型只填工具 JSON。讀寫、Shell、MCP 都由宿主執行。沒有宿主,就沒有倉庫變更。

JSON State 必須是 JSONL 嗎?

不必。Codex 用會話 JSONL 做權威記錄。Claude Code 用會話文本和事件流。要求是能按 id 重建模型當時看見的物件,不是檔案後綴。

壓縮會丟掉 Schema 嗎?

工具定義通常作為穩定前綴再注入。丟掉的是早期對話細節。必須留下的規則寫進專案檔,不要只寫在第一句使用者訊息裡。

換模型要重寫 Harness 嗎?

不該。模型適配器可換。工具 Schema、權限表、狀態形狀應該先穩住。換模型是換填 JSON 的那一層,不是換四層架構。

結論

Coding Agent 的架構不是「一個更大的模型」。是 Model 填 JSON,Harness 跑循環,Tools 過 Schema,State 能回放。

先寫清 A-1042 會進哪一個工具、哪一輪、哪一份狀態記錄。能指到四層物件,才算有 Harness。模型會換。這四層應該先穩定。

延伸閱讀

更新記錄: 首次發布