跳至内容

多智能体

单个智能体如果需要在多个领域进行专门化或管理大量工具,可能会遇到困难。为了解决这个问题,您可以将智能体分解成更小、独立的智能体,并将它们组合成一个多智能体系统

在多智能体系统中,智能体需要相互通信。它们通过移交来实现这一点——移交是一种原语,用于描述将控制权移交给哪个智能体以及发送给该智能体的有效载荷。

两种最流行的多智能体架构是

  • 协调者——个体智能体由一个中央协调者智能体协调。协调者控制所有的通信流和任务委托,根据当前上下文和任务要求决定调用哪个智能体。
  • 集群——智能体根据其专业性动态地将控制权相互移交。系统会记住上一个活跃的智能体,确保在后续交互中与该智能体恢复对话。

协调者

Supervisor

使用langgraph-supervisor库来创建一个协调者多智能体系统

npm install @langchain/langgraph-supervisor
import { ChatOpenAI } from "@langchain/openai";
import { createSupervisor } from "@langchain/langgraph-supervisor";
import { createReactAgent } from "@langchain/langgraph/prebuilt";
import { tool } from "@langchain/core/tools";
import { z } from "zod";

const bookHotel = tool(
  async (input: { hotel_name: string }) => {
    return `Successfully booked a stay at ${input.hotel_name}.`;
  },
  {
    name: "book_hotel",
    description: "Book a hotel",
    schema: z.object({
      hotel_name: z.string().describe("The name of the hotel to book"),
    }),
  }
);

const bookFlight = tool(
  async (input: { from_airport: string; to_airport: string }) => {
    return `Successfully booked a flight from ${input.from_airport} to ${input.to_airport}.`;
  },
  {
    name: "book_flight",
    description: "Book a flight",
    schema: z.object({
      from_airport: z.string().describe("The departure airport code"),
      to_airport: z.string().describe("The arrival airport code"),
    }),
  }
);

const llm = new ChatOpenAI({ modelName: "gpt-4o" });

// Create specialized agents
const flightAssistant = createReactAgent({
  llm,
  tools: [bookFlight],
  prompt: "You are a flight booking assistant",
  name: "flight_assistant",
});

const hotelAssistant = createReactAgent({
  llm,
  tools: [bookHotel],
  prompt: "You are a hotel booking assistant",
  name: "hotel_assistant",
});

const supervisor = createSupervisor({
  agents: [flightAssistant, hotelAssistant],
  llm,
  prompt: "You manage a hotel booking assistant and a flight booking assistant. Assign work to them, one at a time.",
}).compile();

const stream = await supervisor.stream({
  messages: [{
    role: "user",
    content: "first book a flight from BOS to JFK and then book a stay at McKittrick Hotel"
  }]
});

for await (const chunk of stream) {
  console.log(chunk);
  console.log("\n");
}

集群

Swarm

使用langgraph-swarm库来创建一个集群多智能体系统

npm install @langchain/langgraph-swarm
import { createReactAgent } from "@langchain/langgraph/prebuilt";
import { ChatAnthropic } from "@langchain/anthropic";
import { createSwarm, createHandoffTool } from "@langchain/langgraph-swarm";

const transferToHotelAssistant = createHandoffTool({
  agentName: "hotel_assistant",
  description: "Transfer user to the hotel-booking assistant.",
});

const transferToFlightAssistant = createHandoffTool({
  agentName: "flight_assistant",
  description: "Transfer user to the flight-booking assistant.",
});


const llm = new ChatAnthropic({ modelName: "claude-3-5-sonnet-latest" });

const flightAssistant = createReactAgent({
  llm,
  tools: [bookFlight, transferToHotelAssistant],
  prompt: "You are a flight booking assistant",
  name: "flight_assistant",
});

const hotelAssistant = createReactAgent({
  llm,
  tools: [bookHotel, transferToFlightAssistant],
  prompt: "You are a hotel booking assistant",
  name: "hotel_assistant",
});

const swarm = createSwarm({
  agents: [flightAssistant, hotelAssistant],
  defaultActiveAgent: "flight_assistant",
}).compile();

const stream = await swarm.stream({
  messages: [{
    role: "user",
    content: "first book a flight from BOS to JFK and then book a stay at McKittrick Hotel"
  }]
});

for await (const chunk of stream) {
  console.log(chunk);
  console.log("\n");
}

移交

多智能体交互中的一个常见模式是移交,即一个智能体将控制权移交给另一个智能体。移交允许您指定

  • 目标:要导航到的目标智能体
  • 有效载荷:要传递给该智能体的信息

这同时用于 langgraph-supervisor(监督器移交给单个代理)和 langgraph-swarm(单个代理可以移交给其他代理)。

为了使用 createReactAgent 实现移交,你需要

  1. 创建一个特殊工具,可以将控制权转移到不同的智能体

    const transferToBob = tool(
      async (_) => {
        return new Command({
          // name of the agent (node) to go to
          goto: "bob",
          // data to send to the agent
          update: { messages: ... },
          // indicate to LangGraph that we need to navigate to
          // agent node in a parent graph
          graph: Command.PARENT,
        });
      },
      {
        name: ...,
        schema: ...,
        description: ...
      }
    );
    
  2. 创建可以访问移交工具的个体智能体

    const flightAssistant = createReactAgent(
      ..., tools: [bookFlight, transferToHotelAssistant]
    )
    const hotelAssistant = createReactAgent(
      ..., tools=[bookHotel, transferToFlightAssistant]
    )
    
  3. 定义一个父图,其中包含个体智能体作为节点

    import { StateGraph, MessagesAnnotation } from "@langchain/langgraph";
    
    const multiAgentGraph = new StateGraph(MessagesAnnotation)
      .addNode("flight_assistant", flightAssistant)
      .addNode("hotel_assistant", hotelAssistant)
      ...
    

将这些结合起来,以下是如何实现一个简单的包含两个智能体的多智能体系统——一个机票预订助手和一个酒店预订助手

import { ChatAnthropic } from "@langchain/anthropic";
import { createReactAgent } from "@langchain/langgraph/prebuilt";
import { StateGraph, MessagesAnnotation, Command, START, getCurrentTaskInput, END } from "@langchain/langgraph";
import { tool } from "@langchain/core/tools";
import { z } from "zod";
import { ToolMessage } from "@langchain/core/messages";

interface CreateHandoffToolParams {
  agentName: string;
  description?: string;
}

const createHandoffTool = ({
  agentName,
  description,
}: CreateHandoffToolParams) => {
  const toolName = `transfer_to_${agentName}`;
  const toolDescription = description || `Ask agent '${agentName}' for help`;

  const handoffTool = tool(
    async (_, config) => {
      const toolMessage = new ToolMessage({
        content: `Successfully transferred to ${agentName}`,
        name: toolName,
        tool_call_id: config.toolCall.id,
      });

      // inject the current agent state
      const state =
        getCurrentTaskInput() as (typeof MessagesAnnotation)["State"];  // (1)!
      return new Command({  // (2)!
        goto: agentName,  // (3)!
        update: { messages: state.messages.concat(toolMessage) },  // (4)!
        graph: Command.PARENT,  // (5)!
      });
    },
    {
      name: toolName,
      schema: z.object({}),
      description: toolDescription,
    }
  );

  return handoffTool;
};

const bookHotel = tool(
  async (input: { hotel_name: string }) => {
    return `Successfully booked a stay at ${input.hotel_name}.`;
  },
  {
    name: "book_hotel",
    description: "Book a hotel",
    schema: z.object({
      hotel_name: z.string().describe("The name of the hotel to book"),
    }),
  }
);

const bookFlight = tool(
  async (input: { from_airport: string; to_airport: string }) => {
    return `Successfully booked a flight from ${input.from_airport} to ${input.to_airport}.`;
  },
  {
    name: "book_flight",
    description: "Book a flight",
    schema: z.object({
      from_airport: z.string().describe("The departure airport code"),
      to_airport: z.string().describe("The arrival airport code"),
    }),
  }
);

const transferToHotelAssistant = createHandoffTool({
  agentName: "hotel_assistant",
  description: "Transfer user to the hotel-booking assistant.",
});

const transferToFlightAssistant = createHandoffTool({
  agentName: "flight_assistant",
  description: "Transfer user to the flight-booking assistant.",
});

const llm = new ChatAnthropic({ modelName: "claude-3-5-sonnet-latest" });

const flightAssistant = createReactAgent({
  llm,
  tools: [bookFlight, transferToHotelAssistant],
  prompt: "You are a flight booking assistant",
  name: "flight_assistant",
});

const hotelAssistant = createReactAgent({
  llm,
  tools: [bookHotel, transferToFlightAssistant],
  prompt: "You are a hotel booking assistant",
  name: "hotel_assistant",
});

const multiAgentGraph = new StateGraph(MessagesAnnotation)
  .addNode("flight_assistant", flightAssistant, { ends: ["hotel_assistant", END] })
  .addNode("hotel_assistant", hotelAssistant, { ends: ["flight_assistant", END] })
  .addEdge(START, "flight_assistant")
  .compile();

const stream = await multiAgentGraph.stream({
  messages: [{
    role: "user",
    content: "book a flight from BOS to JFK and a stay at McKittrick Hotel"
  }]
});

for await (const chunk of stream) {
  console.log(chunk);
  console.log("\n");
}
  1. 访问智能体状态
  2. Command 原语允许将状态更新和节点转换指定为一个单一操作,这使得它在实现移交时非常有用。
  3. 要移交控制权的智能体或节点的名称。
  4. 获取智能体的消息并将其添加到父级的状态中,作为移交的一部分。下一个智能体将看到父级状态。
  5. 向 LangGraph 表明我们需要在父级多智能体图中导航到智能体节点。

注意

此移交实现假定

  • 多智能体系统中的每个智能体都将整体消息历史记录(所有智能体的)作为其输入
  • 每个智能体将其内部消息历史记录输出到多智能体系统的整体消息历史记录中

参考 LangGraph 监督器swarm 文档,了解如何定制移交。