Agent Card en A2A: ejemplo JSON completo y desglose de campos
Una Agent Card es un documento JSON que indica a un agente cliente a quién llamar, dónde enviar una tarea y qué habilidades están disponibles. En el protocolo A2A (Agent2Agent) la tarjeta suele publicarse en /.well-known/agent-card.json: sin ella el agente es difícil de descubrir; con una descripción vaga, difícil de enrutar bien.
- Agent Card - contrato público de las capacidades del agente
- Discovery - localización de la tarjeta por URL well-known o registry
- skills - habilidades concretas, no un genérico «sé hacerlo todo»
- capabilities - streaming, push, tarjeta extendida
- security - esquemas de autenticación al estilo OpenAPI
Para qué sirve la Agent Card
A2A conecta agentes independientes: uno actúa como cliente y otro como ejecutor. Antes de enviar una tarea, el cliente lee la tarjeta y responde:
- ¿Encaja este agente con la intención del usuario?
- ¿Qué endpoint acepta tareas?
- ¿Qué tipos MIME admite en entrada y salida?
- ¿Hace falta autenticación y de qué tipo?
- ¿Hay streaming de eventos y notificaciones webhook?
La tarjeta no es texto de marketing. La analizan orquestadores y routers LLM. Cuanto más precisos sean description, skills y examples, más estable será la elección del ejecutor.
Ejemplo JSON completo
Abajo hay un ejemplo funcional para un agente que busca productos en un sitio, calcula el precio y crea una solicitud tras la confirmación del usuario. Los campos usan camelCase, como en las tarjetas JSON típicas de A2A.
{
"name": "Site Commerce Agent",
"description": "Busca productos en el catálogo del sitio, calcula precio y plazo de entrega, y crea una solicitud tras la confirmación del usuario. Trabaja con catálogo, carrito borrador y estados de pedido. No procesa pagos ni cambia precios.",
"version": "1.2.0",
"protocolVersion": "0.3.0",
"url": "https://api.example.com/a2a",
"documentationUrl": "https://docs.example.com/a2a/commerce-agent",
"iconUrl": "https://example.com/icons/commerce-agent.svg",
"provider": {
"organization": "Example Shop",
"url": "https://example.com"
},
"capabilities": {
"streaming": true,
"pushNotifications": true,
"stateTransitionHistory": true,
"extendedAgentCard": false
},
"defaultInputModes": [
"text/plain",
"application/json"
],
"defaultOutputModes": [
"text/plain",
"application/json"
],
"skills": [
{
"id": "search-products",
"name": "Búsqueda de productos",
"description": "Busca productos por consulta, categoría, precio y disponibilidad. Devuelve candidatos con id, nombre, precio y descripción breve.",
"tags": ["catalog", "search", "products"],
"examples": [
"Busca portátiles de menos de 800 euros con entrega esta semana",
"Muestra tarifas disponibles para un equipo de 20 personas"
],
"inputModes": ["text/plain", "application/json"],
"outputModes": ["application/json", "text/plain"]
},
{
"id": "calculate-quote",
"name": "Cálculo de presupuesto",
"description": "Calcula precio, impuestos, envío y plazo para las posiciones y cantidades seleccionadas. No crea el pedido.",
"tags": ["pricing", "quote", "shipping"],
"examples": [
"Calcula el coste de 3 unidades de product_id=sku-1042 con entrega a Berlín",
"Compara las tarifas Basic y Pro para 50 usuarios"
],
"inputModes": ["application/json", "text/plain"],
"outputModes": ["application/json"]
},
{
"id": "create-lead",
"name": "Creación de solicitud",
"description": "Crea un borrador de solicitud o lead tras la confirmación explícita del usuario. Requiere contacto y consentimiento para el tratamiento de datos.",
"tags": ["lead", "order-draft", "crm"],
"examples": [
"Crea una solicitud del plan Pro para ACME, contacto: ops@acme.example",
"Prepara un borrador de pedido a partir de quote_id=q-7781"
],
"inputModes": ["application/json"],
"outputModes": ["application/json", "text/plain"]
},
{
"id": "get-order-status",
"name": "Estado del pedido",
"description": "Devuelve el estado de pago y entrega por order_id para un usuario autenticado o un número de seguimiento público.",
"tags": ["orders", "status", "tracking"],
"examples": [
"¿Cuál es el estado del pedido ORD-20441?",
"¿Dónde está el paquete con el tracking TRK-998877?"
]
}
],
"securitySchemes": {
"bearer": {
"type": "http",
"scheme": "bearer",
"bearerFormat": "JWT"
},
"oauth2": {
"type": "oauth2",
"flows": {
"clientCredentials": {
"tokenUrl": "https://auth.example.com/oauth/token",
"scopes": {
"catalog:read": "Lectura de catálogo y presupuestos",
"leads:write": "Creación de solicitudes",
"orders:read": "Lectura de estados de pedido"
}
}
}
}
},
"security": [
{
"oauth2": ["catalog:read"]
},
{
"bearer": []
}
]
}
En A2A v1.0 el endpoint suele describirse con el array supportedInterfaces en lugar de un único url de nivel superior. La idea es la misma: indicar dónde enviar tareas y qué binding usar (JSONRPC, HTTP+JSON, GRPC, etc.).
Fragmento de ejemplo para v1.0:
{
"supportedInterfaces": [
{
"url": "https://api.example.com/a2a",
"protocolBinding": "JSONRPC",
"protocolVersion": "1.0"
}
]
}
Desglose de campos de nivel superior
| Campo | Obligatoriedad | Propósito |
|---|---|---|
name |
Sí | Nombre legible del agente |
description |
Sí | Resumen concreto: qué hace y qué no |
version |
Sí | Versión de la implementación (mejor semver) |
url / supportedInterfaces |
Sí* | Endpoint(s) de tareas, no la URL de la tarjeta |
skills |
Sí | Al menos un skill |
capabilities |
Recomendado | Flags honestos de capacidades |
defaultInputModes / defaultOutputModes |
Recomendado | MIME por defecto |
provider |
No | Organización propietaria |
documentationUrl / iconUrl |
No | Documentación e icono para la UI |
protocolVersion |
Depende del esquema | Versión del protocolo (a menudo arriba en v0.3) |
securitySchemes / security |
No | Cómo debe autenticarse el cliente |
* En esquemas v0.3 suele ser obligatorio url. En v1.0 el rol del endpoint lo asume supportedInterfaces.
name y description
name sirve a personas y logs. description lo leen los routers. Mal: «Un agente útil para el sitio». Bien: listar operaciones, límites y forma del resultado.
version
Es la versión de la implementación del agente, no necesariamente la del protocolo. Sube major ante breaking changes en skills o en el contrato de respuesta. Los clientes pueden cachear la tarjeta y actualizarla al cambiar la versión.
url - error frecuente
url es la dirección a la que van message/send / las tareas. No es la ruta a /.well-known/agent-card.json.
Incorrecto:
"url": "https://example.com/.well-known/agent-card.json"
Correcto:
"url": "https://api.example.com/a2a"
capabilities
| Flag | Significado |
|---|---|
streaming |
Soporta respuestas en streaming (SSE / stream) |
pushNotifications |
Webhooks para tareas largas |
stateTransitionHistory |
Historial de transiciones de estado de la tarea |
extendedAgentCard |
Tras auth hay una tarjeta extendida/privada |
Pon true solo si el comportamiento está implementado de verdad. Un cliente que abra un stream contra un agente sin streaming recibirá un error.
defaultInputModes y defaultOutputModes
MIME por defecto para todo el agente. Un skill puede sobrescribirlos. Valores típicos: text/plain, application/json, application/pdf, image/png.
Desglose de skills
Un skill es una unidad de enrutado. Un skill = una capacidad clara.
| Campo | Obligatoriedad | Comentario |
|---|---|---|
id |
Sí | Único en el agente; kebab-case es práctico |
name |
Sí | Nombre corto para la UI |
description |
Sí | Qué acepta, qué devuelve, qué límites tiene |
tags |
No | Palabras clave para búsqueda y filtrado |
examples |
No, pero muy recomendable | 2-3 prompts reales para el orquestador |
inputModes / outputModes |
No | Override MIME de este skill |
Los ejemplos no son decoración. Sin ellos el orquestador adivina las entradas solo con la descripción y falla más.
Skill malo:
{
"id": "website",
"name": "Website",
"description": "Trabaja con el sitio"
}
Un skill bueno es como en el ejemplo completo: id concreto, límites claros, tags y examples.
Autenticación: securitySchemes y security
Los esquemas suelen seguir el enfoque OpenAPI:
apiKeyhttp(Basic / Bearer)oauth2openIdConnectmutualTLS
securitySchemes describe los métodos disponibles. security define el requisito por defecto:
- varios objetos en el array
security= alternativas (OR); - varias claves en un mismo objeto = hace falta todo a la vez (AND).
Publica cómo autenticarse, no los secretos. No pongas API keys, refresh tokens ni hostnames internos en el JSON.
Discovery: cómo se encuentra la tarjeta
Flujo típico:
- El cliente conoce el dominio base del agente.
- Solicita
https://agent.example.com/.well-known/agent-card.json. - Valida los campos obligatorios.
- Elige un skill por descripción, tags y examples.
- Se autentica según
security. - Envía la tarea a
url/supportedInterfaces.
La tarjeta también se publica en registries o directorios. Entonces el discovery pasa por búsqueda, y well-known sigue siendo la fuente de verdad del propietario.
Comprobación local:
curl -s https://api.example.com/.well-known/agent-card.json
Qué no publicar en la Agent Card
- API keys, contraseñas, private keys;
- URLs internas de admin o staging sin protección;
- operaciones no disponibles para clientes externos;
- capabilities infladas (
streaming: truesin implementación); - skills vagos del tipo «hace de todo en el sitio».
La tarjeta pública es a la vez superficie de ataque y de enrutado. Mantenla precisa y mínimamente suficiente.
Errores frecuentes
- Confundir
urlcon la URL de la tarjeta. - Array
skillsvacío. El agente queda casi imposible de enrutar. - Descripción sin límites. No se dice qué no hace (pago, borrado, cambio de precios).
- Sin
examples. El orquestador entiende peor la entrada válida. - localhost en una tarjeta de producción. El endpoint debe ser alcanzable.
- Un solo skill para todo el producto. Mejor varios skills estrechos con distintos derechos y MIME.
Mini checklist antes de publicar
- La tarjeta se sirve por HTTPS con
Content-Type: application/json. - Tiene
name,description,version, endpoint y al menos un skill. - Las descripciones son concretas.
- Los skills clave tienen
examplesytags. capabilitiescoinciden con el servidor real.- El JSON no contiene secretos.
- El endpoint de la tarjeta responde a una tarea de prueba.
- La versión sube ante breaking changes.
Conclusión
La Agent Card es el contrato principal de discovery en A2A. Un JSON completo con skills precisos, capabilities honestas y security explícita da a los agentes cliente datos suficientes para encontrar al ejecutor correcto y no llamar al equivocado.
Si necesitas ayuda para diseñar una Agent Card, un servidor A2A o la conexión de un agente con la API del sitio - contacta conmigo.
Preguntas frecuentes
¿Dónde debe estar la Agent Card?
La ruta pública estándar es /.well-known/agent-card.json en el dominio del agente. También puedes registrarla en un catálogo o registry, pero la URL well-known sigue siendo un punto de discovery cómodo sin un índice aparte.
¿En qué se diferencia url de la dirección de la tarjeta?
La dirección de la tarjeta sirve para discovery; url (o supportedInterfaces) para ejecutar tareas. El cliente primero lee el JSON y luego envía mensajes/tareas al endpoint de trabajo del agente.
¿Cuántos skills debe tener una tarjeta?
Tantos como capacidades realmente distintas con entradas o permisos diferentes. Suele ser mejor 3-7 skills estrechos que uno genérico «hazlo todo». Para el enrutado importan límites claros, tags y examples.
¿Es obligatoria la autenticación en la Agent Card?
No siempre. Un agente público de solo lectura puede omitir security. Para escritura, datos personales y operaciones de pago declara securitySchemes y security, y guarda los secretos fuera de la tarjeta.
¿Hay que actualizar la tarjeta en cada deploy?
Actualízala cuando cambien skills, endpoint, capabilities, auth o el significado del agente. Un patch técnico sin cambio de contrato puede reflejarse en version; los breaking changes merecen major y documentación explícita.