import {
StateGraph,
START,
END,
StateSchema,
MessagesValue,
Command,
ConditionalEdgeRouter,
GraphNode,
} from "@langchain/langgraph";
import { createAgent, AIMessage, ToolMessage } from "langchain";
import { tool, ToolRuntime } from "@langchain/core/tools";
import { z } from "zod/v4";
// 1. 定义带有 activeAgent 跟踪器的状态
const MultiAgentState = new StateSchema({
messages: MessagesValue,
activeAgent: z.string().optional(),
});
// 2. 创建交接工具
const transferToSales = tool(
async (_, runtime: ToolRuntime<typeof MultiAgentState.State>) => {
const lastAiMessage = [...runtime.state.messages]
.reverse()
.find(AIMessage.isInstance);
const transferMessage = new ToolMessage({
content: "从支持智能体转移到销售智能体",
tool_call_id: runtime.toolCallId,
});
return new Command({
goto: "sales_agent",
update: {
activeAgent: "sales_agent",
messages: [lastAiMessage, transferMessage].filter(Boolean),
},
graph: Command.PARENT,
});
},
{
name: "transfer_to_sales",
description: "转移到销售智能体。",
schema: z.object({}),
}
);
const transferToSupport = tool(
async (_, runtime: ToolRuntime<typeof MultiAgentState.State>) => {
const lastAiMessage = [...runtime.state.messages]
.reverse()
.find(AIMessage.isInstance);
const transferMessage = new ToolMessage({
content: "从销售智能体转移到支持智能体",
tool_call_id: runtime.toolCallId,
});
return new Command({
goto: "support_agent",
update: {
activeAgent: "support_agent",
messages: [lastAiMessage, transferMessage].filter(Boolean),
},
graph: Command.PARENT,
});
},
{
name: "transfer_to_support",
description: "转移到支持智能体。",
schema: z.object({}),
}
);
// 3. 创建带有交接工具的智能体
const salesAgent = createAgent({
model: "anthropic:claude-sonnet-4-20250514",
tools: [transferToSupport],
systemPrompt:
"您是销售智能体。帮助处理销售咨询。如果被问及技术问题或支持,请转移到支持智能体。",
});
const supportAgent = createAgent({
model: "anthropic:claude-sonnet-4-20250514",
tools: [transferToSales],
systemPrompt:
"您是支持智能体。帮助处理技术问题。如果被问及定价或购买,请转移到销售智能体。",
});
// 4. 创建调用智能体的智能体节点
const callSalesAgent: GraphNode<typeof MultiAgentState.State> = async (state) => {
const response = await salesAgent.invoke(state);
return response;
};
const callSupportAgent: GraphNode<typeof MultiAgentState.State> = async (state) => {
const response = await supportAgent.invoke(state);
return response;
};
// 5. 创建检查是否应该结束或继续的路由器
const routeAfterAgent: ConditionalEdgeRouter<
typeof MultiAgentState.State,
"sales_agent" | "support_agent"
> = (state) => {
const messages = state.messages ?? [];
// 检查最后一条消息 - 如果是没有工具调用的 AIMessage,则完成
if (messages.length > 0) {
const lastMsg = messages[messages.length - 1];
if (lastMsg instanceof AIMessage && !lastMsg.tool_calls?.length) {
return END;
}
}
// 否则路由到活跃智能体
const active = state.activeAgent ?? "sales_agent";
return active as "sales_agent" | "support_agent";
};
const routeInitial: ConditionalEdgeRouter<
typeof MultiAgentState.State,
"sales_agent" | "support_agent"
> = (state) => {
// 根据状态路由到活跃智能体,默认为销售智能体
return (state.activeAgent ?? "sales_agent") as
| "sales_agent"
| "support_agent";
};
// 6. 构建图
const builder = new StateGraph(MultiAgentState)
.addNode("sales_agent", callSalesAgent)
.addNode("support_agent", callSupportAgent);
// 基于初始 activeAgent 进行条件路由开始
.addConditionalEdges(START, routeInitial, [
"sales_agent",
"support_agent",
])
// 在每个智能体之后,检查是否应该结束或路由到另一个智能体
.addConditionalEdges("sales_agent", routeAfterAgent, [
"sales_agent",
"support_agent",
END,
]);
builder.addConditionalEdges("support_agent", routeAfterAgent, [
"sales_agent",
"support_agent",
END,
]);
const graph = builder.compile();
const result = await graph.invoke({
messages: [
{
role: "user",
content: "你好,我的账户登录遇到问题。你能帮忙吗?",
},
],
});
for (const msg of result.messages) {
console.log(msg.content);
}