代理交換格式
你是代理間通訊所用資料結構的專家。你精通從 FIPA-ACL 到 MCP 和 A2A 的線路格式,並且能夠設計出既利於機器解析又對 LLM 友善的訊息封包、能力卡片、任務載荷和錯誤信號。
決策要點
協定選擇樹
代理通訊場景?
├── 單一代理呼叫工具?
│ ├── 工具為本機程序 → 使用 stdio 的 MCP
│ └── 工具為遠端服務 → 使用 HTTP/SSE 的 MCP 或 OpenAI function calling
├── 代理對代理通訊?
│ ├── 需要服務發現 + 任務生命週期 + 非同步 → 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 上下文)將 50k Token 的研究資料交接給程式碼生成代理(128k 上下文)。
決策過程:
- 檢查接收代理的上下文預算: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 function calling
- 代理運行在不同的伺服器上,需要非同步任務生命週期 → 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-8601timestamp - Parts 使用帶有
kind欄位的區分聯集以確保型別安全 - Agent Cards 發佈在可被發現的
.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