A2A-integráció

Az Ügynökről ügynökre (A2A) protokoll szabványosított kommunikációt tesz lehetővé az ügynökök között, lehetővé téve a különböző keretrendszerekkel és technológiákkal készült ügynökök zökkenőmentes kommunikációját.

Mi az A2A?

Az A2A egy szabványosított protokoll, amely a következőket támogatja:

  • Ügynökfelderítés ügynökkártyákon keresztül
  • Üzenetalapú kommunikáció ügynökök között
  • Hosszú ideig futó ügynökalapú folyamatok feladatokon keresztül
  • Platformfüggetlen együttműködés a különböző ügynök-keretrendszerek között

További információkért lásd az A2A protokoll specifikációját.

A Microsoft.Agents.AI.Hosting.A2A.AspNetCore kódtár ASP.NET Core-integrációt biztosít az ügynökök A2A protokollon keresztüli felfedéséhez.

NuGet-csomagok:

Example

Ez a minimális példa bemutatja, hogyan tehet közzé egy ügynököt az A2A-on keresztül. A minta OpenAPI- és Swagger-függőségeket tartalmaz a tesztelés egyszerűsítése érdekében.

1. ASP.NET Core Web API-projekt létrehozása

Hozzon létre egy új ASP.NET Core Web API-projektet, vagy használjon egy meglévőt.

2. A szükséges függőségek telepítése

Telepítse a következő csomagokat:

Futtassa a következő parancsokat a projektkönyvtárban a szükséges NuGet-csomagok telepítéséhez:

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

# Libraries to connect to Microsoft Foundry
dotnet add package Azure.AI.Projects --prerelease
dotnet add package Azure.Identity
dotnet add package Microsoft.Agents.AI.Foundry --prerelease

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

3. A Microsoft Foundry-kapcsolat konfigurálása

Az alkalmazáshoz Microsoft Foundry-projektkapcsolat szükséges. Konfigurálja a végpontot és az üzembe helyezés nevét a dotnet user-secrets vagy a környezeti változók használatával. Egyszerűen szerkesztheti is a appsettings.jsondokumentumot, de az éles környezetben üzembe helyezett alkalmazások esetében ez nem ajánlott, mivel egyes adatok titkosnak tekinthetők.

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. Adja hozzá a kódot a Program.cs

Cserélje le a Program.cs tartalmát a következő kóddal, és futtassa az alkalmazást:

using A2A.AspNetCore;
using Azure.AI.Projects;
using Azure.Identity;
using Microsoft.Agents.AI;
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 AIProjectClient(
        new Uri(endpoint),
        new DefaultAzureCredential())
        .GetProjectOpenAIClient()
        .GetProjectResponsesClient()
        .AsIChatClient(deploymentName);

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

Figyelmeztetés

DefaultAzureCredential a fejlesztéshez kényelmes, de a termelési környezetben gondos megfontolást igényel. Éles környezetben fontolja meg egy adott hitelesítő adat (pl. ManagedIdentityCredential) használatát a késési problémák elkerülése, a hitelesítő adatok nem szándékos próbálgatásának és a tartalék mechanizmusokból eredő esetleges biztonsági kockázatok elkerülése érdekében.

Az ügynök tesztelése

Az alkalmazás futtatása után tesztelheti az A2A-ügynököt a következő .http fájl vagy a Swagger felhasználói felületén keresztül.

A bemeneti formátum megfelel az A2A specifikációjának. Megadhat értékeket a következőhöz:

  • messageId - Az adott üzenet egyedi azonosítója. Létrehozhat saját azonosítót (például egy GUID-t), vagy beállíthatja null értékre, hogy az ügynök automatikusan generálhasson egyet.
  • contextId - A beszélgetés azonosítója. Adja meg a saját azonosítóját egy új beszélgetés indításához, vagy egy meglévő folytatásához egy korábbi contextIdújrahasználásával. Az ügynök ugyanahhoz contextId kapcsolódóan fenntartja a beszélgetési előzményeket. Az ügynök önnek is létrehoz egyet, ha nincs megadva.
# 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"
  }
}

Megjegyzés: Cserélje le a {{baseAddress}} kifejezést a kiszolgáló végpontjával.

Ez a kérés a következő JSON-választ adja vissza:

{
	"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"
}

A válasz tartalmazza a contextId (beszélgetés azonosítóját), messageId (üzenetazonosító) és a kalózügynök tényleges tartalmát.

AgentCard-konfiguráció

A AgentCard szolgáltatás metaadatokat biztosít az ügynökről a felderítéshez és az integrációhoz:

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

Az ügynökkártyát a következő kérés elküldésével érheti el:

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

Megjegyzés: Cserélje le a {{baseAddress}} kifejezést a kiszolgáló végpontjával.

AgentCard tulajdonságai

  • Név: Az ügynök megjelenítendő neve
  • Leírás: Az ügynök rövid leírása
  • Verzió: Az ügynök verziószövege
  • Url: Végpont URL-címe (automatikusan hozzárendelve, ha nincs megadva)
  • Képességek: Választható metaadatok a streamelésről, a leküldéses értesítésekről és más funkciókról

Több ügynök leleplezése

Egyetlen alkalmazásban több ügynököt is közzétehet, feltéve, hogy a végpontok nem ütköznek egymással. Íme egy példa:

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

A agent-framework-a2a csomag lehetővé teszi, hogy mindketten külső A2A-kompatibilis ügynökökhöz csatlakozzanak , és közzétehessenek egy Agent Framework-ügynököt az A2A protokollon keresztül.

pip install agent-framework-a2a --pre

Csatlakozás A2A-ügynökhöz

Tetszőleges távoli A2A-végpont burkolására használja a A2AAgent-t. Az ügynök az AgentCardon keresztül feloldja a távoli ügynök képességeit, és kezeli az összes protokollrészletet.

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

Adatfolyam válaszok

Az A2A természetesen támogatja a streamelést Server-Sent eseményeken keresztül – a frissítések valós időben érkeznek a távoli ügynök működése során:

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

Hosszan tartó tevékenységek

Alapértelmezés szerint a A2AAgent megvárja, amíg a távoli ügynök befejezi a műveletet, még mielőtt visszatér. Hosszú ideig futó feladatok esetén állítsa be a background=True értékét egy olyan folytatási jogkivonat megszerzéséhez, amelyet később lekérdezhet vagy újra feliratkozhat.

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)

Beszélgetési azonosító (context_id)

Amikor A2AAgent.run()-t hív AgentSession segítségével, az ügynök automatikusan levezeti az A2A context_id-t session.service_session_id-ből, ha a kimenő üzenet még nem tartalmazza azt. Ez lehetővé teszi a beszélgetések folytonosságának fenntartását több A2A-hívásban anélkül, hogy minden üzenetre manuálisan beállítanál context_id :

from agent_framework import AgentSession
from agent_framework.a2a import A2AAgent

async with A2AAgent(name="remote", url="https://a2a-agent.example.com") as agent:
    session = AgentSession(service_session_id="my-conversation-1")

    # context_id is automatically set to "my-conversation-1"
    response = await agent.run("Hello!", session=session)

    # Subsequent calls with the same session continue the conversation
    response = await agent.run("Follow-up question", session=session)

Ha egy üzenet explicit context_id módon van megadva additional_properties, akkor ez az érték elsőbbséget élvez a munkamenetből származtatott tartalék értékkel szemben.

Authentication

Használjon biztonságos AuthInterceptor A2A-végpontokat:

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

Ügynök-keretrendszer ügynökének felfedése az A2A-n keresztül

Az A2AExecutor ügynök-keretrendszereket Agent az A2A kiszolgálóoldali protokollhoz igazítja. Üzemeltetheti a hivatalos a2a-sdk Starlette/ASGI-kiszolgálóval, hogy más A2A-ügyfelek is felfedezhessék és felhívhassák az ügynököt.

import uvicorn
from a2a.server.apps import A2AStarletteApplication
from a2a.server.request_handlers import DefaultRequestHandler
from a2a.server.tasks import InMemoryTaskStore
from a2a.types import AgentCapabilities, AgentCard, AgentSkill
from agent_framework import Agent
from agent_framework.a2a import A2AExecutor
from agent_framework.openai import OpenAIChatClient

flight_skill = AgentSkill(
    id="Flight_Booking",
    name="Flight Booking",
    description="Search and book flights across Europe.",
    tags=["flights", "travel", "europe"],
    examples=[],
)

public_agent_card = AgentCard(
    name="Europe Travel Agent",
    description="Helps users search and book flights and hotels across Europe.",
    url="http://localhost:9999/",
    version="1.0.0",
    defaultInputModes=["text"],
    defaultOutputModes=["text"],
    capabilities=AgentCapabilities(streaming=True),
    skills=[flight_skill],
)

agent = Agent(
    client=OpenAIChatClient(),
    name="Europe Travel Agent",
    instructions="You are a helpful Europe Travel Agent.",
)

request_handler = DefaultRequestHandler(
    agent_executor=A2AExecutor(agent),
    task_store=InMemoryTaskStore(),
)

server = A2AStarletteApplication(
    agent_card=public_agent_card,
    http_handler=request_handler,
).build()

uvicorn.run(server, host="0.0.0.0", port=9999)

A2AExecutor az ügynökfrissítéseket A2A-összetevőkként streameli, amikor a mögöttes ügynök támogatja a streamelést, az A2A-t context_id az ügynök thread_id-jaként propagálja, és olyan horgokat save_thread/get_thread tesz elérhetővé, amelyeket felül lehet bírálni az állandó száltároláshoz.

Jótanács

Tekintse meg a agent_framework_to_a2a.py mintát egy teljes futtatható példához.

Lásd még:

Következő lépések