Skip to main content
Alpha 版本提示: 本文档涵盖的是 v1-alpha 版本。内容尚不完整,且可能随时变更。如需查阅最新稳定版本,请参阅 v0 版本的 LangChain Python 文档LangChain JavaScript 文档
多智能体系统 将复杂应用拆分为多个专业化的智能体,这些智能体协同工作以解决问题。
相比于依赖单一智能体处理所有步骤,多智能体架构 允许你将多个小型、专注的智能体组合成一个协调的工作流程。
多智能体系统在以下情况下尤为有用:
  • 单一智能体拥有过多工具,难以做出合理选择;
  • 上下文或记忆内容过于庞大,单一智能体无法有效跟踪;
  • 任务需要专业化分工(例如:规划者、研究员、数学专家)。

多智能体模式

模式工作原理控制流示例应用场景
工具调用中央智能体将其他智能体作为“工具”调用。“工具”智能体不直接与用户交互——它们仅执行任务并返回结果。集中式:所有路由均通过调用智能体。任务编排、结构化工作流。
交接控制当前智能体决定将控制权转移给另一个智能体。活跃智能体随之切换,用户可直接与新智能体继续交互。去中心化:智能体可自主决定切换活跃对象。多领域对话、专家接管。

模式选择指南

问题工具调用交接控制
是否需要集中控制工作流?✅ 是❌ 否
是否希望智能体直接与用户交互?❌ 否✅ 是
是否需要专家间进行复杂、类人的对话?❌ 有限✅ 强烈推荐
你可以混合使用两种模式——使用交接控制实现智能体切换,同时让每个智能体调用子智能体作为工具来处理特定任务。

自定义智能体上下文

多智能体设计的核心是上下文工程——决定每个智能体可见的信息。LangChain 提供细粒度控制,包括:
  • 传递给每个智能体的对话或状态的哪些部分;
  • 为子智能体定制的专用提示词;
  • 包含或排除中间推理过程;
  • 按智能体定制输入/输出格式。
系统的质量高度依赖于上下文工程。目标是确保每个智能体(无论是作为工具还是活跃智能体)都能获得完成其任务所需的正确数据。

工具调用

工具调用模式中,一个智能体(“控制器”)将其他智能体视为工具,在需要时调用。控制器负责编排,工具智能体执行特定任务并返回结果。 流程:
  1. 控制器接收输入,决定调用哪个工具(子智能体)。
  2. 工具智能体根据控制器的指令执行任务。
  3. 工具智能体将结果返回给控制器。
  4. 控制器决定下一步操作或结束流程。
作为工具使用的智能体通常不应与用户直接对话。 它们的作用是执行任务并将结果返回给控制器智能体。 如果需要子智能体能与用户对话,请改用交接控制模式。

实现方式

以下是最小示例,主智能体通过工具定义访问单个子智能体:
from langchain.tools import tool
from langchain.agents import create_agent

subagent1 = create_agent(..)

@tool(
    name="subagent1_name",
    description="subagent1_description"
)
def call_subagent1(query: str):
    result = subagent1.invoke({
        "messages": [{"role": "user", "content": query}]
    })
    return result["messages"].text
    
agent = create_agent(..., tools=[call_subagent1])
在此模式中:
  1. 主智能体在判断任务匹配子智能体描述时,调用 call_subagent1
  2. 子智能体独立运行并返回结果。
  3. 主智能体接收结果并继续编排。

可定制点

你可以在多个环节控制主智能体与子智能体之间的上下文传递:
  1. 子智能体名称 ("subagent1_name"):主智能体引用子智能体的方式。名称影响提示词,需谨慎选择。
  2. 子智能体描述 ("subagent1_description"):主智能体对子智能体的“认知”。直接影响主智能体何时调用它。
  3. 子智能体输入:可自定义输入,以更好引导子智能体理解任务。上例中我们直接传递智能体生成的 query
  4. 子智能体输出:这是返回给主智能体的响应。可调整返回内容,以控制主智能体如何解读结果。上例中我们返回最终消息文本,但也可返回额外状态或元数据。

控制子智能体输入

控制主智能体传递给子智能体输入的两个主要方法:
  • 修改提示词 – 调整主智能体提示词或工具元数据(即子智能体名称和描述),以更好引导调用时机和方式。
  • 上下文注入 – 通过调整工具调用从智能体状态中提取信息,添加静态提示词难以捕捉的输入(如完整对话历史、先前结果、任务元数据)。
from typing import Annotated
from langchain.agents import AgentState
from langchain.agents.tool_node import InjectedState

@tool(
    name="subagent1_name",
    description="subagent1_description"
)
def call_subagent1(query: str, state: Annotated[CustomState, InjectedState]):
    # 应用任何必要的逻辑,将消息转换为合适的输入
    subagent_input = some_logic(query, state.messages)
    result = subagent1.invoke({
        "messages": subagent_input,
        # 如有需要,也可传递其他状态键。
        # 请确保在主智能体和子智能体的状态模式中均定义这些键。
        "example_state_key": state.example_state_key
    })
    return result["messages"][-1].text

控制子智能体输出

塑造主智能体从子智能体接收内容的两种常见策略:
  • 修改提示词 – 优化子智能体提示词,明确指定应返回的内容。
    • 适用于输出不完整、过于冗长或缺少关键细节的情况。
    • 常见失败模式:子智能体执行工具调用或推理,但未在最终消息中包含结果。需提醒子智能体:控制器(和用户)仅看到最终输出,因此所有相关信息必须包含在内。
  • 自定义输出格式 – 在将子智能体响应交还主智能体前,通过代码调整或丰富响应。
    • 示例:除最终文本外,向主智能体传递特定状态键。
    • 这需要将结果包装在 Command(或等效结构)中,以便将自定义状态与子智能体响应合并。
from typing import Annotated
from langchain.agents import AgentState
from langchain_core.tools import InjectedToolCallId
from langgraph.types import Command


@tool(
    name="subagent1_name",
    description="subagent1_description"
)
# 需要将 `tool_call_id` 传递给子智能体,以便其使用该 ID 响应工具调用结果
def call_subagent1(
    query: str, 
    tool_call_id: Annotated[str, InjectedToolCallId],
# 若要返回的不仅是最终工具调用,需返回 `Command` 对象
) -> Command:
    result = subagent1.invoke({
        "messages": [{"role": "user", "content": query}]
    })
    return Command(update={
        # 这是我们传回的示例状态键
        "example_state_key": result["example_state_key"],
        "messages": [
            ToolMessage(
                # 需包含工具调用 ID,以便与正确的工具调用匹配
                result["messages"][-1].text, tool_call_id=tool_call_id
            )
        ]
    })

交接控制

交接控制模式中,智能体可直接将控制权传递给彼此。“活跃”智能体发生切换,用户与当前拥有控制权的智能体交互。 流程:
  1. 当前智能体判断需要另一智能体协助。
  2. 它将控制权(及状态)传递给下一智能体
  3. 新智能体直接与用户交互,直至决定再次交接或完成任务。

实现方式(即将推出)