Protocolos de comunicación
Type: Build
Languages: TypeScript
Prerequisites: Phase 14 (Agent Engineering), Lesson 16.01 (Why Multi-Agent)
Time: ~120 minutes
Objetivos de aprendizaje
- Implementar la detección y la invocación de herramientas de MCP para que los agentes puedan utilizar herramientas expuestas por servidores externos
- Construir una tarjeta de agente A2A y un punto final de tarea que permita a un agente delegar trabajo a otro a través de HTTP
- Comparar el MCP (acceso a herramientas), el A2A (agente a agente), el ACP (auditoria empresarial) y el ANP (confianza descentralizada) y explicar qué protocolo resuelve qué problema
- Conectar múltiples protocolos juntos en un solo sistema donde los agentes descubren herramientas a través de MCP y delegan tareas a través de A2A
El problema
Se divide el sistema en múltiples agentes, un investigador, un codificador, un revisor, son excelentes en sus trabajos individuales, pero ahora se necesita que realmente hablen entre sí.
El primer intento es obvio: pasar cadenas. El investigador devuelve un fragmento de texto, el codificador lo analiza de la manera que puede. Funciona hasta que el codificador malinterpreta un resumen de la investigación, o dos agentes se quedan en un punto muerto esperando el uno al otro, o necesitas agentes construidos por diferentes equipos para colaborar. De repente "sólo pasar cadenas" se desmorona.
Sin un contrato compartido para cómo los agentes intercambian información, los sistemas multiagentes son frágiles, inaudibles e imposibles de escalar más allá de un puñado de agentes que usted personalmente escribió.
El ecosistema de IA ha respondido con cuatro protocolos, cada uno resolviendo una parte diferente del problema:
- MCPpara el acceso a las herramientas
- A2Apara la colaboración entre agentes
- ACPpara la auditabilidad de las empresas
- ANPpara la identidad y la confianza descentralizadas
Esta lección va en profundidad. Leerás formatos reales de cada especificación, construirás implementaciones de trabajo y conectarás los cuatro en un sistema unificado.
El concepto
El panorama del protocolo
Piensa en estos cuatro protocolos como capas, cada una abordando una pregunta diferente:
flowchart TD ANP["ANP — How do agents trust strangers?<br/>Decentralized identity (DID), E2EE, meta-protocol"] A2A["A2A — How do agents collaborate on goals?<br/>Agent Cards, task lifecycle, streaming, negotiation"] ACP["ACP — How do agents talk in auditable systems?<br/>Runs, trajectory metadata, session continuity"] MCP["MCP — How does an agent use a tool?<br/>Tool discovery, execution, context sharing"] style ANP fill:#f3e8ff,stroke:#7c3aed style A2A fill:#dbeafe,stroke:#2563eb style ACP fill:#fef3c7,stroke:#d97706 style MCP fill:#d1fae5,stroke:#059669
No son competidores, resuelven diferentes problemas a diferentes niveles.
MCP (recap)
El MCP se cubre en profundidad en la Fase 13. Resumen rápido: MCP estandariza cómo un LLM se conecta con herramientas externas y fuentes de datos.client-serverprotocolo en el que el agente (cliente) descubre y llama a las herramientas expuestas por un servidor.
sequenceDiagram
participant Agent as Agent (client)
participant MCP1 as MCP Server<br/>(database, API, files)
Agent->>MCP1: list tools
MCP1-->>Agent: tool definitions
Agent->>MCP1: call tool X
MCP1-->>Agent: resultEl MCP es agent-to-toolNo ayuda a los agentes a hablar entre sí.
A2A (Protocolo sobre agentes2agentes)
Created by:Google (ahora bajo la Fundación Linux como lf.a2a.v1(en inglés)
Spec version:1.0.1
Problem:¿Cómo colaboran, negocian y se delegan tareas los agentes autónomos?
A2A es el protocolo para peer-to-peer agent collaboration. Cuando MCP conecta a un agente a herramientas, A2A conecta a un agente a otros agentes.Agent Carden una URL conocida, y otros agentes descubren, negocian y delegan tareas a ella.
#### Cómo funciona A2A
sequenceDiagram
participant Client as Client Agent
participant Remote as Remote Agent
Client->>Remote: GET /.well-known/agent-card.json
Remote-->>Client: Agent Card (skills, modes, security)
Client->>Remote: POST /message:send (returnImmediately)
Remote-->>Client: Task (TASK_STATE_SUBMITTED or TASK_STATE_WORKING)
alt Polling
Client->>Remote: GET /tasks/{id}
Remote-->>Client: Task status + artifacts
else Streaming
Client->>Remote: POST /message:stream
Remote-->>Client: SSE: statusUpdate
Remote-->>Client: SSE: artifactUpdate
Remote-->>Client: SSE: statusUpdate TASK_STATE_COMPLETED, stream closes
end#### La tarjeta de agente real
Así es como se ve una tarjeta de agente A2A en la naturaleza.GET /.well-known/agent-card.json¿Qué es esto ?
json{
"name": "Research Agent",
"description": "Searches documentation and summarizes findings",
"version": "1.0.0",
"supportedInterfaces": [
{
"url": "https: TOK0
"protocolBinding": "JSONRPC",
"protocolVersion": "1.0"
},
{
"url": "https://research-agent.example.com/a2a/rest",
"protocolBinding": "HTTP+JSON",
"protocolVersion": "1.0"
}
],
"provider": {
"organization": "Your Company",
"url": "https: TOK2
},
"capabilities": {
"streaming": true,
"pushNotifications": false
},
"defaultInputModes": ["text/plain", "application/json"],
"defaultOutputModes": ["text/plain", "application/json"],
"skills": [
{
"id": "web-research",
"name": "Web Research",
"description": "Searches the web and synthesizes findings",
"tags": ["research", "search", "summarization"],
"examples": ["Research the latest changes in React 19"]
},
{
"id": "doc-analysis",
"name": "Documentation Analysis",
"description": "Reads and analyzes technical documentation",
"tags": ["docs", "analysis"],
"inputModes": ["text/plain", "application/pdf"],
"outputModes": ["application/json"]
}
],
"securitySchemes": {
"bearer": {
"httpAuthSecurityScheme": {
"scheme": "Bearer",
"bearerFormat": "JWT"
}
}
},
"securityRequirements": [{ "schemes": { "bearer": { "list": [] } } }]
}Las cosas clave que hay que notar:
- SkillsCada uno tiene un ID, etiquetas y tipos MIME de entrada/salida compatibles. Así es como un agente cliente decide si este agente remoto puede manejar su solicitud.
- supportedInterfacesUna sola agente puede hablar JSON-RPC, REST y gRPC simultáneamente.
- Securityse incorpora en la tarjeta:
securitySchemesNombrar cada régimen ysecurityRequirementsEl cliente sabe qué autor necesita antes de hacer una sola solicitud.
#### Ciclo de vida de las tareas
Las tareas son la unidad central de trabajo en A2A. Se mueven a través de estados definidos (el diagrama deja caer la TASK_STATE_prefijo que cada estado lleva en el cable):
stateDiagram-v2
[*] --> SUBMITTED
SUBMITTED --> WORKING
WORKING --> INPUT_REQUIRED: needs more info
INPUT_REQUIRED --> WORKING: client sends data
WORKING --> COMPLETED: success
WORKING --> FAILED: error
WORKING --> CANCELED: client cancels
SUBMITTED --> REJECTED: agent declines
COMPLETED --> [*]
FAILED --> [*]
CANCELED --> [*]
REJECTED --> [*]
note right of COMPLETED
Terminal states are immutable.
Follow-ups create new tasks
within the same contextId.
end noteLos 8 estados (la especificación también define UNSPECIFIEDcomo sentinela, omitido aquí):
| State | Terminal? | Meaning |
|---|---|---|
TASK_STATE_SUBMITTED | No | Acknowledged, not yet processing |
TASK_STATE_WORKING | No | Actively being processed |
TASK_STATE_INPUT_REQUIRED | No | Agent needs more info from client |
TASK_STATE_AUTH_REQUIRED | No | Authentication needed |
TASK_STATE_COMPLETED | Yes | Finished successfully |
TASK_STATE_FAILED | Yes | Finished with error |
TASK_STATE_CANCELED | Yes | Canceled before completion |
TASK_STATE_REJECTED | Yes | Agent declined the task |
Una vez que una tarea alcanza un estado terminal, es inmutable. No más mensajes. Seguimiento crea una nueva tarea dentro de la misma.contextId¿ Qué ?
#### Formatos de cable
A2A utiliza JSON-RPC 2.0. Esto es lo que un intercambio de mensajes real se ve:
Client sends a message:
json{
"jsonrpc": "2.0",
"id": 1,
"method": "SendMessage",
"params": {
"message": {
"messageId": "msg-001",
"role": "ROLE_USER",
"parts": [{ "text": "Research React 19 compiler features" }]
},
"configuration": {
"acceptedOutputModes": ["text/plain", "application/json"],
"historyLength": 10
}
}
}Agent responds with a task:
json{
"jsonrpc": "2.0",
"id": 1,
"result": {
"task": {
"id": "task-abc-123",
"contextId": "ctx-xyz-789",
"status": {
"state": "TASK_STATE_COMPLETED",
"timestamp": "2026-03-27T10:30:00Z"
},
"artifacts": [
{
"artifactId": "art-001",
"name": "research-results",
"parts": [{
"data": {
"findings": [
"React 19 compiler auto-memoizes components",
"No more manual useMemo/useCallback needed",
"Compiler runs at build time, not runtime"
]
},
"mediaType": "application/json"
}]
}
]
}
}
}Streaming via SSE:
textPOST /message:stream HTTP/1.1
Content-Type: application/a2a+json
A2A-Version: 1.0
data: {"task":{"id":"task-123","contextId":"ctx-123","status":{"state":"TASK_STATE_WORKING"}}}
data: {"statusUpdate":{"taskId":"task-123","contextId":"ctx-123","status":{"state":"TASK_STATE_WORKING","message":{"messageId":"msg-002","role":"ROLE_AGENT","parts":[{"text":"Searching documentation..."}]}}}}
data: {"artifactUpdate":{"taskId":"task-123","contextId":"ctx-123","artifact":{"artifactId":"art-1","parts":[{"text":"partial findings..."}]},"append":true,"lastChunk":false}}
data: {"statusUpdate":{"taskId":"task-123","contextId":"ctx-123","status":{"state":"TASK_STATE_COMPLETED"}}}ACP (Protocolo de comunicación de los agentes)
Created by:IBM / BeeAI
Spec version:0.2.0 (OpenAPI 3.1.1)
Status:Fusión en A2A bajo la Fundación Linux
Problem:¿Cómo se comunican los agentes con plena auditabilidad, continuidad de la sesión y seguimiento de trayectoria?
ACP es el enterprise protocol.A diferencia de lo que afirman muchos resúmenes, ACP hace notEs una API REST/JSON sencilla definida a través de OpenAPI. Lo que la hace especial es queTrajectoryMetadata: cada respuesta del agente puede llevar un registro detallado de los pasos de razonamiento y las llamadas de herramientas que la produjeron.
sequenceDiagram
participant Client
participant ACP as ACP Agent
participant Audit as Audit Log
Client->>ACP: POST /runs (mode: sync)
ACP->>ACP: Process request...
ACP->>Audit: Log trajectory:<br/>reasoning + tool calls
ACP-->>Client: Response + TrajectoryMetadata
Note over Audit: Every step recorded:<br/>tool_name, tool_input,<br/>tool_output, reasoning#### Agente Discovery en ACP
ACP define cuatro métodos de descubrimiento:
graph LR
A[Agent Discovery] --> B["Runtime<br/>GET /agents"]
A --> C["Open<br/>.well-known/agent.yml"]
A --> D["Registry<br/>Centralized catalog"]
A --> E["Embedded<br/>Container labels"]
style B fill:#dbeafe,stroke:#2563eb
style C fill:#d1fae5,stroke:#059669
style D fill:#fef3c7,stroke:#d97706
style E fill:#f3e8ff,stroke:#7c3aedEl AgentManifestEs más simple que la tarjeta de agente de A2A:
json{
"name": "summarizer",
"description": "Summarizes documents with source citations",
"input_content_types": ["text/plain", "application/pdf"],
"output_content_types": ["text/plain", "application/json"],
"metadata": {
"tags": ["summarization", "RAG"],
"framework": "BeeAI",
"capabilities": [
{
"name": "Document Summarization",
"description": "Condenses long documents into key points"
}
],
"recommended_models": ["llama3.3:70b-instruct-fp16"],
"license": "Apache-2.0",
"programming_language": "Python"
}
}#### Ejecutar el ciclo de vida
ACP utiliza "Runs" en lugar de "Tasks".
| Mode | Behavior |
|---|---|
sync | Blocking. Response contains the complete result. |
async | Returns 202 immediately. Poll GET /runs/{id} for status. |
stream | SSE stream. Events fire as the agent works. |
stateDiagram-v2
[*] --> created
created --> in_progress
in_progress --> completed: success
in_progress --> failed: error
in_progress --> awaiting: needs input
awaiting --> in_progress: client resumes
in_progress --> cancelling: cancel request
cancelling --> cancelled
completed --> [*]
failed --> [*]
cancelled --> [*]#### TrajectoriaMetadatos (El camino de la auditoría)
Este es el diferenciador clave de ACP. Cada parte del mensaje puede incluir metadatos que muestran exactamente lo que hizo el agente:
json{
"role": "agent/researcher",
"parts": [
{
"content_type": "text/plain",
"content": "The weather in San Francisco is 72F and sunny.",
"metadata": {
"kind": "trajectory",
"message": "I need to check the weather for this location",
"tool_name": "weather_api",
"tool_input": { "location": "San Francisco, CA" },
"tool_output": { "temperature": 72, "condition": "sunny" }
}
}
]
}Para las industrias reguladas, esto es oro. Cada respuesta viene con una cadena de razonamiento demostrable: qué herramientas se llamaron, qué entradas se utilizaron, qué salidas se recibieron.
ACP también apoya CitationMetadatapara la atribución de origen:
json{
"kind": "citation",
"start_index": 0,
"end_index": 47,
"url": "https: TOK0
"title": "NWS San Francisco Forecast"
}ANP (Protocolo de red de agentes)
Created by:Comunidad de código abierto (fundada por GaoWei Chang)
Repo: github.com/agent-network-protocol/AgentNetworkProtocol
Problem:¿Cómo pueden los agentes de diferentes organizaciones confiar entre sí sin una autoridad central?
La ANP es la decentralized identity protocol. Construye confianza utilizando identificadores descentralizados (DID) de W3C y cifrado de extremo a extremo. A diferencia de A2A, donde descubres agentes a través de puntos finales conocidos, ANP permite a los agentes probar su identidad criptográficamente.
El ANP tiene tres capas:
graph TB
subgraph Layer3["Layer 3: Application Protocol"]
AD[Agent Description Documents]
DISC[Discovery endpoints]
end
subgraph Layer2["Layer 2: Meta-Protocol"]
NEG[AI-powered protocol negotiation]
CODE[Dynamic code generation]
end
subgraph Layer1["Layer 1: Identity & Secure Communication"]
DID["did:wba (W3C DID)"]
HPKE[HPKE E2EE - RFC 9180]
SIG[Signature verification]
end
Layer3 --> Layer2
Layer2 --> Layer1
style Layer1 fill:#d1fae5,stroke:#059669
style Layer2 fill:#dbeafe,stroke:#2563eb
style Layer3 fill:#f3e8ff,stroke:#7c3aed#### Documentación del DID (estructura real)
ANP utiliza un método personalizado llamado DID did:wbaEl DID .did:wba:example.com:user:alicese resuelve a https://example.com/user/alice/did.json¿Qué es esto ?
json{
"@context": [
"https: TOK0
"https://w3id.org/security/suites/jws-2020/v1",
"https: TOK2
],
"id": "did:wba:example.com:user:alice",
"verificationMethod": [
{
"id": "did:wba:example.com:user:alice#key-1",
"type": "EcdsaSecp256k1VerificationKey2019",
"controller": "did:wba:example.com:user:alice",
"publicKeyJwk": {
"crv": "secp256k1",
"x": "NtngWpJUr-rlNNbs0u-Aa8e16OwSJu6UiFf0Rdo1oJ4",
"y": "qN1jKupJlFsPFc1UkWinqljv4YE0mq_Ickwnjgasvmo",
"kty": "EC"
}
},
{
"id": "did:wba:example.com:user:alice TOK4
"type": "X25519KeyAgreementKey2019",
"controller": "did:wba:example.com:user:alice",
"publicKeyMultibase": "z9hFgmPVfmBZwRvFEyniQDBkz9LmV7gDEqytWyGZLmDXE"
}
],
"authentication": [
"did:wba:example.com:user:alice#key-1"
],
"keyAgreement": [
"did:wba:example.com:user:alice TOK6
],
"humanAuthorization": [
"did:wba:example.com:user:alice#key-1"
],
"service": [
{
"id": "did:wba:example.com:user:alice TOK8
"type": "AgentDescription",
"serviceEndpoint": "https://example.com/agents/alice/ad.json"
}
]
}Las cosas clave que hay que notar:
- Key separationLas claves de firma (secp256k1) están separadas de las claves de cifrado (X25519).
humanAuthorizationLas claves de acceso a los datos de acceso a Internet son las claves de acceso a Internet que son únicas a la ANP. Estas claves requieren la aprobación humana explícita (biométrica, contraseña, HSM) antes de su uso.keyAgreementlas claves se utilizan para el cifrado de extremo a extremo HPKE (RFC 9180).- El serviceEnlaces a la sección del documento de descripción del agente.
#### Cómo funciona la confianza en la ANP
La ANP lo hace.notEl uso de una web de confianza o un gráfico de aprobación.
sequenceDiagram
participant A as Agent A
participant Domain as Agent A's Domain
participant B as Agent B
A->>B: HTTP request + DID + signature
B->>Domain: Fetch DID document (HTTPS)
Domain-->>B: DID document + public key
B->>B: Verify signature with public key
B-->>A: Issue access token
A->>B: Subsequent requests use token
Note over A,B: Trust = TLS domain verification<br/>+ DID signature verification<br/>+ Principle of least trustLa confianza proviene de tres fuentes:
- Domain-level TLSverifica el host del documento DID
- DID cryptographic signaturesverificar la identidad del agente
- Principle of least trustotorga sólo permisos mínimos
No hay propagación de confianza basada en chismes o puntuación de PageRank.
#### Negociación del meta-protocolo
Esta es la característica más novedosa de ANP. Cuando dos agentes de ecosistemas diferentes se encuentran, no necesitan formatos de datos previamente acordados. Negocian en lenguaje natural:
json{
"action": "protocolNegotiation",
"sequenceId": 0,
"candidateProtocols": "I can communicate using:\n1. JSON-RPC with hotel booking schema\n2. REST with OpenAPI 3.1 spec\n3. Natural language over HTTP",
"modificationSummary": "Initial proposal",
"status": "negotiating"
}sequenceDiagram
participant A as Agent A
participant B as Agent B
A->>B: protocolNegotiation (candidateProtocols)
B->>A: protocolNegotiation (counter-proposal)
A->>B: protocolNegotiation (accepted)
Note over A,B: Agents dynamically generate code<br/>to handle the agreed format.<br/>Max 10 rounds, then timeout.Los agentes van y van (máximo 10 disparos) hasta que se acuerdan en un formato, luego generan dinámicamente código para manejarlo.negotiating¿ Qué ?rejected¿ Qué ?accepted¿ Qué ?timeout¿ Qué ?
Esto significa que dos agentes que nunca se han visto pueden descubrir cómo comunicarse sin que nadie pre-definir un esquema compartido.
Comparación (corregida)
| MCP | A2A | ACP | ANP | |
|---|---|---|---|---|
| Created by | Anthropic | Google / Linux Foundation | IBM / BeeAI | Community |
| Spec format | JSON-RPC | JSON-RPC / REST / gRPC | OpenAPI 3.1 (REST) | JSON-RPC |
| Primary use | Agent to Tool | Agent to Agent | Agent to Agent | Agent to Agent |
| Discovery | Tool listing | /.well-known/agent-card.json | GET /agents, /.well-known/agent.yml | /.well-known/agent-descriptions, DID service endpoints |
| Identity | Implicit (local) | Security schemes (OAuth, mTLS) | Server-level | W3C DID (did:wba) with E2EE |
| Audit trail | N/A | Basic (task history) | TrajectoryMetadata (tool calls, reasoning) | Not formally specified |
| State machine | N/A | 9 task states | 7 run states | N/A |
| Streaming | N/A | SSE | SSE | Transport-agnostic |
| Unique feature | Tool schemas | Agent Cards + Skills | Trajectory audit trail | Meta-protocol negotiation |
| Best for | Tools & data | Dynamic collaboration | Regulated industries | Cross-org trust |
| Status | Stable | Stable (v1.0) | Merging into A2A | Active development |
Cómo trabajan juntos
Estos protocolos no se excluyen mutuamente.
graph TB
subgraph org["Your Organization"]
RA[Research Agent] <-->|A2A| CA[Coding Agent]
RA -->|MCP| SS[Search Server]
CA -->|MCP| GS[GitHub Server]
AUDIT["All agent responses carry<br/>ACP TrajectoryMetadata"]
end
subgraph ext["External (DID verified via ANP)"]
EA[External Agent]
PA[Partner Agent]
end
RA <-->|ANP + A2A| EA
CA <-->|ANP + A2A| PA
style org fill:#f8fafc,stroke:#334155
style ext fill:#fef2f2,stroke:#991b1b
style AUDIT fill:#fef3c7,stroke:#d97706- MCPconecta cada agente a sus herramientas
- A2Amaneja la colaboración entre agentes (internos y externos)
- ACPEnvuelve las respuestas en metadatos de trayectoria para su auditabilidad
- ANPprovee verificación de identidad para agentes que no controlas
Construye el mismo
Paso 1: Tipos de mensajes esenciales
Cada sistema multi-agente comienza con un formato de mensaje. Definimos tipos que se corresponden a lo que usan los protocolos reales:
typescriptimport crypto from "node:crypto";
type MessageRole = "ROLE_USER" | "ROLE_AGENT";
type MessagePart =
| { text: string }
| { data: unknown; mediaType: string }
| { url: string; filename: string; mediaType: string };
type TrajectoryEntry = {
reasoning: string;
toolName?: string;
toolInput?: unknown;
toolOutput?: unknown;
timestamp: number;
};
type AgentMessage = {
id: string;
role: MessageRole;
parts: MessagePart[];
trajectory?: TrajectoryEntry[];
replyTo?: string;
timestamp: number;
};
function createMessage(
role: MessageRole,
parts: MessagePart[],
replyTo?: string
): AgentMessage {
return {
id: crypto.randomUUID(),
role,
parts,
replyTo,
timestamp: Date.now(),
};
}
function textMessage(role: MessageRole, text: string): AgentMessage {
return createMessage(role, [{ text }]);
}Nota: MessagePartEl campo de referencia de A2A es el campo de referencia de A2A 1.0, que se encuentra en el campo de referencia de A2A 1.0.text¿ Qué ?data, ourl) dice cuál es la parte; no hay kind- ¿Qué quieres?TrajectoryEntryEl método de cálculo de la meta-datas de la trayectoria de los ACP es el método de cálculo de la meta-datas de la trayectoria de los ACP.
Paso 2: Tarjeta de agente A2A y registro
Construir un agente de descubrimiento que coincida con la especificación real de A2A:
typescripttype Skill = {
id: string;
name: string;
description: string;
tags: string[];
inputModes: string[];
outputModes: string[];
};
type AgentInterface = {
url: string;
protocolBinding: string;
protocolVersion: string;
};
type AgentCard = {
name: string;
description: string;
version: string;
supportedInterfaces: AgentInterface[];
capabilities: {
streaming: boolean;
pushNotifications: boolean;
};
defaultInputModes: string[];
defaultOutputModes: string[];
skills: Skill[];
};
class AgentRegistry {
private cards: Map<string, AgentCard> = new Map();
register(card: AgentCard) {
this.cards.set(card.name, card);
}
discoverBySkillTag(tag: string): AgentCard[] {
return [...this.cards.values()].filter((card) =>
card.skills.some((skill) => skill.tags.includes(tag))
);
}
discoverByInputMode(mimeType: string): AgentCard[] {
return [...this.cards.values()].filter(
(card) =>
card.defaultInputModes.includes(mimeType) ||
card.skills.some((skill) => skill.inputModes.includes(mimeType))
);
}
resolve(name: string): AgentCard | undefined {
return this.cards.get(name);
}
listAll(): AgentCard[] {
return [...this.cards.values()];
}
}Esto es mucho más rico que un simple mapa de nombre a capacidad. Puedes descubrir agentes por etiquetas de habilidad, por tipos de entrada MIME, o por nombre, tal como lo soporta la especificación real A2A.
Paso 3: Ciclo de vida de las tareas A2A
Construir la máquina de estado de tarea completa:
typescripttype TaskState =
| "TASK_STATE_SUBMITTED"
| "TASK_STATE_WORKING"
| "TASK_STATE_INPUT_REQUIRED"
| "TASK_STATE_AUTH_REQUIRED"
| "TASK_STATE_COMPLETED"
| "TASK_STATE_FAILED"
| "TASK_STATE_CANCELED"
| "TASK_STATE_REJECTED";
const TERMINAL_STATES: TaskState[] = [
"TASK_STATE_COMPLETED",
"TASK_STATE_FAILED",
"TASK_STATE_CANCELED",
"TASK_STATE_REJECTED",
];
type TaskStatus = {
state: TaskState;
message?: AgentMessage;
timestamp: number;
};
type Artifact = {
id: string;
name: string;
parts: MessagePart[];
};
type Task = {
id: string;
contextId: string;
status: TaskStatus;
artifacts: Artifact[];
history: AgentMessage[];
};
type TaskEvent =
| { statusUpdate: { taskId: string; status: TaskStatus } }
| {
artifactUpdate: {
taskId: string;
artifact: Artifact;
append: boolean;
lastChunk: boolean;
};
};
type TaskHandler = (
task: Task,
message: AgentMessage
) => AsyncGenerator<TaskEvent>;
class TaskManager {
private tasks: Map<string, Task> = new Map();
private handlers: Map<string, TaskHandler> = new Map();
private listeners: Map<string, ((event: TaskEvent) => void)[]> = new Map();
registerHandler(agentName: string, handler: TaskHandler) {
this.handlers.set(agentName, handler);
}
subscribe(taskId: string, listener: (event: TaskEvent) => void) {
const existing = this.listeners.get(taskId) ?? [];
existing.push(listener);
this.listeners.set(taskId, existing);
}
async sendMessage(
agentName: string,
message: AgentMessage,
contextId?: string
): Promise<Task> {
const handler = this.handlers.get(agentName);
if (!handler) {
const task = this.createTask(contextId);
task.status = {
state: "TASK_STATE_REJECTED",
timestamp: Date.now(),
message: textMessage("ROLE_AGENT", `No handler for ${agentName}`),
};
return task;
}
const task = this.createTask(contextId);
task.history.push(message);
task.status = { state: "TASK_STATE_SUBMITTED", timestamp: Date.now() };
this.processTask(task, handler, message).catch((err) => {
task.status = {
state: "TASK_STATE_FAILED",
timestamp: Date.now(),
message: textMessage("ROLE_AGENT", String(err)),
};
});
return task;
}
getTask(taskId: string): Task | undefined {
return this.tasks.get(taskId);
}
cancelTask(taskId: string): boolean {
const task = this.tasks.get(taskId);
if (!task || TERMINAL_STATES.includes(task.status.state)) return false;
task.status = { state: "TASK_STATE_CANCELED", timestamp: Date.now() };
this.emit(taskId, {
statusUpdate: { taskId, status: task.status },
});
return true;
}
private createTask(contextId?: string): Task {
const task: Task = {
id: crypto.randomUUID(),
contextId: contextId ?? crypto.randomUUID(),
status: { state: "TASK_STATE_SUBMITTED", timestamp: Date.now() },
artifacts: [],
history: [],
};
this.tasks.set(task.id, task);
return task;
}
private async processTask(
task: Task,
handler: TaskHandler,
message: AgentMessage
) {
task.status = { state: "TASK_STATE_WORKING", timestamp: Date.now() };
this.emit(task.id, {
statusUpdate: { taskId: task.id, status: task.status },
});
try {
for await (const event of handler(task, message)) {
if (TERMINAL_STATES.includes(task.status.state)) break;
if ("statusUpdate" in event) {
task.status = event.statusUpdate.status;
}
if ("artifactUpdate" in event) {
const update = event.artifactUpdate;
const existing = task.artifacts.find(
(a) => a.id === update.artifact.id
);
if (existing && update.append) {
existing.parts.push(...update.artifact.parts);
} else {
task.artifacts.push(update.artifact);
}
}
this.emit(task.id, event);
}
} catch (err) {
task.status = {
state: "TASK_STATE_FAILED",
timestamp: Date.now(),
message: textMessage("ROLE_AGENT", String(err)),
};
this.emit(task.id, {
statusUpdate: { taskId: task.id, status: task.status },
});
}
}
private emit(taskId: string, event: TaskEvent) {
for (const listener of this.listeners.get(taskId) ?? []) {
listener(event);
}
}
}Esto implementa el ciclo de vida real de las tareas A2A: TASK_STATE_SUBMITTED¿ Qué ?TASK_STATE_WORKING¿ Qué ?TASK_STATE_INPUT_REQUIREDLos manipuladores son generadores de sincronización que danstatusUpdatey artifactUpdatelos mismos envoltorios que el flujo de SSE.
Paso 4: Camino de auditoría de estilo ACP
Comunicación con seguimiento de trayectoria:
typescripttype AuditEntry = {
runId: string;
agentName: string;
input: AgentMessage[];
output: AgentMessage[];
trajectory: TrajectoryEntry[];
status: "created" | "in-progress" | "completed" | "failed" | "awaiting";
startedAt: number;
completedAt?: number;
sessionId?: string;
};
class AuditableRunner {
private log: AuditEntry[] = [];
private handlers: Map<
string,
(input: AgentMessage[]) => Promise<{
output: AgentMessage[];
trajectory: TrajectoryEntry[];
}>
> = new Map();
registerAgent(
name: string,
handler: (input: AgentMessage[]) => Promise<{
output: AgentMessage[];
trajectory: TrajectoryEntry[];
}>
) {
this.handlers.set(name, handler);
}
async run(
agentName: string,
input: AgentMessage[],
sessionId?: string
): Promise<AuditEntry> {
const entry: AuditEntry = {
runId: crypto.randomUUID(),
agentName,
input: structuredClone(input),
output: [],
trajectory: [],
status: "created",
startedAt: Date.now(),
sessionId,
};
this.log.push(entry);
const handler = this.handlers.get(agentName);
if (!handler) {
entry.status = "failed";
return entry;
}
entry.status = "in-progress";
try {
const result = await handler(input);
entry.output = structuredClone(result.output);
entry.trajectory = structuredClone(result.trajectory);
entry.status = "completed";
entry.completedAt = Date.now();
} catch (err) {
entry.status = "failed";
entry.trajectory.push({
reasoning: `Error: ${String(err)}`,
timestamp: Date.now(),
});
entry.completedAt = Date.now();
}
return entry;
}
getFullAuditLog(): AuditEntry[] {
return structuredClone(this.log);
}
getAuditLogForAgent(agentName: string): AuditEntry[] {
return structuredClone(
this.log.filter((e) => e.agentName === agentName)
);
}
getAuditLogForSession(sessionId: string): AuditEntry[] {
return structuredClone(
this.log.filter((e) => e.sessionId === sessionId)
);
}
getTrajectoryForRun(runId: string): TrajectoryEntry[] {
const entry = this.log.find((e) => e.runId === runId);
return entry ? structuredClone(entry.trajectory) : [];
}
}Cada ejecución de un agente produce una entrada de auditoría completa: lo que entró, lo que salió, y la trayectoria completa de las llamadas de herramientas y los pasos de razonamiento entre ellos.
Paso 5: Verificación de identidad de estilo ANP
Construir identidad y verificación basadas en DID:
typescripttype VerificationMethod = {
id: string;
type: string;
controller: string;
publicKeyDer: string;
};
type DIDDocument = {
id: string;
verificationMethod: VerificationMethod[];
authentication: string[];
keyAgreement: string[];
humanAuthorization: string[];
service: { id: string; type: string; serviceEndpoint: string }[];
};
type AgentIdentity = {
did: string;
document: DIDDocument;
privateKey: crypto.KeyObject;
publicKey: crypto.KeyObject;
};
class IdentityRegistry {
private documents: Map<string, DIDDocument> = new Map();
publish(doc: DIDDocument) {
this.documents.set(doc.id, doc);
}
resolve(did: string): DIDDocument | undefined {
return this.documents.get(did);
}
verify(did: string, signature: string, payload: string): boolean {
const doc = this.documents.get(did);
if (!doc) return false;
const authKeyIds = doc.authentication;
const authKeys = doc.verificationMethod.filter((vm) =>
authKeyIds.includes(vm.id)
);
for (const key of authKeys) {
const publicKey = crypto.createPublicKey({
key: Buffer.from(key.publicKeyDer, "base64"),
format: "der",
type: "spki",
});
const isValid = crypto.verify(
null,
Buffer.from(payload),
publicKey,
Buffer.from(signature, "hex")
);
if (isValid) return true;
}
return false;
}
requiresHumanAuth(did: string, operationKeyId: string): boolean {
const doc = this.documents.get(did);
if (!doc) return false;
return doc.humanAuthorization.includes(operationKeyId);
}
}
function createIdentity(domain: string, agentName: string): AgentIdentity {
const did = `did:wba:${domain}:agent:${agentName}`;
const { publicKey, privateKey } = crypto.generateKeyPairSync("ed25519");
const publicKeyDer = publicKey
.export({ format: "der", type: "spki" })
.toString("base64");
const keyId = `${did}#key-1`;
const encKeyId = `${did}#key-x25519-1`;
const document: DIDDocument = {
id: did,
verificationMethod: [
{
id: keyId,
type: "Ed25519VerificationKey2020",
controller: did,
publicKeyDer,
},
{
id: encKeyId,
type: "X25519KeyAgreementKey2019",
controller: did,
publicKeyDer,
},
],
authentication: [keyId],
keyAgreement: [encKeyId],
humanAuthorization: [],
service: [
{
id: `${did}#agent-description`,
type: "AgentDescription",
serviceEndpoint: `https://${domain}/agents/${agentName}/ad.json`,
},
],
};
return { did, document, privateKey, publicKey };
}
function signPayload(identity: AgentIdentity, payload: string): string {
return crypto
.sign(null, Buffer.from(payload), identity.privateKey)
.toString("hex");
}Esto refleja el modelo de identidad real de la ANP: los agentes tienen documentos DID con autenticación separada, acuerdo clave y claves de autorización humana.IdentityRegistrysimula la resolución DID (en producción esto sería HTTP travesías al dominio del agente).
Paso 6: Puerta de entrada del protocolo
Conecta los cuatro protocolos en un sistema unificado:
graph LR
REQ[Incoming Request] --> ANP_V{ANP: Verify DID}
ANP_V -->|Valid| A2A_D{A2A: Discover Agent}
ANP_V -->|Invalid| REJECT[Reject]
A2A_D -->|Found| ACP_A[ACP: Audit Run]
A2A_D -->|Not Found| REJECT
ACP_A --> A2A_T[A2A: Create Task]
A2A_T --> RESULT[Task + Audit Entry]
style ANP_V fill:#d1fae5,stroke:#059669
style A2A_D fill:#dbeafe,stroke:#2563eb
style ACP_A fill:#fef3c7,stroke:#d97706
style A2A_T fill:#dbeafe,stroke:#2563ebtypescriptclass ProtocolGateway {
private registry: AgentRegistry;
private taskManager: TaskManager;
private auditRunner: AuditableRunner;
private identityRegistry: IdentityRegistry;
constructor(
registry: AgentRegistry,
taskManager: TaskManager,
auditRunner: AuditableRunner,
identityRegistry: IdentityRegistry
) {
this.registry = registry;
this.taskManager = taskManager;
this.auditRunner = auditRunner;
this.identityRegistry = identityRegistry;
}
async delegateTask(
fromDid: string,
signature: string,
targetAgent: string,
message: AgentMessage,
sessionId?: string
): Promise<{ task: Task; audit: AuditEntry } | { error: string }> {
if (!this.identityRegistry.verify(fromDid, signature, message.id)) {
return { error: "Identity verification failed" };
}
const card = this.registry.resolve(targetAgent);
if (!card) {
return { error: `Agent ${targetAgent} not found in registry` };
}
const audit = await this.auditRunner.run(
targetAgent,
[message],
sessionId
);
const task = await this.taskManager.sendMessage(targetAgent, message);
return { task, audit };
}
discoverAndDelegate(
fromDid: string,
signature: string,
skillTag: string,
message: AgentMessage
): Promise<{ task: Task; audit: AuditEntry } | { error: string }> {
const candidates = this.registry.discoverBySkillTag(skillTag);
if (candidates.length === 0) {
return Promise.resolve({
error: `No agents found with skill tag: ${skillTag}`,
});
}
return this.delegateTask(
fromDid,
signature,
candidates[0].name,
message
);
}
}La puerta de entrada hace cuatro cosas en una llamada:
- ANP: Verifica la identidad del solicitante mediante la firma DID
- A2A: Descubre el agente objetivo y verifica las capacidades
- ACP: Envuelve la ejecución en una trayectoria de auditoría
- A2A: Crea una tarea con seguimiento completo del ciclo de vida
Paso 7: Conectadlo todo
typescriptasync function protocolDemo() {
const registry = new AgentRegistry();
registry.register({
name: "researcher",
description: "Searches and summarizes findings",
version: "1.0.0",
supportedInterfaces: [
{
url: "https: TOK0
protocolBinding: "JSONRPC",
protocolVersion: "1.0",
},
],
capabilities: { streaming: true, pushNotifications: false },
defaultInputModes: ["text/plain"],
defaultOutputModes: ["text/plain", "application/json"],
skills: [
{
id: "web-research",
name: "Web Research",
description: "Searches the web",
tags: ["research", "search", "summarization"],
inputModes: ["text/plain"],
outputModes: ["application/json"],
},
],
});
registry.register({
name: "coder",
description: "Writes code from specs",
version: "1.0.0",
supportedInterfaces: [
{
url: "https://coder.local/a2a/v1",
protocolBinding: "JSONRPC",
protocolVersion: "1.0",
},
],
capabilities: { streaming: false, pushNotifications: false },
defaultInputModes: ["text/plain", "application/json"],
defaultOutputModes: ["text/plain"],
skills: [
{
id: "code-gen",
name: "Code Generation",
description: "Generates code",
tags: ["coding", "generation"],
inputModes: ["text/plain", "application/json"],
outputModes: ["text/plain"],
},
],
});
const taskManager = new TaskManager();
const auditRunner = new AuditableRunner();
const researchTrajectory: TrajectoryEntry[] = [];
taskManager.registerHandler(
"researcher",
async function* (task, message) {
yield {
statusUpdate: {
taskId: task.id,
status: {
state: "TASK_STATE_WORKING" as const,
timestamp: Date.now(),
},
},
};
researchTrajectory.push({
reasoning: "Searching for React 19 documentation",
toolName: "web_search",
toolInput: { query: "React 19 compiler features" },
toolOutput: {
results: ["react.dev/blog/react-19", "github.com/react/react"],
},
timestamp: Date.now(),
});
researchTrajectory.push({
reasoning: "Extracting key findings from search results",
toolName: "doc_analysis",
toolInput: { url: "react.dev/blog/react-19" },
toolOutput: {
summary:
"React 19 compiler auto-memoizes, no manual useMemo needed",
},
timestamp: Date.now(),
});
yield {
artifactUpdate: {
taskId: task.id,
artifact: {
id: crypto.randomUUID(),
name: "research-results",
parts: [
{
data: {
findings: [
"React 19 compiler auto-memoizes components",
"No more manual useMemo/useCallback needed",
"Compiler runs at build time, not runtime",
],
sources: ["react.dev/blog/react-19"],
},
mediaType: "application/json",
},
],
},
append: false,
lastChunk: true,
},
};
yield {
statusUpdate: {
taskId: task.id,
status: {
state: "TASK_STATE_COMPLETED" as const,
timestamp: Date.now(),
},
},
};
}
);
auditRunner.registerAgent("researcher", async () => ({
output: [
textMessage("ROLE_AGENT", "React 19 compiler auto-memoizes components"),
],
trajectory: researchTrajectory,
}));
const identityRegistry = new IdentityRegistry();
const coderIdentity = createIdentity("coder.local", "coder");
const researcherIdentity = createIdentity("researcher.local", "researcher");
identityRegistry.publish(coderIdentity.document);
identityRegistry.publish(researcherIdentity.document);
const gateway = new ProtocolGateway(
registry,
taskManager,
auditRunner,
identityRegistry
);
console.log("=== Protocol Demo ===\n");
console.log("1. Agent Discovery (A2A)");
const researchAgents = registry.discoverBySkillTag("research");
console.log(
` Found ${researchAgents.length} agent(s):`,
researchAgents.map((a) => a.name)
);
console.log("\n2. Identity Verification (ANP)");
const message = textMessage("ROLE_USER", "Research React 19 compiler features");
const signature = signPayload(coderIdentity, message.id);
const verified = identityRegistry.verify(
coderIdentity.did,
signature,
message.id
);
console.log(` Coder DID: ${coderIdentity.did}`);
console.log(` Signature verified: ${verified}`);
console.log("\n3. Task Delegation (A2A + ACP + ANP)");
const result = await gateway.delegateTask(
coderIdentity.did,
signature,
"researcher",
message,
"session-001"
);
if ("error" in result) {
console.log(` Error: ${result.error}`);
return;
}
console.log(` Task ID: ${result.task.id}`);
console.log(` Task state: ${result.task.status.state}`);
console.log(` Artifacts: ${result.task.artifacts.length}`);
console.log("\n4. Audit Trail (ACP)");
console.log(` Run ID: ${result.audit.runId}`);
console.log(` Status: ${result.audit.status}`);
console.log(` Trajectory steps: ${result.audit.trajectory.length}`);
for (const step of result.audit.trajectory) {
console.log(` - ${step.reasoning}`);
if (step.toolName) {
console.log(` Tool: ${step.toolName}`);
}
}
console.log("\n5. Full Audit Log");
const fullLog = auditRunner.getFullAuditLog();
console.log(` Total runs: ${fullLog.length}`);
for (const entry of fullLog) {
const duration = entry.completedAt
? `${entry.completedAt - entry.startedAt}ms`
: "in-progress";
console.log(` ${entry.agentName}: ${entry.status} (${duration})`);
}
}
protocolDemo().catch((err) => {
console.error("Protocol demo failed:", err);
process.exitCode = 1;
});¿Qué es lo que va mal?
Los protocolos resuelven el camino feliz.
Schema drift.El agente A publica una publicidad de la tarjeta de agente .application/jsonEn el caso de los modelos de producción, el modelo de producción de JSON cambia entre versiones.versionen el agente Cards por esta razón.
State machine violations.Un agente de manipulación produce un TASK_STATE_COMPLETEDLa tarea es inmutable. Su código deja caer las actualizaciones o arroja silenciosamente.TaskManagerlo hace cumplir con el breakdespués de los estados terminales.
Trust resolution failures.El agente A intenta verificar el DID del agente B, pero el dominio del agente B está apagado. El documento DID no se puede recoger. ¿No se abre (acepta agentes no verificados) o no se cierra (rechaza todo)? ANP recomienda que se cierre con el principio de menor confianza.
Trajectory bloat.El registro de trayectorias ACP es poderoso pero costoso. Un agente complejo que hace 200 llamadas de herramientas por ejecución produce entradas masivas de auditoría.
Discovery thundering herd.50 agentes todos en busca .GET /agentsCorrección: Cachar las tarjetas de agente con TTL, intervalo de descubrimiento escalonado o usar registro basado en push en lugar de encuestas.
Usalo
Implementaciones reales
A2Aes la más madura.official specEs un software de código abierto bajo la Fundación Linux. SDKs para Python y TypeScript. Si sus agentes necesitan descubrimiento dinámico y colaboración, comience aquí.
ACPSe está fusionando en A2A. IBM BeeAI projectEl sistema de transporte de datos de la trayectoria se ha convertido en un sistema de transporte de datos de la trayectoria de la trayectoria de la trayectoria de la trayectoria de la trayectoria de la trayectoria de la trayectoria de la trayectoria de la trayectoria de la trayectoria de la trayectoria de la trayectoria de la trayectoria de la trayectoria de la trayectoria de la trayectoria de la trayectoria de la trayectoria de la trayectoria de la trayectoria de la trayectoria de la trayectoria de la trayectoria de la trayectoria de la trayectoria de la trayectoria de la trayectoria de la trayectoria de la trayectoria de la trayectoria de la trayectoria de la trayectoria de la trayectoria de la trayectoria de la trayectoria de la trayectoria de la trayectoria de la trayectoria de la trayectoria de la trayectoria de la trayectoria de la trayectoria de la trayectoria de la trayectoria de la trayectoria de la trayectoria de la trayectoria de la trayectoria de la trayectoria de la trayectoria de la trayectoria de la trayectoria de la trayectoria de la trayectoria de la trayectoria de la trayectoria de la trayectoria de la trayectoria de trayectoria de la trayectoria de trayectoria de trayectoria de trayectoria de trayectoria de trayectoria de la trayectoria de trayectoria de trayectoria de trayectoria de trayectoria de trayectoria de trayectoria de trayectoria de trayectoria.
ANPEs el más experimental.community repoEl concepto de negociación de meta-protocol es realmente nuevo. vale la pena mirar para el despliegue de agentes trans-organizacionales.
MCPSi quieres que los agentes usen herramientas, MCP es el estándar.
Elegir el protocolo correcto
graph TD
START{Do agents need<br/>to use tools?}
START -->|Yes| MCP_R[Use MCP]
START -->|No| TALK{Do agents need to<br/>talk to each other?}
TALK -->|No| NONE[You don't need<br/>a protocol]
TALK -->|Yes| AUDIT{Need audit trails<br/>for compliance?}
AUDIT -->|Yes| ACP_R[A2A + ACP<br/>trajectory patterns]
AUDIT -->|No| ORG{All agents<br/>within your org?}
ORG -->|Yes| A2A_R[A2A<br/>Agent Cards + Tasks]
ORG -->|No| INFRA{Shared<br/>infrastructure?}
INFRA -->|Yes| BROKER[A2A + message broker]
INFRA -->|No| ANP_R[ANP + A2A<br/>DID verification]
style MCP_R fill:#d1fae5,stroke:#059669
style A2A_R fill:#dbeafe,stroke:#2563eb
style ACP_R fill:#fef3c7,stroke:#d97706
style ANP_R fill:#f3e8ff,stroke:#7c3aed
style BROKER fill:#e0e7ff,stroke:#4338caEnvío
Esta lección produce:
code/main.ts-- la implementación completa de los cuatro patrones de protocolooutputs/prompt-protocol-selector.md-- una solicitud que le ayuda a elegir los protocolos para su sistema
Los ejercicios
- Multi-hop task delegation.Extender el
TaskManagerEl investigador recibe una tarea, delega "busca" y "resumen" las subtareas a dos agentes especializados, espera que ambos completen, luego fusiona los resultados en sus propios artefactos.
- Streaming audit trail.Modificar el
AuditableRunnerEn lugar de esperar el resultado completo, rendirAuditEntrySe puede utilizar un generador de sincronización que produce instantáneas de auditoría.
- DID rotation.Añadir la rotación de la llave a la
IdentityRegistry. Un agente debe poder publicar un nuevo documento DID con claves actualizadas mientras mantiene unpreviousDidLos verificadores deben aceptar firmas de la clave actual y anterior durante un período de gracia.
- Protocol negotiation.Implementar el concepto de meta-protocolo de ANP.
protocolNegotiationLos mensajes con formatos candidatos (por ejemplo, "Puedo hablar JSON-RPC" vs. "Prefiero REST"). Después de un máximo de 3 rondas, se acuerdan de un formato o tiempo de espera.TaskManageroAuditableRunnerque usan.
- Rate-limited discovery.Añadir un
RateLimitedRegistryEnvase que almacena las búsquedas de la tarjeta de agente con un TTL configurable y limita las consultas de descubrimiento por agente por segundo. Simula una manada de 100 agentes que se descubren entre sí en el inicio y mide la diferencia.
Términos clave
| Term | What people say | What it actually means |
|---|---|---|
| MCP | "The protocol for AI tools" | A client-server protocol for agents to discover and use tools. Agent-to-tool, not agent-to-agent. |
| A2A | "Google's agent protocol" | A peer-to-peer protocol for agent collaboration under the Linux Foundation. Discovery via Agent Cards, 9-state task lifecycle, streaming via SSE. Supports JSON-RPC, REST, and gRPC bindings. |
| ACP | "Enterprise agent messaging" | IBM/BeeAI's REST API for agent runs with TrajectoryMetadata: every response carries the full chain of reasoning and tool calls. Merging into A2A. |
| ANP | "Decentralized agent identity" | A community protocol using did:wba (DID) for cryptographic identity, HPKE for E2EE, and AI-powered meta-protocol negotiation for agents that have never seen each other. |
| Agent Card | "An agent's business card" | A JSON document at /.well-known/agent-card.json describing skills, supported MIME types, security schemes, and protocol bindings. |
| DID | "Decentralized ID" | W3C standard for cryptographically verifiable identities hosted on the agent's own domain. ANP uses did:wba method. |
| TrajectoryMetadata | "The audit receipt" | ACP's mechanism for attaching reasoning steps, tool calls, and their inputs/outputs to every agent response. |
| Meta-protocol | "Agents negotiating how to talk" | ANP's approach where agents use natural language to dynamically agree on data formats, then generate code to handle them. |
| Task | "A unit of work" | A2A's stateful object tracking work from submission through completion. Immutable once terminal. |
Leer más
- Google A2A specification-- especificaciones oficiales y SDKs (v1.0.1, Fundación Linux)
- IBM/BeeAI ACP specification-- Específicación de OpenAPI 3.1 para las operaciones de agentes y los metadatos de trayectoria
- Agent Network Protocol-- Identidad basada en DID, E2EE, negociación de meta-protocol
- Model Context Protocol docs-- Especificación del MCP de Anthropic (incluida en la Fase 13)
- W3C Decentralized Identifiers-- el estándar de identidad que sustenta la ANP
- RFC 9180 (HPKE)-- el esquema de cifrado que utiliza ANP para E2EE
- FIPA Agent Communication Language-- el precursor académico de los protocolos de agentes modernos
This free lesson is part of the AI Engineering from Scratch curriculum. Read the full explanation, run the lesson code, and verify the result in the interactive reader or from the repository source.
Browse the complete course catalog or open this lesson on GitHub.