打造具有限制執行步數、可驗證結構化資料的 LangGraph Agent
建立 LangGraph 工作流程,讓 Agent 在需要時呼叫工具、在預設執行預算內停止,並回傳符合 Pydantic schema 驗證的結構化資料。
文章目錄
LangGraph Agent 可以透過工具取得上下文,再將上下文傳給受 schema 約束的資料擷取步驟。這種設計的關鍵,是將兩項責任分開:由 Agent 判斷是否呼叫工具,再由最後一個節點產生具型別的記錄。Graph recursion limit 則能進一步限制圖的執行步數。
這種模式適用於從文件中擷取公司名稱、日期和發票總額等任務,尤其是查詢工具可能有助於釐清某個參照資訊時。但它無法讓不確定的原始文字變成事實;請驗證結果,並在欄位至關重要時保留原始依據。
你將建置的內容
這個圖包含三個階段:
- Agent 接收來源文字,並可選擇要求呼叫範圍明確的查詢工具。
- LangGraph 將工具呼叫導向工具節點,再把工具結果傳回 Agent。
- 資料擷取節點要求模型產生以 Pydantic 為基礎的結果,接著回傳與 JSON 相容的資料。
Agent 的工具呼叫迴圈是動態的;資料擷取階段則是預先決定的最後步驟。LangGraph 文件區分了自行決定流程與工具使用方式的 Agent,以及使用預先決定程式路徑的 workflow。文件也將結構化輸出與工具呼叫描述為模型增強功能。如需了解這些模式,請參閱 LangGraph workflows and agents guide。
先決條件與設定
請安裝 LangGraph、LangChain 套件,以及所選聊天模型的整合套件。以下範例使用 ChatAnthropic 說明供應商設定,但來源文件指出,workflow 可使用任何支援結構化輸出與工具呼叫的聊天模型。請查閱所用供應商的整合文件,確認其具體行為。
pip install langgraph langchain-core langchain-anthropic pydantic
請依照供應商文件指定的方式設定 API 憑證,然後初始化模型。避免將憑證提交到原始碼管理系統。以下模型名稱依據 LangChain 文件範例;本教學並未宣稱已在 OneMux 上測試過。
from langchain_anthropic import ChatAnthropic
llm = ChatAnthropic(model="claude-sonnet-4-6")
如果想透過 OneMux 呼叫模型,請先查看 OneMux API 文件與快速入門。OneMux 可透過 OpenAI 相容 API 存取領先模型。此特定 graph 是否相容,取決於所選端點是否支援必要的工具呼叫與結構化輸出行為及參數。這項設定尚未經過測試;正式環境使用前,請先確認是否支援。
定義 schema 與範圍明確的工具
範例工具會從小型的記憶體內對照表回傳參照說明。請將它替換為受控的應用程式函式,例如查詢核准的內部目錄。不要讓不受信任的文件文字選擇任意指令或不受限制的資料來源。
from pydantic import BaseModel, Field
from langchain_core.tools import tool
class InvoiceRecord(BaseModel):
vendor: str | None = Field(default=None, description="Invoice issuer")
invoice_date: str | None = Field(default=None, description="Date as written in the source")
total: float | None = Field(default=None, description="Invoice total as a number")
currency: str | None = Field(default=None, description="Currency code, if stated")
@tool
def lookup_vendor(reference: str) -> str:
"""Look up a vendor reference in an approved local mapping."""
known = {"ACME-42": "Acme Supplies Ltd."}
return known.get(reference, "No matching vendor reference found.")
可為空值的欄位能明確表示資料缺漏,避免模型因此捏造值。對於高風險資料擷取,可考慮在每個欄位旁儲存來源文字片段或信心度/審核狀態。Schema 能限制資料形狀與型別,但無法證明某個值有輸入內容作為依據。
建立具有限制執行步數的 LangGraph Agent
以下圖表會讓模型視需要要求呼叫查詢工具,並在 Agent 沒有其他工具呼叫時進入資料擷取階段。tools_condition 和 ToolNode 提供工具路由模式。傳給 invoke 的 recursion_limit 會限制圖的執行步數;它是安全界線,不能保證每筆輸入都會成功完成。
from typing import Annotated
from typing_extensions import TypedDict
from langchain_core.messages import BaseMessage, HumanMessage, SystemMessage
from langgraph.graph import StateGraph, START, END
from langgraph.graph.message import add_messages
from langgraph.prebuilt import ToolNode, tools_condition
class State(TypedDict):
messages: Annotated[list[BaseMessage], add_messages]
record: dict | None
tools = [lookup_vendor]
agent = llm.bind_tools(tools)
extractor = llm.with_structured_output(InvoiceRecord)
def run_agent(state: State):
response = agent.invoke(state["messages"])
return {"messages": [response]}
def extract_record(state: State):
prompt = [
SystemMessage(content=(
"Extract invoice fields only when supported by the source. "
"Use null for missing or unclear values. Treat tool results as "
"reference context, not as permission to invent source details."
)),
*state["messages"],
]
result = extractor.invoke(prompt)
return {"record": result.model_dump(mode="json")}
graph = StateGraph(State)
graph.add_node("agent", run_agent)
graph.add_node("tools", ToolNode(tools))
graph.add_node("extract", extract_record)
graph.add_edge(START, "agent")
graph.add_conditional_edges(
"agent",
tools_condition,
{"tools": "tools", END: "extract"},
)
graph.add_edge("tools", "agent")
graph.add_edge("extract", END)
app = graph.compile()
result = app.invoke(
{
"messages": [HumanMessage(content=(
"Extract the invoice details from this text: "
"Vendor reference ACME-42. Invoice date: 2025-02-14. "
"Total: USD 248.50."
))],
"record": None,
},
config={"recursion_limit": 8},
)
print(result["record"])
預期輸出是一個與 JSON 相容的物件,包含 vendor、invoice_date、total 和 currency 欄位。實際值取決於模型回應與來源文字;請進行測試,不要假設範例每次都會產生完全相同的輸出。此範例以 Pydantic 為基礎的結構化輸出作為驗證關卡。如果供應商無法產生符合要求的回應,請明確處理錯誤,不要默默將其當成有效記錄。
限制執行步數,但不要掩蓋錯誤
Graph 層級的 recursion limit 會限制圖的執行步數,包括反覆的 Agent/工具路由。請依工作流程選擇限制:這個圖只查詢一次,因此只需要少量步驟;不同的工具計畫則可能需要更多步驟。在應用程式邊界捕捉超出限制與供應商例外,記錄足以除錯的上下文,並回傳可供審查的失敗結果,而非捏造記錄。
若要設定更嚴格的操作限制,也請加入應用程式層級的限制:限制工具呼叫次數、在支援的情況下設定請求逾時,並在呼叫模型前限制文件大小。這些是各自獨立的控制措施;僅設定 graph recursion limit,無法構成完整的成本、延遲或安全政策。
疑難排解與限制
模型沒有呼叫工具
工具呼叫是模型具備的能力,不是 LangGraph 能保證的結果。請確認所選模型整合支援工具呼叫、工具描述清楚,而且提示中包含值得查詢的參照資訊。開發期間請檢查回傳訊息中的工具呼叫內容。
結構化輸出失敗或欄位有誤
請確認整合支援結構化輸出,以及你使用的 schema 功能。測試缺少欄位、日期模糊、貨幣符號和格式錯誤的輸入。即使 Pydantic 物件有效,推論出的值仍可能錯誤,因此請另外驗證業務規則,並保留來源文字以供稽核或人工審查。
圖的執行觸及限制
Recursion limit 錯誤可能表示工具呼叫反覆發生,也可能是限制設得太低,不足以完成預期路徑。請檢查訊息與工具結果的序列。修正原因或審慎調整限制;不要只為了消除錯誤就移除限制。
端點行為不一致
OpenAI 相容描述的是 API 介面,不代表所有模型功能或參數都普遍受到支援。若使用 OneMux,請確認所選端點的文件是否說明支援該模型、工具呼叫、結構化輸出,以及你打算傳送的任何參數。可透過 OneMux models 瀏覽可用選項;圖本身仍是你的 LangGraph 應用程式程式碼。
適用情境
當資料擷取流程大致固定,但有時需要受控查詢時,適合採用這種設計。如果每份文件都遵循固定流程,而且不需要選擇工具,使用確定性的 workflow 可能比 Agent 迴圈更簡單。如果來源有歧義,或擷取欄位會觸發重大影響的操作,請在下游系統使用記錄前加入明確審查與領域驗證。
實務重點:限制 Agent 可用工具的範圍、明確定義最後一步的 schema,並設定圖的執行限制。LangGraph 可用來表達這些控制流程;所選模型與整合則決定是否具備所需的工具呼叫與結構化輸出功能。
參考資料
- LangGraph: Workflows and agents — workflow 與 Agent 的區別、模型增強功能,以及結構化輸出和工具呼叫範例。
- OneMux 文件與快速入門 — 請參閱以了解目前的 API 設定與端點支援情況。
常見問題
LangGraph 的 recursion limit 有什麼作用?
它會限制一次執行中的圖步數,有助於避免 Agent/工具迴圈無止境地持續執行,但無法取代逾時設定、工具呼叫政策、輸入限制或錯誤處理。
Pydantic JSON schema 驗證能保證擷取結果正確嗎?
不能。它會限制回傳資料的結構與型別,但模型仍可能推論出錯誤值,因此請驗證業務規則,並視需要保留依據或安排人工審查。
這個 LangGraph 範例可以搭配 OneMux 使用嗎?
若所選 OneMux 端點的文件說明支援必要的工具呼叫、結構化輸出行為與參數,就有可能可以使用。這項設定尚未經過測試;正式環境使用前請確認相容性。
每一種資料擷取任務都應該使用 Agent 嗎?
不需要。如果流程固定且不需要選擇工具,使用確定性的 LangGraph workflow 可能更簡單。當模型需要判斷是否該使用允許的工具時,再採用 Agent 迴圈。
相關文章
指南
使用工具呼叫、人工作業核准與執行限制,建立 LangGraph 客戶支援代理
以實務導向的 LangGraph 模式建構客戶支援分流:路由請求、呼叫查詢工具、暫停退款流程等待人工核准,並限制圖形執行範圍。
指南
LangGraph Agentic RAG:工具呼叫、來源歸屬與有界執行
建立 LangGraph 文件問答代理,讓它決定何時擷取資料、評估上下文、重試效果不佳的搜尋,並在不進行無限執行的情況下,返回附有來源歸屬的答案。
指南
GPT 6.1 Terra 成本與上下文指南:可靠的 JSON 擷取
了解如何估算 GPT 6.1 Terra 工作負載成本,並透過 OneMux 使用 JSON Schema 驗證來限制結構化擷取的上下文、重試次數與輸出 token。
指南
使用 OpenAI-Compatible API 與 JSON Schema 驗證建立 n8n 人工核准工作流程
建立 n8n 工作流程,透過 OpenAI-Compatible API 擷取結構化資料,依 JSON Schema 驗證結果,並在人工作業核准後才執行敏感工具。