解析 A2A 市场的架构与协议:服务发现(IPFS 注册表)、 micropayment(x402/USDC)、信任与声誉机制。
如今的 Agent 已经高度专业化:一个感知模块、一个规划器、一个 LLM wrapper、一个数据获取器等等。开发者不再把所有能力都塞进一个单体应用,而是将离散的服务暴露出来(例如"summarize-text-v2"、"fetch-weather-latlon"),让其他 Agent 在运行时发现、付费并组合使用它们。
一个 Marketplace 提供三个核心功能:
注意:协议栈特意设计为模块化。你可以如果愿意承受审查风险,将 IPFS 替换为集中式 CDN;如果你需要不同的流动性,可以将 USDC 替换为另一条 L2 上的稳定币。
Agent 通过向 IPFS gateway(或本地 ipfs 节点)发送简单的 HTTP GET 请求来解析一份 manifest。该 manifest 列出了该 Agent 发布的所有服务,每个服务都有一个 MCP-Lite descriptor URL。
// discover.ts – minimal resolver (Node.js ≥18)
import { createHash } from 'crypto';
import { fetch } from 'undici';
const IPFS_GATEWAY = 'https://ipfs.io/ipfs/';
export async function resolveManifest(cid: string) {
const url = `${IPFS_GATEWAY}${cid}/manifest.json`;
const resp = await fetch(url);
if (!resp.ok) throw new Error(`Manifest fetch failed: ${resp.status}`);
return resp.json(); // { services: [{ name, descriptorUrl, priceUsdc }] }
}
// Example usage
(async () => {
const manifest = await resolveManifest('bafybeigdyrzt5wfp7ud7gku7v2kfulza6mnkykakwlwt3e6t2i2jiuowe');
console.log(manifest.services);
})();
权衡点:IPFS 保证不可变性,但冷读会增加约 200-400ms 的延迟。通过 Filecoin 或专用 gateway 固定服务可以降低方差,但会引入运营成本。
当一个 Agent 想调用某个服务时,它首先发送一个不带支付的探测请求。该服务回复 402 Payment Required,并在 x402-payment-request header 中包含:
付款方随后用其私钥对 payload 签名,并在重新发送的请求中带上 x402-payment header。
// x402Client.ts – generic caller using ethers v6
import { ethers } from 'ethers';
import { fetch } from 'undici';
const USDC_BASE = '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913';
const RPC_URL = 'https://base-mainnet.infura.io/v3/<PROJECT_ID>';
const provider = new ethers.JsonRpcProvider(RPC_URL);
const wallet = new ethers.Wallet(process.env.PRIVATE_KEY!, provider);
/**
* Calls an x402‑protected endpoint and returns the JSON payload.
* @param url Full URL of the service endpoint.
* @param body Optional JSON‑serializable body (POST) or undefined (GET).
*/
export async function x402Fetch(url: string, body?: any) {
// 1️⃣ Probe
let probe = await fetch(url, {
method: body ? 'POST' : 'GET',
headers: body ? { 'Content-Type': 'application/json' } : {},
...(body && { body: JSON.stringify(body) }),
});
if (probe.status !== 402) {
// No payment required – return directly
const data = await probe.json();
return data;
}
// 2️⃣ Parse payment request
const reqHeader = probe.headers.get('x402-payment-request');
if (!reqHeader) throw new Error('Missing x402-payment-request header');
const { scheme, network, token, amount, payload } = JSON.parse(reqHeader);
if (scheme !== 'erc20' || network !== 'base' || token.toLowerCase() !== USDC_BASE.toLowerCase())
throw new Error('Unsupported payment scheme');
// 3️⃣ Sign the payload (EIP‑191 signed message)
const message = ethers.getBytes(payload);
const signature = await wallet.signMessage(message);
// 4️⃣ Resend with payment header
const paid = await fetch(url, {
method: body ? 'POST' : 'GET',
headers: {
...(body ? { 'Content-Type': 'application/json' } : {}),
'x402-payment': `${wallet.address}:${signature}`,
},
...(body && { body: JSON.stringify(body) }),
});
if (!paid.ok) throw new Error(`Paid request failed: ${paid.status}`);
return paid.json();
}
// Example: calling a summarizer service
(async () => {
const result = await x402Fetch(
'https://agent-service.example.com/summarize',
{ text: 'The quick brown fox jumps over the lazy dog.', maxLength: 20 }
);
console.log('Summary:', result.summary);
})();
无状态——无需管理托管合约;每次调用都是原子的。
延迟——两次往返(探测 + 付费)在 Base 上增加约 100-200ms。
成本——x402 header 几乎不产生 gas;USDC 转账本身在 Base 上的成本约为 0.0005 USDC(≈ $0.0005)。
MCP-Lite 文档在 OpenAPI 基础上扩展了一个 x-payment 对象,告诉消费者需要支付多少以及使用什么代币。
openapi: 3.1.0
info:
title: Text Summarizer
version: 2.0.0
servers:
- url: https://agent-service.example.com
paths:
/summarize:
post:
summary: Return a concise summary of the supplied text.
operationId: summarize
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [text]
properties:
text:
type: string
description: Input text to summarize.
maxLength:
type: integer
minimum: 10
maximum: 200
default: 60
responses:
'200':
description: Summary result.
content:
application/json:
schema:
type: object
properties:
summary:
type: string
'402':
description: Payment required.
headers:
x402-payment-request:
schema:
type: string
example: |
{"scheme":"erc20","network":"base","token":"0x833589fCD6e