iT邦幫忙

2026 iThome 鐵人賽

DAY 21
0
Build on Google AI

ADK × A2A × Cloud Run 打造可部署、可互通的 Agent 系統系列 第 21 篇

Day 21:LangGraph(中)conditional edge 與什麼時候需要迴圈

  • 分享至 

  • xImage
  •  

昨天說 LangGraph 是狀態機。今天講為什麼「狀態機」這個形狀對 AI 系統特別重要。

為什麼需要迴圈

chain 只能單向流動:A 到 B 到 C,做完就結束。像一條水管。

但 AI 常常需要繞回去:

  • 答得不夠好,重寫一次
  • 查完資料,再想一次
  • 工具報錯,換個參數重試
  • 使用者退件,回上一步

水管做不到這些,圖做得到。框架名字裡的 graph 就是這個意思。

實作上是 conditional edge:一個函式看完目前的 state,回傳下一個節點的名字。它可以回傳自己上游的節點,於是形成迴圈。

「品質不夠就重寫,最多三次」這種需求在 LangGraph 裡是這樣寫的:state 裡放一個 retry_count,節點每次重寫時加一,conditional edge 檢查「品質達標或 retry_count >= 3」就往出口走,否則回重寫節點。

這段邏輯是純 Python,可以單元測試,可以印出來看,出錯時 stack trace 指得到行號。記住這個對照,之後講另一種風格的框架時會用到。

次數上限不是可有可無的裝飾

上面那個 retry_count >= 3 的判斷,我一開始沒放進條件式,只想著「反正模型應該不會一直錯」。這個假設很危險。

LangGraph 本身有個 recursion_limit,預設值是 25,超過會直接擋下來,防止真的無限迴圈燒爆 token。但這只是安全網。安全網被觸發,代表流程設計本身有漏洞:某個條件永遠不會成立,或者判斷式寫反了。迴圈因此跑到第 25 輪才被框架強制中止,而不是照原本設計在第 3 輪結束。次數或分數的出口一定要自己寫進 conditional edge 裡,不能仰賴框架幫你兜底:25 輪對一個本來只該跑 3 輪的流程來說,代價已經是好幾倍的模型呼叫。

迴圈裡欄位怎麼疊加

迴圈跑很多輪的時候,常常需要留住每一輪的紀錄,而不是被最新一輪蓋掉。State 裡的欄位預設行為是覆蓋:節點回傳 {"答案": "B"},就把前一輪的 "A" 蓋掉。

如果某個欄位你希望是往上疊的,例如每一輪重寫的草稿,或是對話歷史,要在定義 State 的 TypedDict 時,把欄位型別包上 Annotated,搭配一個 reducer,像 Annotated[list, add]。之後節點回傳 {"對話": ["新的一句"]},LangGraph 會接在既有清單後面繼續累加。

這跟迴圈的關係是:沒有這個標記,重寫迴圈只留得住最後一輪的結果,事後想檢討「第一次為什麼判斷錯」會發現資料早就不見了,因為每一輪都把上一輪蓋掉了。反過來說,答案這種只需要最新版本的欄位,就不該加這個標記,不然會一直往下疊,內容越來越長。哪個欄位該疊、哪個該蓋,是設計迴圈當下就該決定的事,不要等結果跑歪了才回頭補。

小結

conditional edge 讓 LangGraph 跳出 chain 的單向限制,能繞回去重試,能等狀況滿足才往下走。次數上限要自己寫進條件式;recursion_limit 只是最後一道安全網。State 裡哪些欄位該疊加、哪些該覆蓋,也是在寫迴圈的當下就該想清楚的事。

明天講另一個讓 LangGraph 真正好用的機制:checkpointer。它解決的是「迴圈跑到一半,能不能先停下來等人」這個 conditional edge 解決不了的問題。


上一篇
Day 20:LangGraph(上)它跟 AI 無關,是一台狀態機
下一篇
Day 22:LangGraph(下)checkpointer
系列文
ADK × A2A × Cloud Run 打造可部署、可互通的 Agent 系統 共 25 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言