Agent Runtime 的重試邊界:逾時不等於沒執行
外部工具逾時時,動作可能已完成。先區分失敗與結果未知,再決定重試、查詢或交由人工處理。
Contents
問題:請求逾時,不代表副作用沒有發生
假設 Agent 呼叫外部系統建立一筆紀錄:遠端已完成寫入,但回應在網路上遺失。Runtime 看到的是 timeout,遠端看到的卻是成功。若把 timeout 一律當成失敗並立即重試,就可能建立兩筆資料。
因此,工具執行結果至少要分成「成功」、「明確失敗」和「結果未知」。這個區分比替所有錯誤加上 retry 更重要。
把模型回合與工具動作分開
模型 generation 可以結束或取消;已送往外部系統的工具動作則有自己的生命週期。兩者共用一個 conversation state,容易讓斷線、重新生成或舊回呼意外重做副作用。
動作從「模型提出」進入「參數與政策驗證」,必要時等待核准,再進入執行中。完成後必須分辨成功、明確失敗與結果未知;最後一種先查詢遠端狀態,無法確認時交由人工處理。
Runtime 應為每個動作建立穩定的 operationId,並持久化狀態轉換。對外呼叫逾時後,不能只靠記憶體中的對話狀態判斷是否可以再送一次。
依副作用選擇重試策略
動作類型 | 逾時後的處理 | 前提 |
|---|---|---|
純讀取 | 可有限次重試 | 請求不會改變外部狀態,且有 timeout / backoff 上限 |
可冪等寫入 | 使用相同冪等鍵重試或查詢結果 | 接收端確實會以冪等鍵去重;鍵須綁定租戶與動作 |
不可冪等或不可逆操作 | 不自動重送 | 先查遠端狀態;無法確認時交由人工處理 |
「本地有 operationId」不等於「遠端已冪等」。如果外部服務不支援冪等鍵,也沒有可查詢的操作狀態,Runtime 就不能保證 exactly-once;它只能記錄不確定結果並避免盲目重送。
核准必須綁定實際動作
高風險動作需要人核准時,核准紀錄應綁定呼叫者、租戶、工具名稱、正規化後的參數摘要與到期時間。核准後若收件對象或參數改變,就必須重新核准;不能把「使用者曾說好」當作對任意後續呼叫都有效的授權。
同樣地,取消生成不一定能撤回已送出的外部請求。Runtime 必須定義取消是「停止尚未送出的動作」、「向 Provider 發出取消」,還是只停止等待;三者不能混為一談。
需要覆蓋的故障測試
- 外部寫入成功後,Worker 在記錄成功前重啟:恢復後不得盲目建立第二筆。
- 相同 webhook 或 queue 訊息重複送達:同一操作只能套用一次,或能安全回報既有結果。
- 外部回應逾時且狀態無法查明:動作進入
unknown,不偽裝成失敗或成功。 - 核准後修改工具參數、租戶或目標資源:舊核准失效。
- 舊 generation 或 stale socket 回呼抵達:不得取消、覆寫或重送新的工具動作。
這些是 Runtime 的驗收案例,不代表每個案例系統都已通過。公開案例若要宣稱已支援重試、回放或冪等,應能對應到實際實作與測試;否則應標示為設計要求。
設計邊界
Runtime 能管理自己的狀態與重試,但無法替不支援冪等或狀態查詢的第三方服務創造 exactly-once。這類限制要留在操作紀錄與使用者流程中,而不是用「每個動作都能重放」帶過。
