代理间交换格式 是做什么的?
您是代理用于通信的数据结构方面的专家。了解从 FIPA-ACL 到 MCP 和 A2A 的线路格式,并且能够设计既机器可解析又对 LLM 友好的消息信封、能力卡片、任务载荷和错误信号。
决策点
协议选择树
Agent通信场景?
├── 单一代理调用工具?
│ ├── 工具是本地进程 → 通过 stdio 的 MCP
│ └── 工具是远程服务 → 通过 HTTP/SSE 的 MCP 或 OpenAI 函数调用
├── 代理间通信?
│ ├── 需要发现 + 任务生命周期 + 异步 → A2A 协议
│ ├── 简单的请求/响应 → 自定义 JSON-RPC 2.0
│ └── 与现有框架集成 → 框架的原生格式
└── 来自 LLM 的结构化输出?
├── 机器可读载荷(API、模式) → 模式优先(Zod/JSON Schema)
└── 创造性/探索性内容 → 验证后解析
模式严格性决策
如果载荷类型为:
├── 工具调用参数 → 始终模式优先(没有结构会出错)
├── 代理能力卡 → 始终模式优先(发现需要可靠性)
├── 任务交接数据 → 始终模式优先(自动化需要结构)
├── 错误/重试信号 → 始终模式优先(编程重试逻辑)
├── 创造性文本输出 → 始终验证后(模式扼杀创造力)
├── 分析结果 → 验证后,使用回退提取
└── 混合内容 → 使用 Parts 数组:DataPart 模式优先,TextPart 验证后
流式与批处理决策
如果用户体验要求:
├── 渐进式输出(面向用户) → 流式(SSE/WebSocket)
├── 长时间运行的任务(>30秒) → 带状态更新的流式
├── 代理到代理管道 → 批处理(更清晰的错误处理)
├── 成本跟踪至关重要 → 批处理(已知的初始 token 计数)
├── 中流恢复需要 → 批处理(流式错误处理很复杂)
└── 简单集成 → 批处理(HTTP 请求/响应)
故障模式
模式漂移
症状: 之前工作的代理间出现运行时验证错误,TypeScript 编译成功但运行时失败 诊断: 模式定义版本不匹配,一个代理更新了模式而没有协调 修复: 在所有模式中添加显式版本字段;实现向后兼容性检查;使用模式注册表进行协调
消息丢失
症状: 对话看起来不完整,代理无限重试,发生重复处理 诊断: 没有去重机制,缺少关联 ID,没有恢复的网络问题 修复: 添加 UUID 消息 ID;实现已见消息跟踪;使用 conversationId 进行线程化;添加带指数退避的重试逻辑
上下文窗口溢出
症状: 代理任务失败并提示“上下文过长”,对话被截断,工具结果不完整 诊断: 交接中没有 token 计数,无限制的上下文积累,缺少总结 修复: 估算每个 Part 的 token 数;实现上下文预算;添加可丢弃优先级系统;使用摘要进行压缩
解析僵化
症状: 代理输出格式错误的 JSON,创造性的任务产生通用响应,高重试率 诊断: 模式优先应用于探索性内容,验证过于严格,没有优雅降级 修复: 对创造性内容使用验证后;实现提取回退;对探索性任务放宽约束
协议巴别塔
症状: 每对代理需要自定义翻译,集成复杂性爆炸,维护负担 诊断: 每个团队发明了自己的线路格式,没有标准化,非我发明综合征 修复: 采用 JSON-RPC 2.0 作为线路标准;对多代理使用 A2A;为遗留系统实现格式适配器
工作示例
示例 1:带上下文窗口限制的任务交接
场景: 研究代理(32k 上下文)向代码生成代理(128k 上下文)交接包含 50k 令牌研究数据的任务。
决策过程:
- 检查接收代理的上下文预算:128k - 8k(系统)- 8k(输出) = 112k 可用
- 研究数据(50k)适合,但为了鲁棒性仍应用上下文预算
- 使用优先级丢弃非关键上下文来构建交接
// 研究代理准备交接
const contextHandoff: ContextHandoff = {
context: [
{ kind: 'text', text: summary, mimeType: 'text/markdown' },
{ kind: 'data', data: criticalFindings, schema: FindingsSchema },
{ kind: 'text', text: detailedNotes, mimeType: 'text/plain' }
],
estimatedTokens: 50000,
droppable: [
{ partIndex: 2, priority: 1, tokenEstimate: 30000 }, // 首先丢弃详细笔记
{ partIndex: 0, priority: 2, tokenEstimate: 15000 } // 不得已时丢弃摘要
],
summary: "关键发现:API 速率限制,需要异步模式",
summaryTokens: 500
};
// 代码生成代理接收并预算
const budget = calculateContextBudget(128000);
if (contextHandoff.estimatedTokens > budget.available) {
// 丢弃低优先级上下文
let remainingBudget = budget.available;
const finalContext = contextHandoff.context.filter((part, index) => {
const droppable = contextHandoff.droppable?.find(d => d.partIndex === index);
if (droppable && droppable.tokenEstimate > remainingBudget) {
return false; // 丢弃这个部分
}
remainingBudget -= droppable?.tokenEstimate || 1000;
return true;
});
}
新手遗漏: 会在没有 token 估算的情况下传递原始研究数据,导致下游上下文溢出。 专家捕获: 使用显式预算和优雅降级来构建交接。
示例 2:A2A 与 MCP 协议选择
场景: 构建一个包含 OCR 代理、分析代理和格式化代理的文档处理系统。
决策过程:
- 多个代理需要发现彼此 → 排除 OpenAI 函数调用
- 代理运行在不同的服务器上,需要异步任务生命周期 → A2A 协议胜过 MCP
- 需要双向通信和任务状态 → 确认选择 A2A
// 文档流经代理管道
const ocrCard: AgentCard = {
agentId: 'ocr-service-v2',
name: 'OCR 文档阅读器',
url: 'https://ocr.company.com',
skills: [{
id: 'extract-text',
inputSchema: { /* PDF/图像模式 */ },
outputSchema: { /* 结构化文本模式 */ }
}],
capabilities: {
streaming: true, // 长时间运行的 OCR 任务需要状态更新
pushNotifications: true, // OCR 完成时通知
stateTransitionHistory: true // 跟踪管道中的进度
}
};
// 向 OCR 代理提交任务
const ocrTask: Task = {
id: generateTaskId(),
state: 'submitted',
messages: [{
id: generateId(),
timestamp: new Date().toISOString(),
sender: { agentId: 'document-processor' },
recipient: { agentId: 'ocr-service-v2' },
conversationId: documentProcessingId,
parts: [
{ kind: 'file', name: 'contract.pdf', content: base64Content, mimeType: 'application/pdf' }
]
}],
artifacts: [],
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString()
};
新手遗漏: 会因“更简单”而选择 MCP,而不考虑双向异步需求。 专家捕获: 认识到需要 A2A 来实现服务发现、任务生命周期和多代理编排。
示例 3:带重试逻辑的错误恢复
场景: 分析代理在处理过程中因速率限制而失败,需要智能重试。
决策过程:
- 从结构化错误代码检测错误类型
- 检查可重试标志和退避参数
- 实现带抖动的指数退避
- 在达到最大重试次数后升级到人工处理
// 代理返回结构化错误
const rateLimitError: AgentError = {
code: 'RATE_LIMITED',
message: 'API 配额已超出。请在 60 秒后重试。',
retryable: true,
retryAfterMs: 60000,
maxRetries: 3,
details: {
quotaType: 'requests_per_minute',
resetTime: '2025-01-08T10:15:00Z'
}
};
// 调用代理实现重试逻辑
async function callAgentWithRetry(agent: AgentCard, task: Task, attempt = 1): Promise<Task> {
try {
return await callAgent(agent, task);
} catch (error) {
if (error instanceof AgentError && error.retryable && attempt <= error.maxRetries) {
// 带抖动的指数退避
const baseDelay = error.retryAfterMs || 1000;
const jitter = Math.random() * 0.1 * baseDelay;
const delay = baseDelay * Math.pow(2, attempt - 1) + jitter;
await sleep(delay);
return callAgentWithRetry(agent, task, attempt + 1);
} else {
// 不可重试或达到最大尝试次数
return {
...task,
state: 'failed',
artifacts: [{
id: generateId(),
name: 'error-report',
parts: [{ kind: 'error', ...error }],
createdAt: new Date().toISOString(),
index: 0
}]
};
}
}
}
新手遗漏: 会立即重试而没有退避,或在第一次失败后就放弃。 专家捕获: 使用结构化错误代码进行智能重试,带有适当的退避和升级机制。
质量门
- 每封邮件信封都包含唯一的
id、conversationId和 ISO-8601 格式的timestamp - Parts 对类型安全使用带
kind字段的判别联合 - 代理卡发布在可发现的
.well-known/agent.jsonURL 上 - 错误对象包含
retryable布尔值和类型化的code枚举 - 上下文交接包含 token 估算和基于优先级的丢弃
- 所有模式验证往返:序列化 → 反序列化 → 与原始值相等
- 二进制内容使用 URI 引用,而不是 base64 嵌入
- 跨模式版本保持向后兼容性
- 流式事件包含单调递增的序列号以保证顺序
- 消息元数据中没有敏感数据(使用适当的认证头)
不适用边界
此技能不应用于:
- 对话语义:代理之间说什么 → 请使用
agent-conversation-protocols - 编排拓扑:代理如何连接 → 请使用
multi-agent-coordination - 基础设施设置:部署代理运行时 → 请使用
agentic-infrastructure-2026 - 单代理框架:构建单个代理 → 请使用
ai-engineer - API 设计:设计 REST/GraphQL API → 请使用
api-design-patterns
委托给:
- 模式验证逻辑 → 对于 Zod/品牌类型,请使用
typescript-advanced-patterns - 网络传输 → 对于 HTTP/WebSocket 设置,请使用
systems-architecture - 认证流程 → 对于 OAuth2/JWT 实现,请使用
auth-patterns