你讓 Agent 整理一批檔案,終端機突然關掉。重新開啟後,聊天紀錄還在,任務卻可能停在「工具到底做完了嗎」的空白處。Pi Durable 想處理的正是這個空白:它把執行步驟寫成可恢復的任務,讓程序重啟後接著處理。
這篇寫給第一次碰持久化 Agent 的讀者。我們會用官方 SQLite 範例建立驗收環境,再設計三個中斷點,分清楚「同一個任務接續」與「外部動作只發生一次」。你不用先懂資料庫;照著每一步保存證據,就能判斷自己的整合是否真的安全。
先說結論:Pi Durable 的續跑等於什麼?
Pi Durable 續跑=已寫入儲存的檢查點+重啟後重新排程;外部副作用仍要獨立對帳。把檢查點想成遊戲存檔:回到上個存檔點,不代表存檔後寄出的信能自動收回。官方將 Pi Durable 標為實驗性,以下是一套可重做的驗收方法,並非本站已完成的故障重現。
Pi Durable 的四個零件:先看懂再動手
官方的Pi Durable README把 Harness 定義為開在某個儲存後端上的執行層。它管理對話、模型回合、工具呼叫和自己的應用狀態。用白話說,聊天紀錄只是日記;Harness 還要記得工作做到哪一格。
- SQLite 是「存檔盒」。
openNodeSqliteStorage("./session.sqlite")把狀態放到檔案。重新開同一檔案,才有機會找回同一段工作;每次改用新路徑就等於換了存檔。 - Task 是「待辦格」。模型請求與工具呼叫都會成為任務。每一步先提交檢查點,讓下一個程序知道要從哪裡接。
- Submission 是「這次交辦」。送出訊息時設定固定的
requestId,重送同一交辦可以找回原提交。這個鍵只約束 Pi Durable 裡的提交,不會自動替外部付款或寄信去重。 - Replay 是「重做規則」。唯讀、能安全再跑的工具可標記
replay: "safe";未宣告可安全重跑的工具若在呼叫中中斷,官方文件描述為向模型回報interrupted,而非直接再執行。
這也解釋了為何Agent Harness 的基本零件與自己組裝 Agent 執行層值得先看:模型會回答問題,但決定如何存檔、重試、交還錯誤的是執行層。
第一關:用 SQLite 建一份能找回的存檔
先備妥 Node.js、npm,以及你有權使用的模型 API 憑證;模型請求可能產生費用。官方目前提供這行安裝指令,請在空的測試資料夾執行,避免碰到正式專案:
npm install @earendil-works/pi-durable @earendil-works/pi-ai @earendil-works/chord
在官方發表文的 SQLite 範例中,核心是 Harness.open(await openNodeSqliteStorage("./agent.sqlite"), …),接著用 harness.root(context, …)取得根對話。新程序要讀同一個 agent.sqlite;取得 root 後呼叫 harness.resume(),或透過提交與等待喚起排程。這裡的省略號代表你自己的模型、工具 registry 與執行環境設定,不能直接把這一小段當完整可跑程式;需要完整起點時,從官方可執行 examples選範例開始。
先做一個不殺程序的基準回合:送出固定 requestId(例如 demo-001),記下 submission ID、對話 ID、工具輸出和外部動作紀錄。正常結束後再次用相同鍵提交,核對回傳的 submission ID 是否相同。官方 README 對 requestId 的保證是「同一提交被找回」,不是外部系統的「剛好執行一次」。
第二關:Pi Durable 重啟前、中、後怎麼驗收?
把範例改成呼叫一個只寫測試帳本的工具,讓它在開始、寫入後、回傳前各記一行時間與同一個操作鍵。每次只改一個中斷點,用獨立的 SQLite 檔與操作鍵重做。終止程序後,重新執行同一份程式、開同一路徑、安裝同名工具,再呼叫 harness.resume()。如果工具程式或 registry 版本換了,觀察會混入程式變更,難以歸因於中斷。
- 工具呼叫前中斷:在提交輸入後、工具開始前終止。重啟後核對同一 submission 與工具是否接到那筆工作;帳本在中斷前應尚無該工具的外部寫入。
- 工具執行中中斷:讓工具先寫入測試帳本、暫停等待,再終止程序。這是最重要的一格:SQLite 可能還沒存下工具的完成回覆,但外部帳本已留下紀錄。若工具設成
replay: "safe",請檢查重跑是否因操作鍵而只形成一筆外部結果;若未設安全重跑,請檢查interrupted是否交給模型與人工決定。 - 工具回覆後中斷:等工具回覆已記入對話,再終止程序。重啟後核對已完成的工具是否被跳過、最終回答是否接續,並比較帳本與對話紀錄。
每一格都保存四個欄位:中斷時點、Pi 的任務/提交狀態、外部帳本筆數、重啟後下一個動作。不要只截最後的聊天回答;它看不出工具有沒有重複寫入。想進一步設計收據,可對照MCP 逾時後的結果驗證。
第三關:外部副作用為何要用冪等鍵?
假設工具要「寄出通知」。它向外部服務送出請求,服務已接受,但程序還沒把回覆寫回 SQLite 就死掉。重啟後,Pi Durable 只能看到自己的存檔;它無法僅憑存檔推斷外部服務是否完成。冪等鍵就是同一筆操作的收據號碼:外部系統若支援同鍵去重,重送時回傳同一結果;若不支援,先查收據或由人確認,再決定是否補做。
示範用的假外部帳本可以採用「操作鍵唯一」規則:第一次寫 notify:demo-001 時記一筆,第二次使用同鍵只讀回原紀錄。這是驗收工具設計,不是 Pi Durable 自帶的外部寄信保證。完成中斷測試時,同時比較 requestId、工具呼叫 ID、外部操作鍵;三者是不同邊界,別把一個鍵的去重範圍誤當成另外兩個。
若外部動作沒有可查的收據,預設讓工具不宣告可安全重跑。等模型收到中斷結果後,由人查外部後台、核對時間與操作對象,再決定補送、標記完成或撤回。付款、部署和正式寄信都應先用假資料演練這個分岔。官方對 replay: "safe" 的描述,是工具作者自己承諾可重跑;標記本身不會讓副作用變安全。
三個常見坑:看到「恢復」仍要檢查什麼
- 只看聊天日記:對話有文字,不代表工具的外部結果已落帳。請同時讀任務狀態與外部收據。
- 把 SQLite 當跨主機保證:官方 README 寫明 Node SQLite 使用 WAL 與
synchronous = NORMAL;其提交可承受程序崩潰,但主機斷電時最新提交可能遺失。測試「殺程序」與測試「斷電」是兩種情境。 - 讓兩個程序同時打開同一存檔:官方文件寫明一個儲存後端由一個程序持有,沒有跨程序鎖。驗收重啟時,先確定舊程序真的結束,再啟動新程序。
這篇與Pi 1.0 的功能與代價分析分工不同:前者幫你判斷套件方向,這裡給你逐格收集證據的方法。若想比較另一種持久任務設計,也可看Agent 狀態與事件紀錄教學。
一筆通知任務的完整對帳範例
把整個流程縮成一筆假通知:使用者提交「通知測試群組」,Pi 記下 requestId=demo-001,模型決定呼叫 send_notice,工具以 notice:demo-001 向假帳本寫入。假設帳本已回應成功,工具卻還來不及把結果回傳給 Pi,程序就在這一秒被終止。這是一個示意情境,用來列出你應觀察的證據,不是本站執行所得的測量結果。
- 先查外部:帳本是否已存在
notice:demo-001?記下原始建立時間與回覆內容。若查不到,別先假定動作失敗;仍要確認外部服務的查詢延遲與狀態定義。 - 再查內部:用同一路徑開 SQLite,找回根對話與同一提交。比較工具任務最後提交的階段,以及對話中有沒有完整工具結果。
- 最後看下一步:若工具可安全重跑,它是否拿相同操作鍵詢問帳本並取回既有結果?若工具不宣告安全重跑,模型看到的中斷回報是否保留足夠資訊供人工對帳?
這個例子裡,一筆提交、一筆外部結果、一個可解釋的重啟動作才算通過你自己的驗收。若看到兩筆外部結果,即使聊天最後仍回答「完成」,也應視為副作用設計失敗;若外部結果是一筆但 Pi 無法續答,則應追查任務排程與工具註冊。兩種故障要分開修。
Pi Durable 常見問題
1. 只保存對話文字,能讓工作續跑嗎?
不能由此推定。你還要找回提交、任務檢查點與未完成工具;對話文字只呈現工作的一部分。
2. 重新開 SQLite 檔案就會自動完成所有工作嗎?
不一定。官方 README 說明 resume() 會啟動任務排程,提交或等待也會啟動它。工具、模型與環境仍須可用。
3. requestId 能防止外部付款重複嗎?
不能直接保證。它用於找回 Pi Durable 裡同一筆提交。付款服務的去重與查詢,要在付款端另設計。
4. 工具可以一律標成 replay: "safe" 嗎?
不要一律標。先證明重跑同一操作不會產生第二份不可接受的外部結果,或能用同一操作鍵取回原結果。
5. 模型請求中途斷掉會怎樣?
官方設計會重送被中斷的模型請求。其發表文說部分答案會留在對話並標為中止;模型再次回答的內容仍需依你的任務驗收。
6. 殺程序與斷電是同一種測試嗎?
不是。前者主要測程序重啟;後者還考驗儲存媒介的落盤設定。官方 README 特別註明 SQLite 在主機故障時可能失去最新提交。
7. 可以拿正式寄信或付款當第一次中斷測試嗎?
先用假帳本。等你能解釋每個中斷點留下的收據和重啟動作,再接上有查詢與去重能力的正式服務。
8. Pi Durable 目前適合直接承接關鍵長任務嗎?
先驗收你的工作負載。截至 2026 年 10 月 3 日,官方 README 仍標示 Experimental,API 可在版本間變動;上線決定應建立在你自己保存的中斷紀錄與外部對帳上。
給新手的下一步
從一個不碰正式資料的範例開始,固定 requestId,保留同一 SQLite 檔,分別在工具前、中、後中斷。每次重啟都回答四個問題:Pi 記得什麼、外部做了什麼、下一步做了什麼、哪一步需要人決定?這四格對得起來,才是你能帶走的「續跑」能力。
接著閱讀
左右滑動查看更多推薦
想把這類驗收方法用在自己的 AI 工作流,可從 AlphaLab 課程挑一個小專案練習;第一份交付物就做成那張四欄中斷紀錄,而不是只留一張成功截圖。






