最新n1n v2.0.1 正式上线!企业级大模型接口聚合平台 (LLM API Gateway),为您接入 500+ AI Models,价格低至 1 折,立即尝试

基于 Agent-to-Agent 协议实现研究员与作者 Agent 的去中心化协作机制

作者
  • avatar
    姓名
    Nino
    职业
    Senior Tech Editor

当今绝大多数智能体(AI Agent)编排演示都存在一个隐蔽的架构局限:它们将多个 Agent 强行绑定在单个框架内部(例如 LangChain、LangGraph 或 Agno)。这种模式虽然适合构建单体应用,但无法解决真正的智能体互操作问题(Agent Interoperability)——不同团队在不同语言、不同运行时上开发的独立 Agent,究竟该如何进行标准的、无侵入的跨平台协作?

Agent-to-Agent (A2A) 协议agent2agent.dev)正是为此而生的开放、中立标准。你可以将它理解为“Agent 领域的 HTTP 协议”。它定义了自包含的 Agent 名片发现机制、任务生命周期模型,以及基于 JSON-RPC 2.0 和 Server-Sent Events (SSE) 的消息传输标准。在构建高性能的多智能体协作架构时,开发者通常依赖于像 n1n.ai 这样稳定且高速的 LLM API 聚合平台,为高并发的代理任务提供强力的底层模型支持。

本文将手把手带你使用纯 Node.js/TypeScript 与 React 构建一个轻量且完整的 A2A 协议实现:一个具备真实 Web 检索能力的 Researcher Agent(研究员),与一个支持逐 Token 实时流式输出 Markdown 文稿的 Writer Agent(作者),并通过浏览器客户端完成无框架依赖的任务交接(Handoff)。


1. 架构设计与 A2A 协议核心机制

A2A 协议将 Agent 间的通信规约分解为以下三个关键层次:

  1. Agent Card 发现机制:每个符合 A2A 规范的 Agent 都在 GET /.well-known/agent.json 或通过 agent/getCard 方法公开其能力名片,声明其支持的 Skill、输入/输出格式及能力参数(如是否支持 Streaming)。
  2. 任务生命周期状态机:任务具备明确的状态变化:submitted(已提交)→ working(处理中)→ completed(已完成),以及 failed(失败)、canceled(已取消)、rejected(拒绝)与 input-required(需补充输入)。
  3. 双模传输协议:同步任务通过 JSON-RPC 2.0 的 message/send 发送;长耗时或流式任务通过 SSE 的 message/stream 订阅 incremental 输出。

系统三节点拓扑架构如下:

┌────────────────────────────────────────────────────────────┐
前端浏览器客户端 (Vite + React)A2A Client 调度器                      │
│     主题输入 · 配置面板 · JSON-RPC 观察时间线 · Markdown 预览    │
└───────────────┬──────────────────────────────┬─────────────┘
JSON-RPC 2.0 over HTTP (CORS)                ▼                              ▼
   ┌────────────────────┐          ┌────────────────────┐
Researcher Agent  │          │    Writer Agent       (Port 3001)    (Port 3002)   │  streaming: false  │          │  streaming: true   │  message/send      │          │  message/stream    │
   │   ├─ Tavily 搜索引擎 │          │   └─ LLM Token Stream│
   │   └─ LLM 汇总生成   │          │                    │
   └────────────────────┘          └────────────────────┘

时序交互图

浏览器客户端 (5173)        研究员 Agent (3001)           作者 Agent (3002)
       │                            │                             │
       │────── agent/getCard ──────>│                             │
<───── 名片响应 (无流式) ─────│                             │
       │                                                          │
       │───────────────────────── agent/getCard ─────────────────><──────────────────────── 名片响应 (支持流式) ──────────────│
       │                                                          │
       │────── message/send { topic } ───────────────────────────><───── Task Completed { 报告内容, 真实来源 URL } ──────────│
       │                                                          │
       │───────────────────────── message/stream { 报告内容 } ----><──────────────────────── SSE: working 状态 ──────────────│
<──────────────────────── SSE: message/part (逐块输出) ───│
<──────────────────────── SSE: message/complete ──────────│

2. 定义标准 Agent 名片(Agent Card)

Agent 名片是实现去中心化智能体发现的基础。Writer Agent 在名片中明确标明了其具备 capabilities.streaming = true,这为客户端选择调用 message/send 还是 message/stream 提供了契约依据。

Writer Agent Card 数据结构

{
  "name": "Writer Agent",
  "description": "将研究报告转化为结构化文档,支持逐 Token 流式输出。",
  "url": "http://localhost:3002",
  "version": "0.1.0",
  "skills": [
    {
      "id": "structured-drafting",
      "name": "Structured Drafting",
      "description": "根据研究资料生成结构良好的 Markdown 初稿"
    }
  ],
  "capabilities": {
    "streaming": true
  },
  "defaultInputModes": ["text/plain"],
  "defaultOutputModes": ["text/plain"]
}

在跨团队协作多智能体系统时,为了避免不同模型提供商接口兼容性带来的繁琐适配,企业级团队常通过 n1n.ai 统一接入各类 LLM API,使得不论底层的模型是 DeepSeek-V3、Claude 3.5 Sonnet 还是 OpenAI o3,都能保证流畅一致的 API 交互与极低的传输延迟。


3. 实现 Researcher Agent(同步任务处理)

Researcher Agent 负责处理同步交互模式。收到主题后,它会使用大语言模型生成 2–3 个针对性的搜索关键词,调用 Tavily Search API 获取实时网络数据,去重后生成带有引用序号的总结报告。

核心实现代码 (researcher-agent/src/index.ts)

import express, { Request, Response } from 'express';
import crypto from 'crypto';

const app = express();
app.use(express.json());

interface JSONRPCRequest {
  jsonrpc: string;
  method: string;
  params: any;
  id: string | number;
}

app.post('/jsonrpc', async (req: Request, res: Response) => {
  const { jsonrpc, method, params, id } = req.body as JSONRPCRequest;

  if (method === 'agent/getCard') {
    return res.json({
      jsonrpc: '2.0',
      id,
      result: {
        name: 'Researcher',
        capabilities: { streaming: false },
        skills: [{ id: 'web-search', name: 'Web Research' }]
      }
    });
  }

  if (method === 'message/send') {
    const { topic, apiKey } = params;
    
    // 1. LLM 自动扩展搜索关键词
    const queries = await generateSearchQueries(topic, apiKey);
    
    // 2. 调用 Tavily 搜索 API 获取真实网页数据
    const sources = await executeTavilySearch(queries);
    
    // 3. LLM 结构化总结并标注引用
    const summary = await synthesizeFindings(topic, sources, apiKey);

    return res.json({
      jsonrpc: '2.0',
      id,
      result: {
        taskId: crypto.randomUUID(),
        status: { state: 'completed' },
        message: {
          role: 'agent',
          parts: [{ kind: 'text', text: summary }]
        },
        sources: sources.map(s => ({ title: s.title, url: s.url }))
      }
    });
  }

  return res.status(404).json({ error: 'Method not found' });
});

诚实原则:容错与降级设计

在开发 Agent 协作流程时,严禁伪造参考数据。如果用户未配置 Tavily 密钥,Researcher 不应伪造检索链接,而是明确告知客户端:

if (!tavilyKey) \{
  return \{
    taskId: crypto.randomUUID(),
    status: \{ state: 'completed' \},
    message: \{
      role: 'agent',
      parts: [\{ kind: 'text', text: "⚠️ 提示:未配置实时搜索密钥,输出结果完全基于模型已有知识库。