

# Implementazione di server A2A in Runtime AgentCore
<a name="runtime-a2a"></a>

Amazon Bedrock AgentCore AgentCore Runtime consente di distribuire ed eseguire server Agent-to-Agent (A2A) nel Runtime. AgentCore Questa guida ti guida nella creazione, nel test e nella distribuzione del tuo primo server A2A.

In questa sezione, imparerai:
+ In che modo Amazon Bedrock AgentCore supporta A2A
+ Come creare un server A2A con funzionalità di agente
+ Come testare il server localmente
+ Come installare il server su AWS 
+ Come richiamare il server distribuito
+ Come recuperare le carte degli agenti per scoprirle

Per ulteriori informazioni su A2A, vedere Contratto di protocollo [A2A](runtime-a2a-protocol-contract.md).

**Topics**
+ [In che modo Amazon Bedrock AgentCore supporta A2A](#runtime-a2a-how-agentcore-supports)
+ [Utilizzo di A2A con Runtime AgentCore](#runtime-a2a-steps)
+ [Appendice](#runtime-a2a-appendix)

## In che modo Amazon Bedrock AgentCore supporta A2A
<a name="runtime-a2a-how-agentcore-supports"></a>

Il supporto AgentCore del protocollo A2A di Amazon Bedrock consente una perfetta integrazione con i server A2A fungendo da livello proxy trasparente. Una volta configurato per A2A, Amazon Bedrock AgentCore prevede che i container eseguano server HTTP stateless e in streaming sulla porta nel percorso principale (`0.0.0.0:9000/`), `9000` in linea con la configurazione predefinita del server A2A.

Il servizio offre un isolamento delle sessioni di livello aziendale mantenendo al contempo la trasparenza del protocollo: i JSON-RPC payload dell'API vengono trasferiti direttamente al contenitore A2A senza modifiche. [InvokeAgentRuntime](https://docs.aws.amazon.com/bedrock-agentcore/latest/APIReference/API_InvokeAgentRuntime.html) Questa architettura preserva le funzionalità standard del protocollo A2A, come il rilevamento integrato degli agenti tramite Agent Cards at `/.well-known/agent-card.json` and JSON-RPC communication, aggiungendo al contempo l'autenticazione aziendale (2.0) e la scalabilità. SigV4/OAuth 

I principali fattori di differenziazione dagli altri protocolli sono la porta (9000 vs 8080 per HTTP), il mount path (`/`vs`/invocations`) e il meccanismo standardizzato di rilevamento degli agenti, che rendono Amazon Bedrock AgentCore una piattaforma di distribuzione ideale per gli agenti A2A negli ambienti di produzione.

Principali differenze rispetto ad altri protocolli:

 **Porta**   
I server A2A funzionano sulla porta 9000 (contro 8080 per HTTP, 8000 per MCP)

 **Path**   
I server A2A sono montati su (rispetto a HTTP, a MCP`/`) `/invocations` `/mcp`

 **Agent Cards**   
A2A offre un servizio integrato di rilevamento degli agenti tramite Agent Cards all'indirizzo `/.well-known/agent-card.json` 

 **Protocollo**   
Usi JSON-RPC per la comunicazione tra agenti

 **Autenticazione**   
Supporta schemi di autenticazione SigV4 e OAuth 2.0

Per ulteriori informazioni, consulta [https://a2a-protocol.org/](https://a2a-protocol.org/).

## Utilizzo di A2A con Runtime AgentCore
<a name="runtime-a2a-steps"></a>

In questo tutorial creerai, testerai e distribuirai un server A2A.

**Topics**
+ [Prerequisiti](#runtime-a2a-prerequisites)
+ [Fase 1: Crea il tuo progetto A2A](#runtime-a2a-create-server)
+ [Fase 2: Esegui il test del server A2A a livello locale](#runtime-a2a-test-locally)
+ [Fase 3: Implementa il server A2A su Bedrock Runtime AgentCore](#runtime-a2a-deploy)
+ [Fase 4: Ottieni la carta dell'agente](#runtime-a2a-step-4)
+ [Fase 5: richiama il server A2A distribuito](#runtime-a2a-step-5)

### Prerequisiti
<a name="runtime-a2a-prerequisites"></a>
+ Python 3.10 o superiore installato e conoscenza di base di Python
+ Node.js 18 o versioni successive installate (richiesta per la AgentCore CLI)
+ La AgentCore CLI installata: `npm install -g @aws/agentcore` 
+ Un AWS account con le autorizzazioni appropriate e le credenziali locali configurate
+ Comprensione del protocollo A2A e dei concetti di comunicazione agente-agente

### Fase 1: Crea il tuo progetto A2A
<a name="runtime-a2a-create-server"></a>

Questo esempio utilizza Strands Agents, ma la AgentCore CLI supporta anche progetti LangChain/LangGraph A2A con Google ADK.

#### Scaffold: il progetto
<a name="runtime-a2a-scaffold-project"></a>

Esegui il seguente comando e seleziona *Strands* come framework quando richiesto:

```
agentcore create --protocol A2A
```

La CLI supporta un progetto completo con tutte le dipendenze e le configurazioni richieste. Il file generato `main.py` contiene il tuo server A2A:

```
from strands import Agent, tool
from strands.multiagent.a2a.executor import StrandsA2AExecutor
from bedrock_agentcore.runtime import serve_a2a
from model.load import load_model

@tool
def add_numbers(a: int, b: int) -> int:
    """Return the sum of two numbers."""
    return a + b

tools = [add_numbers]

agent = Agent(
    model=load_model(),
    system_prompt="You are a helpful assistant. Use tools when appropriate.",
    tools=tools,
)

if __name__ == "__main__":
    serve_a2a(StrandsA2AExecutor(agent))
```

#### Comprendere il codice
<a name="runtime-a2a-understanding-code"></a>

 **Agente Strands**   
Crea un agente con strumenti e funzionalità specifici

 **Strands A2A Executor**   
Avvolge l'agente Strands per fornire la compatibilità del protocollo A2A

 **serve\_a2a**   
L'helper Amazon Bedrock AgentCore SDK che avvia un Bedrock-compatible server A2A. Gestisce l'endpoint `/ping` sanitario, il servizio Agent Card, la variabile di `AGENTCORE_RUNTIME_URL` ambiente, la propagazione dell'intestazione Bedrock e, per impostazione predefinita, viene eseguito sulla porta 9000.

 **Porta 9000**   
Per impostazione predefinita, i server A2A funzionano sulla porta 9000 in Runtime AgentCore 

Per personalizzare questo agente, sostituite `add_numbers` lo strumento con i vostri strumenti e aggiornate il prompt di sistema.

### Fase 2: Esegui il test del server A2A a livello locale
<a name="runtime-a2a-test-locally"></a>

Esegui e testa il tuo server A2A in un ambiente di sviluppo locale.

#### Avvia il tuo server A2A
<a name="runtime-a2a-start-server"></a>

Avvia il tuo server A2A localmente utilizzando la CLI: AgentCore 

```
agentcore dev
```

Questo apre l' AgentCore Agent Inspector nel tuo browser web. Per utilizzare invece la TUI basata su terminale, usa. `agentcore dev --no-browser`

In alternativa, puoi eseguire direttamente il server:

```
python main.py
```

Dovresti vedere un output che indica che il server è in esecuzione sulla porta`9000`.

#### Invoca l'agente
<a name="runtime-a2a-invoke-agent"></a>

```
curl -X POST http://localhost:9000/ \
-H "Content-Type: application/json" \
-d '{
  "jsonrpc": "2.0",
  "id": "req-001",
  "method": "message/send",
  "params": {
    "message": {
      "role": "user",
      "parts": [
        {
          "kind": "text",
          "text": "what is 101 * 11?"
        }
      ],
      "messageId": "12345678-1234-1234-1234-123456789012"
    }
  }
}' | jq .
```

#### Recupero della carta dell'agente di test
<a name="runtime-a2a-test-agent-card"></a>

Puoi testare localmente l'endpoint della carta agente:

```
curl http://localhost:9000/.well-known/agent-card.json | jq.
```

È inoltre possibile testare il server distribuito utilizzando A2A Inspector come descritto [in Test remoti con A2A](https://github.com/a2aproject/a2a-inspector) Inspector.

### Fase 3: Implementa il server A2A su Bedrock Runtime AgentCore
<a name="runtime-a2a-deploy"></a>

#### Configura il pool di utenti di Cognito per l'autenticazione
<a name="runtime-a2a-setup-cognito"></a>

Prima della distribuzione, configura l'autenticazione per un accesso sicuro al server distribuito. Per istruzioni dettagliate sulla configurazione di Cognito, consulta [Configurare il pool di utenti di Cognito](runtime-mcp.md#runtime-mcp-appendix-a) per l'autenticazione. Ciò fornisce i token OAuth necessari per un accesso sicuro al server distribuito.

#### Esegui la distribuzione su AWS
<a name="runtime-a2a-deploy-aws"></a>

Implementa il tuo agente:

```
agentcore deploy
```

Questo comando consentirà di:

1. Package del codice dell'agente e delle dipendenze

1. Carica l'artefatto di distribuzione su Amazon S3

1. Crea un runtime Amazon Bedrock AgentCore 

1. Implementa il tuo agente su AWS 

Dopo la distribuzione, riceverai un ARN di runtime dell'agente simile a:

```
arn:aws:bedrock-agentcore:us-west-2:accountId:runtime/my_a2a_server-xyz123
```

### Fase 4: Ottieni la carta dell'agente
<a name="runtime-a2a-step-4"></a>

Le Agent Card sono documenti di metadati JSON che descrivono l'identità, le capacità, le competenze, l'endpoint di servizio e i requisiti di autenticazione di un server A2A. Consentono l'individuazione automatica degli agenti nell'ecosistema A2A.

#### Impostazione delle variabili di ambiente
<a name="runtime-a2a-step-4-setup-environment-variables"></a>

Impostazione delle variabili di ambiente

1. Esporta il token bearer come variabile di ambiente. Per la configurazione del token Bearer, vedere Configurazione del token [Bearer.](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/runtime-mcp.html#runtime-mcp-appendix)

   ```
   export BEARER_TOKEN="<BEARER_TOKEN>"
   ```

1. Esporta l'ARN dell'agente.

   ```
   export AGENT_ARN="arn:aws:bedrock-agentcore:us-west-2:accountId:runtime/my_a2a_server-xyz123"
   ```

#### Recupera la carta dell'agente
<a name="retrieve-agent-card"></a>

```
import os
import json
import requests
from uuid import uuid4
from urllib.parse import quote

def fetch_agent_card():
    # Get environment variables
    agent_arn = os.environ.get('AGENT_ARN')
    bearer_token = os.environ.get('BEARER_TOKEN')

    if not agent_arn:
        print("Error: AGENT_ARN environment variable not set")
        return

    if not bearer_token:
        print("Error: BEARER_TOKEN environment variable not set")
        return

    # URL encode the agent ARN
    escaped_agent_arn = quote(agent_arn, safe='')

    # Construct the URL
    url = f"https://bedrock-agentcore.us-west-2.amazonaws.com/runtimes/{escaped_agent_arn}/invocations/.well-known/agent-card.json"

    # Generate a unique session ID
    session_id = str(uuid4())
    print(f"Generated session ID: {session_id}")

    # Set headers
    headers = {
        'Accept': '*/*',
        'Authorization': f'Bearer {bearer_token}',
        'X-Amzn-Bedrock-AgentCore-Runtime-Session-Id': session_id
    }

    try:
        # Make the request
        response = requests.get(url, headers=headers)
        response.raise_for_status()

        # Parse and pretty print JSON
        agent_card = response.json()
        print(json.dumps(agent_card, indent=2))

        return agent_card

    except requests.exceptions.RequestException as e:
        print(f"Error fetching agent card: {e}")
        return None

if __name__ == "__main__":
    fetch_agent_card()
```

Dopo aver ottenuto l'URL dalla Agent Card, esporta `AGENTCORE_RUNTIME_URL` come variabile di ambiente:

```
export AGENTCORE_RUNTIME_URL="https://bedrock-agentcore.us-west-2.amazonaws.com/runtimes/<ARN>/invocations/"
```

### Fase 5: richiama il server A2A distribuito
<a name="runtime-a2a-step-5"></a>

Crea codice client per richiamare il server Amazon Bedrock AgentCore A2A distribuito e invia messaggi per testarne la funzionalità.

Crea un nuovo file per richiamare il server `my_a2a_client_remote.py` A2A distribuito:

```
import asyncio
import logging
import os
from uuid import uuid4

import httpx
from a2a.client import A2ACardResolver, ClientConfig, ClientFactory
from a2a.types import Message, Part, Role, TextPart

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

DEFAULT_TIMEOUT = 300  # set request timeout to 5 minutes

def create_message(*, role: Role = Role.user, text: str) -> Message:
    return Message(
        kind="message",
        role=role,
        parts=[Part(TextPart(kind="text", text=text))],
        message_id=uuid4().hex,
    )

async def send_sync_message(message: str):
    # Get runtime URL from environment variable
    runtime_url = os.environ.get('AGENTCORE_RUNTIME_URL')

    # Generate a unique session ID
    session_id = str(uuid4())
    print(f"Generated session ID: {session_id}")

    # Add authentication headers for Amazon Bedrock AgentCore
    headers = {"Authorization": f"Bearer {os.environ.get('BEARER_TOKEN')}",
        'X-Amzn-Bedrock-AgentCore-Runtime-Session-Id': session_id}

    async with httpx.AsyncClient(timeout=DEFAULT_TIMEOUT, headers=headers) as httpx_client:
        # Get agent card from the runtime URL
        resolver = A2ACardResolver(httpx_client=httpx_client, base_url=runtime_url)
        agent_card = await resolver.get_agent_card()

        # Agent card contains the correct URL (same as runtime_url in this case)
        # No manual override needed - this is the path-based mounting pattern

        # Create client using factory
        config = ClientConfig(
            httpx_client=httpx_client,
            streaming=False,  # Use non-streaming mode for sync response
        )
        factory = ClientFactory(config)
        client = factory.create(agent_card)

        # Create and send message
        msg = create_message(text=message)

        # With streaming=False, this will yield exactly one result
        async for event in client.send_message(msg):
            if isinstance(event, Message):
                logger.info(event.model_dump_json(exclude_none=True, indent=2))
                return event
            elif isinstance(event, tuple) and len(event) == 2:
                # (Task, UpdateEvent) tuple
                task, update_event = event
                logger.info(f"Task: {task.model_dump_json(exclude_none=True, indent=2)}")
                if update_event:
                    logger.info(f"Update: {update_event.model_dump_json(exclude_none=True, indent=2)}")
                return task
            else:
                # Fallback for other response types
                logger.info(f"Response: {str(event)}")
                return event

# Usage - Uses AGENTCORE_RUNTIME_URL environment variable
asyncio.run(send_sync_message("what is 101 * 11"))
```

## Appendice
<a name="runtime-a2a-appendix"></a>

**Topics**
+ [Configura il pool di utenti di Cognito per l'autenticazione](#runtime-a2a-setup-cognito-appendix)
+ [Test a distanza con A2A Inspector](#runtime-a2a-remote-testing)
+ [Risoluzione dei problemi](#runtime-a2a-troubleshooting)

### Configura il pool di utenti di Cognito per l'autenticazione
<a name="runtime-a2a-setup-cognito-appendix"></a>

Per istruzioni dettagliate sulla configurazione di Cognito, consulta Configurare il [pool di utenti Cognito per l'autenticazione](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/runtime-mcp.html#set-up-cognito-user-pool-for-authentication) nella documentazione MCP.

### Test a distanza con A2A Inspector
<a name="runtime-a2a-remote-testing"></a>

Per informazioni, consulta [https://github.com/a2aproject/a2a-inspector](https://github.com/a2aproject/a2a-inspector).

### Risoluzione dei problemi
<a name="runtime-a2a-troubleshooting"></a>

 **Problemi comuni A2A-specific ** 

Di seguito sono riportati i problemi più comuni che potresti riscontrare:

Conflitti tra porte  
I server A2A devono essere eseguiti sulla porta 9000 nell'ambiente Runtime AgentCore 

JSON-RPC errori  
Verifica che il tuo client stia inviando messaggi JSON-RPC 2.0 formattati correttamente

Mancata corrispondenza del metodo di autorizzazione  
Assicurati che la richiesta utilizzi lo stesso metodo di autenticazione (OAuth o SigV4) con cui è stato configurato l'agente

 **Gestione delle eccezioni** 

Specifiche A2A per la gestione degli errori: [https://a2a-protocol.org/latest/specification/#81-standard-json-rpc-errors](https://a2a-protocol.org/latest/specification/#81-standard-json-rpc-errors) 

I server A2A restituiscono gli errori come risposte di JSON-RPC errore standard con codici di stato HTTP 200. Gli errori interni di runtime vengono automaticamente tradotti in errori JSON-RPC interni per mantenere la conformità del protocollo.

Il servizio ora fornisce risposte di A2A-compliant errore corrette con codici di JSON-RPC errore standardizzati:


| JSON-RPC Codice di errore | Eccezione di runtime | Codice di errore HTTP | JSON-RPC Messaggio di errore | 
| --- | --- | --- | --- | 
| N/A |  `AccessDeniedException`  | 403 | N/A | 
| -32501 |  `ResourceNotFoundException`  | 404 | Risorsa non trovata: la risorsa richiesta non esiste | 
| -32502 |  `ValidationException`  | 400 | Errore di convalida: dati di richiesta non validi | 
| -32503 |  `ThrottlingException`  | 429 | Limite di frequenza superato: troppe richieste | 
| -32503 |  `ServiceQuotaExceededException`  | 429 | Limite di frequenza superato: troppe richieste | 
| -32504 |  `ResourceConflictException`  | 409 | Conflitto di risorse: la risorsa esiste già | 
| -32505 |  `RuntimeClientError`  | 424 | Errore del client di runtime: controlla i CloudWatch log per ulteriori informazioni. | 