A2A na Prática: Quando Seus Agentes Precisam Conversar Entre Si
Ao final deste guia você será capaz de implementar comunicação padronizada A2A entre agentes remotos opacos (usando Agent Card, Task, Artifact), diferenciar de MCP e decidir quando escalar para agentes distribuídos em produção. No meu sistema, A2A é a camada que permite sistemas compostos de partes independentes que crescem juntos — autonomia real, não ilhas.
Quando isso é para você (nível Intermediário): quem já conecta ferramentas via MCP e precisa de agentes em times/ambientes diferentes colaborando sem compartilhar internals.
MCP conecta agentes a ferramentas. A2A conecta agentes a outros agentes. Se você já montou um pipeline multi-agente com CrewAI ou Hermes, provavelmente resolveu a comunicação com chamadas internas — tudo no mesmo processo, mesma memória, mesmas credenciais. Isso funciona até o dia em que o agente de SEO mora no time de marketing, o agente de billing mora no financeiro, e ninguém quer compartilhar código nem API keys.
O Agent2Agent Protocol (A2A) é o padrão aberto que resolve exatamente isso: comunicação padronizada entre agentes opacos — sistemas que não expõem memória interna, tools nem prompts, mas colaboram em tarefas complexas.
Este guia cobre:
- O que é A2A e por que não substitui o MCP (nem o contrário)
- Os conceitos que você precisa dominar: Agent Card, Task, Message, Artifact
- Um cenário real de Martech com orquestrador + agentes remotos
- Código Python com o SDK oficial (
a2a-sdk) - Segurança, identidade e quando não usar A2A
O Problema: Multi-Agente Interno Não Escala Entre Times
A maioria dos tutoriais de multi-agente assume que todos os agentes rodam no mesmo lugar:
Orquestrador → Agente Pesquisa → Agente Escrita → Agente SEO
↑______________________________________________|
(mesmo processo, mesma máquina)
Funciona para protótipos. Quebra quando:
- O agente de SEO é mantido por outro time (ou outro fornecedor)
- Você quer trocar o agente de escrita sem reescrever o orquestrador
- Cada agente precisa de credenciais diferentes e você não quer centralizar tudo
- O trabalho demora minutos e você precisa de polling, streaming ou webhooks
Sem um protocolo comum, cada integração vira uma API customizada — o mesmo pesadelo que o MCP resolveu para ferramentas, agora repetido para agentes.
A analogia: MCP é o USB-C entre IA e ferramentas. A2A é o protocolo de email entre departamentos — cada um com sua caixa de entrada, suas regras e seus entregáveis, mas todos falando a mesma língua.
O Que é A2A
A2A (Agent2Agent Protocol) é um padrão aberto para comunicação entre agentes de IA. Foi desenvolvido originalmente pelo Google e doado à Linux Foundation, com um comitê técnico que inclui AWS, Microsoft, Salesforce, SAP e outras.
O protocolo define:
- Como um agente anuncia suas capacidades (Agent Card)
- Como outro agente descobre e delega tarefas
- Como tarefas longas são rastreadas (estados, artifacts, contexto)
- Como agentes trocam mensagens sem expor implementação interna
Do ponto de vista do cliente, o agente remoto é uma caixa preta: você sabe o que ele faz (skills declaradas), mas não vê memória, tools nem prompts.
Quem apoia o protocolo
O A2A é mantido pela Linux Foundation com um comitê técnico que inclui AWS, Cisco, Google, IBM Research, Microsoft, Salesforce, SAP e ServiceNow, além de uma comunidade ampla de parceiros. Frameworks como LangGraph, CrewAI, Semantic Kernel e Google ADK já contam com integrações. Os SDKs oficiais cobrem Python, JavaScript, Java, C#/.NET, Go e Rust. (Fonte: a2a-protocol.org)
A2A vs MCP vs Multi-Agente Interno
Esta é a confusão mais comum. Os três não competem — operam em camadas diferentes.
| Camada | Protocolo / Pattern | O que conecta | Exemplo |
|---|---|---|---|
| Ferramentas | MCP | Agente → API, banco, arquivo | Agente consulta GA4 via MCP |
| Agentes remotos | A2A | Agente → Agente (opaco) | Orquestrador delega SEO a agente externo |
| Orquestração local | Framework (CrewAI, LangGraph) | Sub-agentes no mesmo runtime | 4 agentes num pipeline de conteúdo |
Regra prática: use MCP dentro de cada agente para tools. Use A2A entre agentes que pertencem a runtimes, times ou fornecedores diferentes. Use orquestração local (CrewAI, LangGraph, Hermes) quando tudo roda no mesmo processo e você não precisa de interoperabilidade.
Os 5 Conceitos Que Você Precisa Saber
Antes de código, os building blocks do protocolo.
1. Agent Card — o cartão de visita
Um documento JSON que descreve quem é o agente, o que ele faz e como falar com ele. Fica exposto em um endpoint HTTP (tipicamente /.well-known/agent-card.json).
Campos essenciais:
| Campo | Função |
|---|---|
name / description |
Identidade pública |
skills |
Lista de capacidades (id, descrição, exemplos) |
supported_interfaces |
URL + protocolo (JSON-RPC, HTTP+JSON, gRPC) + versão |
capabilities |
Streaming, push notifications, extended card |
security_schemes / security_requirements |
OAuth, API key etc. — declarados no card, credenciais via headers HTTP |
O cliente lê o Agent Card antes de delegar qualquer tarefa. É discovery + contrato.
2. Task — unidade de trabalho com estado
Uma Task é um trabalho rastreável com ciclo de vida definido. Estados principais:
| Estado | Significado |
|---|---|
submitted |
Tarefa recebida, ainda não processada |
working |
Agente executando |
input-required |
Agente precisa de mais informação |
auth-required |
Precisa de credencial adicional |
completed |
Entregue com sucesso |
failed / canceled / rejected |
Terminal — não reinicia |
Tarefas são imutáveis após estado terminal. Refinamentos criam uma nova Task no mesmo contextId.
3. Message — turno de conversa
Uma Message é um turno entre cliente e agente. Contém role (user/agent), messageId e uma ou mais Parts. Use Messages para negociação rápida; use Tasks para trabalho longo.
4. Part e Artifact — conteúdo estruturado
Part é o container de conteúdo: texto, JSON, URL de arquivo ou bytes inline. Artifact é o entregável de uma Task — um brief, um relatório SEO, um rascunho de post. Artifacts podem ser streamed incrementalmente.
5. contextId — agrupando interações
O servidor gera um contextId na primeira interação. Todas as Tasks e Messages relacionadas compartilham esse ID. Isso permite refinamentos, tarefas paralelas e rastreabilidade sem expor memória interna do agente remoto.
Cenário Real: Pipeline de Conteúdo com Agentes Remotos
Vamos adaptar o pipeline do post de Martech para A2A. Em vez de 4 agentes no mesmo processo CrewAI, temos:
- Client Agent (Orquestrador) — recebe "crie um post sobre A2A" e coordena
- Remote Agent: SEO Research — analisa SERP, gera brief (usa MCP internamente)
- Remote Agent: Content Writer — escreve rascunho a partir do brief
- Remote Agent: SEO Review — otimiza e valida
A diferença prática: o time de SEO pode atualizar o agente de pesquisa sem tocar no orquestrador. Basta manter o Agent Card compatível (mesmo skill.id ou versionamento explícito). O orquestrador descobre capacidades via card, não via código compartilhado.
Implementação: Servidor A2A em Python
O SDK oficial é o a2a-sdk (Python 3.10+). Vamos criar um Remote Agent mínimo que gera briefs de SEO.
Instalação
pip install "a2a-sdk[http-server]"
Passo 1: Definir a skill e o Agent Card
from a2a.types import AgentCapabilities, AgentCard, AgentInterface, AgentSkill
seo_skill = AgentSkill(
id="serp_brief",
name="SERP Brief Generator",
description="Analisa SERP e gera brief estruturado para conteúdo.",
input_modes=["text/plain", "application/json"],
output_modes=["application/json"],
tags=["seo", "martech", "research"],
examples=["Brief para 'agentes de ia em produção'"],
)
agent_card = AgentCard(
name="SEO Research Agent",
description="Agente remoto de pesquisa SERP para pipelines de conteúdo.",
version="1.0.0",
default_input_modes=["text/plain"],
default_output_modes=["application/json"],
capabilities=AgentCapabilities(streaming=True),
supported_interfaces=[
AgentInterface(
protocol_binding="JSONRPC",
url="http://127.0.0.1:8001",
protocol_version="1.0",
)
],
skills=[seo_skill],
)
O Agent Card é o contrato público. Clientes leem skills para decidir se este agente resolve a tarefa.
Passo 2: Implementar o executor
O executor é onde sua lógica vive — aqui, simplificado:
import json
from a2a.server.agent_execution import AgentExecutor, RequestContext
from a2a.server.events import EventQueue
from a2a.types import (
Artifact,
Part,
TaskArtifactUpdateEvent,
TaskState,
TaskStatus,
TaskStatusUpdateEvent,
)
class SEOBriefExecutor(AgentExecutor):
async def execute(self, context: RequestContext, event_queue: EventQueue) -> None:
# Extrai keyword do input do cliente
user_text = context.get_user_input()
keyword = user_text.strip()
# Na prática: MCP para SerpAPI, análise LLM, etc.
brief = {
"keyword": keyword,
"angle": "foco em produção e código real",
"sections": ["O que é", "Arquitetura", "Implementação", "Armadilhas"],
"competitor_gaps": ["falta conteúdo em PT-BR", "poucos exemplos Python"],
}
await event_queue.enqueue_event(
TaskArtifactUpdateEvent(
task_id=context.task_id,
context_id=context.context_id,
artifact=Artifact(
name="seo_brief.json",
parts=[Part(text=json.dumps(brief, ensure_ascii=False))],
),
)
)
await event_queue.enqueue_event(
TaskStatusUpdateEvent(
task_id=context.task_id,
context_id=context.context_id,
status=TaskStatus(state=TaskState.TASK_STATE_COMPLETED),
)
)
async def cancel(self, context: RequestContext, event_queue: EventQueue) -> None:
await event_queue.enqueue_event(
TaskStatusUpdateEvent(
task_id=context.task_id,
context_id=context.context_id,
status=TaskStatus(state=TaskState.TASK_STATE_CANCELED),
)
)
Nota:
TaskStatusUpdateEventprecisa ser importado dea2a.types— o padrão do SDK separa atualização de artifact e de status. Em produção, o executor chamaria tools via MCP (SerpAPI, crawl) antes de montar o brief.
Passo 3: Subir o servidor
import uvicorn
from a2a.server.request_handlers import DefaultRequestHandler
from a2a.server.routes import create_agent_card_routes, create_jsonrpc_routes
from a2a.server.tasks import InMemoryTaskStore
from starlette.applications import Starlette
handler = DefaultRequestHandler(
agent_executor=SEOBriefExecutor(),
task_store=InMemoryTaskStore(),
agent_card=agent_card,
)
routes = []
routes.extend(create_agent_card_routes(agent_card))
routes.extend(create_jsonrpc_routes(handler, "/"))
app = Starlette(routes=routes)
uvicorn.run(app, host="127.0.0.1", port=8001)
Com o servidor rodando, o Agent Card fica acessível e clientes A2A podem descobrir a skill serp_brief.
Passo 4: Cliente que delega a tarefa
import asyncio
import json
import httpx
from a2a.client import A2ACardResolver, ClientConfig, create_client
from a2a.helpers import new_text_message
from a2a.types import GetTaskRequest, Role, SendMessageRequest, TaskState
async def request_brief(keyword: str) -> dict:
# 1. Descobre capacidades via Agent Card
async with httpx.AsyncClient() as http_client:
resolver = A2ACardResolver(
httpx_client=http_client,
base_url="http://127.0.0.1:8001",
)
card = await resolver.get_agent_card()
assert any(s.id == "serp_brief" for s in card.skills)
# 2. Cria cliente não-streaming (polling)
client = await create_client(
agent=card,
client_config=ClientConfig(streaming=False),
)
# 3. Envia mensagem — itera sobre StreamResponse até receber a Task
request = SendMessageRequest(
message=new_text_message(keyword, role=Role.ROLE_USER)
)
task = None
async for chunk in client.send_message(request):
if chunk.HasField("task"):
task = chunk.task
break
# 4. Aguarda estado terminal com polling e backoff
delay = 1.0
while task.status.state not in (
TaskState.TASK_STATE_COMPLETED,
TaskState.TASK_STATE_FAILED,
TaskState.TASK_STATE_CANCELED,
):
await asyncio.sleep(delay)
delay = min(delay * 2, 8.0)
task = await client.get_task(GetTaskRequest(task_id=task.id))
# 5. Extrai artifact
brief_json = task.artifacts[0].parts[0].text
await client.close()
return json.loads(brief_json)
# Uso no orquestrador
brief = asyncio.run(request_brief("A2A protocol agentes"))
O orquestrador repete o mesmo padrão para o Content Writer (passando o brief como input) e para o SEO Review (passando o rascunho). Cada chamada pode usar um contextId compartilhado para manter o fio da meada.
Ciclo de Vida de uma Task (O Que Esperar em Produção)
Tarefas A2A não são request/response simples. Em produção, você vai encontrar:
Polling — cliente pergunta get_task(task_id) a cada N segundos até estado terminal. Simples, funciona bem para tarefas de 30s–5min.
Streaming (SSE) — agente envia updates em tempo real (working → artifact parcial → completed). Melhor UX para tarefas longas.
Push notifications — cliente registra um webhook via tasks/pushNotification/set e o agente chama essa URL quando há update. Essencial para tarefas de horas (relatórios pesados, pipelines batch).
Imutabilidade importa: se o cliente pede "refaça o brief com foco em enterprise", isso cria uma nova Task referenciando a anterior via referenceTaskIds — não reinicia a Task original. Isso simplifica auditoria e tracing.
Segurança e Identidade com Agentes Remotos
A2A adiciona uma superfície nova: você confia em agentes que não controla. Três princípios:
1. Autenticação declarada no Agent Card
O card especifica os esquemas em security_schemes e os requisitos em security_requirements (OAuth 2.0, API key etc.). Credenciais vão em headers HTTP, separadas do payload A2A. Nunca embuta tokens em Messages.
2. Identidade por agente, não por humano
Cada Remote Agent que seu orquestrador chama deve ter credencial própria — o mesmo framework do post de Identidade e Permissões. O orquestrador usa agent-orquestrador-prod; o SEO Research usa agent-seo-research-prod. Se um remoto for comprometido, você revoga só aquela identidade.
3. Validação de artifacts
Artifacts vêm de caixas pretas. Antes de passar um brief para o próximo agente (ou publicar), valide:
- Schema esperado (campos obrigatórios)
- Tamanho máximo (evita context stuffing)
- Conteúdo (PII, prompt injection no brief)
Isso se conecta diretamente com a defesa em camadas — A2A é mais uma camada de input/output para sanitizar.
4. Extended Agent Card
Agentes podem expor um card público (skills visíveis) e um card estendido (skills extras) só para clientes autenticados. Útil quando skills sensíveis (ex.: acesso a dados internos) não devem aparecer em discovery público.
Quando Usar A2A (e Quando Não)
| Situação | Recomendação |
|---|---|
| 4 agentes no mesmo script Python | Não — use CrewAI/LangGraph/Hermes local |
| Agente mantido por outro time/fornecedor | Sim — A2A |
| Tarefa < 5s, resposta imediata | Talvez — Message basta; Task é overhead |
| Tarefa longa com updates | Sim — Task + streaming/push |
| Precisa trocar implementação sem mudar cliente | Sim — contrato via Agent Card |
| Tudo roda no Hermes Agent com skills | Não — delegação interna resolve |
Heurística: se a fronteira é entre runtimes ou organizações, use A2A. Se a fronteira é entre funções no mesmo sistema, use orquestração local.
Anti-Patterns Comuns
1. Usar A2A como RPC de tool
Chamar um agente remoto para "somar dois números" é desperdício. Tools via MCP resolvem isso. A2A é para colaboração com raciocínio, estado e entregáveis.
2. Expor memória interna no artifact
O protocolo foi desenhado para opacidade. Não vaze prompts, chain-of-thought ou credenciais nos artifacts — só entregáveis.
3. Ignorar versionamento de skills
Mudar o schema do brief sem atualizar version no Agent Card quebra orquestradores silenciosamente. Versione skills e comunique breaking changes.
4. Polling agressivo
Consultar get_task a cada 100ms sobrecarrega servidor e cliente. Use SSE quando disponível; polling com backoff exponencial caso contrário. Exemplo prático: comece em 1s, dobre até no máximo 8–16s.
import asyncio
from a2a.types import GetTaskRequest, TaskState
terminal_states = {
TaskState.TASK_STATE_COMPLETED,
TaskState.TASK_STATE_FAILED,
TaskState.TASK_STATE_CANCELED,
}
delay = 1.0
while task.status.state not in terminal_states:
await asyncio.sleep(delay)
delay = min(delay * 2, 8.0)
task = await client.get_task(GetTaskRequest(task_id=task.id))
5. Um contextId para tudo
Agrupe interações relacionadas, mas não misture sessões de usuários diferentes no mesmo contextId — isso contamina contexto.
A2A + Hermes Agent + MCP: Como Encaixa
No ecossistema que eu uso no dia a dia:
- Hermes Agent como Client Agent local — recebe tarefa do usuário, descobre Remote Agents via Agent Card, delega via A2A
- MCP dentro de cada agente — SEO Research usa MCP para SerpAPI; Writer usa MCP para style guide no Notion
- A2A entre o orquestrador Hermes e agentes remotos mantidos por outros times ou em outros servidores
Você não precisa abandonar o pipeline CrewAI que já funciona. A2A entra quando uma etapa do pipeline precisa sair do seu runtime — ou quando você quer vender/expor um agente como serviço A2A-compliant.
Checklist Antes de Colocar A2A em Produção
- [ ] Agent Card publicado e acessível via HTTPS
- [ ] Skills com
id, descrição e exemplos claros - [ ] Autenticação configurada (OAuth ou API key scoped)
- [ ] Identidade própria para cada Remote Agent
- [ ] Task store persistente (não só
InMemoryTaskStore) - [ ] Timeout e retry com backoff no cliente
- [ ] Validação de artifacts antes de encadear
- [ ] Logs com
taskId,contextIdeagentIdpara tracing - [ ] Testes com a2a-inspector antes do deploy
Conclusão
A2A não substitui MCP nem seu framework de multi-agente favorito. Ele preenche o espaço que faltava: agentes de times, vendors e runtimes diferentes colaborando com um contrato comum.
O que ficou:
- MCP = agente usa ferramentas
- A2A = agente delega para outro agente
- Agent Card = discovery + contrato
- Task = trabalho rastreável com artifacts
- Opacidade = segurança e propriedade intelectual preservadas
Próximos passos:
- Leia o post de MCP na Prática se ainda não conectou ferramentas
- Clone os samples oficiais e rode o helloworld
- Identifique uma etapa do seu pipeline que poderia ser um Remote Agent
- Publique um Agent Card e teste com o a2a-inspector
Ao final deste guia você implementa A2A para agentes que cooperam sem perder opacidade — passo para sistemas distribuídos que crescem no meu sistema.
O futuro não é um agente gigante que faz tudo. É uma rede de agentes especializados que sabem pedir ajuda uns aos outros — com protocolo, não com gambiarra de API.
Construa seu sistema ou consulte:
- Clone os samples oficiais e rode o helloworld (ação imediata)
- Falar comigo no WhatsApp para desenhar seu primeiro A2A orquestrador remoto
Fontes e Referências
- A2A Protocol — Documentação oficial
- A2A e MCP — Comparação detalhada
- Life of a Task — Ciclo de vida
- a2a-python — SDK oficial
- a2a-samples — Exemplos em Python e JS
- Google Developers Blog — Lançamento A2A
Publicado em andrecosta.ia.br.