多代理¶
单个智能体如果需要专注于多个领域或管理多种工具,可能会面临困难。为了解决这个问题,你可以将你的智能体分解成更小、独立的智能体,并将它们组合成一个多智能体系统。
在多智能体系统中,智能体之间需要相互通信。它们通过交接(handoffs)来实现这一点——这是一种描述将控制权交给哪个智能体以及向该智能体发送什么负载的原始操作。
两种最流行的多智能体架构是
- 主管型(supervisor) — 单个智能体由一个中央主管智能体协调。主管智能体控制所有通信流和任务委派,根据当前上下文和任务要求决定调用哪个智能体。
- 集群型(swarm) — 智能体根据其专业性动态地将控制权移交给彼此。系统会记住哪个智能体最后处于活跃状态,确保在后续交互中,对话能与该智能体继续进行。
主管型¶
使用 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
库来创建集群型多智能体系统
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");
}
交接¶
多智能体交互中的一个常见模式是交接(handoffs),即一个智能体将控制权移交给另一个智能体。交接允许你指定
- 目的地:要导航到的目标智能体
- 负载:要传递给该代理的信息
这被langgraph-supervisor
(主管智能体将控制权移交给单个智能体)和langgraph-swarm
(单个智能体可以将控制权移交给其他智能体)都使用。
要使用createReactAgent
实现交接,你需要
-
创建一个可以将控制权转移给不同智能体的特殊工具
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: ... } );
-
创建可以访问交接工具的单个智能体
-
定义一个包含单个智能体作为节点的父图
综上所述,以下是如何实现一个简单的包含两个智能体的多智能体系统——一个航班预订助手和一个酒店预订助手
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");
}
- 访问智能体状态
Command
原始操作允许将状态更新和节点转换指定为单个操作,这对于实现交接非常有用。- 要移交到的代理或节点的名称。
- 获取智能体的消息并将其添加到父级的状态中,作为交接的一部分。下一个智能体将看到父级状态。
- 指示 LangGraph 我们需要导航到父级多代理图中的代理节点。
注意
此交接实现假定
- 每个智能体接收多智能体系统中所有智能体的整体消息历史作为其输入
- 每个智能体将其内部消息历史输出到多智能体系统的整体消息历史中
查看 LangGraph 主管型(supervisor)和集群型(swarm)文档,了解如何自定义交接。