Протокол Google A2A для межагентного взаимодействия: Agent Cards, Task lifecycle, Streaming, сравнение с MCP.
Agent-to-Agent Protocol (A2A) — это открытый протокол от Google для взаимодействия AI-агентов друг с другом. A2A позволяет агентам, созданным разными разработчиками и на разных фреймворках, обмениваться задачами, данными и статусами выполнения. Протокол был представлен в апреле 2025 года.
Представьте офис, где работают специалисты из разных компаний: дизайнер, программист, маркетолог. Каждый говорит «на своём языке» и использует свои инструменты. A2A — это как общий корпоративный мессенджер с единым форматом задач: любой специалист может поставить задачу другому, отследить статус и получить результат — независимо от того, из какой он компании. Только вместо людей — AI-агенты.
Сейчас AI-агенты — это изолированные системы. Агент на LangChain не умеет общаться с агентом на CrewAI. Корпоративный агент-планировщик не может делегировать подзадачу агенту-исследователю от другого вендора.
A2A решает эту проблему: единый стандарт позволяет любому агенту отправить задачу другому агенту, получать обновления о прогрессе и забирать результат.
Три ключевых концепции:
Agent Card — визитка агента (JSON-файл), описывающая его возможности, навыки и способы связи
Task — единица работы с жизненным циклом: submitted → working → completed / failed
Streaming — обновления в реальном времени через Server-Sent Events (SSE)
A2A и MCP — не конкуренты, а дополнения. MCP стандартизирует подключение агента к инструментам (GitHub, база данных). A2A стандартизирует общение между агентами. Вместе они создают экосистему, где агенты и используют инструменты, и кооперируются друг с другом.
ПромптМультиагентная система с A2A
Агент-координатор получает задачу: «Подготовь отчёт о конкурентах в сегменте AI-поиска»
Ответ модели
Координатор (через A2A):
Находит Agent Card агента-исследователя
→ Навыки: web-research, data-collection
→ Отправляет Task: «Собери данные о Perplexity, Exa, You.com»
Находит Agent Card агента-аналитика
→ Навыки: data-analysis, report-generation
→ (ждёт результат исследователя)
Исследователь: status=working → completed
→ Возвращает Artifact: собранные данные
Координатор отправляет данные аналитику
→ Task: «Проанализируй и создай отчёт»
Аналитик: status=completed
→ Artifact: готовый отчёт в Markdown
Современные AI-агенты работают изолированно. Каждый фреймворк (LangChain, CrewAI, AutoGen, Claude Agent SDK) имеет свой формат взаимодействия. Это создаёт проблемы:
Vendor lock-in — агенты одного фреймворка не общаются с агентами другого
Дублирование — каждая организация создаёт агентов с одинаковым функционалом
Масштабирование — сложно строить системы из агентов разных команд
Без A2A: изолированные системы
LangChain-агент → свой протокол → LangChain-агент
CrewAI-агент → свой протокол → CrewAI-агент
AutoGen-агент → свой протокол → AutoGen-агент
Между фреймворками — стена. Нужен кастомный код для каждой пары.
С A2A: экосистема агентов
Любой агент → A2A Protocol → Любой агент
LangChain → A2A → CrewAI ✓
AutoGen → A2A → Claude Agent SDK ✓
Один стандарт для всех, агенты находят друг друга через Agent Cards.
Agent Card — это JSON-файл, который описывает возможности агента. Каждый A2A-совместимый агент публикует свою карточку по стандартному URL: /.well-known/agent.json
Статус input-required позволяет агенту запросить уточнение. Например, агент-исследователь может спросить: «Нужна информация за какой период — последний месяц или год?». Клиент отправляет ответ, и агент продолжает работу. Это делает A2A пригодным для сложных задач с неопределённостью.
Artifacts — это данные, которые агент возвращает по завершении задачи. Каждый артефакт имеет тип MIME и может содержать текст, JSON, файлы или изображения.
Пример совместного использования: AI-агент для HR получает задачу «найди кандидата на позицию Python-разработчика». Через MCP он обращается к базе данных резюме (MCP-сервер PostgreSQL) и к LinkedIn (MCP-сервер). Через A2A он делегирует техническое интервью агенту-интервьюеру от другого вендора.
Партнёры A2A (количество компаний по категориям)
Облачные платформы (Google, SAP, Salesforce)8%
AI-фреймворки (LangChain, CrewAI, AutoGen)12%
Корпоративный софт (ServiceNow, Workday)10%
Стартапы и инструменты20%
A2A был представлен в апреле 2025 года и продолжает развиваться. Спецификация может меняться, экосистема готовых реализаций ещё формируется. Для продакшена стоит следить за обновлениями спецификации на GitHub.
{
"name": "Research Agent",
"description": "Агент для исследования тем и сбора информации из открытых источников",
"url": "https://research-agent.example.com",
"version": "1.0.0",
"capabilities": {
"streaming": true,
"pushNotifications": true,
"stateTransitionHistory": true
},
"authentication": {
"schemes": ["Bearer"]
},
"defaultInputModes": ["text/plain"],
"defaultOutputModes": ["text/plain", "application/json"],
"skills": [
{
"id": "web-research",
"name": "Web Research",
"description": "Поиск и анализ информации в интернете",
"tags": ["research", "web", "analysis"],
"examples": [
"Исследуй тему 'квантовые компьютеры в 2025'",
"Найди статистику по рынку AI в России"
]
},
{
"id": "summarize",
"name": "Document Summarization",
"description": "Суммаризация документов и статей",
"tags": ["summary", "documents"]
}
]
}
import httpx
import json
async def subscribe_to_task(task_id: str):
"""Подписка на обновления задачи через SSE."""
payload = {
"jsonrpc": "2.0",
"id": 2,
"method": "tasks/sendSubscribe",
"params": {
"id": task_id,
"message": {
"role": "user",
"parts": [{"type": "text", "text": "Начни исследование"}]
}
}
}
async with httpx.AsyncClient() as client:
async with client.stream(
"POST",
A2A_SERVER,
json=payload,
headers={"Accept": "text/event-stream"}
) as response:
async for line in response.aiter_lines():
if line.startswith("data: "):
event = json.loads(line[6:])
result = event.get("result", {})
# Обработка обновлений статуса
if "status" in result:
state = result["status"]["state"]
print(f"Статус: {state}")
if state == "completed":
for artifact in result.get("artifacts", []):
for part in artifact.get("parts", []):
print(f"Результат: {part.get('text', '')}")
break
elif state == "input-required":
msg = result["status"].get("message", {})
print(f"Агент спрашивает: {msg}")
# Здесь нужно отправить ответ
break
elif state == "failed":
msg = result["status"].get("message", {})
print(f"Ошибка: {msg}")
break