跳到主要內容

發表文章

目前顯示的是 7月, 2026的文章

AG Day 17 Human-in-the-loop:interrupt 與人工核准

AG Day 17 Human-in-the-loop:interrupt 與人工核准 執行需求:CPU 可跑 。在昨天 AG Day 16( 原文連結 )中,我們替 research-agent 接上了 SQLite 版的 checkpointer,讓代理能透過 thread_id 記住每一個研究任務的完整對話狀態,即使程式重啟也能從上次停下的地方繼續。今天要利用這個「能被中斷、能被恢復」的能力,實作一個對正式系統很重要的設計:讓代理在準備執行高風險動作之前,主動停下來,等待人類明確核准之後才繼續,而不是自顧自地把所有決定都執行完。今天全部範例都能在沒有 API 金鑰的情況下跑完,唯一需要提前準備的是昨天建立的 checkpointer,因為人工核准機制完全建立在「能被中斷、能被恢復」這個能力之上。 引言 到目前為止, research-agent 的工具都相對溫和:查資料、抓網頁,出錯了大不了重試或回報失敗,不會對外部世界造成不可逆的影響。但一個真正要拿去用的研究助理,遲早會需要做一些「有代價」的動作:呼叫按用量計費的付費 API、把整理好的報告寄出去、或是把資料寫進一個別人也在用的正式資料庫。如果代理完全自主地決定什麼時候該做這些事,一旦提示詞設計有漏洞,或模型偶爾判斷失準,後果可能不是「重試一次就好」,而是「已經花了錢」或「已經寄出去了,收不回來」。 Human-in-the-loop(人機協作、簡稱 HITL)的核心想法很直接:在流程裡插入一個「暫停點」,讓真人看過目前的狀態、決定要不要放行,代理才能繼續往下走。這聽起來像是要另外寫一套暫停與恢復的機制,但昨天我們已經把地基打好了:只要圖有 checkpointer,LangGraph 就能在任何節點裡呼叫一個叫 interrupt() 的函式,暫停目前的執行、把控制權交還給呼叫端;等真人做出決定後,呼叫端再用 Command(resume=...) 把決定送回去,圖會從暫停的那一點,帶著這個決定繼續往下跑。今天我們就是要把這個機制,安裝在 research-agent 呼叫外部搜尋服務之前。 原理與觀念 interrupt() 怎麼暫停一個正在執行的節點 interrupt() 是 LangGraph 提供的一個函式,你可以在圖的任何節點函式內部呼叫它,並傳入一個...

AG Day 16 記憶:checkpointer 與 thread

AG Day 16 記憶:checkpointer 與 thread 執行需求:CPU 可跑 。在昨天 AG Day 15( 原文連結 )中,我們把 research-agent 的工具執行邏輯拆開,改用手動組裝的 StateGraph 搭配 ToolNode ,並且做好了暫時性錯誤與結構性錯誤的分流處理,讓代理面對外部服務不穩定時更有韌性。但不管昨天測試跑了幾次,每次呼叫 app.invoke(...) 都是一段全新的對話,代理完全不記得前一次研究進行到哪裡。今天要解決這個問題:讓 research-agent 具備跨輪、甚至跨行程重啟都能延續的記憶能力,靠的是 LangGraph 的檢查點(checkpointer)機制與 thread_id 概念。今天的範例全程可以在沒有任何 API 金鑰的情況下跑完。 引言 「記憶」這個詞在對話系統裡常被簡化成「把歷史訊息塞進 prompt」,但對一個要花好幾輪、甚至橫跨好幾天才能完成的研究任務來說,這樣還不夠。使用者可能今天問了一半,明天才想起來要接著問;系統也可能因為程式重新部署而重新啟動,這時候如果代理的所有狀態都只活在記憶體裡,一旦行程結束,使用者之前的研究進度就整個消失了。LangGraph 把「狀態怎麼被儲存與還原」這件事抽象成 checkpointer ,它會在圖每執行完一個節點之後,把當下完整的狀態快照存下來;只要有這份快照,我們就能在任何時間點用同一個 thread_id 恢復執行,接著上一次停下的地方繼續。 thread_id 是理解這套機制的關鍵。你可以把它想成「一個對話串的身分證字號」:同一個 thread_id 底下的所有呼叫,會共用同一份不斷累積的狀態;換一個 thread_id ,等於開了一個全新的、彼此獨立的對話。對 research-agent 而言,我們規劃讓每一個研究任務對應一個 thread_id ,並讓它與我們在 AG Day 2( 原文連結 )建立的 runs 資料表裡的 run_id 一致,這樣就能把「LangGraph 內部的執行快照」與「我們自己記錄的任務中繼資料」串在同一把鑰匙下,方便日後查詢與除錯。 原理與觀念 checkpointer 的兩種常見實作:記憶體版與持久化版 LangGraph 提供了不只一種 checkpo...

AG Day 15 ToolNode:工具節點與錯誤處理

AG Day 15 ToolNode:工具節點與錯誤處理 執行需求:CPU+API key 。在昨天 AG Day 14( 原文連結 )中,我們用 LangGraph 內建的 create_react_agent 快速組出一個可以自主推理、呼叫工具的 ReAct 代理,讓 research-agent 第一次擁有「思考、行動、觀察」的完整迴圈。但 create_react_agent 是一個高度封裝的預製函式,內部到底怎麼執行工具、工具出錯時發生什麼事,昨天我們並沒有拆開來看。今天我們要把這個黑盒子打開,改成手動組裝 StateGraph ,直接使用 LangGraph 的 ToolNode ,並且針對研究助理最常遇到的失敗情境(網路逾時、參數錯誤、工具丟例外)設計一套明確的錯誤處理策略。完成今天之後,你會清楚知道工具呼叫失敗時,代理看到的到底是什麼內容,以及你能在哪些地方介入。 引言 ReAct 代理的核心迴圈很單純:模型看歷史訊息、決定要不要呼叫工具、呼叫後把結果塞回歷史、再讓模型看一次。這個迴圈裡「呼叫工具」這一步,在 LangGraph 裡是由一個叫 ToolNode 的內建節點負責。它的工作是讀取最後一則 AIMessage 裡的 tool_calls 欄位,逐一找到對應的工具函式、把參數傳進去執行、再把回傳值包成 ToolMessage 加回狀態。聽起來理所當然,但工程上真正棘手的地方在於:工具是我們自己寫的程式碼,隨時可能因為網路斷線、外部服務逾時、或呼叫方傳了奇怪的參數而丟出例外。如果一個工具的例外直接讓整條圖執行中斷,使用者只會看到一串 Python traceback,完全不知道代理到底想做什麼、卡在哪一步。 更麻煩的是,很多工程師的直覺反應是「把每個工具函式都包一層 try/except,出錯就回傳一個字串」。這樣做在單一工具上沒問題,但當工具數量變多(研究助理未來會有網路搜尋、擷取網頁、寫入知識庫、查詢向量庫等十幾個工具),到處重複同一套 try/except 樣板,會讓程式碼難以維護,而且很容易漏掉某個工具忘記包。LangGraph 的 ToolNode 提供了一個內建的 handle_tool_errors 參數,讓我們可以在節點層級集中定義「工具出錯時要怎麼辦」,而不必在每個工具函式裡各自處理。今天我們...

AG Day 14 ReAct Agent:create_react_agent 實戰

AG Day 14 ReAct Agent:create_react_agent 實戰 執行需求:CPU+API key 。如果暫時沒有 API key,本篇文章提供完整的離線 mock 與 dry-run 模式,不需要外部連線也能在本機完整演練 ReAct 狀態流轉、工具呼叫、訊息交接與結果審查流程。 引言 在過去幾天的探索中,我們一步一腳印地建立了 LangGraph 的完整心智模型。從 AG Day 11( 原文連結 )的 StateGraph 與固定邊、AG Day 12( 原文連結 )的 TypedDict 狀態縮減器,到 AG Day 13( 原文連結 )的條件邊與動態路由,我們已經完全具備了親手編排任何複雜狀態圖的能力。 然而,回顧我們在 AG Day 6( 原文連結 )手刻的第一個自主代理迴圈,以及 AG Day 5( 原文連結 )的函式呼叫機制,工程師在實務中最常建構的拓撲結構,其實是由普林斯頓大學提出的經典範式—— ReAct(Reasoning + Acting,推理與行動) 。在 ReAct 模式下,模型觀察當前對話歷史、推理下一步行動(思考)、發起工具呼叫(行動)、取得工具執行結果(觀察),並反覆迭代直到達成目標或給予最終解答。 如果每一次要建構 ReAct 代理,我們都得從頭手寫 StateGraph、宣告 messages 鍵值、掛載工具節點、設定 tools_condition 條件邊並手動拉回線路,樣板程式碼將不可避免地大幅增加。為了解決這個最常見的高頻場景,LangGraph 在 langgraph.prebuilt 模組中提供了開箱即用的原語—— create_react_agent 。在本文中,我們將深入剖析 create_react_agent 的內部運作機制,為我們的貫穿專案 research-agent 搭建具備學術文獻檢索與統計計算能力的 ReAct 研究代理,並建立完整的離線降級測試架構。 ReAct 範式演進:從文字提示詞到工具狀態機 理解 ReAct 的技術演進史,有助於我們看清現代代理架構的本質。在 2022 年 Yao 等人發表 ReAct 論文的初期,大型語言模型尚未具備原生的 Function Calling 能力。當時的做法純粹依賴「提示...

AG Day 13 條件邊:讓流程學會分岔

AG Day 13 條件邊:讓流程學會分岔 執行需求:CPU 可跑 。本篇文章聚焦於 LangGraph 條件邊(Conditional Edges)的動態路由機制,所有範例皆在本地 CPU 環境下運算,不需要外部模型 API 金鑰,即可完整演練路由函式撰寫、路徑對照字典(Path Mapping)、迴圈重試防護與分支追蹤驗證。 引言 在上一篇 AG Day 12( 原文連結 )中,我們深入拆解了 LangGraph 的狀態聚合心臟,掌握了透過 Annotated 與 add_messages 縮減器管理多輪對話訊息累積與識別碼就地更新的技巧。然而,回顧我們在 AG Day 11( 原文連結 )建立的圖結構,節點之間的流轉完全是由固定邊(Normal Edges)所硬性串聯的線性流程:從規劃、收集到報告,每一步的執行軌跡在編譯期就已完全注定。 但現實世界的代理任務往往充滿了不確定性與情境依賴。試想一個嚴謹的研究助理系統:當使用者提出一個定義明確的基礎名詞查詢時,系統應該直接產出簡答,而不必興師動眾地呼叫搜尋工具;當文獻萃取節點發現檢索到的資料互相矛盾或置信度過低時,系統必須能夠退回檢索節點重新生成關鍵字;當執行達到最大容許輪數時,系統則必須強制熔斷並產出降級警語。如果流程只能單向直行,AI Agent 就失去了最重要的「環境適應性與自主決策力」。 讓靜態管線晉升為智慧代理的關鍵樞紐,正是 LangGraph 的 條件邊(Conditional Edges) 。條件邊賦予了圖在執行時期(Runtime)依據當前狀態動態評估並選擇分支路徑的能力。本文將帶領大家深入條件邊的底層邏輯,從純函式路由設計、嚴格的路徑對照映射(Path Mapping)、迴圈重試的熔斷控制,一路到官方內建的 tools_condition 工具路由,徹底解鎖狀態圖動態分岔與自主決策的強大威力。 條件邊架構原理:狀態評估與動態路由 在圖論狀態機中,固定邊代表「當節點 A 完成後,永遠流向節點 B」;而條件邊則代表「當節點 A 完成後,檢視當前狀態,依據特定規則動態決定下一個目的地可能是節點 B、節點 C 或直接前往終點 END」。 在 LangGraph 1.x 中,宣告一條條件邊主要由三個正交要素所構成: 來源...