部落格
架構

發布於 更新於

Arag 和 Shouryamaan

AI 代理的持久執行:檢查點、重試與復原

以 Markdown 閱讀

持久執行讓 AI 代理能在程序當機、逾時、部署或長時間等待後繼續多步驟工作,而不會重複已完成的副作用。這需要持久保存的進度、可安全重複的寫入,以及處理結果未知呼叫的復原規則。

單純的重試迴圈不是持久執行。回應遺失後重試寄信或付款,可能製造出系統原本想復原的問題。

以外部副作用為中心建立工作流程模型

假設一項工作流程會建立發票、寄出發票,再將工作標記為完成。如果寄送成功,但 worker 在記錄成功前當機,下一次執行就不能安全地假設成功或失敗。

sequenceDiagram
    participant W as Workflow
    participant L as Operation ledger
    participant E as Email provider
    W->>L: Reserve send_invoice:task_442
    W->>E: Send with operation key
    E-->>W: Response lost
    Note over W: Worker restarts
    W->>L: Read operation status
    W->>E: Reconcile by provider ID or key
    E-->>W: Already sent
    W->>L: Mark completed
    W->>W: Continue from checkpoint

工作流程記錄說明系統打算做什麼,供應商或權威後端則說明實際發生什麼。復原流程會先對應兩者,再決定是否重複呼叫。

分開工作流程與活動

工作流程協調步驟、等待、分支及重試;活動則執行外部副作用,例如呼叫 API 或寫入檔案。使用以重播為基礎的引擎時,工作流程決策應維持確定性,網路呼叫、時鐘、隨機值及供應商 SDK 則隔離在活動內。

Temporal 的持久執行模型記錄事件歷史,並透過確定性重播在失敗後還原工作流程狀態。你可以採用該引擎,也可以使用操作資料表與佇列實作較小的狀態機。兩者要求相同:持久保存的歷史必須決定從哪裡繼續。

讓每項可重試寫入具備冪等性

一個邏輯副作用只指定一個鍵,並在用戶端、worker 及供應商重試時重用。儲存第一個終止結果,並拒絕用不同參數重用同一個鍵。

Stripe 的冪等請求合約會保存某個鍵第一次請求的狀態碼與回應內容,包括失敗。其保留行為是 Stripe 特有的,但設計原則可以通用:重複請求是否屬於同一項操作,應由伺服器判斷,而不是模型。

如果供應商不支援冪等性,就在 adapter 周圍加入操作帳本。這能減少自己的重試造成重複,但無法證明逾時的供應商呼叫確實失敗。應加入結果對應查詢;若高影響結果仍無法判斷,則要求人類審查。

對已驗證事實建立檢查點

實用的檢查點會記錄已完成的操作 ID 及下一個合法狀態轉換。在驗證副作用後寫入,並在可行時讓狀態轉換與自己的資料庫寫入不可分割。

不要只對模型訊息建立檢查點。對話記錄中的「電子郵件已寄出」可能只是模型聲稱的結果,而不是供應商回應。應儲存供應商訊息 ID 或操作記錄參照。

持久狀態指南會區分工作進度、記憶及業務資料。

決定每一層的重試責任

模型 SDK、HTTP 用戶端、佇列、工作流程引擎、工具伺服器及供應商都可能重試。這些設定相乘後,原本三次嘗試可能變成數十次呼叫。

每項操作都應記載:

  • 哪些失敗可以重試;
  • 由哪一層執行重試;
  • 嘗試次數上限與最長經過時間;
  • backoff 及供應商速率限制訊號;
  • 每次嘗試重用的冪等鍵;
  • 耗盡嘗試後的終止狀態。

驗證與授權失敗應停止;速率限制可以等待;寫入發生網路逾時時,應先對應結果再重試。模型不該從錯誤字串臨時推測這些規則。

將等待視為持久狀態

人類核准、排定時間、webhook 及長時間執行的部署都是工作流程狀態,而不是持續睡眠的程序。保存等待條件與喚醒訊號,讓重複訊號不會造成問題,並在延後的核准恢復執行時,重新驗證其代表的使用者仍有權限。

將取消公開為狀態轉換。取消應停止未來步驟,但不能抹去已完成的副作用。補償操作,例如將發票作廢,應與取消分開定義。

測試模糊的時間窗

成功路徑測試會漏掉最困難的狀態:伺服器可能完成請求,但用戶端沒有收到回應。應在外部呼叫後、完成記錄前立即注入失敗,改由另一個 worker 重新啟動,再驗證結果只會對應一次。

也要在核准期間、backoff 期間及取消後中斷。原始嘗試與恢復執行應共用工作流程及操作 ID,並記錄在同一條追蹤中。失敗復原指南會把這些情況轉成完整 runbook。

下方提示詞會在不碰觸正式環境的情況下設計第一次中斷測試。如果預期結果是「代理會自己想辦法」,這個工作流程就還沒有復原合約。