向 LangChain 學習:如何為業務級 Agent 提供可靠性的執行時

主題: Agent 工程

發布日期:

最後修改:


前言

Agent 的 demo 很容易讓人興奮。一個模型,幾個工具,一段 prompt,再套一個迴圈,就能做出會搜尋、會寫檔案、會呼叫介面的效果。

但 demo 到業務系統之間,有一條很長的溝。我把它叫做 Runtime 鴻溝——跨過去的不是更強的模型,而是一套能托住複雜、不穩定、可中斷、可恢復的生產環境執行時。

真正進入業務場景後,Agent 可能要跑幾分鐘甚至幾十分鐘,中間會呼叫多個外部系統,可能需要使用者審批,可能遇到網路失敗、工具逾時、模型輸出偏航、權限不足、使用者中途插話、行程重啟、版本升級。更麻煩的是,它往往還帶著狀態:目前任務進展到哪裡、已經查過什麼、寫過哪些中間檔案、哪些結論還沒確認、這個使用者能不能存取某份資料。

這時候,單純最佳化 prompt 沒法解決根本問題。Agent 需要一套執行時,把複雜、不穩定、可中斷、可恢復的執行過程托住。

LangChain 最近圍繞 production deep agents 談的 Runtime 很值得分享下,這對做 Agent 產品的人很重要。因為它提醒我們:業務級 Agent 的護城河,不只在某個更漂亮的 agent loop,還在於能不能把狀態、權限、恢復、觀測和人機協作做成一套穩定的底層能力。



一、業務級 Agent 的失敗,不只發生在模型回答錯的時候

很多人理解 Agent 可靠性時,第一反應是模型的幻覺問題。這當然重要,但業務系統裡,Agent 的失敗範圍要大得多。

它可能在長任務執行到第 8 步時行程掛了。重新執行會浪費成本,還可能重複呼叫外部介面,造成髒資料。

它可能呼叫工具失敗。一次 API 逾時、一段網頁載入失敗、一次資料庫查詢異常,如果沒有重試、降級和狀態儲存,整個任務就會變成一次性賭博。

它可能在等待人工確認時遺失上下文。使用者隔了半小時才回來點「確認」,系統卻不知道之前讓他確認的到底是哪一步。

它也可能在互動層失控。Agent 還在跑,使用者又發來一句「前面那個方向不對,換成另一個方案」,系統到底應該排隊、打斷、重啟,還是拒絕?沒有明確策略,體驗會非常混亂。

所以,業務級 Agent 的可靠性至少包含六件事:執行可靠、狀態可靠、互動可靠、權限可靠、觀測可靠、運維可靠。Runtime 的價值,就在於把這些問題盡量產品化、框架化,而不是讓每個團隊都從零手寫一遍。



二、先把 Harness 和 Runtime 分開

我現在的觀點裡,一個關鍵切分是:Harness 和 Runtime 不是一回事。

Harness 可以理解為 Agent 的行為外殼。它負責怎麼規劃任務、怎麼寫 prompt、能呼叫哪些工具、是否拆子任務、是否有檔案系統、是否使用子 Agent、如何做上下文壓縮。這一層直接影響 Agent 看起來聰不聰明。

Runtime 更底層。它負責 Agent 怎麼被執行、怎麼被儲存、怎麼被恢復、怎麼被中斷、怎麼被觀測、怎麼被排程、怎麼隔離不同使用者、怎麼處理並發請求。這一層直接影響 Agent 能不能支援好業務系統。

我發現很多開源 Agent 裡,把所有問題都塞進 harness:prompt 裡寫規則,工具呼叫裡加 try-catch,資料庫裡隨手存一點狀態,前端再做一個 loading。短期可以跑,長期會變成一團難以維護的邏輯。

LangChain Runtime 的思路是把 agent loop 上下文之外的共性能力抽出來。



三、Durable Execution:可靠性的第一塊地基

如果只能從 LangChain Runtime 學一個設計,我會先看 durable execution。

普通 Web 請求通常是短生命週期:請求進來,處理一下,回傳結果,結束。Agent 不一樣。一個業務 Agent 可能會執行很多步:理解任務、拆解計畫、檢索資料、呼叫工具、寫中間檔案、等待審批、繼續執行、產生報告。這個過程天然跨越多個模型呼叫、多個工具呼叫、多個使用者互動。

一旦任務變長,系統就必須面對一個問題:如果中間掛了,怎麼辦?

LangChain/LangGraph 的答案是 checkpoint。執行過程中的關鍵狀態會被持續儲存。恢復時,不需要完全從頭開始,而是從最近的合理狀態繼續。對業務系統來說,這不只是節省成本,更是避免副作用重複發生。

具體怎麼做?LangGraph 把 Agent 執行建模成一張狀態圖,每個節點是一步——一次模型呼叫、一次工具呼叫、一次條件判斷。狀態在節點之間流轉,每完成一步,整張圖的當前快照就會被序列化寫入 checkpointer。這裡有幾個值得拆開看的設計。

第一,checkpoint 的最小單元是節點邊界,不是函式呼叫邊界。一次模型串流輸出中途掛了,恢復時這次呼叫整體重來。

第二,state 是結構化的,不是黑箱 pickle。LangGraph 要求把狀態拆成有名字的 channel(如 messages、plan、scratchpad),每個 channel 配一個 reducer(messages 用 append,plan 用 overwrite)。這樣 checkpoint 之間是結構化 diff,可以追蹤、回放,也可以 time travel 到任意一步。

第三,checkpoint 之間是一棵樹,不是一條線。每個 checkpoint 都帶 parent 引用,可以從任意歷史節點拉一個分支重新執行——改一下使用者問題、跳過某次審批、試一個不同的工具,都是從同一棵樹上長出新枝。

第四,interrupt 和 checkpoint 是同一套機制。在節點前後設 interrupt,本質上就是執行到這裡寫一個 checkpoint 然後停下來。所以人工審批、使用者修改、外部訊號喚醒,複用的都是這套持久化能力。這也是為什麼 HITL 能做成 Runtime 能力而不是 UI 邏輯。

第五,後端可插拔。dev 用記憶體或 SQLite,生產用 Postgres 或 Redis。Agent 的可靠性級別可以隨業務階段調整,不必第一天就上重型基礎設施。

比如一個 Agent 正在為企業客戶產生一份調研報告。它已經完成了資料蒐集、競品整理、初稿產生,正在等待使用者確認是否需要拉取內部 CRM 資料。如果這時服務重啟,理想狀態不是讓 Agent 重新搜一遍資料,也不是讓使用者重新描述需求,而是恢復到「等待確認」這個狀態。

這就是 durable execution 的意義:把 Agent 的執行過程從一次性函式呼叫,變成可儲存、可恢復、可繼續的任務生命體。

這裡其實還需要回答另一些具體的問題,比如 Agent 的每一步到底如何算可恢復邊界?寫入業務系統的操作能不能重複?



四、狀態要分層:短期狀態、長期記憶、業務資料不能混在一起

Agent 做複雜任務時一定會產生狀態。但狀態不能一鍋燉。

短期狀態是當前任務裡的上下文:計畫是什麼,已經執行到哪一步,中間結果是什麼,哪些工具呼叫完成了,哪些待確認。這類狀態適合跟 thread、run、checkpoint 綁定。

長期記憶是跨會話的上下文:使用者偏好、組織規則、常用工作流、反覆出現的約束、可複用知識。這類狀態應該進入長期 store,並且按使用者、組織、應用、助手等維度做命名空間隔離。

業務資料又是另一層:訂單、題目、課件、客戶資料、組織資產、權限模型。這類資料通常不應該被 Agent Runtime 隨便吞掉,而應該由業務系統自己管理,Agent 透過受控工具存取。

LangChain 的設計對這裡很有啟發:它把 thread checkpoint 和 long-term store 區分開,同時又允許 deep agent 透過類似虛擬檔案系統的方式存取不同層級的狀態。對上層 Agent 來說,讀寫檔案和記憶比較自然;對底層系統來說,狀態仍然有明確邊界。

這對業務系統很關鍵。很多 Agent 產品早期會把聊天記錄、工具結果、使用者偏好、業務資料全塞進一個 conversation memory。實現起來是簡單,後面會在權限、成本、檢索品質、資料清理、合規稽核上一起爆雷。

比較穩的做法是:短期狀態服務於任務恢復,長期記憶服務於體驗連續性,業務資料保持在業務系統內,Agent 只透過權限受控的工具存取。



五、Human-in-the-loop 不是互動裝飾,而是可靠性機制

業務級 Agent 很難完全自動化。尤其是涉及寫操作、外部系統呼叫、重要決策、付費資源、使用者隱私時,人機協作是必要的安全閥。

這裡的關鍵不只是彈一個確認框。研發實現上真正的問題是:Agent 如何暫停?暫停時儲存什麼狀態?使用者多久之後回來都能繼續嗎?使用者能不能修改 Agent 給出的計畫?修改後從哪裡恢復?審批記錄能不能追溯?

LangChain Runtime 把 interrupt/resume 做成執行時能力,而不是讓應用層臨時判斷。因為 HITL 如果只停留在前端互動層,很容易變成 UI 邏輯;一旦任務跨行程、跨 worker、跨時間,前端就托不住了。

業務 Agent 裡有很多場景都需要這種能力:

  • 一個財務 Agent 準備提交報銷,需要人工確認。
  • 一個教研 Agent 準備批量產生課件,需要老師選擇講解風格。
  • 一個客服 Agent 準備執行退款,需要主管審批。
  • 一個資料分析 Agent 想存取敏感欄位,需要使用者臨時授權。

這些都不是普通對話體驗,而是業務流程。Runtime 如果能原生支援暫停、恢復、審批和狀態儲存,Agent 的可靠性會明顯上一個台階。



六、權限和多租戶:Agent 不能拿著萬能鑰匙到處跑

業務級 Agent 最大的風險之一,是權限問題。

普通應用裡,使用者點按鈕、呼叫介面、伺服器端校驗權限,鏈路相對清晰。Agent 介入後,事情變複雜了:模型會決定呼叫哪個工具,工具可能存取外部系統,外部系統可能需要使用者授權,Agent 還可能把中間結果寫入長期記憶。

LangChain 的思路是把身份和權限拆成幾層:終端使用者是誰,使用者能存取哪些 thread 和資源,Agent 能代表使用者存取哪些外部系統,團隊成員對平台本身有什麼操作權限。

在這個設計裡,Agent 不是一個後台超級管理員。它更像一個被委託的執行者,只能在當前使用者、當前組織、當前任務允許的範圍內行動。

如果我們為自己的業務 Agent 設計 Runtime,也應該至少考慮幾條邊界:

  • 使用者身份要進入 run context。Agent 的每次執行都應該知道我正在代表誰行動。
  • 資源存取要按 thread、file、project、organization 做隔離。不能只靠 prompt 告訴模型不要存取別人的資料。
  • 外部工具授權要獨立管理。比如 GitHub、Slack、CRM、OSS、資料庫,都不應該把長期密鑰直接暴露給 Agent 執行環境。
  • 長期記憶要有 namespace。否則 Agent 記住的使用者偏好,很可能在多租戶場景裡變成資料汙染。
  • 高風險工具要有審批或策略攔截。刪除、傳送、支付、發布、批次寫入這類動作,不能只靠模型自覺。

Agent 越像人,系統越容易誤以為它可以繼承人的全部權限。但從工程角度看,Agent 應該拿到的是任務級、時效性、最小化的權限。



七、Middleware:把防護能力放到執行時生命週期裡

很多團隊會把 guardrails 寫進 prompt,比如「不要洩露隱私」「不要執行危險操作」「遇到不確定要詢問使用者」。這有用,但不夠。

模型會忘、prompt 會被覆蓋、工具呼叫路徑會繞開規則,串流輸出和背景任務也可能產生不同的行為。業務系統必須要有更硬的防線。

middleware 設計就是圍繞 Agent 生命週期插入控制點:模型呼叫前、模型呼叫時、工具呼叫時、模型呼叫後,都可以做策略處理。

這意味著很多可靠性能力可以下沉到 Runtime:

  • 呼叫模型前,裁剪上下文、注入權限資訊、檢查 token 預算。
  • 呼叫模型時,做模型 fallback、逾時控制、重試策略、成本記錄。
  • 呼叫工具時,做權限校驗、參數檢查、敏感動作攔截、人工審批。
  • 模型輸出後,做 PII 偵測、格式校驗、結果歸檔、trace 標記。

這比在每個工具裡零散寫邏輯要穩定,也更容易統一治理。

對業務級 Agent 來說,middleware 的意義不只是安全過濾,它是 Runtime 可治理性的入口。



八、Streaming 和 double-texting:互動可靠性也要進入 Runtime

很多人把 streaming 當作體驗最佳化。對 Agent 來說,streaming 還有可靠性意義。

長任務如果沒有即時反饋,使用者不知道系統是否還活著,也不知道執行到了哪一步。尤其是研究、程式設計、資料分析、課件產生這類任務,使用者需要看到中間狀態:正在檢索、正在呼叫工具、正在寫草稿、正在等待確認。

更複雜的是使用者中途插話。Agent 還在跑,使用者發來新指令,這被 LangChain 稱為 double-texting 一類問題。它不是小問題,而是互動協議問題。

系統要明確:新輸入是排隊等待,還是直接打斷當前任務?是合併到當前上下文,還是撤銷後重新執行?是允許使用者中途改目標,還是要求當前任務結束後再處理?

業務系統裡,不同場景答案不同。

寫作 Agent 可以允許使用者中途調整方向。

支付 Agent 不能隨便中斷後繼續執行危險操作。

教研課件 Agent 可能適合把新輸入加入任務佇列。

程式設計 Agent 可能需要暫停當前命令,等待使用者確認是否改計畫。

這說明聊天體驗其實是 Runtime 設計的一部分。



九、Observability:業務 Agent 不能只靠日誌排查

傳統應用出問題,日誌、指標、鏈路追蹤通常夠用。Agent 出問題,單純日誌往往不夠。

因為 Agent 的錯誤很多是過程性錯誤:第一步理解偏了,第三步用了不合適的工具,第五步接受了低品質檢索結果,第七步把中間假設當成結論。最後輸出錯了,但真正原因埋在執行路徑裡。

LangChain/LangSmith 強調 trace、time travel、debug,業務級 Agent 需要的不只是呼叫成功率,還要知道:

  • 這次任務經歷了哪些節點?
  • 每一步模型看到了什麼上下文?
  • 呼叫了哪些工具?參數是什麼?回傳是什麼?
  • 中間狀態如何變化?
  • 在哪一步發生了分支?
  • 是否觸發了 middleware、審批、重試、fallback?
  • 如果把某個 checkpoint 的狀態改一下,後面結果會不會變?

這些能力決定了 Agent 能不能被持續最佳化。否則,團隊只能靠看感覺改 prompt。那不是工程閉環。

更進一步說,Observability 還連接 eval。trace 不是只用於排障,也可以變成評估樣本、回歸測試、成本分析和產品洞察。



十、Agent Runtime 要能橫向擴展,也要能控制成本

業務 Agent 一旦上線開始有使用者,就需要關心運維問題了。

有些任務很短,有些任務很長;有些只是讀資料,有些會呼叫慢工具;有些使用者會連續發訊息,有些任務會定時觸發;模型呼叫成本高,工具呼叫也可能有成本;長任務大量堆積時,API server、queue worker、Redis、Postgres、外部工具都會成為瓶頸。

LangChain Agent Server 有幾個值得學習的點:

API server 和 queue worker 分離。 前者負責接收請求,後者負責執行長任務。這能避免長任務拖垮入口服務。

執行狀態和持久狀態分層。 臨時執行狀態可以放在 Redis 一類系統裡,thread、run、checkpoint、memory 這類資料進入持久儲存。

並發能力可設定。 不同 Agent 的任務形態不同,I/O-heavy 和 CPU-heavy 的 worker 並發策略應該不同。

避免前端輪詢。 對長任務來說,join/stream 比粗暴輪詢更適合,也更節省系統資源。

支援 cron。 很多業務 Agent 不是使用者點一下才執行,而是需要定期檢查、定期總結、定期同步、定期產生內容。

一個可靠的業務 Agent Runtime,必須同時關心任務語義和基礎設施成本。



十一、抽出一份 Runtime 設計清單

如果不照搬 LangChain,而是為自己的業務 Agent 做執行時設計,可以把能力拆成下面這張清單。

第一,任務生命週期。 有沒有 thread、run、step 這樣的基本抽象?一次 Agent 執行能不能被追蹤、取消、暫停、恢復、重試?

第二,持久執行。 每一步關鍵狀態是否 checkpoint?恢復邊界在哪裡?哪些操作可重放,哪些操作必須冪等,哪些操作只能人工確認後繼續?

第三,狀態分層。 短期任務狀態、長期記憶、業務資料是否分開?是否有 namespace?是否支援清理、遷移、稽核?

第四,權限模型。 Agent 是代表誰執行?能存取哪些資源?能呼叫哪些工具?外部系統授權怎麼管理?高風險操作是否需要審批?

第五,工具治理。 工具是否有 schema、權限、逾時、重試、限流、稽核?工具失敗後是重試、降級、跳過,還是中斷?

第六,人機協作。 是否支援執行中 interrupt?使用者確認後能否 resume?審批內容、審批人、審批時間是否可追溯?

第七,互動協議。 streaming 如何設計?使用者中途輸入如何處理?排隊、拒絕、打斷、重啟分別適合哪些場景?

第八,觀測與除錯。 是否有結構化 trace?能否看到模型呼叫、工具呼叫、狀態變化、middleware 觸發?能否把 bad case 轉成 eval?

第九,運維擴展。 入口服務和執行 worker 是否分離?佇列如何設計?儲存瓶頸在哪裡?長任務堆積時如何限流?成本如何歸因?

第十,部署邊界。 哪些能力自己託管,哪些用託管平台?資料是否能留在自己系統裡?未來是否會被某個 runtime 綁定太深?



十二、寫在最後

Agent 產品不止是追逐更聰明,進入業務系統後,很重要的是更可靠:能恢復、能隔離、能審批、能追蹤、能擴展、能控制成本。

這也解釋了為什麼 Agent Harness 和 Runtime 要分開看。Harness 決定 Agent 的能力上限,Runtime 決定 Agent 的業務下限。沒有前者,Agent 不夠聰明;沒有後者,Agent 不敢上線。

如果我們要做自己的業務級 Agent,Runtime 應該從第一天就進入架構設計。哪怕第一版不做完整系統,也應該先定義好邊界:任務狀態怎麼儲存,使用者身份怎麼傳遞,工具權限怎麼控制,人工審批怎麼恢復,trace 怎麼沉澱為評估資料。

Agent 的未來不只是模型更強,也會是 Runtime 更成熟。誰能把複雜 Agent 的執行過程做得穩定、可控、可稽核,誰才更接近真正的業務落地。

這也是 LangChain 這篇 Runtime 文章最值得學習的地方。



參考資料