返回顶部
热门问答 更多热门问答
技术文章 更多技术文章

【AI大模型应用开发】LangGraph节点间进行自定义消息传递

[复制链接]
链载Ai 显示全部楼层 发表于 2025-12-2 10:00:02 |阅读模式 打印 上一主题 下一主题
ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;border-left: none;padding: 1em;border-radius: 8px;color: rgba(0, 0, 0, 0.5);background: rgb(247, 247, 247);margin: 0px 8px 2em;">前面我们学过LangGraph的基本使用,知道了如何添加边,添加Node,组装图,以及将图进行可视化。还有一个重要的点我之前忽略了,那就是如何在这些节点之间进行消息传递。今天我们就来学习一下如何在LangGraph的节点之间进行消息传递以及自定义的消息传递。


ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 1.2em;font-weight: bold;display: table;margin: 2em auto 1em;padding-right: 1em;padding-left: 1em;border-bottom: 2px solid rgb(15, 76, 129);color: rgb(63, 63, 63);">0. 先上代码

ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;border-left: none;padding: 1em;border-radius: 8px;color: rgba(0, 0, 0, 0.5);background: rgb(247, 247, 247);margin: 2em 8px;">

代码来源: https://github.com/langchain-ai/langgraph/blob/main/examples/agent_executor/human-in-the-loop.ipynb

ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;overflow-x: auto;border-radius: 8px;padding: 1em;margin: 10px 8px;">
fromlangchainimporthub
fromlangchain.agentsimportcreate_openai_functions_agent
fromlangchain_openai.chat_modelsimportChatOpenAI
fromlangchain_community.tools.tavily_searchimportTavilySearchResults

tools=[TavilySearchResults(max_results=1)]

#Gettheprompttouse-youcanmodifythis!
prompt=hub.pull("hwchase17/openai-functions-agent")

#ChoosetheLLMthatwilldrivetheagent
llm=ChatOpenAI(model="gpt-3.5-turbo-1106",streaming=True)

#ConstructtheOpenAIFunctionsagent
agent_runnable=create_openai_functions_agent(llm,tools,prompt)

fromtypingimportTypedDict,Annotated,List,Union
fromlangchain_core.agentsimportAgentAction,AgentFinish
fromlangchain_core.messagesimportBaseMessage
importoperator

classAgentState(TypedDict):
#Theinputstring
input:str
#Thelistofpreviousmessagesintheconversation
chat_history:list[BaseMessage]
#Theoutcomeofagivencalltotheagent
#Needs`None`asavalidtype,sincethisiswhatthiswillstartas
agent_outcome:Union[AgentAction,AgentFinish,None]
#Listofactionsandcorrespondingobservations
#Hereweannotatethiswith`operator.add`toindicatethatoperationsto
#thisstateshouldbeADDEDtotheexistingvalues(notoverwriteit)
intermediate_steps:Annotated[list[tuple[AgentAction,str]],operator.add]


fromlangchain_core.agentsimportAgentFinish
fromlanggraph.prebuilt.tool_executorimportToolExecutor

#Thisahelperclasswehavethatisusefulforrunningtools
#Ittakesinanagentactionandcallsthattoolandreturnstheresult
tool_executor=ToolExecutor(tools)


#Definetheagent
defrun_agent(data):
agent_outcome=agent_runnable.invoke(data)
return{"agent_outcome":agent_outcome}


#Definethefunctiontoexecutetools
defexecute_tools(data):
#Getthemostrecentagent_outcome-thisisthekeyaddedinthe`agent`above
agent_action=data["agent_outcome"]
response=input(f"[y/n]continuewith:{agent_action}?")
ifresponse=="n":
raiseValueError
output=tool_executor.invoke(agent_action)
return{"intermediate_steps":[(agent_action,str(output))]}


#Definelogicthatwillbeusedtodeterminewhichconditionaledgetogodown
defshould_continue(data):
#IftheagentoutcomeisanAgentFinish,thenwereturn`exit`string
#Thiswillbeusedwhensettingupthegraphtodefinetheflow
ifisinstance(data["agent_outcome"],AgentFinish):
return"end"
#Otherwise,anAgentActionisreturned
#Herewereturn`continue`string
#Thiswillbeusedwhensettingupthegraphtodefinetheflow
else:
return"continue"


fromlanggraph.graphimportEND,StateGraph

#Defineanewgraph
workflow=StateGraph(AgentState)

#Definethetwonodeswewillcyclebetween
workflow.add_node("agent",run_agent)
workflow.add_node("action",execute_tools)

#Settheentrypointas`agent`
#Thismeansthatthisnodeisthefirstonecalled
workflow.set_entry_point("agent")

#Wenowaddaconditionaledge
workflow.add_conditional_edges(
#First,wedefinethestartnode.Weuse`agent`.
#Thismeansthesearetheedgestakenafterthe`agent`nodeiscalled.
"agent",
#Next,wepassinthefunctionthatwilldeterminewhichnodeiscallednext.
should_continue,
#Finallywepassinamapping.
#Thekeysarestrings,andthevaluesareothernodes.
#ENDisaspecialnodemarkingthatthegraphshouldfinish.
#Whatwillhappeniswewillcall`should_continue`,andthentheoutputofthat
#willbematchedagainstthekeysinthismapping.
#Basedonwhichoneitmatches,thatnodewillthenbecalled.
{
#If`tools`,thenwecallthetoolnode.
"continue":"action",
#Otherwisewefinish.
"end":END,
},
)

#Wenowaddanormaledgefrom`tools`to`agent`.
#Thismeansthatafter`tools`iscalled,`agent`nodeiscallednext.
workflow.add_edge("action","agent")

#Finally,wecompileit!
#ThiscompilesitintoaLangChainRunnable,
#meaningyoucanuseitasyouwouldanyotherrunnable
app=workflow.compile()


inputs={"input":"北京今天的天气怎么样?","chat_history":[]}
forsinapp.stream(inputs):
print(list(s.values())[0])
print("----")

ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;margin: 1.5em 8px;letter-spacing: 0.1em;color: rgb(63, 63, 63);">运行结果:

ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 1.2em;font-weight: bold;display: table;margin: 2em auto 1em;padding-right: 1em;padding-left: 1em;border-bottom: 2px solid rgb(15, 76, 129);color: rgb(63, 63, 63);">1. 代码解释

ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 1.2em;font-weight: bold;display: table;margin: 4em auto 2em;padding-right: 0.2em;padding-left: 0.2em;background: rgb(15, 76, 129);color: rgb(255, 255, 255);">1.1 总结使用LangGraph的步骤

ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;margin: 1.5em 8px;letter-spacing: 0.1em;color: rgb(63, 63, 63);">上面代码其实没什么新鲜的,就是使用LangGraph的步骤,前面入门的文章(【AI Agent系列】【LangGraph】0. 快速上手:协同LangChain,LangGraph帮你用图结构轻松构建多智能体应用)中详细介绍过:

ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;margin: 1.5em 8px;letter-spacing: 0.1em;color: rgb(63, 63, 63);">(1)首先创建一个图:workflow = StateGraph(AgentState)

ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;margin: 1.5em 8px;letter-spacing: 0.1em;color: rgb(63, 63, 63);">(2)然后,往图中添加节点:

workflow.add_node("agent",run_agent)
workflow.add_node("action",execute_tools)

(3)再然后,添加边:

workflow.add_conditional_edges(
"agent",
should_continue,
{
"continue":"action",
"end":END,
},
)

workflow.add_edge("action","agent")

(4)再然后,添加进入节点:workflow.set_entry_point("agent")

(5)编译图:app = workflow.compile()

(6)运行,这里用的是stream函数,也可以使用invoke函数。

1.2 节点定义

定义了两个节点:agentaction,分别对应着两个函数。

  • run_agent函数执行agent,获取执行结果。

  • execute_tools函数首先需要人工介入判断是否要继续执行工具,如果继续,则执行相应工具。如果不继续,则停止程序。

defrun_agent(data):
agent_outcome=agent_runnable.invoke(data)
return{"agent_outcome":agent_outcome}


defexecute_tools(data):
agent_action=data["agent_outcome"]
response=input(f"[y/n]continuewith:{agent_action}?")
ifresponse=="n":
raiseValueError
output=tool_executor.invoke(agent_action)
return{"intermediate_steps":[(agent_action,str(output))]}

2. 节点间信息传递

下面来到本文的主要学习内容:节点间的信息是如何传递的,Graph中的State是如何更新的,

前面我们说过,LangGraph的核心概念之一是状态。每次图的执行都会创建一个状态,该状态在图中的节点之间传递,每个节点在执行后都会更新此状态。所以,LangGraph呈现的是类似状态机(state machine)的机制。而这也是LangGraph节点间进行信息传递的方式。

2.1 代码中的状态定义

下面是代码中的状态定义:

classAgentState(TypedDict):
input:str
chat_history:list[BaseMessage]
agent_outcome:Union[AgentAction,AgentFinish,None]
intermediate_steps:Annotated[list[tuple[AgentAction,str]],operator.add]

定义一个AgentState继承自TypedDict即可。AgentState中自定义了一些传递的信息:inputchat_historyagent_outcomeintermediate_steps。每个node在执行前,都可以从状态中获取这些信息使用,然后执行后,也都可以将返回结果更新到状态中。

agent_outcome 就是agent执行后的返回的执行状态(AgentAction或者AgentFinish,不用过多纠结这是什么,只要知道是个状态就好了。)

看下代码中的使用过程:

(1)首先在创建图的时候要把这个状态设置给图:workflow = StateGraph(AgentState)

(2)然后在各节点中就可以使用了:

execute_tools节点为例:

defexecute_tools(data):
agent_action=data["agent_outcome"]
response=input(f"[y/n]continuewith:{agent_action}?")
ifresponse=="n":
raiseValueError
output=tool_executor.invoke(agent_action)
return{"intermediate_steps":[(agent_action,str(output))]}

在执行前,先从状态中获取agent_outcome,使用这个值给用户提示,是否需要继续。如果继续,则执行工具获取执行结果。最后,执行结果被更新到状态的intermediate_steps字段中。下个节点就可以使用这个intermediate_steps信息了。这就完成了节点间的信息传递。

3. 总结

本文总体来说比较简单,首先回顾了LangGraph的创建与使用的基本步骤,然后学习了LangGraph中状态的定义和节点间信息传递的原理,这算是个新的知识点。总结下自定义信息传递的步骤:

(1)定义class AgentState(TypedDict)

(2)传递给图:workflow = StateGraph(AgentState)

(3)如有需要,在各node中,获取状态:data = data["agent_outcome"]

(4)如有需要,在各node中,更新状态:return {"intermediate_steps": [(agent_action, str(output))]}

这个例子其实是用来展示如何在多智能体交互中让人参与其中的。也可以参考下,就是在node中适当位置加个input函数,等待用户输入即可。


回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

链载AI是专业的生成式人工智能教程平台。提供Stable Diffusion、Midjourney AI绘画教程,Suno AI音乐生成指南,以及Runway、Pika等AI视频制作与动画生成实战案例。从提示词编写到参数调整,手把手助您从入门到精通。
  • 官方手机版

  • 微信公众号

  • 商务合作

  • Powered by Discuz! X3.5 | Copyright © 2025-2025. | 链载Ai
  • 桂ICP备2024021734号 | 营业执照 | |广西笔趣文化传媒有限公司|| QQ