Partager via


Intégration A2A

Le protocole Agent-to-Agent (A2A) permet une communication standardisée entre les agents, ce qui permet aux agents créés avec différents frameworks et technologies de communiquer en toute transparence.

Qu’est-ce qu’A2A ?

A2A est un protocole standardisé qui prend en charge :

  • Découverte de l’agent par le biais de cartes d’agent
  • Communication basée sur les messages entre les agents
  • Processus agentiques de longue durée via des tâches
  • Interopérabilité multiplateforme entre différents frameworks d’agent

Pour plus d’informations, consultez la spécification du protocole A2A.

La Microsoft.Agents.AI.Hosting.A2A.AspNetCore bibliothèque fournit une intégration d'ASP.NET Core pour exposer vos agents via le protocole A2A.

Packages NuGet :

Example

Cet exemple minimal montre comment exposer un agent via A2A. L’exemple inclut les dépendances OpenAPI et Swagger pour simplifier les tests.

1. Créer un projet d’API web core ASP.NET

Créez un projet d’API web core ASP.NET ou utilisez-en un existant.

2. Installer les dépendances requises

Installez les packages suivants :

Exécutez les commandes suivantes dans votre répertoire de projet pour installer les packages NuGet requis :

# 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. Configurer la connexion Azure OpenAI

L’application nécessite une connexion Azure OpenAI. Configurez le point de terminaison et le nom du déploiement à l'aide de dotnet user-secrets ou de variables d'environnement. Vous pouvez également simplement modifier le appsettings.json, mais ce n’est pas recommandé pour les applications déployées en production, car certaines données peuvent être considérées comme secrètes.

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. Ajoutez le code à Program.cs

Remplacez le contenu du Program.cs code suivant et exécutez l’application :

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 de l’agent

Une fois l’application en cours d’exécution, vous pouvez tester l’agent A2A à l’aide du fichier suivant .http ou via l’interface utilisateur Swagger.

Le format d’entrée est conforme à la spécification A2A. Vous pouvez fournir des valeurs pour :

  • messageId - Identificateur unique pour ce message spécifique. Vous pouvez créer votre propre ID (par exemple, un GUID) ou le définir sur null pour permettre à l’agent d’en générer un automatiquement.
  • contextId - Identificateur de conversation. Fournissez votre propre ID pour démarrer une nouvelle conversation ou poursuivre une conversation existante en réutilisant un précédent contextId. L'agent conservera l'historique de conversation pour le même contextId. L’agent en génère également un pour vous, si aucun n’est fourni.
# 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"
  }
}

Remarque : Remplacez {{baseAddress}} par votre point de terminaison de serveur.

Cette requête retourne la réponse JSON suivante :

{
	"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 réponse inclut l' contextId (identificateur de conversation), messageId l’identificateur de message et le contenu réel de l’agent pirate.

Configuration d’AgentCard

Les AgentCard fournissent des métadonnées sur votre agent pour la découverte et l'intégration.

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

Vous pouvez accéder à la carte de l’agent en envoyant cette requête :

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

Remarque : Remplacez {{baseAddress}} par votre point de terminaison de serveur.

Propriétés AgentCard

  • Nom affiché de l’agent
  • Description : brève description de l’agent
  • Version : chaîne de version pour l’agent
  • URL : URL du point de terminaison (automatiquement attribuée si elle n’est pas spécifiée)
  • Fonctionnalités : métadonnées facultatives sur la diffusion en continu, les notifications Push et d’autres fonctionnalités

Exposition de plusieurs agents

Vous pouvez exposer plusieurs agents dans une seule application, tant que leurs points de terminaison ne sont pas en collision. Voici un exemple :

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");

Le agent-framework-a2a package vous permet de vous connecter et de communiquer avec des agents externes conformes à A2A.

pip install agent-framework-a2a --pre

Connexion à un agent A2A

Utilisez A2AAgent pour encapsuler n’importe quel point de terminaison A2A distant. L’agent résout les fonctionnalités de l’agent distant via son AgentCard et gère tous les détails du protocole.

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())

Réponses en continu

A2A prend naturellement en charge la diffusion en continu via des événements Server-Sent : les mises à jour arrivent en temps réel au fur et à mesure que l’agent distant fonctionne :

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))")

Tâches de longue durée

Par défaut, A2AAgent attend que l’agent distant termine avant de retourner. Pour les tâches de longue durée, définissez background=True pour obtenir un jeton de continuation que vous pouvez utiliser pour interroger ou réinscrire ultérieurement :

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

Utilisez un AuthInterceptor point de terminaison A2A sécurisé :

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!")

Voir aussi

Prochaines étapes