LangGraph認知篇-Command函數

Command簡述

????????在 LangGraph 中,Command 是一個極具實用性的功能,它能夠將控制流(邊)和狀態更新(節點)巧妙地結合起來。這意味著開發者可以在同一個節點中,既執行狀態更新操作,又決定下一個要前往的節點,為工作流的構建帶來了極大的靈活性。

Command基本用法

Command?允許你在單個節點函數中完成兩件關鍵任務:

  1. 更新圖狀態 (update): 修改共享的?State?對象。

  2. 指定下一節點 (goto): 顯式決定工作流下一步執行哪個節點。

def my_node(state: State) -> Command[Literal["my_other_node"]]:?return Command(?# 狀態更新?update={"foo": "bar"},?# 控制流?goto="my_other_node"?)

????????在這個示例中,my_node 函數返回一個 Command 對象,

  • update 參數用于指定狀態的更新內容,將狀態中的 "foo" 鍵值設為 "bar";

  • goto 參數則決定了下一個要前往的節點是 "my_other_node"。

關鍵約束

????????在節點函數中返回 Command 時,必須添加返回類型注釋,注明該節點可路由到的節點名稱列表,如 Command[Literal["my_other_node"]]。這一點至關重要,它不僅是 graph 渲染所必需的,還能明確告知 LangGraph 該節點可以導航到 "my_other_node"。

Command 核心應用場景

動態控制流(替代條件邊)

????????直接在節點邏輯中根據狀態判斷跳轉路徑,代碼更內聚:

def check_threshold(state: State) -> Command[Literal["proceed", "halt"]]:if state["value"] > state["threshold"]:return Command(goto="halt")  # 無需更新狀態時update可省略return Command(goto="proceed")

Command 與條件邊的決策

  • Command當您需要同時更新圖形狀態和路由到其他節點時使用。例如,在實現多代理切換時,需要路由到其他代理并向該代理傳遞一些信息。

  • 僅需根據當前狀態選擇分支且不涉及狀態修改(如循環判斷、簡單路由),使用條件邊更清晰。

跨層級節點跳轉(子圖 → 父圖)

????????實現跨子圖的工作流跳轉,需指定?graph=Command.PARENT,代碼示例如下:

from typing import Literal, Optional, Annotated
from operator import addfrom langgraph.checkpoint.memory import MemorySaver
from langgraph.graph import StateGraph, START, END
from langgraph.types import Command
from pydantic import BaseModel# 定義子圖狀態
class SubgraphState(BaseModel):"""子圖狀態定義"""issue: strescalated: bool = False  # 與父圖共享的狀態字段# 定義父圖狀態 reducer(處理子圖與父圖的狀態沖突)
def escalated_reducer(left: bool, right: bool) -> bool:"""共享字段escalated的合并策略:右側值(子圖更新)優先"""return right# 定義父圖狀態
class ParentGraphState(BaseModel):"""父圖狀態定義"""issue: strescalated: Annotated[bool, escalated_reducer] = False  # 使用reducer注解resolution: Optional[str] = None# 子圖節點
def subgraph_worker(state: SubgraphState) -> Command[Literal["manager_approval", END]]:"""子圖中的工作節點,決定是否升級到父圖"""if "critical" in state.issue.lower():return Command(update={"escalated": True},  # 更新共享狀態goto="manager_approval",  # 父圖中的目標節點graph=Command.PARENT  # 關鍵:指定跳轉到父圖)return Command(goto=END)  # 不升級則直接結束子圖# 構建子圖
subgraph_builder = StateGraph(SubgraphState)
subgraph_builder.add_node("worker", subgraph_worker)
subgraph_builder.add_edge(START, "worker")
subgraph = subgraph_builder.compile()# 父圖節點
def manager_approval_node(state: ParentGraphState) -> ParentGraphState:"""父圖中的經理審批節點"""return ParentGraphState(**state.model_dump(), resolution="經理已審批處理")# 構建父圖(包含子圖)
parent_builder = StateGraph(ParentGraphState)
parent_builder.add_node("subgraph", subgraph)  # 嵌入子圖
parent_builder.add_node("manager_approval", manager_approval_node)# 定義父圖邊
parent_builder.add_edge(START, "subgraph")
parent_builder.add_edge("manager_approval", END)# 編譯父圖
parent_graph = parent_builder.compile(checkpointer=MemorySaver()
)# 運行示例
if __name__ == "__main__":print("=== 跨層級跳轉測試 ===")# 測試會觸發升級的情況result1 = parent_graph.invoke({"issue": "Critical error: system down"})print(f"測試1 - 觸發升級: {result1}")# 應輸出包含escalated=True和經理審批結果的狀態# 測試不會觸發升級的情況result2 = parent_graph.invoke({"issue": "Minor issue: slow response"})print(f"測試2 - 不觸發升級: {result2}")# 應輸出escalated=False且無經理審批結果的狀態
  • 狀態同步注意:若父子圖共享狀態字段,需在父圖狀態中為該字段定義?reducer?函數處理沖突。

工具調用與狀態注入

????????一個常見的工具調用場景是從工具內部更新圖譜狀態。例如,在客戶支持應用中,您可能希望在對話開始時根據客戶的賬號或 ID 查找客戶信息。要從工具中更新圖譜狀態,您可以從工具中返回?Command(update={"my_custom_key": "foo", "messages": [...]})。代碼示例如下:

from typing import Annotated, Dict, Any, List
from pydantic import BaseModel
from operator import addfrom langgraph.graph import StateGraph, START, END, Command
from langgraph.prebuilt import ToolNode
from langgraph.checkpoint.memory import MemorySaver
from langchain_core.tools import tool
from langchain_core.messages import AIMessage, ToolMessage# 定義消息列表的reducer
def add_messages(left: List[Any], right: List[Any]) -> List[Any]:"""消息列表的合并策略"""return left + right# 1. 定義狀態模型
class SupportState(BaseModel):user_id: str  # 客戶IDuser_info: Annotated[Dict[str, Any], add] = {}  # 工具返回的用戶信息messages: Annotated[List[Any], add_messages] = []  # 消息歷史(必須包含工具調用記錄)query_status: str = "pending"  # 流程狀態標記# 2. 定義工具函數
@tool
def lookup_user_info(tool_call_id: Annotated[str, "tool_call_id"]) -> Command:"""根據用戶ID查詢客戶信息(內部工具)"""# 假設從線程配置中獲取user_id(實際中可從config獲取)# 注意:此處簡化處理,實際需注入configuser_id = "CUST-789"  # 模擬獲取print(f"正在查詢用戶信息: {user_id}")# 模擬實際查詢邏輯(可替換為數據庫/API調用)user_data = {"user_id": user_id,"name": "陳明亮","membership": "白金會員","contact": "chen@example.com","recent_tickets": "訂單延遲問題"}print(f"查詢結果: {user_data}")# 返回Command更新狀態return Command(update={"user_info": user_data,"messages": [ToolMessage(content=f"已獲取用戶 {user_id} 的詳細信息",tool_call_id=tool_call_id)],"query_status": "user_info_fetched"})# 3. 定義觸發工具調用的節點
def call_tool(state: SupportState) -> SupportState:"""創建工具調用消息的節點"""print(f"\n===== 觸發工具調用 =====")tool_call_message = AIMessage(content="",tool_calls=[{"name": "lookup_user_info","args": {},  # 無額外參數"id": "call_123"}])return SupportState(messages=state.messages + [tool_call_message])# 4. 定義后續處理節點
def handle_support_request(state: SupportState) -> SupportState:"""處理客戶請求的節點(依賴工具返回的用戶信息)"""print(f"\n===== 開始處理客戶請求 =====")print(f"客戶ID: {state.user_id}")print(f"客戶信息: {state.user_info}")print(f"當前狀態: {state.query_status}")print(f"消息記錄: {state.messages}")# 基于用戶信息進行業務處理if state.user_info.get("membership") == "白金會員":priority_msg = "優先處理白金會員請求"else:priority_msg = "標準流程處理請求"# 更新最終狀態return SupportState(user_id=state.user_id,user_info=state.user_info,messages=state.messages + [priority_msg, "客戶請求處理完成"],query_status="completed")# 5. 構建圖譜(使用ToolNode處理Command)
def build_support_graph():builder = StateGraph(SupportState)# 創建ToolNodetool_node = ToolNode([lookup_user_info])# 添加節點builder.add_node("call_tool", call_tool)builder.add_node("tools", tool_node)builder.add_node("process_request", handle_support_request)# 定義邊builder.add_edge(START, "call_tool")builder.add_edge("call_tool", "tools")builder.add_edge("tools", "process_request")builder.add_edge("process_request", END)return builder.compile(checkpointer=MemorySaver())# 6. 運行示例
if __name__ == "__main__":support_graph = build_support_graph()print("=== 客戶支持流程開始 ===")result = support_graph.invoke({"user_id": "CUST-789"})print("\n===== 流程結束 =====")print(f"最終用戶信息: {result['user_info']['name']} ({result['user_info']['membership']})")print(f"流程完成狀態: {result['query_status']}")print(f"完整消息歷史: {result['messages']}")
  • @Tool 工具Command對象返回值:

    • update參數需包含業務數據(如用戶信息、查詢結果)和消息歷史

    • messages字段必須包含ToolMessage,且需關聯對應的tool_call_id
      (這是 LLM 提供商要求的格式,確保工具調用與結果在消息鏈中正確關聯)

  • ToolNode 的核心作用:

    • 自動 Command 處理:解析工具返回的?Command?對象并更新狀態

    • 消息歷史維護:自動添加?ToolMessage?到消息序列

    • 錯誤處理:內置工具執行異常捕獲機制

    • ID 管理:自動處理?tool_call_id?的生成和關聯

人機協同工作流(Human-in-the-Loop)

? ? ? ? Command還可以與?interrupt()?結合實現人工審核中斷與恢復:

from typing import TypedDict
from langgraph.checkpoint.memory import MemorySaver
from langgraph.graph import StateGraph
from langgraph.types import Command, interrupt# 新增模型相關導入
from langchain_core.messages import HumanMessage
from langchain_openai import ChatOpenAI
from dotenv import load_dotenv
load_dotenv()# 定義狀態類型
class State(TypedDict):some_text: str# 初始化大模型(需要設置OPENAI_API_KEY環境變量)
model = ChatOpenAI(model="gpt-4o-mini")# 初始化檢查點存儲
checkpointer = MemorySaver()# 定義人類介入節點
def human_node(state: State):value = interrupt({"text_to_revise": state["some_text"],"instructions": "請修改以下文本:"})return {"some_text": value}# 修改后的自動處理節點(調用大模型)
def process_text(state: State):# 構造模型請求message = model.invoke([HumanMessage(content=f"請處理以下請求:{state['some_text']}。保持回答簡潔。")])# 返回模型生成的文本return {"some_text": message.content}# 構建工作流
graph_builder = StateGraph(State)# 添加節點
graph_builder.add_node("human_review", human_node)
graph_builder.add_node("auto_process", process_text)# 設置流程
graph_builder.set_entry_point("auto_process")
graph_builder.add_edge("auto_process", "human_review")# 編譯圖表
graph = graph_builder.compile(checkpointer=checkpointer,interrupt_before=["human_review"]
)# 使用示例(保持不變)
if __name__ == "__main__":thread_id = "thread_123"thread_config = {"configurable": {"thread_id": thread_id}}initial_state = {"some_text": "輸出一個五五乘法表"}result = graph.invoke(initial_state, config=thread_config)print("自動處理結果:", result["some_text"])human_input = input("請輸入人類輸入:")resume_result = graph.invoke(Command(resume=human_input),config=thread_config)print("最終結果:", resume_result["some_text"])

最佳實踐與注意事項

  1. 類型標注不可少-> Command[Literal["node_a", "node_b"]]?是 LangGraph 靜態檢查和繪圖的基礎。

  2. 跨圖狀態設計:子圖跳轉父圖更新共享狀態時,父圖需定義?reducer?處理沖突(如?lambda current, update: update)。

  3. 命名一致性goto?指定的節點名必須與圖中注冊的節點名完全一致。

  4. 工具安全調用:在工具中使用?Command?時,確保狀態更新不會破壞圖的一致性。

參考文獻

Overview

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/91687.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/91687.shtml
英文地址,請注明出處:http://en.pswp.cn/web/91687.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【目標檢測】小樣本度量學習

小樣本度量學習(Few-Shot Metric Learning)通常用于分類任務?(如圖像分類),但它也可以與目標檢測(Object Detection)結合,解決小樣本目標檢測(Few-Shot Object Detectio…

cmd怎么取消關機命令

在 Windows 的命令提示符(CMD)中取消已計劃的關機操作,可以通過 shutdown 命令的 ?**-a**? 參數實現。以下是具體步驟:?操作方法??打開 CMD?按下 Win R 組合鍵,輸入 cmd 并回車,打開命令提示符窗口。…

網易云音樂硬剛騰訊系!起訴SM娛樂濫用市場支配地位

企查查APP顯示,近日,法院公開杭州樂讀科技有限公司、杭州網易云音樂科技有限公司起訴SM ENTERTAINMENT CO. 、卡斯夢(上海)文化傳播有限公司等開庭信息,案由涉及濫用市場支配地位糾紛。公告顯示,該案件計劃…

[css]切角

使用css實現一個切角的功能&#xff0c;有以下幾種方案&#xff1a; <div class"box"></div>方案一&#xff1a;linear-gradient linear-gradient配合backgroud-image可以實現背景漸變的效果。linear-gradient的漸變過渡區的占比是總的空間&#xff08;高…

分享一個可以測試離線服務器性能的腳本

在日常運維工作中&#xff0c;經常會遇到系統性能莫名跟不上業務需求的情況&#xff1a;服務器響應變慢、應用加載卡頓、資源占用異常飆升等問題頻繁出現&#xff0c;卻難以快速問題根源究竟在CPU過載、內存泄漏、磁盤I/O阻塞還是網絡帶寬瓶頸。這種時候&#xff0c;特別需要一…

Python Pandas.unique函數解析與實戰教程

Python Pandas.unique 函數解析與實戰教程 摘要 本文章旨在全面地解析 pandas 庫中的 unique 函數。pandas.unique 是一個用于從一維數組型(array-like)對象中提取唯一值的高效工具。我們將從其核心功能、函數簽名、參數詳解、返回值類型,到關鍵行為特性(如順序保留、缺失…

排序算法入門:直接插入排序詳解

這里寫目錄標題介紹原理代碼實現分析介紹 直接插入排序是一種簡單直觀的排序算法&#xff0c;適用于小規模數據或基本有序的數據集。其核心思想是構建有序序列&#xff0c;對于未排序數據&#xff0c;在已排序序列中從后向前掃描&#xff0c;找到相應位置并插入。 原理 我們…

ClickHouse MergeTree引擎:從核心架構到三級索引實戰

摘要 MergeTree是ClickHouse最核心的存儲引擎&#xff0c;采用列式存儲LSM-Tree架構設計&#xff0c;支持高效的數據寫入、合并和查詢。本文將全面解析MergeTree引擎的基礎概念、數據流、核心架構、索引系統以及常見問題。 基礎篇&#xff1a; 一、MergeTree引擎基礎概念 1. 定…

電腦手機熱點方式通信(上)

電腦連接手機熱點時的無線鏈路情況&#xff1a; 電腦上網時&#xff08;從服務器下載數據&#xff0c;或者上傳指令、數據&#xff09;&#xff0c;首先電腦與手機之間基于WiFi協議在2.4G頻段或者5G頻段通信&#xff0c;然后手機與基站之間再基于4G LTE或者5G NR協議在2412MHz…

MySQL CPU占用過高排查指南

MySQL CPU 占用過高時&#xff0c;排查具體占用資源的表需結合系統監控、數據庫分析工具和 SQL 診斷命令。&#x1f50d; ?一、快速定位問題根源??確認 MySQL 進程占用 CPU?使用 top 或 htop 命令查看系統進程&#xff0c;確認是否為 mysqld 進程導致 CPU 飆升。若 MySQL 進…

軟件交付終極閘口:驗收測試全解析

驗收測試&#xff1a;軟件交付的關鍵環節 目錄 驗收測試&#xff1a;軟件交付的關鍵環節 一、驗收測試&#xff1a;軟件交付的終極閘口 核心目標與作用 在 SDLC 中的位置 二、驗收測試類型詳解&#xff1a;精準匹配業務場景 三、驗收測試全流程解析&#xff1a;從計劃到…

深度學習核心:卷積神經網絡 - 原理、實現及在醫學影像領域的應用

&#x1f9d1; 博主簡介&#xff1a;CSDN博客專家、CSDN平臺優質創作者&#xff0c;高級開發工程師&#xff0c;數學專業&#xff0c;10年以上C/C, C#,Java等多種編程語言開發經驗&#xff0c;擁有高級工程師證書&#xff1b;擅長C/C、C#等開發語言&#xff0c;熟悉Java常用開發…

多線程(二) ~ 線程核心屬性與狀態

文章目錄一. 線程創建&#xff08;start&#xff09;&#xff08;一&#xff09;繼承Thread類&#xff0c;重寫run&#xff08;二&#xff09;繼承Runnable類&#xff0c;重寫run&#xff08;三&#xff09;Thread匿名內部類重寫&#xff08;四&#xff09;Runnable匿名內部類重…

Linux---編輯器vim

一、vim的基本概念1.三種模式①命令模式控制屏幕光標的移動&#xff0c;字符、字或行的刪除&#xff0c;移動復制某區段及進入插入模式或者進去底行模式②插入模式可進行文本輸入&#xff0c;按Esc回到命令行模式③底行模式文件保存或退出&#xff0c;也可以進行文件替換&#…

如何在 Ubuntu 24.04 或 22.04 LTS Linux 上安裝 Guake 終端應用程序

通過本教程的簡單步驟,在 Ubuntu 24.04 或 22.04 LTS Jammy JellyFish 上安裝 Guake 終端以運行命令。 Guake(基于 Quake)是一個基于 Python 的終端模擬器。Guake 的行為類似于 Quake 中的終端:通過某個按鍵(熱鍵)按下時,窗口會從屏幕頂部滾下來,再次按下相同的按鍵時…

谷歌Gemini 2.5重磅應用:多模態研究助手Multi-Modal Researcher,實現全網自動研究與AI播客生成

在人工智能賦能科研與內容創作的浪潮中,谷歌基于其最新大模型 Gemini 2.5 推出了突破性工具 Multi-Modal Researcher。這一系統通過整合多模態數據(文本、視頻、實時網絡信息),實現了從自動研究到內容生成的全流程自動化。用戶只需輸入研究主題或YouTube視頻鏈接,系統即可…

防御綜合實驗

一、實驗拓補圖二、實驗需求及配置需求一設備接口VLAN接口類型SW2GE0/0/2VLAN 10AccessGE0/0/3VLAN 20AccessGE0/0/1VLAN List : 10 20Trunk[SW2]vlan 10 [SW2]vlan 20 [SW2]interface GigabitEthernet 0/0/2 [SW2-GigabitEthernet0/0/2]port link-type access [SW2-GigabitEt…

堆----2.前 K 個高頻元素

347. 前 K 個高頻元素 - 力扣&#xff08;LeetCode&#xff09; /** 桶排序: 首先遍歷數組,使用HashMap統計每個元素出現的次數 創建一個大小為length 1的List數組,下標代表元素出現次數,出現次數一致的元素放在同一個數組中 倒數遍歷List數組即可得得到前K個高頻元素 細節注…

如何分析Linux內存性能問題

一、Linux中的buffer與cache的區別 Linux的內存管理與監控_linux服務器虛假內存和真實內存怎么區分-CSDN博客文章瀏覽閱讀66次。本文主要是關于【Linux系統的物理內存與虛擬內存講解】【重點對虛擬內存的作用與用法進行了講解說明】【最后還對如何新增擴展、優化、刪除內存交換…

二次型 線性代數

知識結構總覽首先是我們的二次型的定義&#xff0c;就是說什么樣的才算是一個二次型。然后就是如何把二次型化為標準型&#xff0c;最后就是正定二次型的定義和判斷的一些條件。二次型的定義二次型其實是一種函數表達的方式&#xff0c;如上&#xff0c;含義其實就是每個項都是…