代理卡
代理的服务配置文件
一份小型公共文档告诉呼叫者代理的名称、端点、技能、协议版本、安全要求以及是否支持流媒体或通知。
A2A 为 AI 智能体提供了一种标准方式,可以向另一个代理介绍自己、接受作业或任务、报告进度、请求更多信息并返回有用的结果,即使另一个代理在不同的 AI 服务中运行、使用不同的编程语言或代理框架或部署在另一个云中也是如此。两个代理都不需要了解对方是如何构建的。他们使用A2A标准进行通信和协同工作。
ADK-Rust A2A 参考架构
The network contract stays separate from the agent's model, tools, memory, and internal orchestration.
01
代理或应用程序要求另一个代理完成工作。
决定哪位远程专家应接收任务。
发现卡、选择流式传输并发送协议消息。
02
每个兼容的客户端都可以理解的公共合同。
名称、技能、端点、协议版本、安全性和声明的功能。
版本、内容类型、ID、消息部分、元数据、身份和限制。
通过一个共享实现调度 JSON-RPC 或 REST 操作。
03
该框架执行任务并生成类型化的进度。
创建调用上下文并流代理事件。
LLM、工作流、图形、自定义或多代理逻辑。
Rust 工具和 MCP
会话和内存
04
经过验证的状态机使长时间运行的工作变得可检查。
状态、上下文、历史记录、工件、元数据和推送配置。
仅接受有效的转换;终端任务保持终端状态。
05
呼叫者选择接收找零的方式。
返回完整的任务及其工件。
首先是任务,然后是状态和工件更新。
06
长任务可以稍后报告,而无需保持一个连接打开。
客户端监听现有任务的更新。
通过重试和 SSRF 检查进行身份验证的交付。
从想法开始
在一个 ADK-Rust 进程内,代理可以共享 Rust 类型、会话、工具和直接函数调用。一旦代理属于另一个服务或另一个组织,这些私人实施细节就不再是安全的合同。
A2A 定义了该边界处的共享语言。调用者发现远程代理提供的内容、发送结构化消息、通过已知状态跟踪任务并接收工件,而无需知道端点后面运行的模型、框架或工具。
ADK-Rust 在 adk-server 中实现 A2A v1,并将该协议直接连接到 Runner。您在本地测试的同一个代理可以成为网络服务,而 RemoteA2aAgent 让另一个 ADK-Rust 系统通过正常的代理接口使用它。
代理卡
一份小型公共文档告诉呼叫者代理的名称、端点、技能、协议版本、安全要求以及是否支持流媒体或通知。
留言
消息携带角色、唯一 ID 以及一个或多个部分(例如文本或结构化数据)。唯一的 ID 使安全重试成为可能。
任务
任务为远程工作提供 ID、对话上下文、状态、消息历史记录、元数据以及沿途产生的任何工件。
神器
工件是附加到任务的命名结果:报告、决策、计划、生成的文件或其他系统可以使用的其他结构化输出。
关注一份工作
调用者可以等待一个响应、打开实时事件流、订阅现有任务或注册 Webhook 以供以后更新。任务标识和上下文使每种交付模式都附加到同一份工作。
任务状态机
A2A 的作用不仅仅是返回文本。它赋予工作身份、对话上下文、当前状态、历史和工件。 ADK-Rust 在保存之前验证每个转换。
SUBMITTED服务器接受了任务。
WORKING代理正在执行它。
INPUT REQUIRED代理需要更多信息。
AUTH REQUIRED调用者必须提供授权。
COMPLETED工作和工件已准备就绪。
FAILED执行因错误而结束。
CANCELED允许的取消结束了任务。
REJECTED服务器拒绝了任务。
INPUT_REQUIRED,呼叫者发送另一条具有相同内容的消息 contextId。 ADK-Rust 找到任务,返回给 WORKING,附加消息,并继续相同的工作。现实世界的逻辑流程
A customer tells the company's support agent that an order arrived damaged. The support agent remains responsible for the conversation: it understands the request, keeps the customer informed, collects any missing evidence, and presents the final decision. It does not have direct access to warehouse stock, delivery records, or replacement policy.
该操作信息属于单独部署的履行代理。通过 A2A,支持代理可以发现履行代理的职责,将调查作为任务发送给其,跟踪其进度,回答更多信息请求,并接收最终的替换决定。每个服务都有自己的代码、数据、工具、模型提供者和安全控制;它们仅共享 A2A 合约定义的消息、任务状态和工件。
支持协调员读取履行代理的卡并确认其处理订单调查并流式传输进度。
它发送订单号、客户的请求、唯一的 messageId 和新的对话上下文。
远程 ADK-Rust 代理检查订单工具、库存、交付历史记录和公司政策,而不会将这些内部信息暴露给调用者。
如果需要损坏证明,任务将变为 INPUT_REQUIRED,而不是猜测或默默失败。
协调员使用相同的 contextId 提供批准的证据;历史和任务身份保持不变。
该任务完成时会包含状态历史记录以及包含替换决策和后续步骤的工件。
Sequence diagram
Read from top to bottom. The A2A service owns the network contract and task record. The fulfilment agent owns its reasoning and private tools.
Calling agent
Protocol boundary
ADK-Rust Runner
Orders · inventory · policy
GET /.well-known/agent-card.json
Discover skills and streaming
Agent Card
Fulfilment capability published
SendStreamingMessage
ORD-1042 · messageId msg-order-1042
Runner invocation
Create task and execute agent
order.lookup + policy.check
Use private business tools
Evidence required
Damage photo is missing
INPUT_REQUIRED
Persist state and context
SSE status update
Ask support for evidence
SendMessage · same contextId
Approved photo reference
Resume task
INPUT_REQUIRED → WORKING
inventory.reserve
Reserve replacement stock
Artifact + COMPLETED
Replacement decision
Final SSE events
Auditable result returned
代码和电报响应
这些示例使用与 ADK-Rust 实现相同的 v1 操作名称、消息字段、任务状态和 SSE 响应形状。 ID 和订单详细信息是固定的,因此整个对话很容易理解。
let fulfilment = LlmAgentBuilder::new("fulfilment")
.description("Investigates orders and delivery")
.model(model)
.instruction(
"Use the approved order, inventory, and policy tools. Ask for evidence when the replacement policy requires it."
)
.build()?;
A2aServer::builder()
.agent(Arc::new(fulfilment))
.agent_card_name("Fulfilment Agent")
.streaming(true)
.build()?
.serve()
.await?;let fulfilment = RemoteA2aAgent::builder("fulfilment")
.description("Investigates orders and delivery")
.agent_url("https://agents.example.com/fulfilment")
.streaming(true)
.build()?;
let support = LlmAgentBuilder::new("support")
.model(model)
.instruction("Own the customer conversation.")
.sub_agent(Arc::new(fulfilment))
.build()?;{
"jsonrpc": "2.0",
"id": "replace-1",
"method": "SendStreamingMessage",
"params": {
"message": {
"messageId": "msg-order-1042",
"role": "ROLE_USER",
"parts": [{
"text": "Investigate damaged order ORD-1042 and prepare a replacement decision."
}]
}
}
}data: {
"jsonrpc":"2.0", "id":"replace-1",
"result":{"task":{
"id":"task-order-1042",
"contextId":"ctx-order-1042",
"status":{"state":"TASK_STATE_SUBMITTED"}
}}
}
data: {
"jsonrpc":"2.0", "id":"replace-1",
"result":{"statusUpdate":{
"taskId":"task-order-1042",
"contextId":"ctx-order-1042",
"status":{"state":"TASK_STATE_WORKING"}
}}
}{
"statusUpdate": {
"taskId": "task-order-1042",
"contextId": "ctx-order-1042",
"status": {
"state": "TASK_STATE_INPUT_REQUIRED",
"message": {
"role": "ROLE_AGENT",
"parts": [{
"text": "Please provide a photo showing the damaged item."
}]
}
}
}
}{
"jsonrpc": "2.0",
"id": "replace-2",
"method": "SendMessage",
"params": {
"message": {
"messageId": "msg-order-1042-photo",
"contextId": "ctx-order-1042",
"role": "ROLE_USER",
"parts": [{
"text": "Evidence received and approved: damage-photo-8841.jpg"
}]
}
}
}{
"artifactUpdate": {
"taskId": "task-order-1042",
"contextId": "ctx-order-1042",
"artifact": {
"artifactId": "replacement-decision-1042",
"name": "Replacement decision",
"parts": [{
"text": "Approved. Reserve SKU-RED-42 and dispatch with priority shipping."
}]
}
}
}
{
"statusUpdate": {
"taskId": "task-order-1042",
"contextId": "ctx-order-1042",
"status": { "state": "TASK_STATE_COMPLETED" }
}
}A2A v1 API
ADK-Rust实现了A2A v1中的全部11个操作。对于短作业,调用SendMessage并等待任务结果。当工作可能需要更长的时间时,请首先使用 SendStreamingMessage 接收任务,然后通过 SSE 接收实时状态和工件事件。
返回的任务 ID 可让您的客户端重新连接,而无需再次提交作业。它可以获取最新状态、列出相关任务、订阅进一步更新或请求取消。如果客户端无法保持连接打开,它可以注册一个经过身份验证的 Webhook,并让远程代理传递稍后的更改。
发送消息并接收完整的任务或实时流。
SendMessageSendStreamingMessage读取当前工作、列出匹配的任务或在状态允许时取消任务。
GetTaskListTasksCancelTask打开 SSE 订阅以获取已存在任务的更新。
SubscribeToTask创建、读取、列出和删除任务的经过身份验证的 Webhook 目标。
CreatePushConfigGetPushConfigListPushConfigsDeletePushConfig请求代理已发布的服务配置文件的扩展版本。
GetExtendedAgentCardJSON-RPC 和 REST 将调度路由到同一 RequestHandler,因此任务行为不会在传输之间漂移。
传入的 A2A 消息成为 ADK-Rust 内容。 Runner 执行选定的代理并将其事件转换为任务状态和工件。
重复的 messageId 返回现有任务,而不是运行相同的工作两次。生产部署应在重新启动后保留此映射。
第一个 SSE 事件是完整的任务。后续事件携带状态和工件更新,因此客户端始终知道流属于什么。
RemoteA2aAgent 实现 ADK-Rust 代理特征。协调器可以在其代理层次结构中包含网络服务并接收正常的框架事件。
版本协商、消息验证、承载身份验证、速率限制、审计拦截器、Webhook 身份验证和 SSRF 检查可以保护服务。
选择正确的边界
A2A 引入了网络、公共合约、身份验证、故障处理和远程任务状态。当这些成本创造真正的独立性时,它们就很有价值。当每个代理都已经生活在同一个进程中时,它们是不必要的。
当地分代理
远程A2A代理
从Rust代理到网络服务
便利服务器创建一个 Axum 应用程序,其中包含代理卡、会话、A2A 路由和启用的流。远程适配器发现该服务并将其任务更新转换回 ADK-Rust 事件。
use adk_server::a2a::convenience::A2aServer;
let app = A2aServer::quick_start(agent);
let listener = tokio::net::TcpListener::bind(
"0.0.0.0:8080"
).await?;
axum::serve(listener, app).await?;use adk_server::a2a::RemoteA2aAgent;
let fulfilment = RemoteA2aAgent::builder("fulfilment")
.description("Investigates orders and delivery")
.agent_url("https://agents.example.com/fulfilment")
.build()?;
let coordinator = LlmAgentBuilder::new("support")
.model(model)
.sub_agent(Arc::new(fulfilment))
.build()?;RequestHandler::with_runner 显式选择任务存储、推送发送者、代理卡、Runner 服务、JSON-RPC 路由、REST 路由器和版本协商中间件的路径。生产前
ADK-Rust 提供 v1 类型、处理程序、生命周期、客户端、验证、交付原语以及与 Runner 的集成。生产准备情况仍然取决于为您的服务选择的存储、身份、网络、可观察性和操作策略。
仅公布部署真正支持的技能、绑定、流式传输、推送交付和安全方案。
包含的 InMemoryTaskStore 和内存中幂等性映射对于开发很有用。长时间运行的生产工作需要能够在流程重新启动后继续存在的存储。
验证入站呼叫并保护出站推送传送。 HTTP 推送发送器支持承载凭证、通知令牌、重试和私有地址拒绝。
远程工作可能会比请求持续时间更长。定义客户端超时、取消策略、重试行为以及任一服务不可用时会发生什么情况。