Condividi tramite


Integrazione A2A

Il protocollo da agente a agente (A2A) consente la comunicazione standardizzata tra gli agenti, consentendo agli agenti compilati con framework e tecnologie diversi di comunicare senza problemi.

Che cos'è A2A?

A2A è un protocollo standardizzato che supporta:

  • Individuazione agente tramite schede agente
  • Comunicazione basata su messaggi tra agenti
  • Processi agentici a lunga durata tramite attività
  • Interoperabilità multipiattaforma tra diversi framework agente

Per altre informazioni, vedere la specifica del protocollo A2A.

La libreria Microsoft.Agents.AI.Hosting.A2A.AspNetCore fornisce l'integrazione di ASP.NET Core per esporre gli agenti tramite il protocollo A2A.

Pacchetti NuGet:

Example

Questo esempio minimo illustra come esporre un agente tramite A2A. L'esempio include dipendenze OpenAPI e Swagger per semplificare il test.

1. Creare un progetto API Web di base ASP.NET

Creare un nuovo progetto api Web core ASP.NET o usarne uno esistente.

2. Installare le dipendenze necessarie

Installare i pacchetti seguenti:

Eseguire i comandi seguenti nella directory del progetto per installare i pacchetti NuGet necessari:

# Hosting.A2A.AspNetCore for A2A protocol integration
dotnet add package Microsoft.Agents.AI.Hosting.A2A.AspNetCore --prerelease

# Libraries to connect to Azure OpenAI
dotnet add package Azure.AI.OpenAI --prerelease
dotnet add package Azure.Identity
dotnet add package Microsoft.Extensions.AI
dotnet add package Microsoft.Extensions.AI.OpenAI --prerelease

# Swagger to test app
dotnet add package Microsoft.AspNetCore.OpenApi
dotnet add package Swashbuckle.AspNetCore

3. Configurare la connessione OpenAI di Azure

L'applicazione richiede una connessione OpenAI di Azure. Configurare l'endpoint e il nome della distribuzione usando dotnet user-secrets o le variabili di ambiente. È anche possibile modificare semplicemente , appsettings.jsonma non è consigliabile per le app distribuite nell'ambiente di produzione perché alcuni dei dati possono essere considerati segreti.

dotnet user-secrets set "AZURE_OPENAI_ENDPOINT" "https://<your-openai-resource>.openai.azure.com/"
dotnet user-secrets set "AZURE_OPENAI_DEPLOYMENT_NAME" "gpt-4o-mini"

4. Aggiungere il codice a Program.cs

Sostituire il contenuto di Program.cs con il codice seguente ed eseguire l'applicazione:

using A2A.AspNetCore;
using Azure.AI.OpenAI;
using Azure.Identity;
using Microsoft.Agents.AI.Hosting;
using Microsoft.Extensions.AI;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddOpenApi();
builder.Services.AddSwaggerGen();

string endpoint = builder.Configuration["AZURE_OPENAI_ENDPOINT"]
    ?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set.");
string deploymentName = builder.Configuration["AZURE_OPENAI_DEPLOYMENT_NAME"]
    ?? throw new InvalidOperationException("AZURE_OPENAI_DEPLOYMENT_NAME is not set.");

// Register the chat client
IChatClient chatClient = new AzureOpenAIClient(
        new Uri(endpoint),
        new DefaultAzureCredential())
    .GetChatClient(deploymentName)
    .AsIChatClient();
builder.Services.AddSingleton(chatClient);

// Register an agent
var pirateAgent = builder.AddAIAgent("pirate", instructions: "You are a pirate. Speak like a pirate.");

var app = builder.Build();

app.MapOpenApi();
app.UseSwagger();
app.UseSwaggerUI();

// Expose the agent via A2A protocol. You can also customize the agentCard
app.MapA2A(pirateAgent, path: "/a2a/pirate", agentCard: new()
{
    Name = "Pirate Agent",
    Description = "An agent that speaks like a pirate.",
    Version = "1.0"
});

app.Run();

Test dell'agente

Dopo aver eseguito l'applicazione, è possibile testare l'agente A2A usando il file seguente .http o tramite l'interfaccia utente di Swagger.

Il formato di input è conforme alla specifica A2A. È possibile specificare i valori per:

  • messageId - Identificatore univoco per questo messaggio specifico. È possibile creare il proprio ID (ad esempio, un GUID) o impostarlo su null per consentire all'agente di generarne uno automaticamente.
  • contextId - Identificatore della conversazione. Specificare il proprio ID per avviare una nuova conversazione o continuare una esistente riutilizzando un oggetto precedente contextId. L'agente manterrà la cronologia delle conversazioni per lo stesso contextId. Agent genererà anche uno per l'utente, se non ne viene fornito alcuno.
# Send A2A request to the pirate agent
POST {{baseAddress}}/a2a/pirate/v1/message:stream
Content-Type: application/json
{
  "message": {
    "kind": "message",
    "role": "user",
    "parts": [
      {
        "kind": "text",
        "text": "Hey pirate! Tell me where have you been",
        "metadata": {}
      }
    ],
	"messageId": null,
    "contextId": "foo"
  }
}

Nota: sostituire {{baseAddress}} con l'endpoint server.

Questa richiesta restituisce la risposta JSON seguente:

{
	"kind": "message",
	"role": "agent",
	"parts": [
		{
			"kind": "text",
			"text": "Arrr, ye scallywag! Ye’ll have to tell me what yer after, or be I walkin’ the plank? 🏴‍☠️"
		}
	],
	"messageId": "chatcmpl-CXtJbisgIJCg36Z44U16etngjAKRk",
	"contextId": "foo"
}

La risposta include ( contextId identificatore della conversazione), messageId (identificatore del messaggio) e il contenuto effettivo dell'agente pirata.

Configurazione di AgentCard

AgentCard fornisce metadati sull'agente per l'individuazione e l'integrazione:

app.MapA2A(agent, "/a2a/my-agent", agentCard: new()
{
    Name = "My Agent",
    Description = "A helpful agent that assists with tasks.",
    Version = "1.0",
});

È possibile accedere alla scheda agente inviando questa richiesta:

# Send A2A request to the pirate agent
GET {{baseAddress}}/a2a/pirate/v1/card

Nota: sostituire {{baseAddress}} con l'endpoint server.

Proprietà AgentCard

  • Nome: nome visualizzato dell'agente
  • Descrizione: breve descrizione dell'agente
  • Versione: stringa di versione per l'agente
  • URL: URL endpoint (assegnato automaticamente se non specificato)
  • Funzionalità: metadati facoltativi relativi a streaming, notifiche push e altre funzionalità

Esposizione di più agenti

È possibile esporre più agenti in una singola applicazione, purché gli endpoint non si sovrappongano. Ecco un esempio:

var mathAgent = builder.AddAIAgent("math", instructions: "You are a math expert.");
var scienceAgent = builder.AddAIAgent("science", instructions: "You are a science expert.");

app.MapA2A(mathAgent, "/a2a/math");
app.MapA2A(scienceAgent, "/a2a/science");

Il agent-framework-a2a pacchetto consente di connettersi e comunicare con agenti esterni conformi a A2A.

pip install agent-framework-a2a --pre

Connessione a un agente A2A

Usare A2AAgent per eseguire il wrapping di qualsiasi endpoint A2A remoto. L'agente risolve le funzionalità dell'agente remoto tramite AgentCard e gestisce tutti i dettagli del protocollo.

import asyncio
import httpx
from a2a.client import A2ACardResolver
from agent_framework.a2a import A2AAgent

async def main():
    a2a_host = "https://your-a2a-agent.example.com"

    # 1. Discover the remote agent's capabilities
    async with httpx.AsyncClient(timeout=60.0) as http_client:
        resolver = A2ACardResolver(httpx_client=http_client, base_url=a2a_host)
        agent_card = await resolver.get_agent_card()
        print(f"Found agent: {agent_card.name}")

    # 2. Create an A2AAgent and send a message
    async with A2AAgent(
        name=agent_card.name,
        agent_card=agent_card,
        url=a2a_host,
    ) as agent:
        response = await agent.run("What are your capabilities?")
        for message in response.messages:
            print(message.text)

asyncio.run(main())

Risposte in streaming

A2A supporta naturalmente lo streaming tramite eventi di Server-Sent: gli aggiornamenti arrivano in tempo reale man mano che funziona l'agente remoto:

async with A2AAgent(name="remote", url="https://a2a-agent.example.com") as agent:
    async with agent.run("Tell me about yourself", stream=True) as stream:
        async for update in stream:
            for content in update.contents:
                if content.text:
                    print(content.text, end="", flush=True)

        final = await stream.get_final_response()
        print(f"\n({len(final.messages)} message(s))")

Attività a lungo termine

Per impostazione predefinita, A2AAgent attende che l'agente remoto termini prima di restituire. Per le attività a esecuzione prolungata, impostare background=True per ottenere un token di continuazione che è possibile usare per eseguire il polling o ripetere la sottoscrizione in un secondo momento:

async with A2AAgent(name="worker", url="https://a2a-agent.example.com") as agent:
    # Start a long-running task
    response = await agent.run("Process this large dataset", background=True)

    if response.continuation_token:
        # Poll for completion later
        result = await agent.poll_task(response.continuation_token)
        print(result)

Authentication

Usare un AuthInterceptor per gli endpoint A2A protetti:

from a2a.client.auth.interceptor import AuthInterceptor

class BearerAuth(AuthInterceptor):
    def __init__(self, token: str):
        self.token = token

    async def intercept(self, request):
        request.headers["Authorization"] = f"Bearer {self.token}"
        return request

async with A2AAgent(
    name="secure-agent",
    url="https://secure-a2a-agent.example.com",
    auth_interceptor=BearerAuth("your-token"),
) as agent:
    response = await agent.run("Hello!")

Vedere anche

Passaggi successivi