大多数用例都会从单个 Agent开始,但随着工具数量的增加,以及你希望 Agent 解决的问题范围扩大,引入多 Agent 模式可以提升整体性能与可靠性。正如我们不太会把所有代码都放在一个文件里,或把所有后端服务捆在一个单体里一样,在构建包含 AI 与基础模型的系统时,许多关于软件架构与服务设计的经验仍然适用。随着你不断为 Agent 系统添加功能与能力,你很快会发现需要把系统拆分为更小的 Agent,它们可以被独立验证、测试、集成与复用。本章将讨论何时以及如何为你的系统新增 Agent,以及如何组织与管理它们。
我需要多少个 Agent?
从简单入手,只在需要提升性能时再增加复杂度。合适的 Agent 数量与组织方式,会因任务难度、工具数量、以及环境复杂度的不同而有很大差异。
单 Agent 场景
我们从单 Agent 系统讲起:它适用于中等难度的任务、有限数量的工具、以及较低复杂度的环境。当延迟敏感时,它也往往更好,因为多 Agent 系统通常需要 Agent 之间的多轮交互,这会增加用户端的延迟。因此,通常的最佳实践是先从单 Agent 开始:它往往比扩展到多 Agent 更快也更省钱。在这种方式中,一个 Agent 负责调用可用的工具(有上限),然后再向用户回应。也就是说,Agent 执行任务并自行决定何时调用工具或直接给出答案。其主要优势包括:
简单性
— 更易实现与管理
资源占用更少
— 更低的计算开销
时延更低
— 给用户更快的响应
单 Agent 系统是构建 Agent 应用的有力起点。凭借其简单、低成本与低延迟,它非常适合许多实际场景——尤其当任务范围有限且性能要求严格时。尽管它在应对高度复杂或多面向的任务时可能扩展性不足,但从单 Agent 架构起步可以让团队快速验证核心功能并高效迭代。只有当复杂度、工具集或任务协同需求超出单 Agent 的承载能力时,开发者才应考虑演进到更复杂的多 Agent 系统。
举例而言,设想一个用于供应链物流管理的单 Agent 系统。该 Agent 通过一个统一的提示与图(graph)处理库存、运输与供应商等多类工具。对于基础查询它表现良好,但当工具过多时,性能可能下降,因为 Agent 需要从一个很大的集合中选择合适的工具。下面展示了如何用16 个工具搭建一个单 Agent:
from __future__ import annotations
"""
supply_chain_logistics_agent.py
LangGraph workflow for a Supply Chain & Logistics Management agent,
handling inventory management, shipping operations, supplier relations, 
and warehouse optimization.
"""
import os
import json
import operator
import builtins
from typing import Annotated, Sequence, TypedDict, Optional
from langchain_openai.chat_models import ChatOpenAI
from langchain.schema import AIMessage, BaseMessage, HumanMessage, SystemMessage
from langchain_core.messages.tool import ToolMessage
from langchain.callbacks.streaming_stdout import StreamingStdOutCallbackHandler
from langchain.tools import tool
from langgraph.graph import StateGraph, END
from traceloop.sdk import Traceloop
from src.common.observability.loki_logger import log_to_loki
os.environ["OTEL_EXPORTER_OTLP_ENDPOINT"] = "http://localhost:4317"
os.environ["OTEL_EXPORTER_OTLP_INSECURE"] = "true"
@tool
def manage_inventory(sku: str = None, **kwargs) -> str:
   """Manage inventory levels, stock replenishment, audits, 
   and optimization strategies."""
   print(f"[TOOL] manage_inventory(sku={sku}, kwargs={kwargs})")
   log_to_loki("tool.manage_inventory", f"sku={sku}")
   return "inventory_management_initiated"
@tool
def track_shipments(origin: str = None, **kwargs) -> str:
   """Track shipment status, delays, and coordinate delivery logistics."""
   print(f"[TOOL] track_shipments(origin={origin}, kwargs={kwargs})")
   log_to_loki("tool.track_shipments", f"origin={origin}")
   return "shipment_tracking_updated"
@tool
def evaluate_suppliers(supplier_name: str = None, **kwargs) -> str:
   """Evaluate supplier performance, conduct audits, 
   and manage supplier relationships."""
   print(f"[TOOL] evaluate_suppliers(supplier_name={supplier_name}, 
         kwargs={kwargs})")
   log_to_loki("tool.evaluate_suppliers", f"supplier_name={supplier_name}")
   return "supplier_evaluation_complete"
@tool
def optimize_warehouse(operation_type: str = None, **kwargs) -> str:
   """Optimize warehouse operations, layout, capacity, and storage efficiency."""
   print(f"[TOOL] optimize_warehouse(operation_type={operation_type}, 
         kwargs={kwargs})")
   log_to_loki("tool.optimize_warehouse", f"operation_type={operation_type}")
   return "warehouse_optimization_initiated"
@tool
def forecast_demand(season: str = None, **kwargs) -> str:
   """Analyze demand patterns, seasonal trends, and create forecasting models."""
   print(f"[TOOL] forecast_demand(season={season}, kwargs={kwargs})")
   log_to_loki("tool.forecast_demand", f"season={season}")
   return "demand_forecast_generated"
@tool
def manage_quality(supplier: str = None, **kwargs) -> str:
   """Manage quality control, defect tracking, and supplier quality standards."""
   print(f"[TOOL] manage_quality(supplier={supplier}, kwargs={kwargs})")
   log_to_loki("tool.manage_quality", f"supplier={supplier}")
   return "quality_management_initiated"
@tool
def arrange_shipping(shipping_type: str = None, **kwargs) -> str:
   """Arrange shipping methods, expedited delivery, 
   and multi-modal transportation."""
   print(f"[TOOL] arrange_shipping(shipping_type={shipping_type}, 
         kwargs={kwargs})")
   log_to_loki("tool.arrange_shipping", f"shipping_type={shipping_type}")
   return "shipping_arranged"
@tool
def coordinate_operations(operation_type: str = None, **kwargs) -> str:
   """Coordinate complex operations like cross-docking, consolidation, 
   and transfers."""
   print(f"[TOOL] coordinate_operations(operation_type={operation_type}, 
         kwargs={kwargs})")
   log_to_loki("tool.coordinate_operations", f"operation_type={operation_type}")
   return "operations_coordinated"
@tool
def manage_special_handling(product_type: str = None, **kwargs) -> str:
   """Handle special requirements for hazmat, cold chain, and 
   sensitive products."""
   print(f"[TOOL] manage_special_handling(product_type={product_type}, 
         kwargs={kwargs})")
   log_to_loki("tool.manage_special_handling", f"product_type={product_type}")
   return "special_handling_managed"
@tool
def handle_compliance(compliance_type: str = None, **kwargs) -> str:
   """Manage regulatory compliance, customs, documentation, 
   and certifications."""
   print(f"[TOOL] handle_compliance(compliance_type={compliance_type}, 
         kwargs={kwargs})")
   log_to_loki("tool.handle_compliance", f"compliance_type={compliance_type}")
   return "compliance_handled"
@tool
def process_returns(returned_quantity: str = None, **kwargs) -> str:
   """Process returns, reverse logistics, and product disposition."""
   print(f"[TOOL] process_returns(returned_quantity={returned_quantity}, 
         kwargs={kwargs})")
   log_to_loki("tool.process_returns", f"returned_quantity={returned_quantity}")
   return "returns_processed"
@tool
def scale_operations(scaling_type: str = None, **kwargs) -> str:
   """Scale operations for peak seasons, capacity planning, 
   and workforce management."""
   print(f"[TOOL] scale_operations(scaling_type={scaling_type}, 
         kwargs={kwargs})")
   log_to_loki("tool.scale_operations", f"scaling_type={scaling_type}")
   return "operations_scaled"
@tool
def optimize_costs(cost_type: str = None, **kwargs) -> str:
   """Analyze and optimize transportation, storage, and operational costs."""
   print(f"[TOOL] optimize_costs(cost_type={cost_type}, kwargs={kwargs})")
   log_to_loki("tool.optimize_costs", f"cost_type={cost_type}")
   return "cost_optimization_initiated"
@tool
def optimize_delivery(delivery_type: str = None, **kwargs) -> str:
   """Optimize delivery routes, last-mile logistics, 
   and sustainability initiatives."""
   print(f"[TOOL] optimize_delivery(delivery_type={delivery_type}, 
         kwargs={kwargs})")
   log_to_loki("tool.optimize_delivery", f"delivery_type={delivery_type}")
   return "delivery_optimization_complete"
@tool
def manage_disruption(disruption_type: str = None, **kwargs) -> str:
   """Manage supply chain disruptions, contingency planning, 
   and risk mitigation."""
   print(f"[TOOL] manage_disruption(disruption_type={disruption_type}, 
         kwargs={kwargs})")
   log_to_loki("tool.manage_disruption", f"disruption_type={disruption_type}")
   return "disruption_managed"
@tool
def send_logistics_response(operation_id: str = None, message: str = None):
   """Send logistics updates, recommendations, or status reports 
   to stakeholders."""
   print(f"[TOOL] send_logistics_response → {message}")
   log_to_loki("tool.send_logistics_response", f"operation_id={operation_id}, 
              message={message}")
   return "logistics_response_sent"
TOOLS = [
   manage_inventory, track_shipments, evaluate_suppliers, optimize_warehouse,
   forecast_demand, manage_quality, arrange_shipping, coordinate_operations,
   manage_special_handling, handle_compliance, process_returns, scale_operations,
   optimize_costs, optimize_delivery, manage_disruption, send_logistics_response
]
这些工具覆盖了供应链 Agent 的核心职能,从追踪运输到需求预测,再到应对中断。用 LangChain 的 @tool 装饰器定义它们,使 Agent 能根据用户查询动态调用。这个设置很直接,无需复杂协同——Agent 分析提示并选择合适的工具。例如,一个基础的 Agent 可以按顺序调用 manage_inventory 与 forecast_demand 来处理库存短缺,后面执行流程会看到。
然而,随着工具集扩大(此处达 16 个),Agent 的系统提示必须描述所有可能性,这可能导致混淆或次优选择。此时单 Agent 模式的局限开始显现,也就为多 Agent 分解铺平了道路。下面完成 Agent 的基础模型绑定、状态定义与图构建:
Traceloop.init(disable_batch=True, app_name="supply_chain_logistics_agent")
llm = ChatOpenAI(model="gpt-5", temperature=0.0, 
                callbacks=[StreamingStdOutCallbackHandler()], 
                verbose=True).bind_tools(TOOLS)
class AgentState(TypedDict):
   operation: Optional[dict]  # Supply chain operation information
   messages: Annotated[Sequence[BaseMessage], operator.add]
def call_model(state: AgentState):
   history = state["messages"]
  
   # Handle missing or incomplete operation data gracefully
   operation = state.get("operation", {})
   if not operation:
       operation = {"operation_id": "UNKNOWN", "type": "general", 
           "priority": "medium", "status": "active"}
  
   operation_json = json.dumps(operation, ensure_ascii=False)
   system_prompt = (
       "You are an experienced Supply Chain & Logistics professional.\n"
       "Your expertise covers:\n"
       "- Inventory management and demand forecasting\n"
       "- Transportation and shipping optimization\n"
       "- Supplier relationship management and evaluation\n"
       "- Warehouse operations and capacity planning\n"
       "- Quality control and compliance management\n"
       "- Cost optimization and operational efficiency\n"
       "- Risk management and disruption response\n"
       "- Sustainability and green logistics initiatives\n"
       "\n"
       "When managing supply chain operations:\n"
       "  1) Analyze the logistics challenge or opportunity\n"
       "  2) Call the appropriate supply chain management tool\n"
       "  3) Follow up with send_logistics_response to provide recommendations\n"
       "  4) Consider cost, efficiency, quality, and sustainability impacts\n"
       "  5) Prioritize customer satisfaction and business continuity\n"
       "\n"
       "Always balance cost with quality and risk mitigation.\n"
       f"OPERATION: {operation_json}"
   )
   full = [SystemMessage(content=system_prompt)] + history
   first: ToolMessage | BaseMessage = llm.invoke(full)
   messages = [first]
   if getattr(first, "tool_calls", None):
       for tc in first.tool_calls:
           print(first)
           print(tc['name'])
           fn = next(t for t in TOOLS if t.name == tc['name'])
           out = fn.invoke(tc["args"])
           messages.append(ToolMessage(content=str(out), tool_call_id=tc["id"]))
       second = llm.invoke(full + messages)
       messages.append(second)
   return {"messages": messages}
def construct_graph():
   g = StateGraph(AgentState)
   g.add_node("assistant", call_model)
   g.set_entry_point("assistant")
   return g.compile()
graph = construct_graph()
if __name__ == "__main__":
   example = {"operation_id": "OP-12345", "type": "inventory_management", 
              "priority": "high", "location": "Warehouse A"}
   convo = [HumanMessage(content="We're running critically low on SKU-12345. 
   Current stock is 50 units but we have 200 units on backorder. What's our 
   reorder strategy?")]
   result = graph.invoke({"operation": example, "messages": convo})
   for m in result["messages"]:
       print(f"{m.type}: {m.content}")
随着 Agent 组装完成,我们可以看到单节点 LangGraph 的优雅:状态里保存操作信息与消息,模型调用负责分析查询并调用工具,而图本身极简——只有一个 “assistant” 节点。这种结构把开销降到最低,因为不存在跨 Agent 的通信。在实践中,正如 2025 年的 LangGraph 供应链教程所展示的,这样的设置在标准硬件上可在不到一秒内处理查询,非常适合运营看板或实时告警。
不过在大多数用例中,关键瓶颈出现在工具与职责数量增加时。当 Agent 需要在大量工具中选择正确的一个,潜在选择空间增大就会拖累性能。在转向多 Agent 之前,先考虑在单 Agent 框架内扩展:例如,把多个工具封装为更大的分组(如分层式工具选择);或使用向量数据库做语义工具选择(见第 5 章编排)。如果这些方法仍然不足,再将工具按职责拆分为不同的 Agent,通常可以提升可靠性与性能,但也会引入协调开销。
多 Agent 场景
在多 Agent 系统中,多个 Agent 协同完成共同目标。这种方法在任务复杂且需要多样化工具集、并行处理或对动态环境具备适应性时尤为有利。多 Agent 系统的一个关键好处是专业化:可以为每个 Agent 分配特定的角色或专长领域,从而有效发挥各自的优势。这种分工让 Agent 聚焦于任务的明确方面,提升效率,并确保在最需要的地方应用专用工具。通过把工具与职责分散到各个 Agent,多 Agent 系统可以应对单 Agent 所面临的局限,尤其是当任务跨越不同领域的专业知识、或者所需工具数量超过单个 Agent 可可靠管理的范围时。
基于上一小节的单 Agent 供应链示例,我们把它演进为多 Agent 系统。这里,我们将 16 个工具拆分给三个专长 Agent:一个负责库存与仓储管理,一个负责运输与物流,一个负责供应商关系与合规。一个监督(supervisor)Agent负责把查询路由给合适的专家,这正体现了“经理式协调”(详见“Manager Coordination”)。这种设置通过收窄每个 Agent 的工具集与提示词,展现专业化,减少选择错误并提升可靠性。代码从导入与一个共享的响应工具开始,确保所有专家都能以统一方式对外沟通结果。这个共享工具在允许分散执行的同时,减少了重复:
import os
import json
import operator
from typing import Annotated, Sequence, TypedDict, Optional
from langchain_openai.chat_models import ChatOpenAI
from langchain.schema import AIMessage, BaseMessage, HumanMessage, SystemMessage
from langchain_core.messages.tool import ToolMessage
from langchain.callbacks.streaming_stdout import StreamingStdOutCallbackHandler
from langchain.tools import tool
from langgraph.graph import StateGraph, END
from traceloop.sdk import Traceloop
from src.common.observability.loki_logger import log_to_loki
os.environ["OTEL_EXPORTER_OTLP_ENDPOINT"] = "http://localhost:4317"
os.environ["OTEL_EXPORTER_OTLP_INSECURE"] = "true"
# Shared tool for all specialists
@tool
def send_logistics_response(operation_id = None, message = None):
   """Send logistics updates, recommendations, or status reports to 
   stakeholders."""
   print(f"[TOOL] send_logistics_response → {message}")
   log_to_loki("tool.send_logistics_response", 
               f"operation_id={operation_id}, message={message}")
   return "logistics_response_sent"
# Inventory & Warehouse Specialist Tools
@tool
def manage_inventory(sku: str = None, **kwargs) -> str:
   """Manage inventory levels, stock replenishment, audits, 
   and optimization strategies."""
   print(f"[TOOL] manage_inventory(sku={sku}, kwargs={kwargs})")
   log_to_loki("tool.manage_inventory", f"sku={sku}")
   return "inventory_management_initiated"
@tool
def optimize_warehouse(operation_type: str = None, **kwargs) -> str:
   """Optimize warehouse operations, layout, capacity, and storage efficiency."""
   print(f"[TOOL] optimize_warehouse(operation_type={operation_type}, 
        kwargs={kwargs})")
   log_to_loki("tool.optimize_warehouse", f"operation_type={operation_type}")
   return "warehouse_optimization_initiated"
@tool
def forecast_demand(season: str = None, **kwargs) -> str:
   """Analyze demand patterns, seasonal trends, and create forecasting models."""
   print(f"[TOOL] forecast_demand(season={season}, kwargs={kwargs})")
   log_to_loki("tool.forecast_demand", f"season={season}")
   return "demand_forecast_generated"
@tool
def manage_quality(supplier: str = None, **kwargs) -> str:
   """Manage quality control, defect tracking, and supplier quality standards."""
   print(f"[TOOL] manage_quality(supplier={supplier}, kwargs={kwargs})")
   log_to_loki("tool.manage_quality", f"supplier={supplier}")
   return "quality_management_initiated"
@tool
def scale_operations(scaling_type: str = None, **kwargs) -> str:
   """Scale operations for peak seasons, capacity planning, and 
   workforce management."""
   print(f"[TOOL] scale_operations(scaling_type={scaling_type}, 
        kwargs={kwargs})")
   log_to_loki("tool.scale_operations", f"scaling_type={scaling_type}")
   return "operations_scaled"
@tool
def optimize_costs(cost_type: str = None, **kwargs) -> str:
   """Analyze and optimize transportation, storage, and operational costs."""
   print(f"[TOOL] optimize_costs(cost_type={cost_type}, kwargs={kwargs})")
   log_to_loki("tool.optimize_costs", f"cost_type={cost_type}")
   return "cost_optimization_initiated"
INVENTORY_TOOLS = [manage_inventory, optimize_warehouse, forecast_demand,
manage_quality, scale_operations, optimize_costs, send_logistics_response]
# Transportation & Logistics Specialist Tools
@tool
def track_shipments(origin: str = None, **kwargs) -> str:
   """Track shipment status, delays, and coordinate delivery logistics."""
   print(f"[TOOL] track_shipments(origin={origin}, kwargs={kwargs})")
   log_to_loki("tool.track_shipments", f"origin={origin}")
   return "shipment_tracking_updated"
@tool
def arrange_shipping(shipping_type: str = None, **kwargs) -> str:
   """Arrange shipping methods, expedited delivery, 
   and multi-modal transportation."""
   print(f"[TOOL] arrange_shipping(shipping_type={shipping_type}, 
        kwargs={kwargs})")
   log_to_loki("tool.arrange_shipping", f"shipping_type={shipping_type}")
   return "shipping_arranged"
@tool
def coordinate_operations(operation_type: str = None, **kwargs) -> str:
   """Coordinate complex operations like cross-docking, consolidation, 
   and transfers."""
   print(f"[TOOL] coordinate_operations(operation_type={operation_type}, 
        kwargs={kwargs})")
   log_to_loki("tool.coordinate_operations", f"operation_type={operation_type}")
   return "operations_coordinated"
@tool
def manage_special_handling(product_type: str = None, **kwargs) -> str:
   """Handle special requirements for hazmat, cold chain, 
   and sensitive products."""
   print(f"[TOOL] manage_special_handling(product_type={product_type}, 
        kwargs={kwargs})")
   log_to_loki("tool.manage_special_handling", f"product_type={product_type}")
   return "special_handling_managed"
@tool
def process_returns(returned_quantity: str = None, **kwargs) -> str:
   """Process returns, reverse logistics, and product disposition."""
   print(f"[TOOL] process_returns(returned_quantity={returned_quantity}, 
        kwargs={kwargs})")
   log_to_loki("tool.process_returns", f"returned_quantity={returned_quantity}")
   return "returns_processed"
@tool
def optimize_delivery(delivery_type: str = None, **kwargs) -> str:
   """Optimize delivery routes, last-mile logistics, 
   and sustainability initiatives."""
   print(f"[TOOL] optimize_delivery(delivery_type={delivery_type}, 
        kwargs={kwargs})")
   log_to_loki("tool.optimize_delivery", f"delivery_type={delivery_type}")
   return "delivery_optimization_complete"
@tool
def manage_disruption(disruption_type: str = None, **kwargs) -> str:
   """Manage supply chain disruptions, contingency planning, 
   and risk mitigation."""
   print(f"[TOOL] manage_disruption(disruption_type={disruption_type}, 
        kwargs={kwargs})")
   log_to_loki("tool.manage_disruption", f"disruption_type={disruption_type}")
   return "disruption_managed"
TRANSPORTATION_TOOLS = [track_shipments, arrange_shipping, coordinate_operations, 
    manage_special_handling, process_returns, optimize_delivery, 
    manage_disruption, send_logistics_response]
# Supplier & Compliance Specialist Tools
@tool
def evaluate_suppliers(supplier_name: str = None, **kwargs) -> str:
   """Evaluate supplier performance, conduct audits, 
   and manage supplier relationships."""
   print(f"[TOOL] evaluate_suppliers(supplier_name={supplier_name}, 
        kwargs={kwargs})")
   log_to_loki("tool.evaluate_suppliers", f"supplier_name={supplier_name}")
   return "supplier_evaluation_complete"
@tool
def handle_compliance(compliance_type: str = None, **kwargs) -> str:
   """Manage regulatory compliance, customs, documentation, 
   and certifications."""
   print(f"[TOOL] handle_compliance(compliance_type={compliance_type}, 
        kwargs={kwargs})")
   log_to_loki("tool.handle_compliance", f"compliance_type={compliance_type}")
   return "compliance_handled"
SUPPLIER_TOOLS = [evaluate_suppliers, handle_compliance, send_logistics_response]
Traceloop.init(disable_batch=True, app_name="supply_chain_logistics_agent")
llm = ChatOpenAI(model="gpt-4o", temperature=0.0, 
    callbacks=[StreamingStdOutCallbackHandler()], verbose=True)
# Bind tools to specialized LLMs
inventory_llm = llm.bind_tools(INVENTORY_TOOLS)
transportation_llm = llm.bind_tools(TRANSPORTATION_TOOLS)
supplier_llm = llm.bind_tools(SUPPLIER_TOOLS)
随着工具分组,我们把它们分别绑定到各自专家的语言模型实例。这允许为每个专家定制提示词,并缩小每个 Agent 的上下文规模,从而提升聚焦度与效率。这样的多 Agent 架构可以实现并行处理(例如,一个 Agent 优化配送的同时,另一个在评估供应商),在高吞吐物流场景下降低响应时间。共享的状态确保无缝交接。
监督节点作为中央协调者,分析查询并路由给专家——体现了在不引入“全体共识”开销的情况下做出精简决策。各专家节点随后独立处理,调用工具并给出响应。该结构通过清晰的角色边界缓解冲突,并在需要时通过扩展边实现并行:
class AgentState(TypedDict):
   operation: Optional[dict]  # Supply chain operation information
   messages: Annotated[Sequence[BaseMessage], operator.add]
# Supervisor (Manager) Node: Routes to the appropriate specialist
def supervisor_node(state: AgentState):
   history = state["messages"]
   operation = state.get("operation", {})
   operation_json = json.dumps(operation, ensure_ascii=False)
  
   supervisor_prompt = (
       "You are a supervisor coordinating a team of supply chain specialists.\n"
       "Team members:\n"
       "- inventory: Handles inventory levels, forecasting,\n"
       "quality, warehouse optimization, scaling, and costs.\n"
       "- transportation: Handles shipping tracking,\n"
       "arrangements, operations coordination,\n"
        specialhandling, returns, delivery optimization, and disruptions.\n"
       "- supplier: Handles supplier evaluation and compliance.\n"
       "\n"
       "Based on the user query, select ONE team member to handle it.\n"
       "Output ONLY the selected member's name\n"
       "(inventory, transportation, or supplier), nothing else.\n\n"
       f"OPERATION: {operation_json}"
   )
   full = [SystemMessage(content=supervisor_prompt)] + history
   response = llm.invoke(full)
   return {"messages": [response]}
# Specialist Node Template
def specialist_node(state: AgentState, specialist_llm, system_prompt: str):
   history = state["messages"]
   operation = state.get("operation", {})
   if not operation:
       operation = {"operation_id": "UNKNOWN", "type": "general",   
           "priority": "medium", "status": "active"}
   operation_json = json.dumps(operation, ensure_ascii=False)
   full_prompt = system_prompt + f"\n\nOPERATION: {operation_json}"
  
   full = [SystemMessage(content=full_prompt)] + history
   first: ToolMessage | BaseMessage = specialist_llm.invoke(full)
   messages = [first]
   if getattr(first, "tool_calls", None):
       for tc in first.tool_calls:
           print(first)
           print(tc['name'])
           # Find the tool (assuming tools are unique by name across all)
           all_tools = INVENTORY_TOOLS + TRANSPORTATION_TOOLS + SUPPLIER_TOOLS
           fn = next(t for t in all_tools if t.name == tc['name'])
           out = fn.invoke(tc["args"])
           messages.append(ToolMessage(content=str(out), tool_call_id=tc["id"]))
       second = specialist_llm.invoke(full + messages)
       messages.append(second)
   return {"messages": messages}
# Inventory Specialist Node
def inventory_node(state: AgentState):
   inventory_prompt = (
       "You are an inventory and warehouse management specialist.\n"
       "When managing:\n"
       "  1) Analyze the inventory/warehouse challenge\n"
       "  2) Call the appropriate tool\n"
       "  3) Follow up with send_logistics_response\n"
       "Consider cost, efficiency, and scalability."
   )
   return specialist_node(state, inventory_llm, inventory_prompt)
# Transportation Specialist Node
def transportation_node(state: AgentState):
   transportation_prompt = (
       "You are a transportation and logistics specialist.\n"
       "When managing:\n"
       "  1) Analyze the shipping/delivery challenge\n"
       "  2) Call the appropriate tool\n"
       "  3) Follow up with send_logistics_response\n"
       "Consider efficiency, sustainability, and risk mitigation."
   )
   return specialist_node(state, transportation_llm, transportation_prompt)
# Supplier Specialist Node
def supplier_node(state: AgentState):
   supplier_prompt = (
       "You are a supplier relations and compliance specialist.\n"
       "When managing:\n"
       "  1) Analyze the supplier/compliance issue\n"
       "  2) Call the appropriate tool\n"
       "  3) Follow up with send_logistics_response\n"
       "Consider performance, regulations, and relationships."
   )
   return specialist_node(state, supplier_llm, supplier_prompt)
最后,通过带有条件边的图把系统装配起来,使监督者能根据查询进行动态选择并路由。这在执行中让系统可高效处理多样任务,而不会在单点上过载。尽管协调会带来一些时延,但对复杂环境而言,可扩展性与可靠性的收益远大于成本:
# Routing function for conditional edges
def route_to_specialist(state: AgentState):
   last_message = state["messages"][-1]
   agent_name = last_message.content.strip().lower()
   if agent_name == "inventory":
       return "inventory"
   elif agent_name == "transportation":
       return "transportation"
   elif agent_name == "supplier":
       return "supplier"
   else:
       # Fallback if no match
       return END
def construct_graph():
   g = StateGraph(AgentState)
   g.add_node("supervisor", supervisor_node)
   g.add_node("inventory", inventory_node)
   g.add_node("transportation", transportation_node)
   g.add_node("supplier", supplier_node)
  
   g.set_entry_point("supervisor")
   g.add_conditional_edges("supervisor", route_to_specialist,
    {"inventory": "inventory", "transportation": 
    "transportation", "supplier": "supplier"})
  
   g.add_edge("inventory", END)
   g.add_edge("transportation", END)
   g.add_edge("supplier", END)
  
   return g.compile()
graph = construct_graph()
if __name__ == "__main__":
   example = {"operation_id": "OP-12345", "type": "inventory_management", 
              "priority": "high", "location": "Warehouse A"}
   convo = [HumanMessage(content='''We're running critically
     low on SKU-12345. Current stock is 50 units 
     but we have 200 units on backorder. What's our reorder  
     strategy?''')]
   result = graph.invoke({"operation": example, "messages": convo})
   for m in result["messages"]:
       print(f"{m.type}: {m.content}")
这个多 Agent 框架展现了适应性在实际中的力量。举例来说,如果一个查询涉及旺季期间的突发供应中断,监督者可以把请求路由给运输专家以便立刻遏制影响,同时库存专家并行地扩容仓储作业。这类动态重路由已相当常见,使系统能根据天气事件或市场波动等实时数据快速转向,从而把停机时间降到最低并优化资源分配。在我们的代码中,条件边提供了这种灵活性:监督者的输出决定了后续流程,使系统无需僵化的预定义路径也能应对不断演变的状况。这不仅通过潜在的并行(例如扩展为同时分叉到多个专家)提高吞吐量,也增强了韧性,因为某个 Agent 的失败(如某个 API 宕机)不会拖垮整个流程。
适应性是另一个核心优势:多 Agent 系统可以对变化的条件动态响应。通过协调行动,各 Agent 可以按需重新分配角色与职责,实时适应新的信息或环境变化。这让系统在复杂且不可预期的场景中依然高效、有效,而静态的单 Agent 方法可能难以跟上。
不过,多 Agent 系统也并非没有挑战。随着多个 Agent 交互,协调复杂度上升,需要更复杂的通信与同步机制来确保协同一致。通信开销也是一大挑战:Agent 需要频繁交换信息以保持一致、避免重复劳动;这会拖慢系统并增加资源消耗,尤其是在大规模应用中。此外,如果 Agent 追求的目标有重叠或未能有效排序,冲突也可能出现,需要制定冲突解决与资源分配的协议。
总之,尽管多 Agent 系统在处理复杂、复合任务方面具有强大优势,但也需要谨慎规划以管理它带来的额外复杂度与协调需求。通过为 Agent 分派清晰的角色、启用并行处理,并引入适应性与冗余,多 Agent 系统在单 Agent 难以胜任的场景中,能够实现高性能、可靠性与灵活性。
群智(Swarms)
“群智”是一种独特的 Agent 系统设计思路,灵感来自自然界中的去中心化系统——例如鸟群、鱼群或蚁群。在基于群智的系统中,大量简单的 Agent各自只具备极少的个体智能,但通过局部交互与简单规则的叠加,集体会涌现出智能的整体行为。
与常见的多 Agent 系统(往往依赖明确的角色分配和集中式协调)不同,群智系统强调去中心化与自组织。每个 Agent 仅遵循自身的一组本地策略或行为,通常并不具备系统的全局视角。然而,通过反复的局部交互——例如广播小规模更新、对邻居做出反应、或根据共享信号自适应——群体能够适应变化、解决复杂问题,并表现出稳健的群体级行为。群智系统的关键优势包括:
可扩展性
由于群体中的 Agent 松耦合且由本地驱动,系统可以在只需极少协调开销的情况下扩展到数百甚至上千个 Agent。
鲁棒性
没有单点故障。即便某些 Agent 失效,其他 Agent 仍可继续运行,整体性能不会显著劣化。
灵活性
群智能够实时适应目标或环境的变化,因而非常适合动态或不可预测的场景。
分布式问题求解
诸如探索、监测、形成共识或分布式搜索等任务,可以通过群体动力学被有效地推进。
群智在集中式控制不切实际或并不可取的环境中尤其有效。例如,它适用于大规模数据发现、跨多源的研究,或分布式决策。在这些场景中,Agent 可以半独立地运行,贡献细小的洞见或动作,并让整体行为从无数本地行动的累积中自发涌现。
然而,构建群智系统也带来独特挑战,尤其体现在可预测性、可观测性与效率方面。尽管存在这些限制,群智为那些受益于去中心化、并行性与弹性的问题提供了一种强大而优雅的解决方案。虽然它并不适用于所有领域,但在分布式环境中表现突出,并在边缘计算、传感器网络、实时协作系统等领域日益重要——特别是在灵活性与稳健性比精确度或中心化控制更重要的场合。
增加 Agent 的原则(Principles for Adding Agents)
在通过新增 Agent 扩展系统时,需要采取战略性的方法,确保系统依旧高效、可管理且有效。以下原则可作为优化基于 Agent 的设计与功能性的指南:
任务分解(Task decomposition)
任务分解是基础性原则,强调将复杂任务拆解为更小、可管理的子任务。通过分解,每个 Agent 可以聚焦于工作负载的特定方面,简化职责并提升效率。清晰的任务边界可减少重叠与冗余,确保每个 Agent 的贡献都有价值且不被浪费。这样的分解不仅提升单个 Agent 的性能,也让系统更易协调与扩展。
专业化(Specialization)
专业化使 Agent 能被分派到与其优势相匹配的角色,从而最大化系统的整体能力。当每个 Agent 执行与其特定功能相契合的活动时,系统运行将更为精准与高效。专门化的 Agent 更擅长处理特定类型的工作,这会转化为整体性能的提升与更快的任务执行。通过为 Agent 设计明确且独立的职责,系统可利用多样化的专长来应对复杂或跨学科任务。
简约性(Parsimony)
简约性是指导原则,鼓励仅添加达到所需功能与性能所必需的最少数量的 Agent。该原则强调简单与高效,并提醒开发者:每增加一个 Agent,都会带来额外的通信开销、协调复杂度与资源需求。遵循简约性可避免不必要的 Agent 膨胀,从而减少维护负担与潜在的性能瓶颈。实行简约性需要对每个 Agent 的角色进行谨慎评估,并以自律的方式进行资源分配,确保每一次新增都为系统带来明确价值。在添加 Agent 之前,应考虑其职责是否可由现有 Agent 承担或通过增强当前能力来实现。聚焦于简洁可带来更为精炼、易管理且高效的系统,在最大化功能的同时,将由复杂性带来的风险与成本最小化。
协调(Coordination)
协调对于多 Agent 系统的和谐运行至关重要。为保持 Agent 之间的一致性,必须建立健壮的通信协议,以促进高效的信息共享并降低冲突风险。协调机制还应包含冲突解决的协议,特别是在 Agent 任务或资源需求存在重叠时。当 Agent 能够无缝交换信息并自主解决问题时,系统会更具弹性与适应性,能够高效应对动态情境。
鲁棒性(Robustness)
鲁棒性对于提升容错与韧性至关重要。冗余意味着添加可在其他 Agent 失效时接管的 Agent,提供备援以确保不中断的运行。在高风险环境中,冗余对于维持系统稳定与可靠尤为宝贵。鲁棒性还体现在设计能够承受意外中断(如网络故障或 Agent 宕机)的 Agent 与工作流。通过在系统中嵌入冗余与鲁棒性,开发者可确保其在不利条件下仍能保持功能。
效率(Efficiency)
效率用于评估新增 Agent 与其引入的复杂性或资源需求之间的权衡。每添加一个 Agent 都会增加计算需求与协调开销,因此必须权衡功能扩展带来的好处与这些成本。通过仔细评估每次新增的成本与收益,开发者能做出在系统性能、资源效率与可扩展性之间取得平衡的明智决策。
遵循以上原则,开发者可以确定实现性能、效率与复杂性最佳平衡所需的Agent 数量与配置。这种深思熟虑的方法能够打造既有能力又可持续的多 Agent 系统,在最大化新增 Agent 带来的收益的同时,将潜在负面影响降至最低。
多 Agent 协调(Multiagent Coordination)
在多 Agent 系统中,有效的协调对成功至关重要。可采用多种协同策略,每种都有其优势与挑战。本节将探讨几种主流的协调策略,同时也承认未来可能出现新的方法。
民主式协调(Democratic Coordination)
在民主式协调中,系统中的每个 Agent 都拥有平等的决策权,目标是就行动与方案达成共识。这种方式以去中心化控制为特征,没有单一的“领导”Agent。相反,Agent 彼此协作、等量共享信息,贡献各自的视角以共同形成决策。
其关键优势之一是鲁棒性:由于没有占主导地位的 Agent,系统没有单点故障;即使一个或多个 Agent 发生故障,整体仍可有效运作。另一个优势是灵活性:当 Agent 开放协作时,可以通过更新集体输入来迅速适应环境变化,这在需要对新信息快速响应的动态场景中尤为重要。民主式协调还促进 Agent 之间的公平,确保所有参与者都有平等的话语权,从而可能带来更公正的结果。
然而,民主式协调也有挑战。达成共识往往需要大量通信,带来显著的通信开销;同时,由于每个 Agent 都需表达与博弈,决策过程可能变慢,在需要快速响应的环境中会造成延迟。此外,实施民主式协议通常较复杂,需要明确的通信与冲突解决机制来促进共识构建。尽管如此,民主式协调非常适合优先考虑公平与鲁棒性的应用,如分布式传感网络或协作机器人场景,在这些场景中每个 Agent 的贡献都很宝贵,而共识是系统成功的关键。
经理式协调(Manager Coordination)
经理式协调采用更中心化的方法:指定一个或多个 Agent 作为管理者(manager) ,负责监督与指挥下属 Agent 的行动。在这种模式下,管理者承担监督角色,做出决策、分派任务并在其指导范围内解决冲突。
主要优势是决策高效:因为管理者拥有代表团队做决定的权力,系统可以避免民主系统中冗长的协商过程,从而更高效地运作。中心化还使任务与职责分配清晰,确保 Agent 聚焦于特定目标,避免重复与冲突;同时简化通信路径——下属主要与各自的管理者沟通,而不是与所有 Agent 互通,从而降低协调复杂度。
劣势在于对管理者的依赖带来单点故障风险:一旦管理者失败或被攻破,系统可能出现中断。随着系统规模增长,管理者还可能成为瓶颈,难以处理更高的任务/交互量。最后,中心化决策可能降低适应性:管理者未必总能基于每个下属的实时环境做出最充分的信息化决策。该协调方式在制造系统或客服中心等结构化、层级化场景尤其有效,集中控制可优化流程并加速冲突解决。
分层式协调(Hierarchical Coordination)
分层式协调采用多层架构,在结构化层级中结合了中心化与去中心化要素。系统将 Agent 组织为多个层级,上层 Agent 监督并指挥下层,同时赋予下层一定的自主性。
这种方法带来显著的可扩展性:通过在多个层级分担协调职责,系统比完全中心化模型更高效地管理大量 Agent。分层设计还引入冗余,可在不同层次处理任务,提升容错性。清晰的权责边界可优化操作:上层负责战略决策,下层聚焦战术执行。
挑战在于设计复杂:必须谨慎规划每个层级,以确保层间协调顺畅。由于信息需跨多层传播,可能出现通信延迟,从而降低对紧急变化的响应速度。高层决策也可能引入时延,下层在行动前需要等待指令。尽管存在这些挑战,分层式协调非常适合大型复杂系统,如供应链管理或军事行动,不同层级可同时处理高层规划与地面执行。
行动者–评论者方法(Actor-Critic Approaches)
在 Agent 系统中,行动者–评论者模式是一种轻量的基于评估驱动的迭代。其中,“行动者(actor)”负责生成候选输出(答案、计划或动作),而“评论者(critic)”作为质量闸门,依据预设的评估准则接受或拒绝输出。
流程很简单:行动者不断产出候选,直到评论者判断其满足目标质量阈值。这可视作一种测试时计算(test-time compute):用额外的推理轮次换取更高的可靠性与性能。其权衡是计算成本增加,但往往能显著改善结果。该方法在下述情形尤为有效:
- 存在清晰的评估规范/清单(例如正确性、完整性、语气)。
 - 相比质量提升,生成额外输出的成本可接受。
 - 任务具备模糊或生成特性,单次尝试常不如重排序/筛选后的结果。
 
在供应链示例中,“行动者”Agent 生成补货计划,“评论者”从可行性(如成本、风险)方面评估,直至通过。下面的代码在监督者之后加入一个 actor-critic 循环:
# Actor Node: Generates candidate plans
def actor_node(state: AgentState):
   history = state["messages"]
   actor_prompt = '''Generate 3 candidate supply chain plans
     as JSON list: [{'plan': 'description', 'tools': [...]}]'''
   response = llm.invoke([SystemMessage(content=actor_prompt)] + history)
   state["candidates"] = json.loads(response.content)
   return state
# Critic Node: Evaluates and selects/iterates
def critic_node(state: AgentState):
   candidates = state["candidates"]
   history = state["messages"]
   critic_prompt = f'''Score candidates {candidates} on scale 
    1-10 for feasibility, cost, risk. Select the best if greater than 
    8, else request regeneration.'''
   response = llm.invoke([SystemMessage(content=critic_prompt)] + history)
   eval = json.loads(response.content)
   if eval['best_score'] > 8:
       winning_plan = eval['selected']
       # Execute winning plan's tools (similar to specialist execution)
       messages = []
       for tool_info in winning_plan['tools']:
           tc = {'name': tool_info['tool'], 'args': tool_info['args'], 
                 'id': 'dummy'}
           fn = next(t for t in all_tools if t.name == tc['name'])
           out = fn.invoke(tc["args"])
           messages.append(ToolMessage(content=str(out), tool_call_id=tc["id"]))
       # Send response
       send_fn.invoke({"message": winning_plan['plan']})
       return {"messages": history + messages}
   else:
       # Iterate: Add feedback to history for actor
       return {"messages": history +  
               [AIMessage(content="Regenerate with improvements: " +
                eval['feedback'])]}
def construct_actor_critic_graph():
   g = StateGraph(AgentState)
   g.add_node("actor", actor_node)
   g.add_node("critic", critic_node)
  
   g.set_entry_point("actor")
   g.add_edge("actor", "critic")
   # Loop back if not approved (conditional)
   g.add_conditional_edges("critic", lambda s: "actor" 
    if "regenerate" in s["messages"][-1].content.lower() else 
    END)
  
   return g.compile()
当评估比生成更容易时,actor-critic 设置尤其有用。如果你能可靠地说“这份输出是好的”,但很难一次就生成,那么一个简单的 actor-critic 循环就是强有力的工具——无需训练。由于实现简单,当你愿意用少量额外算力换取显著的性能提升时,非常值得一试。
Agent 系统的自动化设计(Automated Design of Agent Systems)
Agentic 系统自动化设计(ADAS) 是一种具有变革性的 Agent 开发生方法论:它从手工打造架构转向让系统自行设计、评估并迭代改进。正如 Shengran Hu、Cong Lu 与 Jeff Clune 在其 2024 年原始论文中所阐述的那样,ADAS 的核心思想是:与其由人类逐一手工构建 Agent 的每个组件,不如让更高层次的元 Agent 搜索(MAS, Meta Agent Search)算法自动创建、评估并优化 Agent 系统。这一思路打开了一条新的研究前沿——有望让 Agent 在复杂且变化的环境中自适应,并在无需直接人工干预的情况下持续提升自身能力。正如图 8-1 所示,ADAS 建立在这样一个历史趋势之上:在机器学习中,手工设计的解决方案往往会被学习式或自动化的替代方案所取代,这暗示着 Agent 系统同样可能从这种转变中受益。
在 ADAS 中,基础模型(foundation models)充当 Agent 架构中灵活的通用模块。这些模型已经支撑了诸如链式思维(CoT) 、自我反思(self-reflection)以及基于 Toolformer 的 Agent 等策略,是在其之上叠加更专门或更任务化能力的基座。然而,ADAS 试图进一步超越这些传统做法:使 Agent 能够自主发明全新的结构和模块。基础模型的通用性提供了理想的起点,但 ADAS 通过自动化流程突破预定义能力边界,使 Agent 能演化出新的提示词、控制流与工具使用方式。这些构件并非静态,而是由元 Agent 动态生成:它能根据变化的需求或改进机会,不断尝试新的设计。
图 8-1. ADAS 框架的核心组件。搜索空间(search space)界定了可表示的 Agent 架构范围;搜索算法(search algorithm)决定在此空间中的探索策略;评估函数(evaluation function)量化候选 Agent 在性能、鲁棒性与效率等目标上的有效性。摘自原始论文。
ADAS 的脊梁是以代码来定义 Agent。借助图灵完备的编程语言,从理论上说,该框架允许 Agent 发明任何可想象的结构或行为——包括复杂的工作流、创造性的工具集成,以及人类设计者未必预见的创新决策过程。ADAS 的力量就在于这种基于代码的方式:它把 Agent 视为可重定义、可修改、可优化的可塑构造,而不是静态实体。其潜力十分广阔:原则上,一个元 Agent 可以无穷无尽地开发多种 Agent,不断重组并优化组件,以追求在多样任务上的更高表现。
在 ADAS 中的核心,是一个具体展示元 Agent 如何自主生成与改进 Agent 系统的方法:MAS 算法。在 MAS 中,元 Agent 作为设计者,编写代码定义新 Agent,并在一系列任务上测试这些 Agent。每一个成功的设计都会被归档,形成一个不断增长的知识库,用于指导未来 Agent 的创建。MAS 以迭代循环运作:元 Agent 在已有归档的条件化下,生成高层设计描述、将其实现为代码(为 Agent 定义一个 forward 函数),并通过两步自我反思来检验新颖性与正确性。新 Agent 会在验证数据上评估;若出现错误,最多触发五轮调试改进。成功的 Agent 会连同性能指标(如准确率或 F1 分数)一起归档,影响未来的迭代。这一过程类似进化:在对新颖设计的探索与对高性能方案的利用之间平衡。元 Agent 因而既是创造者也是策展者,在推陈出新的同时,充分利用既有成功模式。这与生物系统的演化相呼应:成功特征被保留,并在新挑战下不断迭代修饰。
为说明 MAS 如何将这些理念落地,下面给出一个受开源 ADAS 启发的通用 Python 实现示例。该框架使用基础模型(如 GPT-5)作为元 Agent来生成并改进 Agent 代码。关键组件包括:用于提示的基础模型 Agent 基类、用于迭代进化的搜索循环、以及用于适应度评分的评估函数。这些要素使元 Agent 能为诸如ARC(抽象与推理语料库)的网格谜题或MMLU多选推理等任务动态发明 Agent,并将高表现者归档以供复用:
class LLMAgentBase:
    def __init__(self, output_fields: list, agent_name: str,
     role='helpful assistant', model='gpt-4o-2024-05-13', 
     temperature=0.5):
        self.output_fields = output_fields
        self.agent_name = agent_name
        self.role = role
        self.model = model
        self.temperature = temperature
        self.id = random_id()  # Unique ID for agent instances
    def generate_prompt(self, input_infos, instruction, output_description):
        # Builds system prompt with role and JSON format instructions
        system_prompt = f"You are a {self.role}.\n\n" + 
                          FORMAT_INST(output_description)
        # Constructs user prompt from inputs and instruction
        prompt = ''  # (Build input text from infos) + instruction
        return system_prompt, prompt
    def query(self, input_infos: list, instruction, output_description, 
              iteration_idx=-1):
        system_prompt, prompt = self.generate_prompt(input_infos, 
                                                     instruction, 
                                                     output_description)
        response_json = get_json_response_from_gpt(prompt, 
            self.model, system_prompt, self.temperature)
        # Handle errors, parse JSON
        output_infos = [Info(key, self.__repr__(), value, 
            iteration_idx) for key, value in response_json.items()]
        return output_infos
LLMAgentBase 类是元 Agent 的核心,封装了与基础模型的交互以生成结构化响应(如思路、代码)。它强制 JSON 输出以便解析,并优雅处理错误,使元 Agent 能在已有归档的条件化下查询新的 Agent 设计。这种模块化设计确保了灵活性:可调节角色(如“乐于助人的助手”)与温度(控制创造性),而输出描述引导任务特定行为(例如在 MMLU 只返回单字母答案)。
MAS 的中心是搜索函数:它跨“世代”迭代以进化 Agent。从初始归档(例如基于提示的基础 Agent)出发,算法在过去成功经验的条件化下,生成新代码、应用Reflexion做两步改进、在验证数据上评估并归档带适应度分数的方案。该循环在**探索(新颖设计)与利用(基于强者构建)**之间权衡,常运行 25–30 代:
def search(args, task):
    archive = task.get_init_archive()  # Or load existing
    for n in range(args.n_generation):
        # Generate prompt from archive
        msg_list = [{"role": "system", "content": system_prompt},
            {"role": "user", "content": prompt}]
        next_solution = get_json_response_from_gpt_reflect(
            msg_list, args.model)  
        # Initial generation
        # Reflexion: Two steps to refine
        next_solution = reflect_and_refine(msg_list, 
            task.get_reflexion_prompt())  
        # Pseudocode for reflections
        # Evaluate and debug
        acc_list = evaluate_forward_fn(args, next_solution["code"], task)
        next_solution['fitness'] = bootstrap_confidence_interval(acc_list)
        archive.append(next_solution)
def evaluate_forward_fn(args, forward_str, task):
    # Dynamically load agent code as function
    exec(forward_str, globals(), namespace)
    func = namespace['forward']  # Assume single function
    data = task.load_data(SEARCHING_MODE)  # Val or test
    task_queue = task.prepare_task_queue(data)
    # Parallel evaluate
    with ThreadPoolExecutor() as executor:
        acc_list = list(executor.map(process_item, task_queue))  
        # process_item: run func, score vs truth
        return acc_list
评估函数会将生成的 Agent 代码(通过 exec)动态加载为可调用的 forward 函数,在任务数据上并行执行(使用多线程以提升效率),并按任务特定的评分标准计算准确率。该模块化结构便于拓展到新问题:只需继承一个 BaseTask 抽象类,定义数据加载、格式化与预测解析等方法。比如在 MMLU 中,将字母选项(A–D)映射为索引以做精确匹配打分;在 ARC 中,则评估网格变换的像素级准确。这些实现显示了 ADAS 的通用性,并带来了强劲的实证结果。
MAS 的结果揭示了通过 ADAS 设计的 Agent 的一个有趣性质:当应用到新领域与新模型时,它们往往仍能保持高水平的性能。例如,在 ARC 挑战(网格变换谜题)上,MAS 发现的 Agent 超越了手工基线,如 Chain-of-Thought(CoT) 、Self-Refine 与 LLM-Debate。在推理基准上,MAS 在 DROP(阅读理解)上取得 F1 79.4 ± 0.8(较角色分配基线 +13.6),在 MGSM(数学)上达 53.4% ± 3.5(较 LLM-Debate +14.4%),在 MMLU(多任务)上达 69.6% ± 3.2(较 OPRO 提示优化 +2%),在 GPQA(科学)上达 34.6% ± 3.2(较 OPRO +1.7%)。跨领域迁移也很稳健(如将 ARC Agent 应用于 MMLU),并且在更换模型(如从 GPT-3.5 到 GPT-4)时表现仍能保持。
这种跨领域的鲁棒性表明,通过 MAS 产生的 Agent 并非只对一次性任务做过拟合;相反,它们蕴含了更通用的原则与自适应结构,即便环境细节改变也能出色发挥。这种可迁移性体现了自动化设计的根本优势:通过生成内在灵活的 Agent,MAS 所产出的方案往往比为窄场景手工设计的方案更具泛化能力。
当然,ADAS 前景广阔,但其发展也需要同时审慎考虑伦理与技术层面。让系统自动化设计更强大的 Agent,会引出关于安全、可靠性与与人类价值对齐的问题。尽管 MAS 提供了结构化且具探索性的路径,但必须确保不断演化的 Agent 遵守伦理标准,不产生与人意图不一致的不可预见行为。要确保这些系统的有益性,需要在自主性与约束之间取得平衡:既给予 Agent 创新的自由,又引导其在安全与可预测的边界内运作。
ADAS 的发展轨迹预示着一个未来:Agent 系统可以自主适应与改进,以最小的人类干预应对不断扩展的任务范围。随着 ADAS 的推进,Agent 自行演化更复杂设计的能力很可能成为 AI 研究的基石之一,提供能处理日益复杂、不断演化挑战的工具。由此,ADAS 让我们一窥一个可自我改进与创新的智能系统未来——从静态、预先设计的 Agent,走向自适应、自治并能与不断扩张的需求同步成长的系统。
通信技术(Communication Techniques)
当 Agent 系统从单体原型走向多 Agent、分布式系统时,通信架构的选择就变得愈发关键。最初的进程内消息传递或函数调用,在系统的业务范围、Agent 数量、地域分布或部署复杂度增长后,很快就难以为继。本节将探讨用于在 Agent 之间管理通信、协同与任务流的一些核心技术与方法——特别是在系统从单设备实验过渡到面向生产的分布式部署时。你会注意到可行路径很多,而它们在开发投入、时延、可扩展性、可靠性与成本上各有取舍。
本地通信 vs. 分布式通信
在小规模场景(如单设备或单进程)中,Agent 往往通过直接函数调用、共享内存或内存队列通信。这些方法简单高效,但不易扩展。一旦 Agent 被分布到不同服务、容器或节点,通信就必须显式化、异步化,并且具备容错性。
在本地部署中,诸如 AutoGen 等框架常用进程内路由器来编排 Agent 之间的消息传递与工具调用。这类设置适合研究与原型,尤其在单线程/单 Agent配置下表现良好。但在生产环境中,通信与状态管理必须随之演进。
Agent 对 Agent 协议(A2A Protocol)
由 Google 提出的 Agent-to-Agent (A2A) 协议,是让自治 Agent 协作完成复杂目标的一步雄心勃勃且颇具前景的尝试。它提供一种标准化、跨平台的机制,使 Agent 能发现彼此、协商协作并交换结构化请求——而无需暴露各自的内部逻辑或实现细节。通过让异构 Agent在 HTTP 传输之上互操作,A2A 创造了一种共享语言,未来或可让多 Agent 协作像微服务之间的 API 调用一样常态化。
A2A 的核心是Agent Card:每个 Agent 发布的机器可读 JSON 描述,用于声明其身份、能力、端点以及支持的认证方式。借助这些卡片,Agent 可以发现同伴、评估其功能,并协商安全通信通道。能力以显式方式定义(如 generateReport、summarizeLegalDocument),并附带输入/输出模式,以支持对 Agent 工作流的结构化组合。端点与认证方式(如 OAuth 2、API Key)确保通信可被安全、程序化地建立;可选的版本信息与媒体支持等元数据进一步提升发现与兼容性。示例中,下面是一个用于摘要的 Agent Card(Python 字典):
agent_card = {
    "identity": "SummarizerAgent",
    "capabilities": ["summarizeText"],
    "schemas": {
        "summarizeText": {
            "input": {"text": "string"},
            "output": {"summary": "string"}
        }
    },
    "endpoint": "http://localhost:8000/api",
    "auth_methods": ["none"],  # In production: OAuth2, API keys, etc.
    "version": "1.0"
}
该 JSON 可通过 /.well-known/agent.json 之类的固定路径对外发布以供发现。A2A 在参考实现中使用 JSON-RPC 2.0 over HTTPS,但协议被设计为与传输无关,这为未来基于 gRPC、WebSocket 或其他流式/多路复用协议的集成敞开了大门。JSON-RPC 让请求、响应与错误的处理保持一致,从而在不同语言或框架实现的 Agent 之间建立共享语义模型。
在实际使用中,Agent 通过一个注册中心(集中式或分布式)发现彼此,该注册中心保存 Agent Card。一旦识别到对端,发起方会进行握手:互换 Agent Card,并协商协议版本、超时时间、负载上限等会话参数。示例中,客户端可能如下(使用 Python requests)进行发现与兼容性检查:
import requests
import json
# Discover Agent Card (mocked as direct access; in production, query a registry)
card_url = 'http://localhost:8000/.well-known/agent.json'
response = requests.get(card_url)
if response.status_code != 200:
    raise ValueError("Failed to retrieve Agent Card")
agent_card = response.json()
print("Discovered Agent Card:", json.dumps(agent_card, indent=2))
# Handshake: Check compatibility
if agent_card['version'] != '1.0':
    raise ValueError("Incompatible protocol version")
if "summarizeText" not in agent_card['capabilities']:
    raise ValueError("Required capability not supported")
print("Handshake successful: Agent is compatible.")
通过验证后,Agent 便可开始协调工作:Agent A 发起对 Agent B 的 summarizeText 请求,B 处理后返回结构化结果或错误。继续示例,客户端发起 JSON-RPC 请求如下:
# Issue JSON-RPC request
rpc_url = agent_card['endpoint']
rpc_request = {
    "jsonrpc": "2.0",
    "method": "summarizeText",
    "params": {"text": '''This is a long example text that needs summarization. 
        It discusses multiagent systems and communication protocols.'''},
    "id": 123  # Unique request ID
}
response = requests.post(rpc_url, json=rpc_request)
if response.status_code == 200:
    rpc_response = response.json()
    print("RPC Response:", json.dumps(rpc_response, indent=2))
else:
    print("Error:", response.status_code, response.text)
服务器端的处理(为简洁起见,使用 Python http.server)可能如下:
# Excerpt from server handler (in do_POST method)
import os 
from openai import OpenAI  
content_length = int(self.headers['Content-Length'])
post_data = self.rfile.read(content_length)
rpc_request = json.loads(post_data)
# Handle JSON-RPC request (core of A2A)
if rpc_request.get('jsonrpc') == '2.0' 
    and rpc_request['method'] == 'summarizeText':
    text = rpc_request['params']['text']
    # Real LLM summarization using OpenAI API 
    client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
    try:
        llm_response = client.chat.completions.create(
            model="gpt-4o",
            messages=[
                {"role": "system", "content": '''You are a helpful assistant that 
                    provides concise summaries.'''},
                {"role": "user", "content": f"""Summarize the following text:
                {text}"""}
            ],
            max_tokens=150,
            temperature=0.7
        )
        summary = llm_response.choices[0].message.content.strip()
    except Exception as e:
        summary = f"Error in summarization: {str(e)}"  # Fallback for errors
    
    response = {
        "jsonrpc": "2.0",
        "result": {"summary": summary},
        "id": rpc_request['id']
    }
    # Send response
    self.send_response(200)
    self.send_header('Content-type', 'application/json')
    self.end_headers()
    self.wfile.write(json.dumps(response).encode())
else:
    # Error response
    error_response = {
        "jsonrpc": "2.0",
        "error": {"code": -32601, "message": "Method not found"},
        "id": rpc_request.get('id')
    }
    self.send_response(400)
    self.send_header('Content-type', 'application/json')
    self.end_headers()
    self.wfile.write(json.dumps(error_response).encode())
虽然 A2A 为多 Agent 系统指明了令人兴奋的方向——提供一种模块化、与运行时无关的委派与协作方式——但它仍处于早期。特别是在安全方面仍有大量开放问题:认证虽支持可插拔机制,但授权、限流、信任建立、滥用防护等仍远未解决。与任何早期协议一样,我们应既热情又审慎地对待:早期使用者需要预期漏洞、实现缺口与规范演进。
尽管如此,A2A 指向一个未来:Agent 不再各自为政,而是作为动态、松耦合生态的一部分,能够处理更广泛、更复杂的问题。正如 HTTP 促进了 Web 的可组合性,A2A 也希望为 AI Agent 做到同样的事情。它是否会成为业界标准尚言之过早——但在让 Agent 协作变得无缝、可扩展且安全的征途上,它无疑是一个值得期待的开端。
消息代理与事件总线(Message Brokers and Event Buses)
随着基于 Agent 的系统扩展,点对点通信会变得脆弱且不灵活。常见的替代方案是采用消息代理或事件总线,它们将发送方与接收方解耦,使 Agent 能通过共享的通信织体以异步方式交互。此模式能建立可扩展、具容错性且可观测的工作流,尤其适合松耦合的多 Agent 架构。
为了直观展示这种方法的价值,考虑把本章前面的供应链多 Agent 系统接入一个消息代理。在原先的同步方案中,监督者(supervisor)通过图上的边直接路由到专家节点,造成紧耦合。引入消息代理后,监督者可以把任务发布到一个共享主题(如 “supply-chain-tasks”),而专家以异步订阅的方式只处理与自己相关的消息。这样一来,Agent 被解耦,可以实现独立伸缩(如重放库存任务实例)、故障容忍(如重放漏处理的消息),并且在无需重写图结构的情况下更容易增加新 Agent。关键选型包括:
Apache Kafka
一款高吞吐、分布式的事件流平台,适合需要发布/消费结构化事件的 Agent 系统。Kafka 提供强持久化、按分区并行以及消费者组用于协作协调。它在构建日志式通信架构方面尤其高效,可保存并可重放所有交互。
Redis Stream 与 RabbitMQ
适用于较低吞吐或更简单的场景,更低时延、部署也更容易。特别是 Redis Stream 提供了基于内存的快速通信,但持久化能力相对有限。
NATS(Neural Autonomic Transport System)
一款轻量、云原生的消息系统,为低时延、高吞吐通信而设计。NATS 适合微服务或边缘场景中的实时 Agent 协作,支持 pub/sub、request/reply,并可通过 JetStream 获得持久消息流与重放。NATS 强调简单、速度与可扩展性,非常适合需要快速且可靠通信、同时开销极低的分布式 Agent 系统。
对于供应链 Agent 系统,Redis Stream 能在原型期提供快速、低时延的解耦。监督者把任务写入 Stream,各专家在独立进程中消费/处理。假设 Redis 已运行(例如通过 Docker:docker run -p 6379:6379 redis),并使用 redis-py(pip install redis)。监督者判断专家并发布任务:
import redis
import json
import uuid
# Helper to serialize messages
def serialize_messages(messages):
    return [m.dict() for m in messages]
def supervisor_publish(operation: dict, messages):
    # ... (existing supervisor prompt and LLM logic to get agent_name)
    r = redis.Redis(host='localhost', port=6379)
    task_id = str(uuid.uuid4())
    task_message = {
        'task_id': task_id,
        'agent': agent_name,
        'operation': operation,
        'messages': serialize_messages(messages)
    }
    r.xadd('supply-chain-tasks', {'data': json.dumps(task_message)})
    return task_id
专家(例如库存专家)在循环中消费,按其节点逻辑处理,并发布响应:
import redis
import json
# Helper to deserialize messages
def deserialize_messages(serialized):
    # Rehydrate based on type (HumanMessage, AIMessage, etc.)
    return [...]  # Implementation as in full code
def inventory_consumer():
    r = redis.Redis(host='localhost', port=6379)
    last_id = '0'
    # ... (inventory_prompt)
    while True:
        msgs = r.xread({'supply-chain-tasks': last_id}, count=1, block=5000)
        if msgs:
            stream, entries = msgs[0]
            for entry_id, entry_data in entries:
                task = json.loads(entry_data[b'data'])
                if task['agent'] == 'inventory':
                    state = {
                        'operation': task['operation'],
                        'messages': deserialize_messages(task['messages'])
                    }
                    result = specialist_node(state, inventory_llm, 
                                             inventory_prompt)
                    response = {
                        'task_id': task['task_id'],
                        'from': 'inventory',
                        'result': {'messages': serialize_messages(
                                   result['messages'])}
                    }
                    r.xadd('supply-chain-responses', {'data': 
                           json.dumps(response)})
                last_id = entry_id
随后为运输与供应商专家设置类似的消费者循环。等待响应示例:
import time
def wait_for_response(task_id, timeout=60):
    r = redis.Redis(host='localhost', port=6379)
    last_id = '0'
    start = time.time()
    while time.time() - start < timeout:
        msgs = r.xread({'supply-chain-responses': last_id}, count=1, block=5000)
        if msgs:
            stream, entries = msgs[0]
            for entry_id, entry_data in entries:
                resp = json.loads(entry_data[b'data'])
                if resp['task_id'] == task_id:
                    return resp
                last_id = entry_id
    raise TimeoutError("No response")
一般来说,建议把专家运行在独立进程(例如使用 multiprocessing)中。这既能实现快速的异步协同——比如供应商 Agent 可以在不阻塞其他 Agent 的情况下处理合规任务——同时在低规模系统里保持设置简洁。
消息总线支持 Agent 之间的松耦合,便于弹性扩展、通过日志管道提高可观测性,并能重放失败或漏掉的消息。但它也带来如最终一致性与更复杂错误处理等挑战。
Actor 框架:Ray、Orleans 与 Akka
消息总线主要通过异步路由事件来解耦通信,关注数据流而不规定执行方式;而 Actor 框架则把消息传递与计算统一到一个模型里。这里,Actor(代表 Agent)不仅交换消息,还封装自身状态与行为,并通过顺序处理消除传统多线程系统中常见的竞争与共享状态问题。这与许多团队最初采用的单体式做法形成鲜明对比:将全部逻辑集中在单容器 Agent 服务中,依赖同步的基础模型调用与进程内编排。虽然便于原型开发,但在规模上会变成瓶颈——容易产生单点故障、空闲期资源利用低,并且在并行化多样 Agent 角色方面困难重重,往往需要自制的并发“土办法”。
当你需要细粒度分布、弹性与高可用时,Actor 框架表现突出:例如在多 Agent 仿真(每个 Agent 具备持久化的会话记忆,如对话历史或习得行为)、高并发(实时竞价、IoT 协同)或跨集群的异构 Agent 集成等场景中。它们支持位置透明调用(Actor 可迁移/复制而无需改代码),以及内建的监督机制用于自动故障恢复;相比手动管理队列或容器,能显著降低运维开销。
当系统超出少量 Agent 或工作负载波动较大时(如生产级“群智”Agent 集群、或从本地原型演进到云原生部署),这类基础设施投入就会带来回报。对于较小、低流量系统,可能不值得引入这份复杂度——继续使用总线或单体服务即可。但当 Agent 数量超过 10–20个或延迟要求变得严格时,Actor 模型提供的弹性与容错优势无可匹敌。三大代表性框架及其特点:
Ray
面向 Python 的分布式计算框架,支持Actor 模型来进行有状态、可扩展的计算。使用 @ray.remote 定义 Actor,可进行异步方法调用,并在调用间保持内部状态。Ray 自动管理分布与资源感知调度,提供容错(重启/重试可选)与集群支持,适合与 AutoGen、LangGraph 等 Agent 库搭配,在 Python 环境中以易用性与快速原型为先。
Orleans
提供虚拟 Actor 模型:Actor 可按需自动实例化、挂起或恢复,并处理状态持久化、并发与生命周期管理,样板代码极少。它屏蔽了大量分布式系统复杂性,使“把每个 Agent 当成服务”成为自然选择,能随系统需求动态伸缩,同时保留内部状态与身份。(主要基于 .NET,适配 Windows 或企业集成场景。)
Akka
JVM 生态中久经考验的 Actor 框架,支持 Java/Scala。Akka 经典 Actor 模型性能出色,适合构建容错的分布式系统,并能细粒度控制 Actor 行为。借助 Akka Cluster,Actor 可分布到多节点,支持分片、持久化、监督与自适应负载均衡。非常适合高吞吐、低时延且需要严格并发控制的应用,已在从电信到交易平台的生产环境中广泛使用。
这种 Actor 风格设计与多 Agent 协作天然契合:每个 Agent 保有自身身份、角色与内部状态;Actor 系统让这些 Agent 能被动态调用、对消息或事件作出反应,并通过消息传递而非共享状态/全局控制来管理复杂工作流。
鉴于本书以 Python 技术栈为主(如结合 LangChain 及相关库)介绍多 Agent 实现,下面以 Ray 集成供应链系统为例阐释 Actor 模型。相同原则可迁移到 Orleans(偏 .NET、适合 Windows/企业集成)与 Akka(JVM、适合高性能 Java/Scala 应用),但代码需要进行语言层面的改写,这超出了本书的 Python 侧重点。
在供应链多 Agent 系统中,可将专家 Agent(如库存、运输)实现为 Ray Actor,以会话(operation_id)为粒度隔离:每个会话、每种专家类型各自持有一个 Actor 实例,从而实现干净的状态管理(每会话独立的历史或缓存),并保证会话内任务的顺序执行。这样避免跨会话污染,并能在集群中跨会话并行处理。一个会话管理器 Actor按需追踪与创建这些实例。下面是专家 Actor 的核心类,它顺序处理任务并维持会话内的独立状态:
@ray.remote
class SpecialistActor:
    def __init__(self, name: str, specialist_llm, tools: list, 
                 system_prompt: str):
        self.name = name
        self.llm = specialist_llm
        self.tools = {t.name: t for t in tools}
        self.prompt = system_prompt
        self.internal_state = {}  
    def process_task(self, operation: dict, messages: Sequence[BaseMessage]):
        if not operation:
            operation = {"operation_id": "UNKNOWN", "type": "general", 
                         "priority": "medium", "status": "active"}
        operation_json = json.dumps(operation, ensure_ascii=False)
        full_prompt = self.prompt + f"\n\nOPERATION: {operation_json}"
        
        full = [SystemMessage(content=full_prompt)] + messages
        first = self.llm.invoke(full)
        result_messages = [first]
        if hasattr(first, "tool_calls"):
            for tc in first.tool_calls:
                print(first)
                print(tc['name'])
                fn = self.tools.get(tc['name'])
                if fn:
                    out = fn.invoke(tc["args"])
                    result_messages.append(ToolMessage(content=str(out), 
                                           tool_call_id=tc["id"]))
            second = self.llm.invoke(full + result_messages)
            result_messages.append(second)
        # Update internal state (example: track processed steps within session)
        step_key = str(len(self.internal_state) + 1)  
        # Or use a more specific key
        self.internal_state[step_key] = {"status": "processed", 
                                         "timestamp": time.time()}
        return {"messages": result_messages}
    def get_state(self):
        return self.internal_state  # Return entire session state
该 Actor 封装了基础模型与工具逻辑,通过 process_task 串行处理消息(任务)——Ray 会将对同一 Actor 的并发调用排队,逐一执行以保持顺序与状态完整性。由于每个 Actor 按会话创建,internal_state 也按会话隔离,可在无共享内存风险下实现每会话持久(例如步骤追踪)。一个会话管理器 Actor负责按需创建,确保隔离:
@ray.remote
class SessionManager:
    def __init__(self):
        self.sessions: Dict[str, Dict[str, ray.actor.ActorHandle]] = {}
    def get_or_create_actor(self, session_id: str, agent_name: str, 
        llm, tools: list, prompt: str):
        if session_id not in self.sessions:
            self.sessions[session_id] = {}
        if agent_name not in self.sessions[session_id]:
            actor = SpecialistActor.remote(agent_name, llm, tools, prompt)
            self.sessions[session_id][agent_name] = actor
        return self.sessions[session_id][agent_name]
    def get_session_state(self, session_id: str, agent_name: str):
        if session_id in self.sessions and 
               agent_name in self.sessions[session_id]:
            actor = self.sessions[session_id][agent_name]
            return actor.get_state.remote()  # Returns future
        return None
该管理器用字典按 session_id 与 agent_name 管理 Actor,并惰性创建。这支持可扩展性:Ray 会把 Actor 分布到集群节点上;查询状态(如 ray.get(manager.get_session_state.remote(session_id, agent_name)))能获取特定会话的数据,而无需全局共享。
对正在构建 Agent 系统的开发者而言,像 Orleans 与 Akka 这类 Actor 框架,为把每个 Agent 表达为自治、内聚的单元提供了成熟且可扩展的基石——它们能处理异步工作流、维护持久记忆,并与分布式基础设施自然集成。
编排与工作流引擎(Orchestration and Workflow Engines)
即便拥有稳健的消息与 Agent 执行模型,真实世界的系统仍然需要编排——也就是在多个 Agent 之间串联任务、处理重试、跟踪依赖并管理失败的逻辑。对于长时运行或多步骤、跨越时间与组件的交互,这一点尤为重要。工作流编排工具提供了更高层的抽象,确保在复杂的 Agent 系统中实现耐久性(durability)与可恢复性(recoverability) 。
当流程涉及不可靠的外部依赖(如 API、基础模型或人工审批)、潜在失败或持续时间较长(比如由于异步 Agent 行为或现实中的延误而需要数天的供应链流程)时,工作流编排工具尤其有用。通过持久化状态并自动化恢复,这些引擎能防止数据丢失与重复工作;当简单的进程内协调捉襟见肘时,它们对生产级可靠性至关重要。当你从原型扩展到高韧性部署,尤其是在金融交易、合规性强的运营或分布式 AI Agent等高风险场景,应当使用它们;而对于快速、低风险的试验,基础脚本往往已足够。
Temporal 提供可持久、有状态的工作流,支持长时任务、重试与失败恢复。它非常适合管理多 Agent 系统中每个 Agent 的异步、多步骤操作。Temporal 工作流为跨多个服务或 Agent、跨长时间跨度的业务逻辑提供了简洁抽象。
为了在本章的供应链多 Agent 系统中说明 Temporal 的持久化执行,考虑这样一个工作流:按顺序编排 Agent 步骤(如库存管理 → 运输安排 → 供应商合规),并在失败时自动重试、持久化状态以便恢复。即使崩溃,Temporal 也能从上一步的成功处继续执行,因此非常适合生产环境中的 Agent 协同。假设已完成 Temporal 的安装与活动(activity)定义(将各专家的基础模型/工具逻辑封装为活动),下面是一个简化的工作流定义:
from datetime import timedelta
from temporalio import workflow
from temporalio.common import RetryPolicy
# Assume activities are defined elsewhere, e.g., inventory_activity, 
# transportation_activity, supplier_activity
# Each takes operation dict and messages, returns result
@workflow.defn
class SupplyChainWorkflow:
    @workflow.run
    async def run(self, operation: dict, initial_messages: list) -> dict:
        # Step 1: Inventory management with retry
        inventory_result = await workflow.execute_activity(
            "inventory_activity",
            {"operation": operation, "messages": initial_messages},
            start_to_close_timeout=timedelta(seconds=30),
            retry_policy=RetryPolicy(maximum_attempts=3)
        )
        
        # Update state and proceed to transportation
        updated_messages = initial_messages + inventory_result["messages"]
        transportation_result = await workflow.execute_activity(
            "transportation_activity",
            {"operation": operation, "messages": updated_messages},
            start_to_close_timeout=timedelta(seconds=30),
            retry_policy=RetryPolicy(maximum_attempts=3)
        )
        
        # Final step: Supplier compliance
        final_messages = updated_messages + transportation_result["messages"]
        supplier_result = await workflow.execute_activity(
            "supplier_activity",
            {"operation": operation, "messages": final_messages},
            start_to_close_timeout=timedelta(seconds=30),
            retry_policy=RetryPolicy(maximum_attempts=3)
        )
        
        # Compile and return results
        return {
            "inventory": inventory_result,
            "transportation": transportation_result,
            "supplier": supplier_result
        }
这个工作流以可持久的方式串联各 Agent。每个活动(Agent 的一步)都带有重试,Temporal 会持久化进度——例如运输步骤失败时,只会重试运输,而不会重跑库存。对于更长时的流程,可加入**信号(signals)**以接收用户输入或暂停,类似完整示例中的确认环节。
Apache Airflow 广泛用于数据流水线,但也可通过 DAG(有向无环图)编排 Agent 流程。尽管功能强大,Airflow 更适合批处理或定时触发的工作流。它仍是计划性、工具无关编排在数据工程和业务运营(如 ETL、模型训练)中的中流砥柱。当处理周期性、依赖重的管线,且受益于其成熟生态与可视化时可选用 Airflow;但它不适合实时或高度动态的 Agent 交互。
若你偏好在本地原型与运行编排、再扩展到分布式环境,像 Dagger 这样的工具很实用:它允许用代码组合容器、基础模型和其他资源,具备自动缓存与类型安全,确保本地开发、CI/CD 与生产环境的一致性;还支持基于基础模型的自动化等 Agent 集成。因此,它是一个按技术栈弹性选择的方向。总体来说,工作流引擎提供更高一层的抽象——把协调逻辑与通信机制分离。它们帮助保证幂等性、可恢复性与持久状态——当 Agent 失败、阻塞或必须响应环境变化时,这些特性就变得不可或缺。
状态与持久化管理(Managing State and Persistence)
仅有通信还不够——多 Agent 系统还必须管理共享状态、Agent 记忆与任务元数据,而这些常常横跨多次执行、多个工作流或系统重启。随着系统扩展,这在数据持久性、一致性与访问模式上引入显著复杂度。
如表 8-1 所示,传统方案依赖有状态数据库(如 PostgreSQL、Redis 或向量库)来持久化任务结果、交互日志与 Agent 记忆。它们提供细粒度控制,可按 Agent 需求定制,但也要求开发者显式管理模式设计、读写一致性、缓存与恢复逻辑——增加工程负担并带来隐蔽的缺陷风险。
对于非结构化或大规模输出(如计划、工具调用轨迹、JSON 大对象),对象存储(如 Amazon S3、Azure Blob Storage)提供低成本、高可用、耐久的存储,非常适合不可变制品;代价是访问延迟较高,并需要额外的索引/跟踪系统把制品关联回 Agent 任务或状态。
表 8-1. 持久化存储选项概览
| 方案 | 优点 | 缺点 | 最适用场景 | 
|---|---|---|---|
| 关系型数据库(如 PostgreSQL)/Redis | 灵活、可查询、性价比高 | 需手动管理,可能出现不一致 | 定制化、查询密集型系统 | 
| 向量数据库(如 Pinecone) | 语义检索、可扩展嵌入 | 成本更高、部署更专业 | 知识密集型 Agent | 
| 对象存储(如 S3) | 低成本、对大数据耐久 | 访问慢、无原生索引 | 归档类输出 | 
| 有状态编排框架 | 自动恢复、模板代码少 | 框架绑定 | 韧性强、长时工作流 | 
像 Temporal 与 Orleans 这样的框架提供不同思路:它们把状态管理与 Agent/工作流生命周期紧密集成,从而屏蔽了大量持久化复杂性。Temporal 会自动检查点工作流进度,支持确定性回放并透明处理失败;Orleans 让每个 Actor(Agent)以事件驱动的方式维护可持久状态,且样板代码极少。这些抽象减少了开发工作并提升韧性,但也带来框架特定的约束——比如序列化格式、执行模型或语言绑定——未必适配所有架构。
正确的选择取决于记忆与协调的性质:
- 情节性记忆(Episodic) :短期、任务专属状态;只需内存或临时存储、最低限度的持久性。
 - 语义记忆(Semantic) :跨交互的长期知识;通常需要可持久存储并配合搜索/向量索引。
 - 工作流耐久性(Workflow durability) :要求在中途失败时仍能存活;最受益于像 Temporal/Orleans 这样的集成引擎,自动检查点进度与状态。
 
归根结底,持久化决策是在开发投入、性能、耐久性与灵活性之间的权衡。具有严格 SLO、多 Agent 依赖或实时协同需求的系统,往往受益于工作流原生的持久化层;而更模块化或偏研究型的系统,则可能更偏好显式、以数据库为中心的状态管理以获得更强的可控性与可见性。
结论(Conclusion)
从单 Agent 向多 Agent 系统的转变,在应对复杂任务、提升适应性和提高效率方面具有显著优势。然而,正如本章所探讨的那样,伴随 Agent 数量增长而来的可扩展性,也带来了需要谨慎规划的挑战。确定 最优的 Agent 数量,需要对任务复杂度、任务可分解性,以及多 Agent 协作的成本—收益平衡有细致入微的理解。
协调是多 Agent 系统成功的关键。多种协调策略——如民主式、经理式、分层式、行动者–评论者(actor-critic)方法,以及 ADAS 自动化设计——在鲁棒性、效率与复杂度之间提供了不同的取舍。每种协调策略都有其独特的优势与局限,适用于特定场景;谨慎选择可以显著提升系统的有效性与可靠性。
同样关键的还有通信基础设施的选择。随着系统扩展,Agent 之间对可靠、低时延且可持久的消息传递需求也随之增长。虽然进程内队列在简单环境下即可满足需求,但面向生产的系统往往依赖消息代理(如 Kafka、NATS、RabbitMQ)、Actor 框架(如 Orleans、Akka)以及工作流引擎(如 Temporal、Conductor),以同时管理通信、状态、重试与执行耐久性。有效通信的设计不仅是实现细节,更是一等公民:它塑造了 Agent 如何感知、响应与协作其所处环境。为帮助开发者权衡选择,表 8-2 总结了多 Agent 系统的关键通信与执行方案,并在供应链示例的语境下对其概念、取舍与理想用例进行了对比。
表 8-2. Agent 协调技术对比
| 方法 | 关键概念 | 优势 | 挑战 | 用例与示例 | 
|---|---|---|---|---|
| 单容器部署 | 单体 Agent/服务在一个容器中;同步调用、进程内状态/编排 | 部署简单、低时延、便于原型 | 单点故障、可扩展性差、并发问题 | 原型阶段的基础供应链查询;少量 Agent/工具的快速试验(如单个 Agent 处理客服询问) | 
| A2A 协议 | 通过 Agent Card 标准化发现与协商;使用 JSON-RPC 进行结构化请求;与传输无关(HTTP/gRPC) | 跨异构 Agent 互操作、模块化、可建立安全通道 | 仍处早期(安全空白、规范演进中)、发现有额外开销 | 动态生态中的 Agent 协作(如一个 Agent 请求另一个 Agent 做供应链分析中的摘要) | 
| 消息代理 | 发布/订阅实现解耦异步消息(Kafka 提供持久化,Redis Stream 低时延,NATS 实时) | 松耦合、可扩展、可通过重放实现容错 | 最终一致性、错误处理复杂、可能引入时延 | 供应链中的分布式任务路由(如监督者发布到流,专家订阅/处理/响应) | 
| Actor 框架 | 有状态 Actor 顺序处理消息(Ray 面向 Python/分布式;Orleans 虚拟 Actor;Akka 面向 JVM/高性能) | 状态与行为一体、具韧性(自动恢复)、位置透明的弹性伸缩 | 基础设施投入、框架绑定、每个 Actor 的顺序处理上限 | 供应链中的按会话隔离的 Agent(如为特定 operation 的库存任务动态创建 Actor 并维护会话状态) | 
通过理解并审慎应用这些因素,开发者可以构建出既稳健又能干的多 Agent 系统,足以应对现实应用中日益复杂与动态的任务需求。这种战略性的方法使多 Agent 系统得以演化为强大的解决方案,在各个领域推动有意义的进步。