Consumir agentes externos con A2A: comprar, no criar
Resumen
Criar un segundo agente no es lo mismo que comprar uno. A2A (Linux Foundation) es el contrato agent-to-agent: Agent Card en /.well-known/agent-card.json, SendMessage/GetTask/CancelTask, estados SUBMITTED→WORKING→COMPLETED. Filtro build-vs-buy, wrapper tipado y evals como si el remoto fuera un proveedor. Distinto de orquestar los tuyos y de MCP.

Qué resuelve
Esta pieza se queda en la decisión práctica: qué instalar, qué riesgo agrega y cómo aplicarlo sin romper operación.
Orquestar es criar: tú pones el supervisor, los especialistas y el presupuesto de tokens. Esta guía es comprar: un agente de otro vendor (o de otro equipo) expone un endpoint A2A y tú lo consumes como proveedor. No heredas su prompt, sus tools ni su memoria. Heredas un contrato: Agent Card, tareas con ciclo de vida y un wrapper que valida, recorta y evalúa.
A2A nació en Google y vive en la Linux Foundation. La spec (verificada 2026-09-06) lo dice sin rodeos: agentes opacos. MCP equipa a un agente con tools; A2A deja que dos agentes colaboren sin mezclar contextos. No es MCP y no es envolver tu API como tools.
Contrato: si no hay Agent Card, no hay proveedor. Si no hay wrapper tipado, no hay cliente. Si no hay eval contra el remoto, no hay compra: hay fe.
Una línea
Descubre el Card, autentica, envía una Task, espera un estado terminal, recorta el Artifact. Cero tools del proveedor en tu prompt.
Build vs buy (filtro de 7 minutos)
| Señal | Cría (tuyos) | Compra (A2A) |
|---|---|---|
| El especialista cambia cada sprint | Un subagente en tu repo | No: el Card se mueve sin tu deploy |
| El vendor ya resuelve el dominio (KYC, nómina, legal) | Reinventar es caro | Consume el Card y evalúa SLA |
| Necesitas su memoria o su toolset | No es A2A: es integración íntima | Rechaza; A2A es opaco a propósito |
| Latencia p95 > 8 s mata el webhook | Un tool local | Solo si el Card declara streaming o tú haces async |
| El fallo del remoto no puede tumbar tu bot | Circuito interno | Breaker por dependencia |
| Quieres “un segundo cerebro” por moda | Orquestación dice que no | Tampoco: compra un skill, no un alma |
Si la fila ganadora es “cría”, cierra esta pestaña. A2A no sustituye a un buen tool.
El Card es el contrato, no el README
El servidor MUST publicar un Agent Card. El path canónico (spec §8 + discovery, RFC 8615) es:
GET /.well-known/agent-card.json HTTP/1.1
Host: agente.proveedor.example
El JSON declara identidad, skills, endpoint, capabilities (streaming, pushNotifications, extendedAgentCard) y securitySchemes. Tres estrategias de discovery: well-known, registro curado, o URL pegada a mano. Para un SaaS, well-known o URL fija. No scrapees un marketing site.
Reglas del cliente:
- Cachea el Card con TTL corto (minutos, no días). Un skill que desaparece es un 400, no un alucinación.
- Si
extendedAgentCard: true, pideGetExtendedAgentCarddespués de autenticar. La spec: el Card público puede ocultar skills. - Si
streamingesfalse, no llamesSendStreamingMessage. El servidor MUST devolverUnsupportedOperationError. - Verifica firma JWS si el Card trae
signatures(RFC 7515). Un Card sin autenticar es un menú, no un pasaporte.
Auth vive en securitySchemes, no en el prompt. Si el remoto pide OAuth del usuario, eso es consentimiento, no un header inventado.
Operaciones que tu wrapper sí conoce
La spec separa operaciones abstractas de bindings (JSON-RPC 2.0, gRPC, HTTP/REST). El cliente mínimo no habla “el protocolo entero”: habla cuatro verbos.
| Operación | Para qué | Qué no hagas |
|---|---|---|
SendMessage | Crear o continuar una Task | Meter el system prompt del proveedor |
GetTask | Poll del estado | Parsear HTML de un dashboard |
CancelTask | Abortar; es idempotente | Reintentar cancel contra un terminal |
SendStreamingMessage | SSE/chunks si capabilities.streaming | Asumir que todos lo soportan |
Estados de TaskState (spec §4.1.3) que el wrapper traduce a tu dominio:
| Estado | Qué significa para ti |
|---|---|
SUBMITTED / WORKING | Sigue vivo. No dispares un segundo Send |
COMPLETED | Lee Artifacts. Recorta. Guarda el task_id |
FAILED / REJECTED | Error de proveedor. No reintentes a ciegas |
CANCELED | Terminal. Un segundo Cancel MAY ser TaskNotFoundError |
INPUT_REQUIRED | El remoto te pide más. Eso es HITL del otro, no el tuyo |
AUTH_REQUIRED | Credencial, no otro prompt. Interrumpe, no inventes |
return_immediately en SendMessageConfiguration decide si bloqueas o contestas el webhook y sigues por push/poll. Un bot de Telegram no espera 40 s: envía, guarda task_id, contesta “en proceso”.

Wrapper tipado: el modelo no es el cliente A2A
El LLM no debe ver JSON-RPC crudo. Expón una o dos tools de intención (consultar_kyc, pedir_dictamen_legal) cuyo adapter:
- Resuelve el Card (cache).
- Inyecta auth fuera del contexto.
- Arma un
MessageconPartsde texto o data — no un dump de tu historial. - Espera un estado terminal o se suscribe si hay streaming.
- Devuelve un recorte:
status,artifact_preview,task_id. Presupuesto duro. Tijera muda prohibida: marcatruncated.
Idempotencia: el task_id es la clave. Un retry de red no es un segundo trabajo. Si el proveedor no es idempotente, tú guardas el mapa intent_hash → task_id.
Timeouts: AbortSignal en el HTTP del adapter, no setTimeout decorativo. Si el remoto se pone Open, el breaker corta esa dependencia. Tu bot sigue vivo.
Evalúa al proveedor como evalúas una tool
Comprar sin eval es un vendor lock emocional. Trata el remoto como caja negra:
- Golden set de 20–50 casos: input canónico → Artifact esperado (schema, no prosa).
- Contrato de Card: si un skill desaparece o
securitySchemescambia, el CI falla antes de producción. - SLA: p95, tasa
FAILED/REJECTED, tiempo enWORKING. Eso entra a evals, no a un dashboard de marketing. - Canary: 5 % del tráfico real con comparación humana semanal. Kappa, no “se siente bien”.
Si el proveedor no te deja un sandbox A2A, no lo compras. Un PDF de “enterprise ready” no es un Card.
Checklist de compra
- Card en well-known o URL fija; TTL de cache documentado.
-
securitySchemesreales; token fuera del prompt. - Wrapper con 1–2 tools de intención; el modelo no habla JSON-RPC.
- Mapeo explícito de
TaskState→ tu dominio (incluidoAUTH_REQUIRED). -
CancelTaskcableado; no dejes WORKING eternos. - Breaker por este proveedor; kill switch aparte.
- Golden set + alerta si el Card cambia skills.
- Recorte de Artifacts; PII del remoto no se loguea cruda.
- Distinción escrita: MCP = tools propias; A2A = agente ajeno.

Errores que ya vimos
Pegar el Card entero al system prompt. El Card es para el adapter. El modelo necesita el nombre del skill y dos frases de cuándo usarlo.
Tratar A2A como MCP. MCP te da tools/list. A2A te da un agente que piensa. Si lo que quieres es create_invoice, envuelve la API; no pagues un LLM remoto.
Poll infinito en WORKING. Sin techo (N intentos o wall clock) el webhook ya contestó 200 y tú sigues gastando. Cancela y marca fallo.
Reusar task_id de otro tenant. El contexto A2A agrupa tasks. Tu clave es tenant_id + task_id, siempre.
FAQ
¿A2A reemplaza a LangGraph o CrewAI? No. La spec: A2A no es un ADK. Es el cable entre agentes ya construidos.
¿JSON-RPC es obligatorio? No. La spec tiene bindings JSON-RPC, gRPC y HTTP/REST. El Card declara lo que habla el servidor. Tu wrapper habla uno.
¿Puedo exponer mi agente por A2A y a la vez consumir otro? Sí. Entonces eres servidor y cliente. Dos Cards, dos breakers. No mezcles los task_id.
¿Y si el remoto pide input a mitad? INPUT_REQUIRED no es tu HITL interno. Tradúcelo a una pregunta al usuario o rechaza el skill: no dejes al modelo “adivinar el dato que el otro agente quiere”.
Siguiente paso: el curso para el loop local; esta guía solo cuando el especialista no vive en tu repo. Hub: construir agentes.
Lecturas relacionadas
Sigue explorando Arquitectura y otras piezas para builders.

Orquestación multi-agente: cuándo sí y cuándo es un error

Arquitectura mínima de un agente en producción: webhooks, colas, memoria y handoff

SLO y error budget en agentes: 4 SLIs, burn rápido/lento y política 50/100
