AI 智能体与应用——多智能体系统

0 阅读23分钟

本章涵盖以下内容:

  • 将工具连接到数据源
  • 使用路由器(router)和监督者(supervisor)模式组合多智能体系统
  • 调试、测试与追踪多智能体交互

在第 11 章中,我们通过构建一个旅行信息智能体,探讨了构建 AI 智能体的基础。这个智能体能够回答用户关于目的地、路线和交通方式的查询。虽然单个、专门化的智能体已经很强大,但现实世界的应用通常需要多个智能体协同工作,每个智能体处理不同的专业领域。在本章中,我们将踏上这段旅程——把我们的旅行信息智能体升级为一个健壮的多智能体旅行助手系统。

想象一下,当你规划一次旅行时,你不仅需要最新的旅行信息,还希望能够无缝预订住宿。我们增强后的多智能体旅行助手正是为此而设计:它既能回答旅行相关问题,也能帮助你在所选目的地预订酒店或家庭旅馆(B&B)。为了实现这一目标,我们将首先构建一个新的智能体——住宿预订智能体。

住宿预订智能体将使用户能够从两个不同的数据源预订住宿。第一,它会对接一个本地住宿数据库,该数据库主要提供酒店优惠信息,并通过一个专用工具暴露给智能体使用。第二,它会连接到一个外部的 B&B REST API,从而访问更广泛的 B&B 选项,该 API 同样通过其专属工具供智能体调用。根据用户请求,智能体会使用其中一个或两个工具来提供相关的住宿选项。

在新智能体构建完成后,我们会将它与上一章中的旅行信息智能体结合起来。最终结果将是一个统一的多智能体旅行助手,它能够处理各种与旅行相关的查询,既能回答信息类请求,也能处理住宿预订,甚至还能将两者结合起来,提供更加流畅的一体化体验。下面就让我们从构建新的住宿预订智能体开始。

12.1 构建住宿预订智能体

为了构建一个真正实用、真正有帮助的旅行助手,我们需要的不仅仅是信息检索能力——还需要执行操作的能力。在本节中,我们将从零开始开发一个住宿预订智能体,首先构建它所需的工具:一个基于本地房间可用性数据库的酒店预订工具,以及另一个对接外部 REST API 的 B&B 预订工具。到本节结束时,你将拥有一个 ReAct 风格的智能体,它能够在康沃尔(Cornwall)查询并预订酒店和 B&B 房间。

12.1.1 酒店预订工具

我们先从创建酒店预订工具开始。为了让智能体能够检索酒店优惠信息和房间可用性,我们将使用 LangChain 的 SQL Database 工具包。该工具包将一个 SQL 数据库封装为一组可供智能体调用的工具。借助这个工具包,智能体可以通过工具调用直接运行查询、获取酒店详情并检查房间可用性,而无需在提示词中编写原始 SQL。

酒店数据(包括当前优惠和可用性)存储在一个名为 cornwall_hotels.db 的本地 SQLite 数据库中,该数据库由后端合作方保持最新。我们无需关心数据是如何被推送进去的——只需要相信它始终存在,并会按需刷新。

注意 我建议使用普通的命令提示符(cmd),而不是 PowerShell 来启动 SQLite shell,因为 PowerShell 可能会报错。本节假设 SQLite 已经安装好。如果尚未安装,请参见第 10 章的 10.3.1 节,以及附录 D 中的安装步骤,其中也包括如何把安装目录加入系统的 Path 环境变量。

首先,将最新脚本 main_03_01.py 复制为一个新脚本 main_04_01.py。然后,按照以下步骤准备环境:

创建一个名为 hotel_db 的文件夹。
将提供的 SQL 模式文件 cornwall_hotels_schema.sql 放入该文件夹中。
打开一个普通的命令提示符(可以在 Visual Studio Code [VS Code] 内部打开,也可以通过 Windows 搜索框中的 cmd 单独打开),进入该文件夹,并使用以下命令创建数据库(为方便起见,我省略了 ch11 文件夹的根路径):

\ch11>cd hotel_db
\ch11\hotel_db>sqlite3 cornwall_hotels.db < cornwall_hotels_schema.sql

现在让我们检查数据库是否正常工作。打开 SQLite shell:

\ch11\hotel_db>sqlite3 cornwall_hotels.db

在 SQLite shell 中,运行以下查询来验证配置是否正确:

sqlite> .tables

sqlite> SELECT * FROM hotels;

sqlite> SELECT * FROM hotel_room_offers;

数据库准备好之后,我们继续进行 Python 实现。导入所需的 LangChain SQL 集成库:

from langchain_community.utilities.sql_database import SQLDatabase
from langchain_community.agent_toolkits import SQLDatabaseToolkit

实例化 SQLite 数据库:

hotel_db = SQLDatabase.from_uri("sqlite:///hotel_db/cornwall_hotels.db")

现在创建 SQL Database 工具包实例:

hotel_db_toolkit = SQLDatabaseToolkit(db=hotel_db, llm=llm_model)

就这样!现在你可以通过如下方式访问该工具包提供的工具:

hotel_db_toolkit_tools = hotel_db_toolkit.get_tools()

12.1.2 B&B 预订工具

接下来,我们来创建一个 B&B 预订工具。这个工具将从一个 REST 服务中检索 B&B 房间可用性。在开发和测试阶段,我们会对这个服务进行模拟(mock)。

首先,我们将定义工具的返回类型,然后创建一个 BnBBookingService 的模拟实现,如代码清单 12.1 所示。(为了方便,这里的示例只使用了精简版的模拟数据。完整实现可在本书提供的代码文件中找到。)

代码清单 12.1 BnBBookingService

class BnBBookingService:  #1
    @staticmethod
    def get_offers_near_town(town: str, num_rooms: int) \
        -> List[BnBOffer]:  #2

        mock_bnb_offers = [  #3
            {"bnb_id": 1, "bnb_name": "Seaside BnB", 
            "town": "Newquay", "available_rooms": 3, 
            "price_per_room": 80.0},
            {"bnb_id": 2, "bnb_name": "Surfside Guesthouse", 
            "town": "Newquay", "available_rooms": 2, 
            "price_per_room": 85.0},
            # Falmouth
            {"bnb_id": 3, "bnb_name": "Harbour View BnB", 
            "town": "Falmouth", "available_rooms": 4, 
            "price_per_room": 78.0},
            {"bnb_id": 4, "bnb_name": "Seafarer's Rest", 
            "town": "Falmouth", "available_rooms": 1, 
            "price_per_room": 90.0},,
            ... 
            # Port Isaac
            {"bnb_id": 27, "bnb_name": "Port Isaac View BnB", 
            "town": "Port Isaac", "available_rooms": 2, 
            "price_per_room": 99.0},
            {"bnb_id": 28, "bnb_name": "Fisherman's Cottage BnB", 
            "town": "Port Isaac", "available_rooms": 2, 
            "price_per_room": 101.0},
            # Fowey
            {"bnb_id": 29, "bnb_name": "Fowey Quay BnB", 
            "town": "Fowey", "available_rooms": 2, 
            "price_per_room": 94.0},
            {"bnb_id": 30, "bnb_name": "Riverside Rest BnB", 
            "town": "Fowey", "available_rooms": 2, 
            "price_per_room": 96.0},
        ]
        offers = [offer for offer in 
            mock_bnb_offers 
            if offer["town"].lower() == town.lower() 
               and offer["available_rooms"] >= num_rooms]
        return offers
#1 定义 B&B 可用性工具
#2 调用 B&B 预订服务以获取报价
#3 模拟的 B&B 报价数据

现在,我们可以在下面的代码清单中定义 check_bnb_availability 工具。

代码清单 12.2 check_bnb_availability 工具

@tool(description="""Check BnB room availability and 
price for a destination in Cornwall.""")  #1
def check_bnb_availability(destination: str, num_rooms: int) \
    -> List[Dict]: #2

    offers = BnBBookingService.get_offers_near_town(
 …  destination, num_rooms)
    if not offers:
 …  return [{"error": f"No available BnBs found 
 …  ↪in {destination} for {num_rooms} rooms."}]
    return offers
    return offers
#1 定义 B&B 可用性工具
#2 定义 B&B 可用性工具的输入与返回类型

12.1.3 ReAct 住宿预订智能体

酒店和 B&B 预订工具都准备好之后,就该构建 ReAct 风格的住宿预订智能体了。这个智能体将根据用户请求使用这两个工具。如果用户没有明确指定偏好,智能体会同时搜索酒店和 B&B 的可用房间:

BOOKING_TOOLS = hotel_db_toolkit_tools + \
   [check_bnb_availability]  #1

accommodation_booking_agent = create_react_agent(  #2
    model=llm_model,
    tools=BOOKING_TOOLS,
    state_schema=AgentState,
    prompt="""You are a helpful assistant that can check 
    hotel and BnB room availability and price for a
    destination in Cornwall. You can use the tools to 
    get the information you need. If the users does 
    not specify the accommodation type, you should 
    check both hotels and BnBs.""",
)
#1 定义预订工具,即酒店数据库工具包中的工具加上 B&B 可用性工具
#2 创建住宿预订智能体

现在,你可以把 chat_loop() 中调用智能体的那一行替换为:

...
result = accommodation_booking_agent.invoke(state) 
...

让我们以调试模式运行 main_04_01.py 脚本,并提出如下问题:

UK Travel Assistant (type 'exit' to quit)
You: Are there any hotel or BnB rooms available in Penzance?

按下 Enter 后,你可能会看到类似如下的回答(这里我只展示 text 属性中的内容):

I have found Penzance Pier BnB with available rooms at £95 per room, and Cornish Charm BnB with 3 available rooms at £87 per room. 

For hotels, Penzance Palace has 3 available rooms with prices of £130 for a single room and £200 for a double room. Would you like to book a room or need more information?

正如你所看到的,智能体使用了两个工具,从酒店数据库和模拟的 B&B 服务中都检索到了结果。

到这里,你的住宿预订智能体已经按预期工作了。强烈建议你调试其执行过程,并查看 LangSmith 的 trace,以更好地理解智能体是如何一步一步进行推理和采取行动的。

虽然你现在已经有了旅行信息智能体和住宿预订智能体,但它们仍然是彼此分离的。你可以使用其中任何一个,但无法在一个统一的体验中同时使用二者。在下一节中,我们将构建一个多智能体旅行助手,把这两种能力整合起来,从而为旅行规划和住宿预订提供无缝体验。

12.2 构建基于路由器的旅行助手

到目前为止,我们已经开发了两个独立的智能体——一个旅行信息智能体和一个住宿预订智能体——它们各自具备专门化能力。虽然这种模块化方式很强大,但它引出了一个关键设计问题:我们该如何把这些智能体组合起来,以提供无缝的用户体验——既能在一次对话中回答旅行信息查询,又能处理住宿预订?

一种常见且有效的解决方案,是引入一个路由器智能体(router agent)。这个智能体充当智能入口:它接收用户消息,判断应该由哪个专门化智能体来处理该请求,然后将任务分发过去。

12.2.1 设计路由器智能体

要实现我们的多智能体旅行助手,首先将你之前的脚本 main_04_01.py 复制为 main_05_01.py。接下来,我们需要引入一些额外的库,以支持基于图的工作流:

from langgraph.graph import StateGraph, END
from langgraph.types import Command

下一步是清晰定义可供路由的智能体集合。我们通过声明一个枚举来表示这两类智能体:

class AgentType(str, Enum):
    travel_info_agent = "travel_info_agent"
    accommodation_booking_agent = "accommodation_booking_agent"

为了确保路由器智能体能够从 LLM 获得清晰且结构化的决策结果,我们定义一个 Pydantic 模型来承载 LLM 的输出——即指定每个查询应由哪个智能体处理:

class AgentTypeOutput(BaseModel): 
    agent: AgentType = Field(..., 
    description="Which agent should handle the query?")

通过将 OpenAI 的 LLM 客户端配置为输出这种结构化格式,我们就不再需要进行字符串解析或手工后处理:

llm_router = llm_model.with_structured_output(
    AgentTypeOutput)

路由器将始终生成 travel_info_agentaccommodation_booking_agent 这两者之一作为结果。

12.2.2 路由逻辑

路由器智能体的核心是它的系统提示词,它以简洁的方式指示 LLM 如何对每个用户请求进行分类:

ROUTER_SYSTEM_PROMPT = (
    """You are a router. Given the following user message, 
    decide if it is a travel information question 
    (about destinations, attractions, or general travel info) """
    """or an accommodation booking question (about hotels, 
    BnBs, room availability, or prices).\n"""
    """If it is a travel information question, 
    respond with 'travel_info_agent'.\n"""
    """If it is an accommodation booking question, 
    respond with 'accommodation_booking_agent'."""
)

借助这个系统提示词,路由器智能体会对每条用户输入进行评估,并决定应由哪个专家智能体接手。路由器被实现为 LangGraph 工作流的入口节点,而旅行信息智能体和住宿预订智能体则作为后续节点。你可以在下面的代码清单中看到路由器的实现。

代码清单 12.3 路由器智能体节点

def router_agent_node(state: AgentState) -> Command[AgentType]:
    """Router node: decides which agent 
    should handle the user query."""
    messages = state["messages"]  #1
    last_msg = messages[-1] if messages else None  #2
    if isinstance(last_msg, HumanMessage):  #3
        user_input = last_msg.content  #4router_messages = [  #5
 … …SystemMessage(content=ROUTER_SYSTEM_PROMPT),
 … …HumanMessage(content=user_input)
 …  ]
        router_response = llm_router.invoke(
 … …router_messages)  #6agent_name = router_response.agent.value  #7
 …  return Command(update=state, 
 … …goto=agent_name)  #8

    return Command(update=state, 
 …  goto=AgentType.travel_info_agent)  #9
#1 从 state 中获取消息
#2 从消息列表中获取最后一条消息
#3 检查最后一条消息是否为 HumanMessage
#4 获取最后一条消息的内容
#5 构造路由消息,包括系统提示词和用户输入
#6 调用路由模型,返回对应的智能体名称
#7 从路由响应中获取智能体名称
#8 返回命令:更新 state 并跳转到对应智能体
#9 如果最后一条消息不是 HumanMessage,则返回命令:更新 state 并默认跳转到 travel_info_agent

如果你仔细查看代码清单 12.3 中的实现,会发现路由器先提取用户消息,再连同系统提示词一起提交给 LLM。LLM 返回一个 AgentTypeOutput 类型的结构化输出,其中包含请求应被路由到的智能体名称。接着,路由器使用一个 Command 将对话流重定向到图中选定的智能体节点。在像本例这样简单的工作流中,Command 可以把未修改的 state 直接交给新节点;而在更复杂的流程中,它也允许对 state 进行更新。

12.2.3 构建多智能体图

到这一步,你已经拥有组装这个基于图的多智能体系统所需的全部组件了。你可以在下面的代码清单中看到图的实现。

代码清单 12.4 基于路由器的多智能体旅行助手图

graph = StateGraph(AgentState)  #1
graph.add_node("router_agent", router_agent_node)  #2
graph.add_node("travel_info_agent", 
    travel_info_agent)  #3
graph.add_node("accommodation_booking_agent", 
    accommodation_booking_agent)  #4

graph.add_edge("travel_info_agent", END)  #5
graph.add_edge("accommodation_booking_agent", END)  #6

graph.set_entry_point("router_agent")  #7
travel_assistant = graph.compile()  #8
#1 定义图
#2 添加路由器智能体节点
#3 添加旅行信息智能体节点
#4 添加住宿预订智能体节点
#5 添加从旅行信息智能体到结束节点的边
#6 添加从住宿预订智能体到结束节点的边
#7 将入口点设置为路由器智能体
#8 编译图

这个工作流图把路由器智能体连接到两个专门化智能体。值得注意的是,你显式定义的边只有两条:从旅行信息智能体到工作流结束节点,以及从住宿预订智能体到工作流结束节点。至于从路由器到专门化智能体的连接,则是在运行时由 LLM 的响应动态决定,并通过 Command 来完成。

图 12.1 展示了当前多智能体旅行助手图的图形化表示。路由器智能体会把用户查询分发到旅行信息智能体或住宿预订智能体中的一个,而这两个智能体都配备了各自的专用工具。

image.png

图 12.1 基于路由器的多智能体旅行助手

正如该图所示,这是一种混合式架构。在上层,系统呈现为一种确定性的、由工作流驱动的路由逻辑;而在下层,每个专门化智能体都使用自己的工具集(例如旅行数据 API 或住宿预订接口),并遵循一种基于工具的决策过程,这本质上更加灵活和动态。

12.2.4 试用路由器智能体

为了看到系统实际运行的效果,请以调试模式启动 main_05_01.py,运行你的多智能体旅行助手,并尝试输入以下两个用户查询:

St Ives 的主要景点有哪些?
这个周末 Penzance 还有房间可订吗?

关于这种设计,有一个很重要的点需要注意:每个用户问题都只会被路由到一个智能体来处理——换句话说,每个查询在工作流中都只会走一张“单程票”。路由器会做出清晰且明确的交接,而被选中的智能体会直接向用户作答,然后工作流结束。例如,当你问:

St Ives(Cornwall)的主要景点有哪些?

该请求会被路由到旅行信息智能体。你可以在图 12.2 中看到相应的 LangSmith 执行 trace。

image.png

图 12.2 一个旅行信息问题的 LangSmith 执行 trace

如果你问:

Penzance 这个周末还有酒店或 BnB 房间可订吗?

系统则会把该查询分发给住宿预订智能体。

在这两种情况下,工作流(见图 12.2)都很清晰:路由器智能体判断意图,并将查询交给最合适的专家智能体,后者处理响应并结束会话。这种模块化、基于图的设计,为更高级的工作流奠定了坚实基础。在后续章节中,你将看到如何将这个系统演进为能够处理更复杂、多步骤,甚至协作式智能体场景的架构。

12.3 使用 Supervisor 组件处理多智能体请求

我们在上一节中开发的基于工作流的多智能体架构,对于简单的、单一目的的查询效果很好——也就是那些可以明确路由到旅行信息智能体或住宿预订智能体之一的问题。但如果用户提出的是一个横跨两个领域的请求,又该怎么办?在此前基于路由器的设计中,像下面这样的问题就无法被有效回答:

“你能找一个康沃尔海边、现在天气不错的小镇,并帮我查一下那个镇上一间双人酒店房的可用性和价格吗?”

因为这个问题需要两个智能体共同工作,并共享中间结果。

为了解决这个问题,我们需要将架构转向一种更加灵活、更加协作的智能体系统——一种由更高层管理者来协调多个专门化智能体,并把它们作为子工具使用的系统。在 LangGraph 中,这正是 Supervisor 的用武之地:它是一个内置组件,专门用于编排多个智能体,使它们能够协作处理复杂请求。

12.3.1 Supervisor 模式:智能体中的智能体

从概念上讲,Supervisor 是一个“智能体的智能体”:它充当编排者,管理一组其他智能体(这些智能体本身也可能使用工具),并决定激活哪一个智能体,而且在单个工作流中可能会多次激活。每个智能体都像是一个专门化工具,Supervisor 可以按需调用它们。下面我们来看如何在你的多智能体旅行助手中设置这种模式。首先,将你之前的一个实现版本 main_04_01.py 复制为一个新脚本 main_06_01.py。接着,安装所需的包:

pip install langgraph-supervisor

然后,导入 Supervisor:

from langgraph_supervisor.supervisor import create_supervisor

在定义由 Supervisor 管理的智能体时,为每个智能体分配一个唯一名称非常重要。你可以在下面的代码清单中看到如何为智能体命名并实例化。

代码清单 12.5 设置叶子智能体

travel_info_agent = create_react_agent(
    model=llm_model,
    tools=TOOLS,
    state_schema=AgentState,
    name="travel_info_agent",
    prompt="""You are a helpful assistant that can search 
    travel information and get the weather forecast. 
    Only use the tools to find the information you 
    need (including town names).""",
)

accommodation_booking_agent = create_react_agent( 
    model=llm_model,
    tools=BOOKING_TOOLS,
    state_schema=AgentState,
    name="accommodation_booking_agent",
    prompt="""You are a helpful assistant that can check 
    hotel and BnB room availability and price for a 
    destination in Cornwall. You can use the tools 
    to get the information you need. If the user 
    does not specify the accommodation type, you 
    should check both hotels and BnBs.""",
)

现在,你就可以按照下面的代码清单,将旅行助手实现为一个 Supervisor。

代码清单 12.6 设置 Supervisor 智能体

travel_assistant = create_supervisor(  #1
    agents=[travel_info_agent, 
        accommodation_booking_agent],  #2
    model= ChatOpenAI(model="gpt-5", 
        use_responses_api=True),  #3
    supervisor_name="travel_assistant",
    prompt=(  #4
        """You are a supervisor that manages two agents: 
        a travel information agent and an accommodation booking agent. """
        """You can answer user questions that might require 
        calling both agents when needed. """
        """Decide which agent(s) to use for each user request 
        and coordinate their responses."""
    )
).compile()  #5
#1 创建 Supervisor
#2 定义将被 Supervisor 使用的智能体
#3 定义 Supervisor 所使用的 LLM,宜使用 GPT-5 这类高阶模型
#4 定义 Supervisor 的提示词(系统提示词),用于引导其行为
#5 编译 Supervisor,本质上它是一个 LangGraph 图

你会注意到,配置一个 Supervisor 和设置一个 ReAct 智能体很相似,只不过这里传入的不再是工具列表,而是智能体列表。由于 Supervisor 需要分析复杂的多步骤请求,并协调多个智能体,因此最好使用更强大的 LLM(例如 GPT-5),以最大化准确性和任务拆解能力。

提示 试着为 Supervisor 使用不同模型,例如 GPT-5,并比较助手在处理越来越复杂、越来越多面的问题时的表现差异。

和之前的设计一样,你只需要更新聊天循环,让其调用基于 Supervisor 的旅行助手即可:

result = travel_assistant.invoke(state)

12.3.2 从“单程票”到“往返票”的交互

与基于工作流的路由器不同——在那里,每个用户问题只会被路由一次,并且只会被交给某一个特定智能体处理(单程票)——Supervisor 能够实现更加丰富的交互。Supervisor 可以根据需要调用各个智能体,甚至在一次会话中多次重新访问某些智能体(往返票),以收集、整合并推理中间结果。这使系统能够处理更复杂、更开放以及由多个部分组成的查询。

在图 12.3 中,你可以看到一个表示这种基于 Supervisor 的架构的图示,在该架构中,无论是高层(Supervisor)还是低层(Agent/Tool)的编排都遵循基于工具的方法,从而最大程度地提升灵活性和可组合性。Supervisor 成为中央决策者,确保在每一个复杂的旅行请求中,都能激活正确的智能体(或正确的智能体序列)。

image.png

图 12.3 路由器智能体将用户查询分发给旅行信息智能体或住宿预订智能体,每个智能体都配备了各自的专用工具。

这种由 Supervisor 驱动的架构,开启了多智能体协作的新层级,为构建更高级、更开放式的 AI 旅行助手奠定了基础,使其能够处理真实世界中多步骤的需求。

12.3.3 试用 Supervisor 智能体

现在,以调试模式启动 main_06_01.py(并启用 LangSmith tracing),运行你的旅行助手,然后输入一个复杂的、多部分问题,例如:

UK Travel Assistant (type 'exit' to quit)
You: Can you find a nice seaside Cornwall town with good weather right now and find availability and price for one double hotel room in that town?

当你查看 LangSmith trace 时,你会注意到一个更加复杂的智能体调用轨迹,类似于图 12.4 所示,其中 travel_assistant 就是 Supervisor 智能体。

image.png

图 12.4 一个组合型旅行信息与预订问题的 LangSmith 执行 trace

下面我总结了该执行 trace 中的关键步骤,以便你更好地理解整个流程(请记住,travel_assistant 就是 Supervisor):

travel assistant
tools
transfer_to_travel_info_agent
travel_info_agent
tools
search_travel_info
tools
weather_forecast
travel_assistant
tools
transfer_to_accommodation_booking_agent
accommodation_booking_agent
tools
check_bnb_availability
tools
sql_db_query

这表明,基于 Supervisor 的旅行助手能够协调两个智能体,根据需要使用它们及其底层工具,从而完整回答用户的问题。从技术上讲,智能体现在是以工具的形式被编排的,而 Supervisor 则动态管理这种协作过程。

总结

  • 智能体工具不仅可以扩展信息检索能力,还可以执行具体动作。它们可以查询 SQL 数据库中的客户记录、发送电子邮件、创建 Jira 工单,或通过券商 API 执行交易指令。

  • 路由器智能体使用基于 LLM 的分类机制对进入的查询进行分类,并将其委派给专门化智能体。比如,一个客服路由器会把账单问题转给计费智能体,把技术问题转给技术支持智能体。

  • Supervisor 智能体通过将复杂请求拆解为子任务来协调多智能体工作流。比如,一个研究型 Supervisor 可能会把网页搜索分配给一个智能体,把数据库查询交给另一个智能体,再把综合归纳交给第三个智能体。

  • LangSmith trace 会展示决策树。它会显示哪个智能体接收了每个查询、调用了哪些工具、中间结果是什么,以及最终是如何交接给其他智能体或返回给用户的。这使得识别瓶颈成为可能,例如工具调用过慢,或者某些智能体在特定查询类型上选择了错误工具。

  • 多智能体系统需要为每个智能体精心设计提示词。每个智能体都应该有清晰定义的职责范围、工具列表,以及它应处理哪些查询的示例。

  • 路由器智能体应当包含针对边界情况(例如模糊查询)的明确判定标准。应定义默认路由,或者在分类置信度低于某个阈值时请求澄清。

  • Supervisor 智能体需要了解各专门化智能体的能力。应在 Supervisor 的规划提示词中提供每个专门化智能体的工具列表和能力描述。

  • 当智能体之间传递数据时,应使用结构化格式(JavaScript Object Notation,JSON),而不是自然语言。解析非结构化的智能体间通信会提高错误率。

  • 要创建一个支持工具调用的路由器,可以把“路由”定义为一个工具,由 LLM 根据查询分类结果选择要调用的专门化智能体。

  • 在实现 Supervisor 模式时,Supervisor 智能体拥有可调用其他智能体的工具。每个专门化智能体都会被包装成一个工具,供 Supervisor 调用。

  • 为了在状态中追踪智能体交接过程,可以在状态对象中加入 current_agentagent_history 字段,用于记录工作流每一步是由哪个智能体处理的。

  • 为了测试路由准确率,可以创建一个带标签的数据集,其中包含查询及其正确的智能体分配结果,测量分类准确率,并基于错误分析调整路由逻辑。

  • Supervisor 模式更进一步,它负责编排智能体之间的协作,因此可以让多个智能体共同回答复杂的、多部分问题。

  • 借助 LangSmith 进行追踪和调试,可以让你清楚看到智能体决策与工具使用情况,从而更容易优化和扩展你的系统。