// Documentação Técnica

A2A Protocol

Guia completo do protocolo Agent-to-Agent — do funcionamento interno à integração com LangGraph e API Gateway de produção.

HTTP + JSON-RPC 2.0 LangGraph Linux Foundation

O que é o A2A?

O Agent-to-Agent (A2A) é um protocolo aberto criado pelo Google em abril de 2025 e posteriormente transferido para a Linux Foundation. Ele padroniza a comunicação entre agentes de IA de diferentes frameworks e fornecedores, sem que nenhum agente precise expor seu estado interno, memória ou lógica.

Mais de 150 organizações já suportam o A2A, incluindo Google, Microsoft (Azure AI Foundry), Amazon (Bedrock AgentCore), Salesforce, SAP, ServiceNow, Atlassian e PayPal.

Problema que resolve

Sem um padrão, cada par de agentes exigia um conector customizado. O A2A cria uma linguagem comum — permitindo que um agente do LangGraph colabore com um do CrewAI, Semantic Kernel ou qualquer framework compatível.

Agent Card
📋 Descoberta

JSON publicado em /.well-known/agent.json descrevendo capacidades, endpoint e autenticação do agente.

Task
📦 Unidade de trabalho

Unidade fundamental de trabalho, com lifecycle próprio e ID único. Pode ser síncrona ou assíncrona.

Message
💬 Comunicação

Turno de comunicação entre cliente e agente remoto, composto por Parts (Text, File, Data).

Artifact
📤 Saída

Saída tangível gerada pelo agente: documento, dataset, imagem — entregue em chunks via SSE.

Primitivas do protocolo

Papéis na comunicação

PapelDescriçãoResponsabilidade
Client Agent Agente que inicia e delega a tarefa Envia JSON-RPC, monitora status, consome artefatos
Remote Agent Agente que recebe e executa a tarefa Processa, atualiza lifecycle, retorna resultado

Types de Parts

TypeUso
TextPartTexto simples — instrução, resposta, pergunta
FilePartArquivo binário (base64 inline ou URL referenciada)
DataPartJSON estruturado — parâmetros, resultados tabelados

Transporte

Todo o tráfego A2A usa HTTP + JSON-RPC 2.0 como base. Para respostas em tempo real, o protocolo usa Server-Sent Events (SSE). A partir da v0.3, há suporte opcional a gRPC para deployments de alta performance.

Ciclo de uma Task

Cada task percorre um estado bem definido. O contextId agrupa tasks relacionadas ao longo de múltiplas interações.

submitted
Task criada
→
working
Processando
→
input-required
Aguarda input
→
auth-required
Aguarda auth
→
completed / failed / canceled
Estado final
Na primeira mensagem, omita contextId e taskId — o servidor os gera e retorna. Em todas as mensagens subsequentes, inclua-os para manter a continuidade da conversa.

Integração com LangGraph

O LangGraph Server expõe o endpoint A2A automaticamente em /a2a/{assistant_id} quando você roda via langgraph dev ou faz deploy em produção. Não é necessário implementar o protocolo manualmente.

O LangSmith implementa suporte A2A nativo. O endpoint fica disponível automaticamente no Agent Server em /a2a/<assistant_id>.

Iniciando os servidores

bash
# Terminal 1 — Agente A
langgraph dev --port 2024

# Terminal 2 — Agente B
langgraph dev --port 2025

Definindo o agente

Cada agente é um StateGraph do LangGraph. O servidor expõe automaticamente o endpoint A2A.

python
from langgraph.graph import StateGraph, MessagesState
from langchain_anthropic import ChatAnthropic

# Instancia o LLM
llm = ChatAnthropic(model="claude-sonnet-4-20250514")

# Nó de processamento
def call_model(state: MessagesState):
    response = llm.invoke(state["messages"])
    return {"messages": [response]}

# Constrói o grafo
builder = StateGraph(MessagesState)
builder.add_node("agent", call_model)
builder.set_entry_point("agent")
builder.set_finish_point("agent")

graph = builder.compile()

Comunicação A2A entre agentes

O orquestrador envia mensagens JSON-RPC 2.0 para o endpoint de cada agente e mantém o contextId ao longo das rodadas.

python
import asyncio, aiohttp, uuid

async def send_message(session, url, message,
                         context_id=None, task_id=None):
    payload = {
        "jsonrpc": "2.0",
        "method": "message/send",
        "id": str(uuid.uuid4()),
        "params": {
            "message": {
                "role": "user",
                "parts": [{"type": "text", "text": message}],
                # Inclui contextId após primeira mensagem
                **({"contextId": context_id} if context_id else {}),
                **({"taskId": task_id}     if task_id    else {}),
            }
        }
    }
    async with session.post(url, json=payload) as resp:
        data = await resp.json()
        result  = data["result"]
        text    = result["artifacts"][0]["parts"][0]["text"]
        return text, result.get("contextId"), result.get("id")

async def run_conversation():
    agent_a = "http://localhost:2024/a2a/<AGENT_A_ID>"
    agent_b = "http://localhost:2025/a2a/<AGENT_B_ID>"
    message = "Olá, vamos colaborar numa tarefa!"
    context_id = task_id = None

    async with aiohttp.ClientSession() as session:
        for _ in range(3):
            message, context_id, task_id = await send_message(
                session, agent_a, message, context_id, task_id)
            message, context_id, task_id = await send_message(
                session, agent_b, message, context_id, task_id)

asyncio.run(run_conversation())

Arquitetura com Gateway

Como A2A usa HTTP puro, um API gateway é o ponto natural de controle para todo o tráfego entre agentes — autenticação, roteamento, rate limiting e observabilidade.

Orquestrador
Client Agent
→
API Gateway
Auth · Rate Limit · Logs
→
Agente A
/a2a/id_A · :2024
+
Agente B
/a2a/id_B · :2025

Configuração Kong (YAML)

yaml
services:
  - name: agente-a
    url: http://langgraph-agent-a:2024
    routes:
      - name: a2a-agente-a
        paths: ["/agentes/a"]
        strip_path: true
    plugins:
      - name: jwt
        config:
          key_claim_name: iss
          claims_to_verify: [exp]
      - name: rate-limiting
        config:
          minute: 60
          policy: local

Autenticação no Gateway

O Agent Card declara os esquemas de auth suportados, no mesmo formato do OpenAPI. O gateway valida as credenciais antes de encaminhar ao agente.

SchemeHeader HTTPUso típico
apiKeyAPI-Key: <valor>Agentes internos
http BearerAuthorization: Bearer <token>JWT/OAuth2
oauth2Bearer + token endpointAgentes terceiros
openIdConnectBearer + OIDC discoveryEnterprise SSO
mTLSCertificado clienteAlta segurança
O acesso pode ser controlado por skill, conforme declarado no Agent Card. Escopos OAuth específicos podem conceder ao client agent acesso apenas a determinadas skills do remote agent.

Configurando SSE no Gateway

O A2A usa Server-Sent Events para respostas em streaming. O gateway não pode fazer buffering das respostas, caso contrário o cliente só recebe a resposta completa ao final.

NGINX

nginx
location /agentes/ {
    proxy_pass         http://langgraph_upstream;

    # Desabilita buffering — essencial para SSE
    proxy_buffering    off;
    proxy_cache        off;
    proxy_read_timeout 300s;

    # Headers para SSE
    proxy_set_header   Connection '';
    proxy_http_version 1.1;
    chunked_transfer_encoding on;
}
No AWS API Gateway, use HTTP APIs (não REST APIs) — elas suportam streaming nativo. REST APIs têm timeout de 29s, insuficiente para tasks longas.

Proxy A2A com FastAPI

Um gateway leve que combina autenticação JWT, roteamento dinâmico por agente e proxy com suporte a SSE.

python
from fastapi import FastAPI, Request, HTTPException
from fastapi.responses import StreamingResponse
import httpx, jwt

app = FastAPI()

AGENTES = {
    "planejador": "http://agente-planejador:2024/a2a/assistente-abc",
    "executor":   "http://agente-executor:2025/a2a/assistente-xyz",
}

@app.post("/a2a/{agente}")
async def proxy_a2a(agente: str, request: Request):
    # 1. Autenticação JWT
    token = request.headers.get("Authorization", "").replace("Bearer ", "")
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=["HS256"])
    except jwt.InvalidTokenError:
        raise HTTPException(status_code=401, detail="Token inválido")

    # 2. Roteamento
    if agente not in AGENTES:
        raise HTTPException(status_code=404, detail="Agente não encontrado")

    # 3. Proxy com suporte a SSE
    body = await request.json()

    async def stream():
        async with httpx.AsyncClient() as client:
            async with client.stream("POST", AGENTES[agente], json=body) as r:
                async for chunk in r.aiter_bytes():
                    yield chunk

    return StreamingResponse(stream(), media_type="text/event-stream")

Logging e rastreamento

O campo contextId é o identificador de sessão do A2A — use-o para correlacionar todas as mensagens de uma conversa nos seus logs.

python
async def a2a_middleware(request, call_next):
    body = await request.json()

    # Extrai metadados do JSON-RPC
    method     = body.get("method")     # ex: "message/send"
    context_id = (
        body.get("params", {})
            .get("message", {})
            .get("contextId")
    )

    logger.info({
        "protocol":  "a2a",
        "method":    method,
        "context_id": context_id,
        "agent":    request.url.path,
        "timestamp": datetime.utcnow().isoformat(),
    })

    return await call_next(request)

A2A vs MCP

Os dois protocolos são complementares — um agente usa MCP para acessar ferramentas e A2A para delegar subtarefas a outros agentes.

DimensãoA2AMCP
Para quêAgente ↔ AgenteAgente ↔ Ferramentas/APIs
ModeloPeer-to-peer, colaborativoHost-client-server
EstadoStateful (lifecycle de tasks)Stateless (chamadas discretas)
DescobertaAgent Card com skillsLista de tools com schema
StreamingSSE nativo + push webhooksOpcional por implementação
Quem criouGoogle → Linux FoundationAnthropic

O que o Gateway entrega para A2A

  • 1
    Autenticação centralizada

    JWT, OAuth2, mTLS e API Key validados antes de qualquer tráfego chegar ao agente LangGraph.

  • 2
    Roteamento por skill/agente

    O gateway roteia para o agente correto com base no path, header ou Agent Card discovery — os agentes nunca ficam expostos diretamente.

  • 3
    Rate limiting máquina-a-máquina

    Tráfego A2A é mais intenso que tráfego humano — limite por agente/cliente usando headers como X-Agent-Role.

  • 4
    Proxy SSE sem buffering

    proxy_buffering off no NGINX ou HTTP APIs no AWS — essencial para streaming funcionar.

  • 5
    Observabilidade via contextId

    Logue o contextId e o method JSON-RPC em cada request para correlacionar toda a conversa entre agentes.