此为历史版本和 IPFS 入口查阅区,回到作品页
Ryan Vale
IPFS 指纹 这是什么

作品指纹

AI agent 的下一個戰場不是模型,而是可重跑的執行環境

Ryan Vale
·
·
把 task、tool、approval、state 和 receipt 畫成可恢復的邊界,讓 agent 在 timeout 或升級後仍能安全接手。

小團隊很容易遇到一種看似成功、其實無法交付的 agent 執行:模型回覆「完成」,前端畫面也短暫看起來正常,但程序剛好在最後一個工具呼叫後 timeout。下一次重跑時,沒人知道哪些檔案已經寫入、哪個 API 呼叫已經送出、哪個人工核准曾經通過。Prompt 還在,流程卻失憶。

開發者通常先問「這個 agent 要用哪個模型」,卻很少先問任務能不能暫停、失敗後能不能接著跑,以及完成之後要留下什麼證據。模型當然重要,但它只是執行環境裡的一層。當工作開始包含工具、排程、隔離環境、長時間任務和人工決策,產品可靠度會由另一組設計決定。

我會先替每個 coding-agent 任務畫出可重跑的執行環境。它不需要一開始就很複雜,但要能回答:現在做到哪裡、下一步是什麼、什麼可以安全重做,以及完成後留下哪些證據。

先把一次呼叫改成一個 task

一次模型呼叫通常只有 request 和 response。可交付的 task 則需要更清楚的生命週期:它從哪裡開始,目前做到哪裡,下一步是什麼,遇到 timeout 要重試還是暫停,最後用什麼條件判定完成。

這不代表每個小功能都要做成大型工作流。小團隊先替任務保存幾個欄位就有差異:task ID、輸入版本、目前狀態、已完成的步驟、下一個可執行步驟,以及驗收檢查。狀態至少要能分辨「尚未開始」、「執行中」、「等待核准」、「部分完成」、「重試中」和「已驗收」。只留下最後一段文字,無法回答這些問題。

這個轉換也會改變 prompt 的角色。Prompt 描述意圖,task 定義責任。前者可以調整,後者要讓系統和人都看得懂。

五個邊界,比模型名稱更值得先畫出來

Task:工作的單位是什麼

先把工作切成可以檢查的單位,而不是讓 agent 一次包辦「完成這個功能」。例如新增設定頁的通知開關,可以拆成讀取現有設定、修改 schema、更新介面、執行測試和等待部署前檢查。每一步都應該有輸入、輸出和失敗後的去處。

切得太細,流程會變得難以維護;切得太粗,重跑時就只能整段賭一次。適合的邊界通常是:這一步完成後,團隊可以合理地保存一個 checkpoint,下一步也能從這個 checkpoint 繼續。

Tool:agent 可以碰到什麼

工具清單不是單純的函式列表。每個工具還有作用範圍、輸入格式、可能的副作用、錯誤行為和是否能安全重複執行。

讀取 repository、查詢測試結果和產生 diff,通常可以先歸在低風險工具。寫入檔案、修改資料或呼叫外部服務,則要清楚標示副作用。尤其是不能安全重複執行的操作,必須有 idempotency key 或其他去重方式,否則一次 timeout 就可能留下兩份結果。

工具本身也要回傳可檢查的結果。只回傳「成功」不夠,至少要讓 runtime 知道版本、識別碼、輸出位置和錯誤原因,之後才能把它接到 state 和 receipt。

Approval:誰在什麼時候做決定

「需要人工核准」不應該是一個模糊的總開關。團隊要先分出讀取、可逆修改和破壞性操作,再決定哪些動作需要人介入。

核准也應該綁定具體內容,而不是只記一個「使用者同意」。例如核准某次資料 migration 時,同時保存 migration 版本、影響範圍、提出核准的 task,以及核准時間。Agent 之後如果改了計畫,就必須重新核准。這樣才能避免一個寬泛的 yes 被拿去套用到另一個完全不同的工具呼叫。

State:誰持有可以恢復的真相

可恢復的狀態不等於把整段對話永遠存下來。對重跑真正有用的,通常是任務狀態、必要輸入、工具結果、已完成的步驟和下一個可執行動作。對話可以拿來輔助理解,但不應該成為唯一的資料庫。

這個邊界在 agent 開始支援長時間工作和 stateless HTTP workload 後會更明顯。Session 可能過期,執行程序可能被換掉,甚至協定的 session 使用方式也可能需要遷移。只要團隊沒有說清楚 state 放在哪裡、哪一份狀態是 authoritative,所謂的 resume 其實只是重新發一個相似的 prompt。

狀態保存還要考慮安全和成本。不要為了「完整」而保留所有秘密、所有上下文和所有中間輸出。保存能讓下一步正確執行的最小集合,並替每個欄位指定 owner。

Receipt:執行之後剩下什麼

最後要有一張精簡的執行收據。它不是給行銷看的報表,而是讓下一個人或下一次執行知道剛才發生了什麼。

一張實用的 receipt 可以包含:輸入版本、task 狀態、實際呼叫過的工具、工具結果位置、人工核准、重試次數、錯誤、產出版本,以及最後一次 acceptance check。Markdown 可以先做起來,等欄位穩定後再轉成 JSON 或接進既有的觀測系統。

收據最重要的用途,是把「模型說做完了」和「產品確認做完了」分開。前者是一段輸出,後者是一個可重跑的判斷。兩者不一致時,系統應該停在可調查的狀態,而不是自動把綠燈亮起來。

用一個前端功能跑過完整流程

  1. 使用者建立一個有明確輸出和驗收條件的 task。Agent 先讀取相關檔案,提出要修改的範圍,不直接寫入。

  2. Runtime 保存 tool plan 和目前的輸入版本。讀取和產生 diff 可以自動執行,寫檔與資料庫 migration 分別標上副作用。

  3. 使用者核准特定 diff 後,agent 才能執行寫入。核准紀錄和 diff 版本一起進入 task state。

  4. 每個可恢復的步驟完成後保存 checkpoint,包括實際修改、測試結果和下一步。若程序在這裡中斷,重跑不必猜測哪些步驟已經完成。

  5. 測試通過後,系統產生 receipt,列出變更檔案、測試命令、結果、未處理的警告和驗收狀態。若測試只跑了一半,receipt 就應該寫成部分完成,而不是沿用模型的結論。

升級成本也是 runtime 的一部分

當 SDK 開始把 tool approval、durable workflow、timeout、sandbox、telemetry 和 MCP Apps 放在同一個 agent 開發面上,這不只是多了幾個 API。它也代表團隊必須面對執行環境的升級成本。像 Node.js minimum 版本改變,就可能牽動部署映像、CI、套件相依和本機開發流程。

協定更新也一樣。新的長時間 task 或 stateless transport 方向,可能讓原本依賴 session ID 的 client 需要重新檢查。隔離環境和 recoverable state 可以降低部分重建工作,但不能自動證明跨供應商可攜,也不能替團隊決定哪一份狀態可信。

因此,升級清單不該只有「換版本、跑測試、部署」。還要有一組小而固定的工作樣本:正常輸入、邊界輸入和預期失敗的輸入各幾個。新 runtime 先用有界 canary 執行,對照實際產物與人工驗收條件,再決定是否放大流量。Fallback 也要寫出觸發條件和回復方式,不能靜默換模型後繼續回報成功。

先建立執行環境,再追下一個模型

Agent 的價值不會只由模型輸出的漂亮程度決定。對小團隊來說,真正昂貴的是一次中斷後沒有人知道該從哪裡接手,或一次錯誤重跑後留下無法分辨的副作用。

先把 task、tool、approval、state、receipt 五個邊界畫出來,團隊才知道哪些部分應該由 runtime 持有,哪些部分可以交給模型處理。模型可以替換,工具可以遷移,框架也會改版,但任務要如何恢復、誰能核准、哪份狀態算數,以及什麼證據才叫完成,這些規則不能交給下一次聊天臨時決定。

Source notes

CC BY-NC-ND 4.0 授权