Skip to content

多代理系统

一个单一的代理在需要专精于多个领域或管理许多工具时可能会遇到困难。为了解决这个问题,你可以将你的代理分解成更小的独立代理,并将它们组合成一个多代理系统多代理系统

在多代理系统中,代理之间需要相互沟通。它们通过交接——一种描述将控制权传递给哪个代理以及发送给该代理的数据包的机制——来进行通信。

两种最受欢迎的多代理架构是:

  • 监督者 — 个体代理由一个中央监督者代理协调。监督者控制所有通信流和任务分配,根据当前上下文和任务需求决定调用哪个代理。
  • 群集 — 代理根据其专长动态地将控制权传递给彼此。系统会记住最后一个活跃的代理,确保在后续交互中对话能够从该代理继续进行。

监管者

监管者

使用langgraph-supervisor库来创建一个监管者多代理系统:

pip install langgraph-supervisor

API Reference: create_react_agent | create_supervisor

from langchain_openai import ChatOpenAI
from langgraph.prebuilt import create_react_agent
from langgraph_supervisor import create_supervisor

def book_hotel(hotel_name: str):
    """预订酒店"""
    return f"成功预订了{hotel_name}酒店的住宿。"

def book_flight(from_airport: str, to_airport: str):
    """预订航班"""
    return f"成功预订了从{from_airport}{to_airport}的航班。"

flight_assistant = create_react_agent(
    model="openai:gpt-4o",
    tools=[book_flight],
    prompt="你是航班预订助手",
    name="flight_assistant"
)

hotel_assistant = create_react_agent(
    model="openai:gpt-4o",
    tools=[book_hotel],
    prompt="你是酒店预订助手",
    name="hotel_assistant"
)

supervisor = create_supervisor(
    agents=[flight_assistant, hotel_assistant],
    model=ChatOpenAI(model="gpt-4o"),
    prompt=(
        "你管理着一个酒店预订助手和一个航班预订助手。分配任务给他们。"
    )
).compile()

for chunk in supervisor.stream(
    {
        "messages": [
            {
                "role": "user",
                "content": "预订从BOS到JFK的航班以及在McKittrick酒店的住宿"
            }
        ]
    }
):
    print(chunk)
    print("\n")

蜂群

蜂群

使用langgraph-swarm库创建一个蜂群多代理系统:

pip install langgraph-swarm

API Reference: create_react_agent | create_swarm | create_handoff_tool

from langgraph.prebuilt import create_react_agent
from langgraph_swarm import create_swarm, create_handoff_tool

transfer_to_hotel_assistant = create_handoff_tool(
    agent_name="hotel_assistant",
    description="将用户转移到酒店预订助手。",
)
transfer_to_flight_assistant = create_handoff_tool(
    agent_name="flight_assistant",
    description="将用户转移到航班预订助手。",
)

flight_assistant = create_react_agent(
    model="anthropic:claude-3-5-sonnet-latest",
    tools=[book_flight, transfer_to_hotel_assistant],
    prompt="您是一位航班预订助手",
    name="flight_assistant"
)
hotel_assistant = create_react_agent(
    model="anthropic:claude-3-5-sonnet-latest",
    tools=[book_hotel, transfer_to_flight_assistant],
    prompt="您是一位酒店预订助手",
    name="hotel_assistant"
)

swarm = create_swarm(
    agents=[flight_assistant, hotel_assistant],
    default_active_agent="flight_assistant"
).compile()

for chunk in swarm.stream(
    {
        "messages": [
            {
                "role": "user",
                "content": "从BOS到JFK预订航班,并在McKittrick酒店预订住宿"
            }
        ]
    }
):
    print(chunk)
    print("\n")

交接

在多代理交互中,一个常见的模式是**交接**,其中一个代理将控制权移交给另一个代理。交接允许您指定:

  • 目标:要导航到的目标代理
  • 负载:传递给该代理的信息

这既用于langgraph-supervisor(监督者将控制权移交给单个代理)也用于langgraph-swarm(单个代理可以将控制权移交给其他代理)。

使用create_react_agent实现交接,您需要:

  1. 创建一个特殊的工具,可以将控制权转移到不同的代理上

    def transfer_to_bob():
        """转移至Bob."""
        return Command(
            # 目标代理(节点)名称
            goto="bob",
            # 发送给代理的数据
            update={"messages": [...]},
            # 告诉LangGraph我们需要导航到父图中的代理节点
            graph=Command.PARENT,
        )
    
  2. 创建具有访问交接工具权限的独立代理:

    flight_assistant = create_react_agent(
        ..., tools=[book_flight, transfer_to_hotel_assistant]
    )
    hotel_assistant = create_react_agent(
        ..., tools=[book_hotel, transfer_to_flight_assistant]
    )
    
  3. 定义包含独立代理作为节点的父图:

    from langgraph.graph import StateGraph, MessagesState
    multi_agent_graph = (
        StateGraph(MessagesState)
        .add_node(flight_assistant)
        .add_node(hotel_assistant)
        ...
    )
    

综合以上步骤,这里是如何实现一个简单的双代理系统——一个航班预订助手和一个酒店预订助手:

from typing import Annotated
from langchain_core.tools import tool, InjectedToolCallId
from langgraph.prebuilt import create_react_agent, InjectedState
from langgraph.graph import StateGraph, START, MessagesState
from langgraph.types import Command

def create_handoff_tool(*, agent_name: str, description: str | None = None):
    name = f"transfer_to_{agent_name}"
    description = description or f"Transfer to {agent_name}"

    @tool(name, description=description)
    def handoff_tool(
        state: Annotated[MessagesState, InjectedState], # (1)!
        tool_call_id: Annotated[str, InjectedToolCallId],
    ) -> Command:
        tool_message = {
            "role": "tool",
            "content": f"成功转移到{agent_name}",
            "name": name,
            "tool_call_id": tool_call_id,
        }
        return Command(  # (2)!
            goto=agent_name,  3)!
            update={"messages": state["messages"] + [tool_message]},  # (4)!
            graph=Command.PARENT,  # (5)!
        )
    return handoff_tool

# 交接
transfer_to_hotel_assistant = create_handoff_tool(
    agent_name="hotel_assistant",
    description="将用户转移到酒店预订助手.",
)
transfer_to_flight_assistant = create_handoff_tool(
    agent_name="flight_assistant",
    description="将用户转移到航班预订助手.",
)

# 简单代理工具
def book_hotel(hotel_name: str):
    """预订酒店"""
    return f"成功预订了{hotel_name}的住宿."

def book_flight(from_airport: str, to_airport: str):
    """预订航班"""
    return f"成功预订了从{from_airport}{to_airport}的航班."

# 定义代理
flight_assistant = create_react_agent(
    model="anthropic:claude-3-5-sonnet-latest",
    tools=[book_flight, transfer_to_hotel_assistant],
    prompt="您是一个航班预订助手",
    name="flight_assistant"
)
hotel_assistant = create_react_agent(
    model="anthropic:claude-3-5-sonnet-latest",
    tools=[book_hotel, transfer_to_flight_assistant],
    prompt="您是一个酒店预订助手",
    name="hotel_assistant"
)

# 定义多代理图
multi_agent_graph = (
    StateGraph(MessagesState)
    .add_node(flight_assistant)
    .add_node(hotel_assistant)
    .add_edge(START, "flight_assistant")
    .compile()
)

# 运行多代理图
for chunk in multi_agent_graph.stream(
    {
        "messages": [
            {
                "role": "user",
                "content": "预订从BOS到JFK的航班和McKittrick酒店的住宿"
            }
        ]
    }
):
    print(chunk)
    print("\n")
  1. 访问代理的状态
  2. Command 原语允许指定状态更新和节点转换为单一操作,使其成为实现交接的有用工具。
  3. 要交接的代理或节点名称。
  4. 取代理的消息并将其添加到父图的状态中,作为交接的一部分。下一个代理将看到父图状态。
  5. 告诉LangGraph我们需要导航到父图中的代理节点。

Note

此交接实现假设:

  • 每个代理接收整个消息历史记录(跨所有代理)作为其输入
  • 每个代理将其内部消息历史记录输出到多代理系统的整体消息历史记录中

查看LangGraph 监督者群集 文档以了解如何自定义交接。

Comments