Agent通信协议的核心问题

当多个Agent需要协作时,“说什么"和"怎么说"决定了系统的天花板。一个好的通信协议需要回答:

  1. 消息格式:Agent间交换什么结构的数据?
  2. 寻址机制:消息发给谁?谁能收到?
  3. 语义对齐:不同Agent对同一概念的理解是否一致?
  4. 会话管理:多轮对话如何维持上下文?
  5. 错误处理:消息无法理解或处理失败怎么办?

目前主流的三种路线——MCP(Model Context Protocol)、ACP(Agent Communication Protocol)和自定义协议——各有不同的权衡。

MCP:工具集成的事实标准

设计理念

MCP由Anthropic提出,核心定位是标准化LLM与外部工具/数据源的连接。它不是Agent间通信协议,而是Agent与"世界"的接口协议。

[LLM Agent] ←MCP→ [File System MCP Server]
                ←MCP→ [Database MCP Server]  
                ←MCP→ [API MCP Server]

协议结构

// MCP协议核心消息类型

// 1. 工具发现
{
  "jsonrpc": "2.0",
  "method": "tools/list",
  "id": 1
}

// 响应
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "tools": [
      {
        "name": "search_docs",
        "description": "搜索文档库",
        "inputSchema": {
          "type": "object",
          "properties": {
            "query": {"type": "string"},
            "limit": {"type": "integer", "default": 10}
          },
          "required": ["query"]
        }
      }
    ]
  }
}

// 2. 工具调用
{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "name": "search_docs",
    "arguments": {"query": "架构设计", "limit": 5}
  },
  "id": 2
}

MCP Server实现

from mcp.server import Server
from mcp.types import Tool, TextContent
import json

class DocSearchMCPServer:
    def __init__(self):
        self.server = Server("doc-search")
        self._register_handlers()

    def _register_handlers(self):
        @self.server.list_tools()
        async def list_tools() -> list[Tool]:
            return [
                Tool(
                    name="search_docs",
                    description="搜索内部文档库",
                    inputSchema={
                        "type": "object",
                        "properties": {
                            "query": {
                                "type": "string",
                                "description": "搜索关键词"
                            },
                            "limit": {
                                "type": "integer",
                                "default": 10,
                                "minimum": 1,
                                "maximum": 50
                            }
                        },
                        "required": ["query"]
                    }
                ),
                Tool(
                    name="get_doc",
                    description="根据ID获取文档全文",
                    inputSchema={
                        "type": "object",
                        "properties": {
                            "doc_id": {"type": "string"}
                        },
                        "required": ["doc_id"]
                    }
                )
            ]

        @self.server.call_tool()
        async def call_tool(name: str, arguments: dict) -> list[TextContent]:
            if name == "search_docs":
                results = await self._search(
                    arguments["query"], 
                    arguments.get("limit", 10)
                )
                return [TextContent(
                    type="text",
                    text=json.dumps(results, ensure_ascii=False)
                )]
            elif name == "get_doc":
                doc = await self._get_doc(arguments["doc_id"])
                return [TextContent(type="text", text=doc)]

    async def _search(self, query: str, limit: int) -> list[dict]:
        # 实际搜索逻辑
        pass

    async def _get_doc(self, doc_id: str) -> str:
        # 实际获取逻辑
        pass

ACP:Agent间通信的学术路线

FIPA ACL基础

ACP源自FIPA(Foundation for Intelligent Physical Agents)标准,定义了Agent间的言语行为类型(Communicative Acts)

行为类型 含义 示例
Inform 声明事实 “文件已保存”
Request 请求执行 “请分析这个文件”
Query 查询信息 “数据库有多少条记录?”
Propose 提出方案 “我建议用方案A”
Agree 同意 “同意执行”
Refuse 拒绝 “无法在限定时间完成”
Cancel 取消 “取消之前的请求”

消息结构

from dataclasses import dataclass, field
from enum import Enum
from datetime import datetime

class Performative(Enum):
    INFORM = "inform"
    REQUEST = "request"
    QUERY = "query"
    PROPOSE = "propose"
    AGREE = "agree"
    REFUSE = "refuse"
    CANCEL = "cancel"

@dataclass
class ACLMessage:
    performative: Performative
    sender: str
    receivers: list[str]
    content: str
    language: str = "JSON"        # 内容编码语言
    ontology: str = "default"     # 本体/概念体系
    conversation_id: str = field(default_factory=lambda: str(uuid.uuid4()))
    reply_with: str | None = None
    in_reply_to: str | None = None
    reply_by: str | None = None    # 超时时间
    protocol: str = "fipa-request"  # 交互协议

    def to_dict(self) -> dict:
        return {
            "performative": self.performative.value,
            "sender": self.sender,
            "receivers": self.receivers,
            "content": self.content,
            "conversation_id": self.conversation_id,
            "in_reply_to": self.in_reply_to,
            "protocol": self.protocol
        }

交互协议示例:FIPA-Request

Agent A                    Agent B
   │── request(分析报告) ──→│
   │                        │── agree(同意) ──→│
   │                        │── inform(报告内容) ──→│
   │                        │
   │←── (完成) ─────────────│
class FIPARequestProtocol:
    """FIPA Request交互协议实现"""
    
    async def initiate(self, agent_a, agent_b: str, content: str):
        msg = ACLMessage(
            performative=Performative.REQUEST,
            sender=agent_a.id,
            receivers=[agent_b],
            content=content,
            conversation_id=str(uuid.uuid4()),
            reply_with=f"req-{uuid.uuid4().hex[:8]}"
        )
        await agent_a.send(msg)
        
        # 等待响应
        response = await agent_a.wait_for_reply(msg, timeout=30)
        
        if response.performative == Performative.AGREE:
            # 等待结果
            result = await agent_a.wait_for_reply(response, timeout=300)
            if result.performative == Performative.INFORM:
                return result.content
        elif response.performative == Performative.REFUSE:
            raise Exception(f"Agent B refused: {response.content}")

自定义协议:实用主义路线

设计思路

当MCP的"工具调用"模型和ACP的"言语行为"模型都不够用时,自定义协议可以根据业务需求精确设计:

from pydantic import BaseModel
from typing import Literal, Any

class AgentMessage(BaseModel):
    """自定义Agent通信消息"""
    msg_type: Literal[
        "task_assign",      # 任务分配
        "task_result",      # 任务结果
        "clarify",          # 澄清请求
        "handoff",          # 移交
        "broadcast",        # 广播通知
        "status_sync"       # 状态同步
    ]
    sender: str
    target: str | None = None  # None=广播
    payload: dict[str, Any]
    context_id: str             # 会话上下文ID
    priority: int = 0           # 0=普通, 1=紧急, 2=关键
    requires_ack: bool = True   # 是否需要确认

class TaskAssignPayload(BaseModel):
    task_id: str
    task_type: str
    description: str
    deadline: str
    dependencies: list[str] = []

class ClarifyPayload(BaseModel):
    question: str
    options: list[str] | None = None
    context: str

消息路由器

class MessageRouter:
    def __init__(self):
        self.handlers: dict[str, dict[str, callable]] = {}
        self.middleware: list[callable] = []

    def register(self, agent_id: str, msg_type: str, handler: callable):
        self.handlers.setdefault(agent_id, {})[msg_type] = handler

    def add_middleware(self, mw: callable):
        """日志、鉴权、限流等中间件"""
        self.middleware.append(mw)

    async def route(self, msg: AgentMessage) -> Any:
        # 中间件链
        for mw in self.middleware:
            msg = await mw(msg)
            if msg is None:
                return  # 被中间件拦截

        # 路由到目标Agent
        if msg.target is None:
            return await self._broadcast(msg)
        
        handler = self.handlers.get(msg.target, {}).get(msg.msg_type)
        if not handler:
            raise ValueError(f"No handler for {msg.target}.{msg.msg_type}")
        
        return await handler(msg)

三种协议对比

维度 MCP ACP 自定义协议
定位 Agent↔工具 Agent↔Agent 灵活
标准化
学习成本
生态 快速增长 学术为主
灵活性
语义丰富度 可调
序列化 JSON-RPC JSON/XML 任意
适用规模 单Agent+多工具 多Agent协作 任意

选型决策

你的场景是什么?
├─ Agent连接外部工具/数据源
│   └→ MCP(生态最好,工具复用)
├─ 多个自主Agent协作
│   ├─ 需要丰富语义(协商/拒绝)?
│   │   └→ ACP(言语行为完备)
│   └─ 只需要简单的任务传递?
│       └→ 自定义协议(简单高效)
└─ 混合场景
    └→ MCP(工具层) + 自定义协议(Agent层)

总结

协议选择没有对错,只有匹配度。MCP是当前Agent-工具连接的事实标准,生态优势明显。ACP在学术研究中语义更完备,但工业采用率低。自定义协议最灵活但缺乏生态。实践建议:MCP做工具层 + 轻量自定义协议做Agent层,取各家之长。