Início / Trilha 4 — Multi-Agentes / Módulo 4.10 — Protocolo A2A
10

Trilha 4 · Módulo 10 · Final

Protocolo A2A

O protocolo Agent-to-Agent (A2A) do Google define como agentes de diferentes sistemas, empresas e frameworks se comunicam de forma padronizada. O fim dos silos de agentes — um padrão aberto para interoperabilidade universal.

6 tópicos ~50 min Avançado Módulo Final
1

Por que o A2A Surgiu

Em 2025, o ecossistema de agentes explodiu. LangChain, CrewAI, AutoGen, Vertex AI, LlamaIndex — cada framework criou sua própria forma de agentes se comunicarem internamente. O problema: um agente LangChain não falava com um agente CrewAI sem código customizado de integração.

O Problema que A2A Resolve

Antes do A2A:

  • Cada framework tem protocolo proprietário
  • Integração entre sistemas requer código customizado
  • Agentes não se descobrem dinamicamente
  • Sem padrão de capacidades, auth ou schema
  • Multi-cloud multi-vendor impossível sem wrapper

Com A2A:

  • Protocolo HTTP padrão, JSON-RPC 2.0
  • Qualquer agente descobre e chama qualquer outro
  • Agent Card autodescritivo (como OpenAPI)
  • Autenticação padronizada via OAuth 2.0
  • Interoperabilidade cross-vendor nativa

Linha do Tempo A2A

Abril 2025 — Lançamento

Google anuncia A2A com suporte de 50+ parceiros (Salesforce, SAP, Atlassian, Deloitte)

Junho 2025 — Spec v1.0

Especificação estabilizada com suporte a streaming, push notifications e artifacts

2026 — Adoção enterprise

Principais cloud providers oferecem suporte nativo; frameworks open-source adotam como padrão

A2A é complementar ao MCP

MCP (Model Context Protocol da Anthropic) define como agentes se conectam a ferramentas e dados. A2A define como agentes se conectam entre si. Não competem — são camadas diferentes de um mesmo ecossistema.

2

Arquitetura A2A

A2A usa HTTP como transporte e JSON-RPC 2.0 como protocolo de mensagens. Cada agente expõe um endpoint — o "A2A Server" — que responde requisições de outros agentes (A2A Clients).

Diagrama de Componentes

Orquestrador

A2A Client

HTTP POST /tasks/send

Agente Remoto

A2A Server

Agente remoto expõe Agent Card em /.well-known/agent.json

Endpoints Padrão A2A

GET /.well-known/agent.json
POST /tasks/send
POST /tasks/sendSubscribe
GET /tasks/{'{'}id{'}'}/status
POST /tasks/{'{'}id{'}'}/cancel

Modos de Comunicação

Síncrono

/tasks/send — aguarda resultado completo

Streaming (SSE)

/tasks/sendSubscribe — recebe atualizações em tempo real via Server-Sent Events

Push (Webhook)

Agente notifica URL configurada quando task completa

JSON-RPC — Estrutura de Requisição A2A

{
  "jsonrpc": "2.0",
  "id": "req-abc123",
  "method": "tasks/send",
  "params": {
    "id": "task-uuid-456",
    "sessionId": "session-789",
    "message": {
      "role": "user",
      "parts": [
        {
          "type": "text",
          "text": "Analise o relatório Q4 e extraia os KPIs principais"
        },
        {
          "type": "file",
          "mimeType": "application/pdf",
          "uri": "gs://bucket/relatorio-q4.pdf"
        }
      ]
    },
    "metadata": {
      "priority": "high",
      "timeout_seconds": 120
    }
  }
}
  
3

Agent Card

O Agent Card é o "cartão de visita" do agente — um JSON autodescritivo servido em /.well-known/agent.json que declara o que o agente sabe fazer, como se autenticar, quais formatos aceita e quais skills possui. É para agentes o que o OpenAPI é para APIs REST.

JSON — Agent Card Completo

{
  "name": "Analista Financeiro IA",
  "description": "Especialista em análise de demonstrativos financeiros, KPIs e forecasting",
  "version": "2.1.0",
  "url": "https://agents.minhaempresa.com/financial-analyst",
  "documentationUrl": "https://docs.minhaempresa.com/financial-agent",

  "capabilities": {
    "streaming": true,
    "pushNotifications": true,
    "stateTransitionHistory": true
  },

  "authentication": {
    "schemes": ["Bearer"],
    "oauthConfig": {
      "tokenUrl": "https://auth.minhaempresa.com/token",
      "scopes": ["agent:financial:read", "agent:financial:write"]
    }
  },

  "defaultInputModes": ["text/plain", "application/json"],
  "defaultOutputModes": ["application/json", "text/plain"],

  "skills": [
    {
      "id": "analyze_balance_sheet",
      "name": "Análise de Balanço Patrimonial",
      "description": "Analisa balanços e extrai índices financeiros (liquidez, endividamento, rentabilidade)",
      "tags": ["financial", "balance-sheet", "kpi"],
      "examples": [
        "Analise o balanço do Q3 e calcule o índice de liquidez corrente",
        "Compare endividamento dos últimos 4 trimestres"
      ],
      "inputModes": ["application/pdf", "application/json"],
      "outputModes": ["application/json"]
    },
    {
      "id": "forecast_revenue",
      "name": "Previsão de Receita",
      "description": "Gera forecast de receita para próximos N períodos com intervalos de confiança",
      "tags": ["forecast", "revenue", "ml"],
      "examples": [
        "Projete receita para os próximos 6 meses com base no histórico"
      ],
      "inputModes": ["application/json"],
      "outputModes": ["application/json", "text/csv"]
    }
  ]
}
  

Descoberta Dinâmica de Agentes

O orquestrador pode buscar agentes em um registro (agent registry) filtrado por tags. Ex: registry.find(tags=["financial", "kpi"]) retorna todos os agentes registrados com essas capacidades — sem precisar hardcodar URLs.

4

Task Protocol

O Task Protocol define o ciclo de vida de uma tarefa no A2A: estados, transições e formato de resposta. Uma task tem um ID único, passa por estados bem definidos e pode retornar artefatos (artifacts) como resultado.

Ciclo de Vida de uma Task A2A

submitted

Recebida

working

Executando

input-required

Aguardando

completed

Concluída

failed

canceled

JSON — Resposta de Task Concluída

{
  "id": "task-uuid-456",
  "sessionId": "session-789",
  "status": {
    "state": "completed",
    "timestamp": "2026-03-03T14:23:45Z"
  },
  "artifacts": [
    {
      "name": "kpi_analysis",
      "description": "KPIs extraídos do relatório Q4",
      "mimeType": "application/json",
      "parts": [
        {
          "type": "data",
          "data": {
            "receita_liquida": 4250000,
            "margem_ebitda": 0.284,
            "crescimento_yoy": 0.187,
            "nps": 72,
            "churn_rate": 0.031
          }
        }
      ]
    },
    {
      "name": "executive_summary",
      "description": "Resumo executivo em texto",
      "mimeType": "text/plain",
      "parts": [
        {
          "type": "text",
          "text": "Q4 demonstrou crescimento de 18.7% YoY com melhora de margem..."
        }
      ]
    }
  ],
  "history": [
    {"role": "user", "parts": [{"type": "text", "text": "Analise o relatório Q4..."}]},
    {"role": "agent", "parts": [{"type": "text", "text": "Processando PDF..."}]}
  ]
}
  

Estado input-required

Quando o agente precisa de mais informação para continuar, transita para input-required e aguarda o client enviar /tasks/{'{'}id{'}'}/send com os dados adicionais. Isso permite diálogos multi-turno entre agentes.

5

Implementando em Python

Como criar um servidor A2A (agente que outros podem chamar) e um cliente A2A (orquestrador que chama outros agentes) usando Python com FastAPI e httpx.

Python — Servidor A2A (Agente Remoto)

from fastapi import FastAPI, HTTPException
from fastapi.responses import StreamingResponse
import uuid, json, asyncio
from pydantic import BaseModel

app = FastAPI()

# Agent Card
AGENT_CARD = {
    "name": "Analista de Texto IA",
    "version": "1.0.0",
    "url": "https://meu-agente.com",
    "capabilities": {"streaming": True},
    "skills": [
        {
            "id": "summarize",
            "name": "Resumir Texto",
            "description": "Gera resumo conciso de textos longos",
            "tags": ["nlp", "summarization"]
        }
    ]
}

# Registry de tasks ativas
tasks: dict = {}

@app.get("/.well-known/agent.json")
async def get_agent_card():
    return AGENT_CARD

@app.post("/tasks/send")
async def send_task(request: dict):
    task_id = request.get("id") or str(uuid.uuid4())
    message = request["params"]["message"]

    # Cria task
    tasks[task_id] = {"state": "submitted", "result": None}

    # Executa (em background)
    asyncio.create_task(process_task(task_id, message))

    # Retorna imediatamente com estado submitted
    return {
        "jsonrpc": "2.0",
        "id": request.get("id"),
        "result": {
            "id": task_id,
            "status": {"state": "working"}
        }
    }

@app.get("/tasks/{task_id}/status")
async def get_task_status(task_id: str):
    if task_id not in tasks:
        raise HTTPException(404, "Task não encontrada")
    return tasks[task_id]

async def process_task(task_id: str, message: dict):
    tasks[task_id]["state"] = "working"
    text = message["parts"][0]["text"]

    # Chama LLM
    summary = await summarize_with_llm(text)

    tasks[task_id] = {
        "state": "completed",
        "artifacts": [{
            "name": "summary",
            "mimeType": "text/plain",
            "parts": [{"type": "text", "text": summary}]
        }]
    }
  

Python — Cliente A2A (Orquestrador)

import httpx
import asyncio
from typing import Optional

class A2AClient:
    def __init__(self, agent_url: str, token: Optional[str] = None):
        self.agent_url = agent_url.rstrip("/")
        self.headers = {"Authorization": f"Bearer {token}"} if token else {}

    async def get_agent_card(self) -> dict:
        async with httpx.AsyncClient() as client:
            resp = await client.get(
                f"{self.agent_url}/.well-known/agent.json",
                headers=self.headers
            )
            return resp.json()

    async def send_task(self, message: str, task_id: str = None) -> dict:
        payload = {
            "jsonrpc": "2.0",
            "id": "req-1",
            "method": "tasks/send",
            "params": {
                "id": task_id or str(uuid.uuid4()),
                "message": {
                    "role": "user",
                    "parts": [{"type": "text", "text": message}]
                }
            }
        }
        async with httpx.AsyncClient(timeout=30) as client:
            resp = await client.post(
                f"{self.agent_url}/tasks/send",
                json=payload,
                headers=self.headers
            )
            return resp.json()

    async def wait_for_completion(
        self,
        task_id: str,
        poll_interval: float = 0.5,
        timeout: float = 120.0
    ) -> dict:
        """Polling até task completar."""
        import time
        start = time.time()

        while time.time() - start < timeout:
            async with httpx.AsyncClient() as client:
                resp = await client.get(
                    f"{self.agent_url}/tasks/{task_id}/status",
                    headers=self.headers
                )
                status = resp.json()

            state = status.get("state")
            if state in ("completed", "failed", "canceled"):
                return status

            await asyncio.sleep(poll_interval)

        raise TimeoutError(f"Task {task_id} não completou em {timeout}s")


# Uso no orquestrador
async def orchestrate():
    client = A2AClient("https://meu-agente.com", token="bearer-token")

    # Descobre capacidades
    card = await client.get_agent_card()
    print(f"Agente: {card['name']} — Skills: {[s['id'] for s in card['skills']]}")

    # Envia task
    result = await client.send_task("Resuma o relatório anual...")
    task_id = result["result"]["id"]

    # Aguarda resultado
    final = await client.wait_for_completion(task_id)
    summary = final["artifacts"][0]["parts"][0]["text"]
    print(f"Resumo: {summary}")
  
6

A2A vs MCP vs Chamada Direta

Três abordagens para integração entre agentes — cada uma com trade-offs claros de complexidade, flexibilidade e interoperabilidade. Escolher a certa depende do contexto.

Critério Chamada Direta MCP A2A
Complexidade Baixa Média Alta
Interoperabilidade Nenhuma Ferramentas Total
Descoberta dinâmica Não Parcial Sim (Agent Card)
Autenticação padronizada Não Básica OAuth 2.0
Streaming nativo Não Parcial SSE nativo
Casos de uso Agentes internos, mesmo framework Agente + tools externas Multi-empresa, cross-cloud, enterprise

Use Chamada Direta quando...

  • Agentes no mesmo processo/framework
  • Equipe pequena, MVP rápido
  • Não precisa de interoperabilidade
  • Latência é crítica

Use MCP quando...

  • Agente precisa de tools externas padronizadas
  • Quer reusar servidores MCP existentes
  • Foco em agente + contexto + dados
  • Ecossistema Anthropic

Use A2A quando...

  • Agentes de múltiplos vendors/times
  • Necessidade de descoberta dinâmica
  • Enterprise cross-cloud
  • Publicar agente como serviço

Visão de Futuro: Ecossistema Unificado

A convergência de A2A (agente-a-agente) + MCP (agente-a-ferramenta) + modelos cada vez mais capazes cria um ecossistema onde qualquer agente pode colaborar com qualquer outro, usar qualquer ferramenta, e ser descoberto por qualquer orquestrador — independente de vendor ou framework. Quem dominar essa arquitetura hoje tem vantagem definitiva em 2026-2027.

Resumo do Módulo

Módulo 10 de 10 da Trilha 4 — Multi-Agentes e Orquestração

Conceitos centrais

  • A2A resolve interoperabilidade cross-vendor de agentes
  • HTTP + JSON-RPC 2.0 como protocolo de transporte
  • Agent Card é o OpenAPI dos agentes
  • Task lifecycle: submitted → working → completed

Na prática

  • FastAPI + httpx para servidor e cliente A2A
  • A2A e MCP são complementares, não concorrentes
  • Streaming nativo via SSE para tasks longas
  • Descoberta dinâmica via registry + tags
4

Trilha 4 Concluida

Voce completou a Trilha 4 — Multi-Agentes e Orquestracao. Da arquitetura hierarquica ao protocolo A2A, agora voce tem o repertorio completo para construir sistemas agênticos de producao.

Proximo passo: Trilha 5 — Memoria e Contexto