Integrasi A2A

Protokol Agent-to-Agent (A2A) memungkinkan komunikasi standar antar agen, memungkinkan agen yang dibangun dengan kerangka kerja dan teknologi yang berbeda untuk berkomunikasi dengan mulus.

Apa itu A2A?

A2A adalah protokol standar yang mendukung:

  • Identifikasi agen dengan kartu agen
  • Komunikasi berbasis pesan antar agen
  • Proses agenik yang berjalan lama melalui tugas
  • Interoperabilitas lintas platform antara kerangka kerja agen yang berbeda

Untuk informasi selengkapnya, lihat spesifikasi protokol A2A.

Library Microsoft.Agents.AI.Hosting.A2A.AspNetCore menyediakan integrasi ASP.NET Core untuk memperlihatkan agen Anda melalui protokol A2A.

Paket NuGet:

Contoh

Contoh minimal ini menunjukkan cara mengekspos agen melalui A2A. Sampel termasuk dependensi OpenAPI dan Swagger untuk menyederhanakan pengujian.

1. Buat proyek ASP.NET Core Web API

Buat proyek ASP.NET Core Web API baru atau gunakan yang sudah ada.

2. Pasang dependensi yang diperlukan

Instal paket berikut:

Jalankan perintah berikut di direktori proyek Anda untuk menginstal paket NuGet yang diperlukan:

# 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. Mengatur koneksi Microsoft Foundry

Aplikasi ini memerlukan koneksi proyek Microsoft Foundry. Konfigurasikan titik akhir dan nama penyebaran menggunakan dotnet user-secrets atau variabel lingkungan. Anda juga dapat mengedit appsettings.json, tetapi hal ini tidak disarankan untuk aplikasi yang disebarkan dalam lingkungan produksi karena beberapa data dapat dianggap rahasia.

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. Tambahkan kode ke Program.cs

Ganti konten Program.cs dengan kode berikut dan jalankan aplikasi:

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

Peringatan

DefaultAzureCredential nyaman untuk pengembangan tetapi membutuhkan pertimbangan yang cermat dalam produksi. Dalam produksi, pertimbangkan untuk menggunakan kredensial tertentu (misalnya, ManagedIdentityCredential) untuk menghindari masalah latensi, pemeriksaan kredensial yang tidak diinginkan, dan potensi risiko keamanan dari mekanisme fallback.

Menguji Agen

Setelah aplikasi berjalan, Anda dapat menguji agen A2A menggunakan file berikut .http atau melalui antarmuka pengguna Swagger.

Format input mematuhi spesifikasi A2A. Anda dapat memberikan nilai untuk:

  • messageId - Pengidentifikasi unik untuk pesan spesifik ini. Anda dapat membuat ID Anda sendiri (misalnya GUID) atau mengaturnya ke null untuk membiarkan agen membuatnya secara otomatis.
  • contextId - Pengidentifikasi percakapan. Berikan ID Anda sendiri untuk memulai percakapan baru atau melanjutkan percakapan yang sudah ada dengan menggunakan kembali contextId sebelumnya. Agen akan mempertahankan riwayat percakapan untuk hal yang sama contextId. Agen juga akan menghasilkan satu untuk Anda, jika tidak ada yang disediakan.
# 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"
  }
}

Catatan: Ganti {{baseAddress}} dengan titik akhir server Anda.

Permintaan ini mengembalikan respons JSON berikut:

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

Respons mencakup contextId (pengidentifikasi percakapan), messageId (pengidentifikasi pesan), dan konten aktual dari agen bajak laut.

Konfigurasi AgentCard

AgentCard menyediakan metadata tentang agen Anda untuk penemuan dan integrasi:

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

Anda dapat mengakses kartu agen dengan mengirim permintaan ini:

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

Catatan: Ganti {{baseAddress}} dengan titik akhir server Anda.

Properti AgentCard

  • Nama: Nama yang ditampilkan dari agen
  • Deskripsi: Deskripsi singkat agen
  • Versi: String versi untuk agen
  • Url: URL Titik Akhir (ditetapkan secara otomatis jika tidak ditentukan)
  • Kemampuan: Metadata opsional tentang streaming, pemberitahuan push, dan fitur lainnya

Mengekspos Beberapa Agen

Anda dapat mengekspos beberapa agen dalam satu aplikasi, selama titik akhir mereka tidak bertabrakan. Berikut adalah sebuah contoh:

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

Paket ini agent-framework-a2a memungkinkan Anda terhubung ke agen eksternal yang mematuhi A2A dan mengekspos agen Kerangka Kerja Agen melalui protokol A2A.

pip install agent-framework-a2a --pre

Menyambungkan ke Agen A2A

Gunakan A2AAgent untuk membungkus titik akhir A2A jarak jauh apa pun. Agen menyelesaikan kemampuan agen jarak jauh melalui AgentCard-nya dan menangani semua detail protokol.

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

Respons yang Mengalir

A2A secara alami mendukung streaming melalui Server-Sent Events — pembaruan tiba secara real time saat agen jarak jauh bekerja:

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

Tugas Berjalan Lama

Secara default, A2AAgent menunggu agen jarak jauh selesai sebelum kembali. Untuk tugas yang berjalan lama, atur background=True untuk mendapatkan token kelanjutan yang dapat Anda gunakan untuk melakukan polling atau berlangganan ulang nanti:

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)

Identitas Pembicaraan (context_id)

Ketika Anda memanggil A2AAgent.run() dengan AgentSession, agen secara otomatis mendapatkan A2A context_id dari session.service_session_id jika pesan keluar belum membawanya. Ini memungkinkan Anda mempertahankan kelangsungan percakapan di beberapa panggilan A2A tanpa mengatur context_id setiap pesan secara manual:

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)

Jika suatu pesan memiliki elemen context_id eksplisit dalam additional_properties, nilai tersebut akan diutamakan dibandingkan dengan fallback yang diturunkan dari sesi.

Authentication

Gunakan sebuah AuthInterceptor untuk titik akhir A2A yang aman.

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

Mengekspos Agen Kerangka Kerja Agen melalui A2A

A2AExecutor mengadaptasi Kerangka Kerja Agen apa pun ke protokol sisi server A2A. Anda dapat menghostingnya dengan server Starlette/ASGI resmi a2a-sdk sehingga klien A2A lainnya dapat menemukan dan memanggil agen Anda.

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 mengalirkan pembaruan agen sebagai artefak A2A ketika agen yang mendasar mendukung streaming, menyebarluaskan A2A context_id sebagai agen thread_id, dan mengekspos save_thread/get_thread kait yang dapat Anda ambil alih untuk penyimpanan utas persisten.

Tip

agent_framework_to_a2a.py Lihat sampel untuk contoh lengkap yang dapat dijalankan.

Lihat Juga

Langkah selanjutnya