构建多智能体系统 - LangChain 框架 --知识铺
构建多智能体系统¶
如果单个智能体需要在多个领域进行专业化或管理许多工具,它可能会面临困难。为了解决这个问题,您可以将智能体分解为更小、独立的智能体,并将它们组合成一个多智能体系统。
在多智能体系统中,智能体之间需要相互通信。它们通过交接实现这一点——交接是一种原语,描述了将控制权移交给哪个智能体以及要发送给该智能体的数据负载。
本指南涵盖以下内容
- 实现智能体之间的交接
- 使用交接和预构建的智能体来构建自定义多智能体系统
要开始构建多智能体系统,请查看 LangGraph 预构建的两种最流行的多智能体架构实现——监督者和群组。
交接¶
为了在多智能体系统中设置智能体之间的通信,您可以使用交接(handoffs)——这是一种一个智能体将控制权“交接”给另一个智能体的模式。交接允许您指定
- 目标:要导航到的目标智能体(例如,要前往的 LangGraph 节点的名称)
- 数据负载:要传递给该智能体的信息(例如,状态更新)
创建交接¶
要实现交接,您可以从智能体节点或工具中返回 Command 对象
API 参考:tool | InjectedToolCallId | create_react_agent | InjectedState | StateGraph | START | Command
<span id="__span-0-1">from typing import Annotated
<span id="__span-0-2">from langchain_core.tools import tool, InjectedToolCallId
<span id="__span-0-3">from langgraph.prebuilt import create_react_agent, InjectedState
<span id="__span-0-4">from langgraph.graph import StateGraph, START, MessagesState
<span id="__span-0-5">from langgraph.types import Command
<span id="__span-0-6">
<span id="__span-0-7">def create_handoff_tool(*, agent_name: str, description: str | None = None):
<span id="__span-0-8"> name = f"transfer_to_{agent_name}"
<span id="__span-0-9"> description = description or f"Transfer to {agent_name}"
<span id="__span-0-10">
<span id="__span-0-11"> @tool(name, description=description)
<span id="__span-0-12"> def handoff_tool(
<span id="__span-0-13"> state: Annotated[MessagesState, InjectedState],
<span id="__span-0-14"> tool_call_id: Annotated[str, InjectedToolCallId],
<span id="__span-0-15"> ) -> Command:
<span id="__span-0-16"> tool_message = {
<span id="__span-0-17"> "role": "tool",
<span id="__span-0-18"> "content": f"Successfully transferred to {agent_name}",
<span id="__span-0-19"> "name": name,
<span id="__span-0-20"> "tool_call_id": tool_call_id,
<span id="__span-0-21"> }
<span id="__span-0-22"> return Command(
<span id="__span-0-23"> goto=agent_name,
<span id="__span-0-24"> update={"messages": state["messages"] + [tool_message]},
<span id="__span-0-25"> graph=Command.PARENT,
<span id="__span-0-26"> )
<span id="__span-0-27"> return handoff_tool
提示
如果您想使用返回 Command 的工具,您可以使用预构建的 [create_react_agent](https://langgraph.com.cn/reference/agents.1.html#langgraph.prebuilt.chat_agent_executor.create_react_agent “ create_react_agent”) / [ToolNode](https://langgraph.com.cn/reference/agents.1.html#langgraph.prebuilt.tool_node.ToolNode “ ToolNode”) 组件,或者实现自己的工具执行节点,该节点收集工具返回的 Command 对象并返回它们的列表,例如。
<span id="__span-1-1">def call_tools(state):
<span id="__span-1-2"> ...
<span id="__span-1-3"> commands = [tools_by_name[tool_call["name"]].invoke(tool_call) for tool_call in tool_calls]
<span id="__span-1-4"> return commands
重要
此交接实现假定
-
多智能体系统中的每个智能体都将整体消息历史(跨所有智能体)作为其输入。如果您想更精细地控制智能体输入,请参阅此部分
-
每个智能体将其内部消息历史输出到多智能体系统的整体消息历史中。如果您想更精细地控制**智能体输出的添加方式**,请将智能体包装在一个单独的节点函数中
<span id="__span-2-1">def call_hotel_assistant(state): <span id="__span-2-2"> # return agent's final response, <span id="__span-2-3"> # excluding inner monologue <span id="__span-2-4"> response = hotel_assistant.invoke(state) <span id="__span-2-5"> return {"messages": response["messages"][-1]}
控制智能体输入¶
您可以使用 [Send()](https://langgraph.com.cn/reference/types/index.html#langgraph.types.Send “ Send”) 原语在交接期间直接向工作智能体发送数据。例如,您可以要求调用智能体为下一个智能体填充任务描述
API 参考:tool | InjectedToolCallId | InjectedState | StateGraph | START | Command | Send
<code tabindex="0"><span id="__span-3-1">from typing import Annotated
<span id="__span-3-2">from langchain_core.tools import tool, InjectedToolCallId
<span id="__span-3-3">from langgraph.prebuilt import InjectedState
<span id="__span-3-4">from langgraph.graph import StateGraph, START, MessagesState
<span id="__span-3-5">from langgraph.types import Command, Send
<span id="__span-3-6">
<span id="__span-3-7">def create_task_description_handoff_tool(
<span id="__span-3-8"> *, agent_name: str, description: str | None = None
<span id="__span-3-9">):
<span id="__span-3-10"> name = f"transfer_to_{agent_name}"
<span id="__span-3-11"> description = description or f"Ask {agent_name} for help."
<span id="__span-3-12">
<span id="__span-3-13"> @tool(name, description=description)
<span id="__span-3-14"> def handoff_tool(
<span id="__span-3-15"> # this is populated by the calling agent
<span id="__span-3-16"> task_description: Annotated[
<span id="__span-3-17"> str,
<span id="__span-3-18"> "Description of what the next agent should do, including all of the relevant context.",
<span id="__span-3-19"> ],
<span id="__span-3-20"> # these parameters are ignored by the LLM
<span id="__span-3-21"> state: Annotated[MessagesState, InjectedState],
<span id="__span-3-22"> ) -> Command:
<span id="__span-3-23"> task_description_message = {"role": "user", "content": task_description}
<span id="__span-3-24"> agent_input = {**state, "messages": [task_description_message]}
<span id="__span-3-25"> return Command(
<span id="__span-3-26"> goto=[Send(agent_name, agent_input)],
<span id="__span-3-27"> graph=Command.PARENT,
<span id="__span-3-28"> )
<span id="__span-3-29">
<span id="__span-3-30"> return handoff_tool
有关在交接中使用 [Send()](https://langgraph.com.cn/reference/types/index.html#langgraph.types.Send “ Send”) 的完整示例,请参阅多智能体监督者教程。
构建多智能体系统¶
您可以在任何使用 LangGraph 构建的智能体中使用交接。我们建议使用预构建的智能体或ToolNode,因为它们原生支持返回 Command 的交接工具。以下是您如何使用交接实现用于旅行预订的多智能体系统的示例
API 参考:create_react_agent | StateGraph | START
<code tabindex="0"><span id="__span-4-1">from langgraph.prebuilt import create_react_agent
<span id="__span-4-2">from langgraph.graph import StateGraph, START, MessagesState
<span id="__span-4-3">
<span id="__span-4-4">def create_handoff_tool(*, agent_name: str, description: str | None = None):
<span id="__span-4-5"> # same implementation as above
<span id="__span-4-6"> ...
<span id="__span-4-7"> return Command(...)
<span id="__span-4-8">
<span id="__span-4-9"># Handoffs
<span id="__span-4-10">transfer_to_hotel_assistant = create_handoff_tool(agent_name="hotel_assistant")
<span id="__span-4-11">transfer_to_flight_assistant = create_handoff_tool(agent_name="flight_assistant")
<span id="__span-4-12">
<span id="__span-4-13"># Define agents
<span id="__span-4-14">flight_assistant = create_react_agent(
<span id="__span-4-15"> model="anthropic:claude-3-5-sonnet-latest",
<span id="__span-4-16"> tools=[..., transfer_to_hotel_assistant],
<span id="__span-4-17"> name="flight_assistant"
<span id="__span-4-18">)
<span id="__span-4-19">hotel_assistant = create_react_agent(
<span id="__span-4-20"> model="anthropic:claude-3-5-sonnet-latest",
<span id="__span-4-21"> tools=[..., transfer_to_flight_assistant],
<span id="__span-4-22"> name="hotel_assistant"
<span id="__span-4-23">)
<span id="__span-4-24">
<span id="__span-4-25"># Define multi-agent graph
<span id="__span-4-26">multi_agent_graph = (
<span id="__span-4-27"> StateGraph(MessagesState)
<span id="__span-4-28"> .add_node(flight_assistant)
<span id="__span-4-29"> .add_node(hotel_assistant)
<span id="__span-4-30"> .add_edge(START, "flight_assistant")
<span id="__span-4-31"> .compile()
<span id="__span-4-32">)
完整示例:用于旅行预订的多智能体系统
<span id="__span-5-1">from typing import Annotated
<span id="__span-5-2">from langchain_core.messages import convert_to_messages
<span id="__span-5-3">from langchain_core.tools import tool, InjectedToolCallId
<span id="__span-5-4">from langgraph.prebuilt import create_react_agent, InjectedState
<span id="__span-5-5">from langgraph.graph import StateGraph, START, MessagesState
<span id="__span-5-6">from langgraph.types import Command
<span id="__span-5-7">
<span id="__span-5-8"># We'll use `pretty_print_messages` helper to render the streamed agent outputs nicely
<span id="__span-5-9">
<span id="__span-5-10">def pretty_print_message(message, indent=False):
<span id="__span-5-11"> pretty_message = message.pretty_repr(html=True)
<span id="__span-5-12"> if not indent:
<span id="__span-5-13"> print(pretty_message)
<span id="__span-5-14"> return
<span id="__span-5-15">
<span id="__span-5-16"> indented = "\n".join("\t" + c for c in pretty_message.split("\n"))
<span id="__span-5-17"> print(indented)
<span id="__span-5-18">
<span id="__span-5-19">
<span id="__span-5-20">def pretty_print_messages(update, last_message=False):
<span id="__span-5-21"> is_subgraph = False
<span id="__span-5-22"> if isinstance(update, tuple):
<span id="__span-5-23"> ns, update = update
<span id="__span-5-24"> # skip parent graph updates in the printouts
<span id="__span-5-25"> if len(ns) == 0:
<span id="__span-5-26"> return
<span id="__span-5-27">
<span id="__span-5-28"> graph_id = ns[-1].split(":")[0]
<span id="__span-5-29"> print(f"Update from subgraph {graph_id}:")
<span id="__span-5-30"> print("\n")
<span id="__span-5-31"> is_subgraph = True
<span id="__span-5-32">
<span id="__span-5-33"> for node_name, node_update in update.items():
<span id="__span-5-34"> update_label = f"Update from node {node_name}:"
<span id="__span-5-35"> if is_subgraph:
<span id="__span-5-36"> update_label = "\t" + update_label
<span id="__span-5-37">
<span id="__span-5-38"> print(update_label)
<span id="__span-5-39"> print("\n")
<span id="__span-5-40">
<span id="__span-5-41"> messages = convert_to_messages(node_update["messages"])
<span id="__span-5-42"> if last_message:
<span id="__span-5-43"> messages = messages[-1:]
<span id="__span-5-44">
<span id="__span-5-45"> for m in messages:
<span id="__span-5-46"> pretty_print_message(m, indent=is_subgraph)
<span id="__span-5-47"> print("\n")
<span id="__span-5-48">
<span id="__span-5-49">
<span id="__span-5-50">def create_handoff_tool(*, agent_name: str, description: str | None = None):
<span id="__span-5-51"> name = f"transfer_to_{agent_name}"
<span id="__span-5-52"> description = description or f"Transfer to {agent_name}"
<span id="__span-5-53">
<span id="__span-5-54"> @tool(name, description=description)
<span id="__span-5-55"> def handoff_tool(
<span id="__span-5-56"> state: Annotated[MessagesState, InjectedState],
<span id="__span-5-57"> tool_call_id: Annotated[str, InjectedToolCallId],
<span id="__span-5-58"> ) -> Command:
<span id="__span-5-59"> tool_message = {
<span id="__span-5-60"> "role": "tool",
<span id="__span-5-61"> "content": f"Successfully transferred to {agent_name}",
<span id="__span-5-62"> "name": name,
<span id="__span-5-63"> "tool_call_id": tool_call_id,
<span id="__span-5-64"> }
<span id="__span-5-65"> return Command(
<span id="__span-5-66"> goto=agent_name,
<span id="__span-5-67"> update={"messages": state["messages"] + [tool_message]},
<span id="__span-5-68"> graph=Command.PARENT,
<span id="__span-5-69"> )
<span id="__span-5-70"> return handoff_tool
<span id="__span-5-71">
<span id="__span-5-72"># Handoffs
<span id="__span-5-73">transfer_to_hotel_assistant = create_handoff_tool(
<span id="__span-5-74"> agent_name="hotel_assistant",
<span id="__span-5-75"> description="Transfer user to the hotel-booking assistant.",
<span id="__span-5-76">)
<span id="__span-5-77">transfer_to_flight_assistant = create_handoff_tool(
<span id="__span-5-78"> agent_name="flight_assistant",
<span id="__span-5-79"> description="Transfer user to the flight-booking assistant.",
<span id="__span-5-80">)
<span id="__span-5-81">
<span id="__span-5-82"># Simple agent tools
<span id="__span-5-83">def book_hotel(hotel_name: str):
<span id="__span-5-84"> """Book a hotel"""
<span id="__span-5-85"> return f"Successfully booked a stay at {hotel_name}."
<span id="__span-5-86">
<span id="__span-5-87">def book_flight(from_airport: str, to_airport: str):
<span id="__span-5-88"> """Book a flight"""
<span id="__span-5-89"> return f"Successfully booked a flight from {from_airport} to {to_airport}."
<span id="__span-5-90">
<span id="__span-5-91"># Define agents
<span id="__span-5-92">flight_assistant = create_react_agent(
<span id="__span-5-93"> model="anthropic:claude-3-5-sonnet-latest",
<span id="__span-5-94"> tools=[book_flight, transfer_to_hotel_assistant],
<span id="__span-5-95"> prompt="You are a flight booking assistant",
<span id="__span-5-96"> name="flight_assistant"
<span id="__span-5-97">)
<span id="__span-5-98">hotel_assistant = create_react_agent(
<span id="__span-5-99"> model="anthropic:claude-3-5-sonnet-latest",
<span id="__span-5-100"> tools=[book_hotel, transfer_to_flight_assistant],
<span id="__span-5-101"> prompt="You are a hotel booking assistant",
<span id="__span-5-102"> name="hotel_assistant"
<span id="__span-5-103">)
<span id="__span-5-104">
<span id="__span-5-105"># Define multi-agent graph
<span id="__span-5-106">multi_agent_graph = (
<span id="__span-5-107"> StateGraph(MessagesState)
<span id="__span-5-108"> .add_node(flight_assistant)
<span id="__span-5-109"> .add_node(hotel_assistant)
<span id="__span-5-110"> .add_edge(START, "flight_assistant")
<span id="__span-5-111"> .compile()
<span id="__span-5-112">)
<span id="__span-5-113">
<span id="__span-5-114"># Run the multi-agent graph
<span id="__span-5-115">for chunk in multi_agent_graph.stream(
<span id="__span-5-116"> {
<span id="__span-5-117"> "messages": [
<span id="__span-5-118"> {
<span id="__span-5-119"> "role": "user",
<span id="__span-5-120"> "content": "book a flight from BOS to JFK and a stay at McKittrick Hotel"
<span id="__span-5-121"> }
<span id="__span-5-122"> ]
<span id="__span-5-123"> },
<span id="__span-5-124"> subgraphs=True
<span id="__span-5-125">):
<span id="__span-5-126"> pretty_print_messages(chunk)
多轮对话¶
用户可能希望与一个或多个智能体进行[多轮对话](https://langgraph.com.cn/reference/types/index.html#langgraph.types.interrupt “ interrupt")。为了构建一个能够处理这种情况的系统,您可以创建一个使用中断来收集用户输入并路由回**活跃**智能体的节点。
然后,智能体可以作为图中的节点来实现,该图执行智能体步骤并确定下一个动作
- 等待用户输入以继续对话,或者
- 通过交接路由到另一个智能体(或返回到自身,例如在循环中)
<code tabindex="0"><span id="__span-6-1">def human(state) -> Command[Literal["agent", "another_agent"]]:
<span id="__span-6-2"> """A node for collecting user input."""
<span id="__span-6-3"> user_input = interrupt(value="Ready for user input.")
<span id="__span-6-4">
<span id="__span-6-5"> # Determine the active agent.
<span id="__span-6-6"> active_agent = ...
<span id="__span-6-7">
<span id="__span-6-8"> ...
<span id="__span-6-9"> return Command(
<span id="__span-6-10"> update={
<span id="__span-6-11"> "messages": [{
<span id="__span-6-12"> "role": "human",
<span id="__span-6-13"> "content": user_input,
<span id="__span-6-14"> }]
<span id="__span-6-15"> },
<span id="__span-6-16"> goto=active_agent
<span id="__span-6-17"> )
<span id="__span-6-18">
<span id="__span-6-19">def agent(state) -> Command[Literal["agent", "another_agent", "human"]]:
<span id="__span-6-20"> # The condition for routing/halting can be anything, e.g. LLM tool call / structured output, etc.
<span id="__span-6-21"> goto = get_next_agent(...) # 'agent' / 'another_agent'
<span id="__span-6-22"> if goto:
<span id="__span-6-23"> return Command(goto=goto, update={"my_state_key": "my_state_value"})
<span id="__span-6-24"> else:
<span id="__span-6-25"> return Command(goto="human") # Go to human node
完整示例:用于旅行推荐的多智能体系统
在此示例中,我们将构建一个旅行助手智能体团队,它们可以通过交接相互通信。
我们将创建2个智能体
- travel_advisor:可以帮助推荐旅行目的地。可以向 hotel_advisor 寻求帮助。
- hotel_advisor:可以帮助推荐酒店。可以向 travel_advisor 寻求帮助。
<code tabindex="0"><span id="__span-7-1">from langchain_anthropic import ChatAnthropic
<span id="__span-7-2">from langgraph.graph import MessagesState, StateGraph, START
<span id="__span-7-3">from langgraph.prebuilt import create_react_agent, InjectedState
<span id="__span-7-4">from langgraph.types import Command, interrupt
<span id="__span-7-5">from langgraph.checkpoint.memory import MemorySaver
<span id="__span-7-6">
<span id="__span-7-7">
<span id="__span-7-8">model = ChatAnthropic(model="claude-3-5-sonnet-latest")
<span id="__span-7-9">
<span id="__span-7-10">class MultiAgentState(MessagesState):
<span id="__span-7-11"> last_active_agent: str
<span id="__span-7-12">
<span id="__span-7-13">
<span id="__span-7-14"># Define travel advisor tools and ReAct agent
<span id="__span-7-15">travel_advisor_tools = [
<span id="__span-7-16"> get_travel_recommendations,
<span id="__span-7-17"> make_handoff_tool(agent_name="hotel_advisor"),
<span id="__span-7-18">]
<span id="__span-7-19">travel_advisor = create_react_agent(
<span id="__span-7-20"> model,
<span id="__span-7-21"> travel_advisor_tools,
<span id="__span-7-22"> prompt=(
<span id="__span-7-23"> "You are a general travel expert that can recommend travel destinations (e.g. countries, cities, etc). "
<span id="__span-7-24"> "If you need hotel recommendations, ask 'hotel_advisor' for help. "
<span id="__span-7-25"> "You MUST include human-readable response before transferring to another agent."
<span id="__span-7-26"> ),
<span id="__span-7-27">)
<span id="__span-7-28">
<span id="__span-7-29">
<span id="__span-7-30">def call_travel_advisor(
<span id="__span-7-31"> state: MultiAgentState,
<span id="__span-7-32">) -> Command[Literal["hotel_advisor", "human"]]:
<span id="__span-7-33"> # You can also add additional logic like changing the input to the agent / output from the agent, etc.
<span id="__span-7-34"> # NOTE: we're invoking the ReAct agent with the full history of messages in the state
<span id="__span-7-35"> response = travel_advisor.invoke(state)
<span id="__span-7-36"> update = {**response, "last_active_agent": "travel_advisor"}
<span id="__span-7-37"> return Command(update=update, goto="human")
<span id="__span-7-38">
<span id="__span-7-39">
<span id="__span-7-40"># Define hotel advisor tools and ReAct agent
<span id="__span-7-41">hotel_advisor_tools = [
<span id="__span-7-42"> get_hotel_recommendations,
<span id="__span-7-43"> make_handoff_tool(agent_name="travel_advisor"),
<span id="__span-7-44">]
<span id="__span-7-45">hotel_advisor = create_react_agent(
<span id="__span-7-46"> model,
<span id="__span-7-47"> hotel_advisor_tools,
<span id="__span-7-48"> prompt=(
<span id="__span-7-49"> "You are a hotel expert that can provide hotel recommendations for a given destination. "
<span id="__span-7-50"> "If you need help picking travel destinations, ask 'travel_advisor' for help."
<span id="__span-7-51"> "You MUST include human-readable response before transferring to another agent."
<span id="__span-7-52"> ),
<span id="__span-7-53">)
<span id="__span-7-54">
<span id="__span-7-55">
<span id="__span-7-56">def call_hotel_advisor(
<span id="__span-7-57"> state: MultiAgentState,
<span id="__span-7-58">) -> Command[Literal["travel_advisor", "human"]]:
<span id="__span-7-59"> response = hotel_advisor.invoke(state)
<span id="__span-7-60"> update = {**response, "last_active_agent": "hotel_advisor"}
<span id="__span-7-61"> return Command(update=update, goto="human")
<span id="__span-7-62">
<span id="__span-7-63">
<span id="__span-7-64">def human_node(
<span id="__span-7-65"> state: MultiAgentState, config
<span id="__span-7-66">) -> Command[Literal["hotel_advisor", "travel_advisor", "human"]]:
<span id="__span-7-67"> """A node for collecting user input."""
<span id="__span-7-68">
<span id="__span-7-69"> user_input = interrupt(value="Ready for user input.")
<span id="__span-7-70"> active_agent = state["last_active_agent"]
<span id="__span-7-71">
<span id="__span-7-72"> return Command(
<span id="__span-7-73"> update={
<span id="__span-7-74"> "messages": [
<span id="__span-7-75"> {
<span id="__span-7-76"> "role": "human",
<span id="__span-7-77"> "content": user_input,
<span id="__span-7-78"> }
<span id="__span-7-79"> ]
<span id="__span-7-80"> },
<span id="__span-7-81"> goto=active_agent,
<span id="__span-7-82"> )
<span id="__span-7-83">
<span id="__span-7-84">
<span id="__span-7-85">builder = StateGraph(MultiAgentState)
<span id="__span-7-86">builder.add_node("travel_advisor", call_travel_advisor)
<span id="__span-7-87">builder.add_node("hotel_advisor", call_hotel_advisor)
<span id="__span-7-88">
<span id="__span-7-89"># This adds a node to collect human input, which will route
<span id="__span-7-90"># back to the active agent.
<span id="__span-7-91">builder.add_node("human", human_node)
<span id="__span-7-92">
<span id="__span-7-93"># We'll always start with a general travel advisor.
<span id="__span-7-94">builder.add_edge(START, "travel_advisor")
<span id="__span-7-95">
<span id="__span-7-96">
<span id="__span-7-97">checkpointer = MemorySaver()
<span id="__span-7-98">graph = builder.compile(checkpointer=checkpointer)
让我们测试一下此应用程序的多轮对话。
<code tabindex="0"><span id="__span-8-1">import uuid
<span id="__span-8-2">
<span id="__span-8-3">thread_config = {"configurable": {"thread_id": str(uuid.uuid4())}}
<span id="__span-8-4">
<span id="__span-8-5">inputs = [
<span id="__span-8-6"> # 1st round of conversation,
<span id="__span-8-7"> {
<span id="__span-8-8"> "messages": [
<span id="__span-8-9"> {"role": "user", "content": "i wanna go somewhere warm in the caribbean"}
<span id="__span-8-10"> ]
<span id="__span-8-11"> },
<span id="__span-8-12"> # Since we're using `interrupt`, we'll need to resume using the Command primitive.
<span id="__span-8-13"> # 2nd round of conversation,
<span id="__span-8-14"> Command(
<span id="__span-8-15"> resume="could you recommend a nice hotel in one of the areas and tell me which area it is."
<span id="__span-8-16"> ),
<span id="__span-8-17"> # 3rd round of conversation,
<span id="__span-8-18"> Command(
<span id="__span-8-19"> resume="i like the first one. could you recommend something to do near the hotel?"
<span id="__span-8-20"> ),
<span id="__span-8-21">]
<span id="__span-8-22">
<span id="__span-8-23">for idx, user_input in enumerate(inputs):
<span id="__span-8-24"> print()
<span id="__span-8-25"> print(f"--- Conversation Turn {idx + 1} ---")
<span id="__span-8-26"> print()
<span id="__span-8-27"> print(f"User: {user_input}")
<span id="__span-8-28"> print()
<span id="__span-8-29"> for update in graph.stream(
<span id="__span-8-30"> user_input,
<span id="__span-8-31"> config=thread_config,
<span id="__span-8-32"> stream_mode="updates",
<span id="__span-8-33"> ):
<span id="__span-8-34"> for node_id, value in update.items():
<span id="__span-8-35"> if isinstance(value, dict) and value.get("messages", []):
<span id="__span-8-36"> last_message = value["messages"][-1]
<span id="__span-8-37"> if isinstance(last_message, dict) or last_message.type != "ai":
<span id="__span-8-38"> continue
<span id="__span-8-39"> print(f"{node_id}: {last_message.content}")
<code tabindex="0"><span id="__span-9-1">--- Conversation Turn 1 ---
<span id="__span-9-2">
<span id="__span-9-3">User: {'messages': [{'role': 'user', 'content': 'i wanna go somewhere warm in the caribbean'}]}
<span id="__span-9-4">
<span id="__span-9-5">travel_advisor: Based on the recommendations, Aruba would be an excellent choice for your Caribbean getaway! Aruba is known as "One Happy Island" and offers:
<span id="__span-9-6">- Year-round warm weather with consistent temperatures around 82°F (28°C)
<span id="__span-9-7">- Beautiful white sand beaches like Eagle Beach and Palm Beach
<span id="__span-9-8">- Clear turquoise waters perfect for swimming and snorkeling
<span id="__span-9-9">- Minimal rainfall and location outside the hurricane belt
<span id="__span-9-10">- A blend of Caribbean and Dutch culture
<span id="__span-9-11">- Great dining options and nightlife
<span id="__span-9-12">- Various water sports and activities
<span id="__span-9-13">
<span id="__span-9-14">Would you like me to get some specific hotel recommendations in Aruba for your stay? I can transfer you to our hotel advisor who can help with accommodations.
<span id="__span-9-15">
<span id="__span-9-16">--- Conversation Turn 2 ---
<span id="__span-9-17">
<span id="__span-9-18">User: Command(resume='could you recommend a nice hotel in one of the areas and tell me which area it is.')
<span id="__span-9-19">
<span id="__span-9-20">hotel_advisor: Based on the recommendations, I can suggest two excellent options:
<span id="__span-9-21">
<span id="__span-9-22">1. The Ritz-Carlton, Aruba - Located in Palm Beach
<span id="__span-9-23">- This luxury resort is situated in the vibrant Palm Beach area
<span id="__span-9-24">- Known for its exceptional service and amenities
<span id="__span-9-25">- Perfect if you want to be close to dining, shopping, and entertainment
<span id="__span-9-26">- Features multiple restaurants, a casino, and a world-class spa
<span id="__span-9-27">- Located on a pristine stretch of Palm Beach
<span id="__span-9-28">
<span id="__span-9-29">2. Bucuti & Tara Beach Resort - Located in Eagle Beach
<span id="__span-9-30">- An adults-only boutique resort on Eagle Beach
<span id="__span-9-31">- Known for being more intimate and peaceful
<span id="__span-9-32">- Award-winning for its sustainability practices
<span id="__span-9-33">- Perfect for a romantic getaway or peaceful vacation
<span id="__span-9-34">- Located on one of the most beautiful beaches in the Caribbean
<span id="__span-9-35">
<span id="__span-9-36">Would you like more specific information about either of these properties or their locations?
<span id="__span-9-37">
<span id="__span-9-38">--- Conversation Turn 3 ---
<span id="__span-9-39">
<span id="__span-9-40">User: Command(resume='i like the first one. could you recommend something to do near the hotel?')
<span id="__span-9-41">
<span id="__span-9-42">travel_advisor: Near the Ritz-Carlton in Palm Beach, here are some highly recommended activities:
<span id="__span-9-43">
<span id="__span-9-44">1. Visit the Palm Beach Plaza Mall - Just a short walk from the hotel, featuring shopping, dining, and entertainment
<span id="__span-9-45">2. Try your luck at the Stellaris Casino - It's right in the Ritz-Carlton
<span id="__span-9-46">3. Take a sunset sailing cruise - Many depart from the nearby pier
<span id="__span-9-47">4. Visit the California Lighthouse - A scenic landmark just north of Palm Beach
<span id="__span-9-48">5. Enjoy water sports at Palm Beach:
<span id="__span-9-49"> - Jet skiing
<span id="__span-9-50"> - Parasailing
<span id="__span-9-51"> - Snorkeling
<span id="__span-9-52"> - Stand-up paddleboarding
<span id="__span-9-53">
<span id="__span-9-54">Would you like more specific information about any of these activities or would you like to know about other options in the area?
预构建实现¶
LangGraph 提供了两种最流行的多智能体架构的预构建实现
- 监督者(supervisor)——个体智能体由一个中央监督者智能体协调。监督者控制所有通信流和任务委派,根据当前上下文和任务要求决定调用哪个智能体。您可以使用
langgraph-supervisor库来创建监督者多智能体系统。 - 群组(swarm)——智能体根据其专业特长动态地将控制权相互交接。系统会记住上次活跃的智能体,确保在后续交互中,对话与该智能体恢复。您可以使用
langgraph-swarm库来创建群组多智能体系统。
- 原文作者:知识铺
- 原文链接:https://index.zshipu.com/ai002/post/20251125/%E6%9E%84%E5%BB%BA%E5%A4%9A%E6%99%BA%E8%83%BD%E4%BD%93%E7%B3%BB%E7%BB%9F-LangChain-%E6%A1%86%E6%9E%B6/
- 版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可,非商业转载请注明出处(作者,原文链接),商业转载请联系作者获得授权。
- 免责声明:本页面内容均来源于站内编辑发布,部分信息来源互联网,并不意味着本站赞同其观点或者证实其内容的真实性,如涉及版权等问题,请立即联系客服进行更改或删除,保证您的合法权益。转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。也可以邮件至 sblig@126.com