первыйБитБИТ.АГЕНТЫ/туториал

A2A Protocol

Глава 11 из 12

Agent-to-AgentGoogle → Linux Foundation2025

Зачем A2A?

Когда в системе работают несколько агентов, им нужно договариваться: кто что делает, кто кому передаёт результат, как уточнять детали. Без стандарта каждый разработчик изобретает свой протокол — JSON-схемы, REST-ручки, форматы ошибок.

Agent2Agent (A2A) Protocol — открытый стандарт, разработанный Google и переданный Linux Foundation в апреле 2025 года. Он определяет единый язык для взаимодействия агентов независимо от фреймворка, языка или вендора.

A2A vs MCP

A2A и MCP — не конкуренты, а взаимодополняющие стандарты:

MCPA2A
Что соединяетАгент → ИнструментыАгент → Агент
ФорматJSON-RPCJSON-RPC, gRPC, HTTP/REST
DiscoveryКлиент сам знает серверAgent Card через /.well-known/agent.json
МодельЗапрос → ОтветTask-oriented: клиент ставит задачу, агент выполняет
Long-running tasksНе предусмотреноPolling, Streaming, Push-уведомления
UX negotiationНетИзображения, видео, веб-формы, контент-тайпы

MCP отвечает за "как агенту подключиться к данным и инструментам", A2A — за "как агентам сотрудничать друг с другом".

Ключевые понятия

Agent Card

"Визитка" агента в JSON. Содержит имя, описание, URL, список навыков (skills), поддерживаемые виды аутентификации. Доступна по стандартному пути /.well-known/agent.json.

Task

Единица работы с жизненным циклом: submitted → working → completed/failed. Может требовать уточнений (input_required). Результат — артефакты.

Artifact

Результат выполнения задачи. Может быть текстом, изображением, JSON, файлом. Содержит MIME-тип для согласования формата (content-type negotiation).

Message

Сообщение между агентом-клиентом и агентом-сервером. Содержит роль (client/agent), контент и опциональные part-ы (изображения, формы, iframe).

Протокол работы

A2A использует архитектуру клиент — сервер. Агент-клиент находит агента-сервера через Agent Card, отправляет задачу и получает результат:

  1. Discovery: клиент запрашивает /.well-known/agent.json
  2. Task submission: клиент отправляет POST с task_id и query
  3. Execution: сервер выполняет задачу (возможно, с уточнениями)
  4. Delivery: клиент получает результат через polling, streaming или push
  Агент-клиент                  Агент-сервер (пиццерия)
      │                              │
      │  GET /.well-known/agent.json  │
      │─────────────────────────────>│
      │         Agent Card           │
      │<─────────────────────────────│
      │                              │
      │  POST /a2a/task              │
      │  { query: "Закажи пиццу" }   │
      │─────────────────────────────>│
      │  { status: "working" }       │
      │<─────────────────────────────│
      │                              │
      │  (агент готовит пиццу...)    │
      │                              │
      │  GET /a2a/task/:id           │
      │─────────────────────────────>│
      │  { status: "completed",      │
      │    artifacts: [...] }        │
      │<─────────────────────────────│

Модель данных

A2A определяет canonical data model через Protocol Buffers. Вот ключевые типы на TypeScript:

a2a-types.ts
// A2A Task Lifecycle
type TaskStatus =
  | "submitted"   // задача отправлена агенту
  | "working"     // агент выполняет задачу
  | "input_required" // агенту нужны уточнения
  | "completed"   // задача выполнена, есть результат
  | "failed"      // ошибка выполнения
  | "canceled"    // отменено клиентом

interface A2ATask {
  id: string
  status: TaskStatus
  created: string
  updated?: string
  artifacts?: A2AArtifact[]
  error?: { code: string; message: string }
}

interface A2AArtifact {
  type: "text" | "image" | "json" | "file"
  content: string
  content_type?: string  // MIME type, e.g. "text/markdown"
}

interface A2AMessage {
  role: "client" | "agent"
  content: string
  parts?: Array<{
    type: string
    data: unknown
  }>
}

Agent Card

Каждый A2A-совместимый агент публикует Agent Card — JSON-документ с описанием своих возможностей. Это аналог OpenAPI-спецификации или well-known эндпоинта в OAuth:

.well-known/agent.json
// A2A Agent Card — "визитка" агента, доступна по /.well-known/agent.json
{
  "name": "pizza-ordering-agent",
  "description": "Принимает и обрабатывает заказы на пиццу",
  "url": "https://pizza.example.com/a2a",
  "version": "1.0.0",
  "capabilities": {
    "skills": [
      {
        "id": "order_pizza",
        "name": "Заказ пиццы",
        "description": "Оформляет заказ: выбирает размер, топпинги, адрес доставки"
      },
      {
        "id": "check_status",
        "name": "Статус заказа",
        "description": "Проверяет статус текущего заказа"
      }
    ],
    "streaming": true,
    "push_notifications": false
  },
  "authentication": {
    "schemes": [
      { "type": "bearer" }
    ]
  }
}

Сервер (A2A Agent)

Сервер реализует два эндпоинта: /.well-known/agent.json для discovery и /a2a/task для приёма задач. Для long-running задач — отдельный эндпоинт для проверки статуса:

a2a-server.ts
// A2A Server — минимальная реализация
import express from "express"
const app = express()
app.use(express.json())

// Agent Card — эндпоинт для discovery
app.get("/.well-known/agent.json", (req, res) => {
  res.json(agentCard)
})

// A2A Task: принять и выполнить задачу
app.post("/a2a/task", async (req, res) => {
  const { task_id, query, context } = req.body

  // Создаём задачу
  const task = {
    id: task_id,
    status: "working",
    created: new Date().toISOString(),
  }
  res.json(task)

  // Выполняем в фоне (для long-running задач)
  const result = await executeTask(query, context)

  // Отправляем результат через polling/streaming
  await updateTask(task_id, {
    status: "completed",
    artifacts: [{ type: "text", content: result }],
  })
})

// Polling: клиент проверяет статус
app.get("/a2a/task/:id", (req, res) => {
  const task = getTask(req.params.id)
  res.json(task)
})

Клиент (A2A Consumer)

Клиент находит агента через discovery, отправляет задачу и опрашивает статус через polling. Для быстрых задач можно использовать streaming:

a2a-client.ts
// A2A Client — находит агента и отправляет задачу
class A2AClient {
  async discoverAgent(agentUrl: string) {
    const res = await fetch(`${agentUrl}/.well-known/agent.json`)
    return res.json() // Agent Card
  }

  async submitTask(
    agentUrl: string,
    query: string,
    context?: Record<string, unknown>
  ) {
    const taskId = crypto.randomUUID()

    // Отправляем задачу
    const res = await fetch(`${agentUrl}/a2a/task`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        task_id: taskId,
        query,
        context,
      }),
    })
    return { taskId, status: res.status }
  }

  async pollTask(agentUrl: string, taskId: string) {
    while (true) {
      const res = await fetch(`${agentUrl}/a2a/task/${taskId}`)
      const task = await res.json()

      if (task.status === "completed" || task.status === "failed") {
        return task
      }
      await new Promise(r => setTimeout(r, 500)) // polling interval
    }
  }
}

// Использование:
const client = new A2AClient()
const agentCard = await client.discoverAgent("https://pizza.example.com")
// → узнаём, что агент умеет: order_pizza, check_status

const { taskId } = await client.submitTask(
  "https://pizza.example.com",
  "Закажи большую пепперони на ул. Ленина, 10"
)

const result = await client.pollTask("https://pizza.example.com", taskId)
console.log(result.artifacts) // → результат выполнения

Симуляция A2A-диалога

Ниже — симуляция диалога между агентом-консьержем и агентом-пиццерией по протоколу A2A. Клиент находит агента, отправляет задачу, получает уточняющий вопрос и финальный результат:

Экосистема A2A

A2A поддерживается ведущими фреймворками:

Google ADK

Нативная поддержка A2A: RemoteA2aAgent, Agent Engine

LangGraph / CrewAI

A2A-совместимые агенты через Python SDK

Semantic Kernel

C# / Python — встроенная поддержка A2A

Cisco agntcy

Internet of Agents: discovery + group communication + A2A

Далее: в главе 12 — Coding Agents: как агенты пишут код.