A2A-agenttjänst

Gör A2AAgent att ditt program kan ansluta till fjärragenter som exponeras via A2A-protokollet (Agent-till-Agent). Den omsluter alla A2A-kompatibla slutpunkter som standard AIAgent, så att du kan använda välbekanta metoder som RunAsync och RunStreamingAsync interagera med fjärragenter oavsett vilket ramverk eller vilken teknik de har skapats med.

Information om hur du exponerar en Agent Framework-agent som en A2A-server finns i Värdagenter med A2A.

Getting Started

Lägg till det nödvändiga NuGet-paketet i projektet:

dotnet add package Microsoft.Agents.AI.A2A --prerelease

Agentidentifiering

Innan du kommunicerar med en fjärransluten A2A-agent måste du identifiera den och skapa en AIAgent instans. A2A-protokollet definierar tre identifieringsstrategier som var och en stöds av Agent Framework.

Well-Known URI

A2A-agenter kan göra agentkortet identifierbart på en standardiserad sökväg: https://{domain}/.well-known/agent-card.json. A2ACardResolver Använd för att hämta kortet och skapa en agent i ett enda anrop:

using A2A;
using Microsoft.Agents.AI;

// Initialize a resolver pointing at the remote agent's host.
A2ACardResolver resolver = new(new Uri("https://a2a-agent.example.com"));

// Resolve the agent card and create an AIAgent in one step.
AIAgent agent = await resolver.GetAIAgentAsync();

// Use the agent.
Console.WriteLine(await agent.RunAsync("Hello!"));

Tips/Råd

GetAIAgentAsync accepterar också en valfri A2AClientOptions parameter för protokollval.

Catalog-Based identifiering

I företagsmiljöer eller offentliga marknadsplatser hanteras agentkort ofta av ett centralt register. Om du redan har hämtat AgentCard från ett sådant register konverterar du det direkt till en AIAgent:

using A2A;
using Microsoft.Agents.AI;

// Assume agentCard was retrieved from a registry or catalog.
AgentCard agentCard = await GetAgentCardFromRegistryAsync("travel-planner");

AIAgent agent = agentCard.AsAIAgent();

Console.WriteLine(await agent.RunAsync("Plan a trip to Paris."));

Direktkonfiguration

För nära kopplade system eller utvecklingsscenarier där agentslutpunkten är känd i förväg skapar du en A2AClient direkt och konverterar den till :AIAgent

using A2A;
using Microsoft.Agents.AI;

// Create a client pointing at the known agent endpoint.
A2AClient a2aClient = new(new Uri("https://a2a-agent.example.com"));

AIAgent agent = a2aClient.AsAIAgent(name: "my-agent", description: "A helpful assistant.");

Console.WriteLine(await agent.RunAsync("What can you help me with?"));

Protokollval

A2A-agenter kan exponera flera protokollbindningar som HTTP+JSON och JSON-RPC. Som standard föredras HTTP+JSON framför JSON-RPC. Använd A2AClientOptions.PreferredBindings för att explicit kontrollera vilken protokollbindning som används:

Anmärkning

Den fjärranslutna A2A-agenten måste vara tillgänglig vid en slutpunkt som stöder den valda protokollbindningen.

using A2A;
using Microsoft.Agents.AI;

A2ACardResolver agentCardResolver = new(new Uri("https://a2a-agent.example.com"));

AgentCard agentCard = await agentCardResolver.GetAgentCardAsync();

// Prefer HTTP+JSON protocol binding. For JSON-RPC, set PreferredBindings = [ProtocolBindingNames.JsonRpc]
A2AClientOptions options = new()
{
    PreferredBindings = [ProtocolBindingNames.HttpJson]
};

AIAgent agent = agentCard.AsAIAgent(options: options);

Console.WriteLine(await agent.RunAsync("Tell me a joke about a pirate."));

Streaming

A2A stöder strömmande svar via Server-Sent-händelser. Använd RunStreamingAsync för att ta emot uppdateringar i realtid när fjärragenten bearbetar begäran:

using A2A;
using Microsoft.Agents.AI;

A2ACardResolver resolver = new(new Uri("https://a2a-agent.example.com"));
AIAgent agent = await resolver.GetAIAgentAsync();

await foreach (var update in agent.RunStreamingAsync("Write a short story about a robot."))
{
    if (!string.IsNullOrEmpty(update.Text))
    {
        Console.Write(update.Text);
    }
}

Bakgrundssvar

A2A-agenter stöder bakgrundssvar för hantering av långvariga åtgärder. När en fjärransluten A2A-agent returnerar en uppgift i stället för ett omedelbart meddelande, tillhandahåller Agent Framework en fortsättningstoken som du kan använda för att söka efter resultat eller återansluta till avbrutna strömmar.

Avsökning för slutförande av aktivitet

För scenarier som inte strömmas använder du AllowBackgroundResponses för att ta emot en fortsättningstoken och avsöka tills uppgiften har slutförts:

using A2A;
using Microsoft.Agents.AI;

A2ACardResolver resolver = new(new Uri("https://a2a-agent.example.com"));
AIAgent agent = await resolver.GetAIAgentAsync();

AgentSession session = await agent.CreateSessionAsync();

// AllowBackgroundResponses must be true so the server returns immediately with a continuation token
// instead of blocking until the task is complete.
AgentRunOptions options = new() { AllowBackgroundResponses = true };

// Start the initial run with a long-running task.
AgentResponse response = await agent.RunAsync(
    "Conduct a comprehensive analysis of quantum computing applications in cryptography.",
    session,
    options: options);

// Poll until the response is complete.
while (response.ContinuationToken is { } token)
{
    // Wait before polling again.
    await Task.Delay(TimeSpan.FromSeconds(2));

    // Continue with the token.
    response = await agent.RunAsync(session, options: new AgentRunOptions { ContinuationToken = token });
}

Console.WriteLine(response);

Stream Reconnection

I strömningsscenarier kan varje uppdatering innehålla en fortsättningstoken. Om strömmen avbryts använder du token för att återansluta och hämta svarsströmmen från början:

using A2A;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;

A2ACardResolver resolver = new(new Uri("https://a2a-agent.example.com"));
AIAgent agent = await resolver.GetAIAgentAsync();

AgentSession session = await agent.CreateSessionAsync();

ResponseContinuationToken? continuationToken = null;

await foreach (var update in agent.RunStreamingAsync(
    "Conduct a comprehensive analysis of quantum computing applications in cryptography.",
    session))
{
    // Save the continuation token to reconnect later if the stream is interrupted.
    // Continuation tokens are only returned for long-running tasks. If the A2A agent
    // returns a message instead of a task, the continuation token will not be initialized.
    if (update.ContinuationToken is { } token)
    {
        continuationToken = token;
    }
}

// If the stream was interrupted and a continuation token was captured,
// reconnect to the response stream using the saved continuation token.
if (continuationToken is not null)
{
    await foreach (var update in agent.RunStreamingAsync(
        session,
        options: new() { ContinuationToken = continuationToken }))
    {
        if (!string.IsNullOrEmpty(update.Text))
        {
            Console.WriteLine(update.Text);
        }
    }
}

Anmärkning

A2A-agenter har stöd för strömåteranslutning (hämtar samma svarsström från början), inte att dataströmmen återupptas från en specifik punkt i strömmen.

Tools

A2AAgent är en omslutning på transportnivå runt en fjärransluten A2A-agent. Vilka verktyg fjärragenten än använder live på fjärrsidan och är osynliga för din kod. Agent Framework-verktygstyper (funktionsverktyg, kodtolkare, filsökning, värdbaserad/lokal MCP osv.) är inte konfigurerade på A2AAgent sig själv – för att utöka fjärragentens funktioner ändrar du fjärragentens konfiguration.

Getting Started

Installera A2A-paketet:

pip install agent-framework-a2a --pre

Initialisering

A2AAgent kan initieras på tre sätt beroende på hur mycket du vet om fjärragenten i förväg.

Direkt-URL

För utveckling eller nära kopplade system där slutpunkten är känd:

from agent_framework.a2a import A2AAgent

async with A2AAgent(name="remote", url="https://a2a-agent.example.com") as agent:
    response = await agent.run("Hello!")
    print(response.messages[0].text)

När endast en URL tillhandahålls A2AAgent skapar du ett minimalt agentkort internt och ansluter med JSON-RPC.

Agentkort

Om du har en AgentCard från ett register eller en katalog skickar du den direkt:

from agent_framework.a2a import A2AAgent

async with A2AAgent(agent_card=agent_card) as agent:
    response = await agent.run("Plan a trip to Paris.")
    print(response.messages[0].text)

När en AgentCard tillhandahålls, A2AAgent standardvärden name och description från kortet. Den förhandlar transport med kortets supported_interfaces.

Well-Known URI (A2ACardResolver)

Använd A2ACardResolver från a2a-sdk för att identifiera fjärragenten på den välkända standardsökvägen (/.well-known/agent.json):

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

async with httpx.AsyncClient(timeout=60.0) as http_client:
    resolver = A2ACardResolver(httpx_client=http_client, base_url="https://a2a-agent.example.com")
    agent_card = await resolver.get_agent_card()

async with A2AAgent(agent_card=agent_card) as agent:
    response = await agent.run("What can you help me with?")
    print(response.messages[0].text)

Streaming

Använd stream=True för att ta emot uppdateringar i realtid när fjärragenten bearbetar begäran:

from agent_framework.a2a import A2AAgent

async with A2AAgent(name="remote", url="https://a2a-agent.example.com") as agent:
    stream = agent.run("Write a short story about a robot.", stream=True)
    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))")

Långvariga uppgifter

Som standard väntar A2AAgent på att fjärragenten ska slutföra innan det returneras. För långvariga uppgifter anger du background=True till att visa en fortsättningstoken som du kan använda för att avsöka eller prenumerera senare:

from agent_framework.a2a import A2AAgent

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)

Du kan också prenumerera på SSE-strömmen igen i stället för att avsöka:

# Resubscribe to the task's event stream
response = await agent.run(continuation_token=response.continuation_token)

Konversationsidentitet (context_id)

A2AAgent lagrar varaktigt protokolltillstånd i AgentSession.service_session_id som en A2AServiceSessionId mappning:

Fält Type Purpose
context_id str Identifierar A2A-konversationen.
task_id str \| None Spårar den senaste fjärraktiviteten när svaret skapade en.
task_state TaskState \| None Registrerar det senaste aktivitetstillståndet så att nästa begäran kan fortsätta med en uppgift som krävs för indata eller referera till en slutförd aktivitet.

Skapa en session med strukturerat tillstånd när ditt program redan känner till A2A-kontexten:

from agent_framework import AgentSession
from agent_framework.a2a import A2AAgent, A2AServiceSessionId

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

    # The A2A message uses context_id="my-conversation-1".
    response = await agent.run("Hello!", session=session)

    # A2AAgent updates task_id and task_state from the response.
    response = await agent.run("Follow-up question", session=session)

Du kan också börja med AgentSession() och låta A2AAgent fylla i den strukturerade mappningen från det första svaret. Spara den vanliga sessionen med session.to_dict() och återställ den med AgentSession.from_dict(...). A2A-kontexten, aktivitets-ID:t och uppgiftstillståndet förblir tillsammans.

För en aktivitet i TASK_STATE_INPUT_REQUIREDanger nästa meddelande att task_id samma uppgift ska fortsätta. För andra aktivitetstillstånd skickas det tidigare aktivitets-ID:t via reference_task_ids så att fjärragenten kan förfina eller fortsätta från det tidigare resultatet.

Authentication

Använd en AuthInterceptor för skyddade A2A-slutpunkter:

from a2a.client.auth.interceptor import AuthInterceptor
from agent_framework.a2a import A2AAgent

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

Timeout-konfiguration

A2AAgent accepterar en timeout parameter för att kontrollera tidsgränser för begäran:

import httpx
from agent_framework.a2a import A2AAgent

# Simple timeout (applies to all components)
async with A2AAgent(name="remote", url="https://example.com", timeout=120.0) as agent:
    ...

# Fine-grained timeout
async with A2AAgent(
    name="remote",
    url="https://example.com",
    timeout=httpx.Timeout(connect=10.0, read=120.0, write=10.0, pool=5.0),
) as agent:
    ...

När ingen tidsgräns har angetts är standardvärdena: 10s connect, 60s read, 10s write, 5s pool.

Tools

A2AAgent är en omslutning på transportnivå runt en fjärransluten A2A-agent. Vilka verktyg fjärragenten än använder live på fjärrsidan och är osynliga för din kod. Agent Framework-verktygstyper (funktionsverktyg, kodtolkare, filsökning, värdbaserad/lokal MCP osv.) är inte konfigurerade på A2AAgent sig själv – för att utöka fjärragentens funktioner ändrar du fjärragentens konfiguration.

Om du vill att en Foundry-agent ska anropa en A2A-agent som ett verktyg läser du fabriken påget_a2a_toolFoundryChatClient.

Go stöder fjärranslutna provider/a2aprovider A2A-agenter via paketet.

Installera Agent Framework- och A2A-paketen:

go get github.com/microsoft/agent-framework-go
go get github.com/a2aproject/a2a-go/v2

Ansluta till en fjärransluten A2A-agent

Lös fjärragentkortet, skapa en A2A-klient från det och omslut klienten som en Standard Agent Framework-agent:

import (
    "context"

    "github.com/a2aproject/a2a-go/v2/a2aclient"
    "github.com/a2aproject/a2a-go/v2/a2aclient/agentcard"
    "github.com/microsoft/agent-framework-go/agent"
    "github.com/microsoft/agent-framework-go/provider/a2aprovider"
)

ctx := context.Background()

card, err := agentcard.DefaultResolver.Resolve(ctx, "http://localhost:5000")
if err != nil {
    panic(err)
}

client, err := a2aclient.NewFromCard(ctx, card)
if err != nil {
    panic(err)
}

a := a2aprovider.NewAgent(
    client,
    a2aprovider.AgentConfig{
        Config: agent.Config{
            Name:        card.Name,
            Description: card.Description,
        },
    },
)

resp, err := a.RunText(ctx, "Hello!").Collect()

Providern lagrar A2A context_id - och aktivitets-ID:t i Agent Framework-sessionen så att uppföljningsmeddelanden kan bevara konversationskontinuitet.

Protokollval

Om en fjärragent annonserar flera transportbindningar konfigurerar du önskad transport när du skapar A2A-klienten:

client, err := a2aclient.NewFromCard(
    ctx,
    card,
    a2aclient.WithConfig(a2aclient.Config{
        PreferredTransports: []a2a.TransportProtocol{a2a.TransportProtocolHTTPJSON},
    }),
)

Använd a2a.TransportProtocolJSONRPC när du vill föredra JSON-RPC.

Tidskrävande uppgifter

A2A-uppgifter dyker upp via Agent Frameworks fortsättningstoken. Starta körningen med en uttrycklig session och agent.AllowBackgroundResponses(true), och gör sedan upprepade förfrågningar genom att anropa Run utan några nya meddelanden och med fortsättningstokenen:

session, err := a.CreateSession(ctx)
if err != nil {
    panic(err)
}

resp, err := a.RunText(
    ctx,
    "Process this large dataset.",
    agent.WithSession(session),
    agent.AllowBackgroundResponses(true),
).Collect()
if err != nil {
    panic(err)
}

for resp.ContinuationToken != "" {
    resp, err = a.Run(
        ctx,
        nil,
        agent.WithSession(session),
        agent.WithContinuationToken(resp.ContinuationToken),
    ).Collect()
    if err != nil {
        panic(err)
    }
}

För avbrutna strömningskörningar samlar du in update.ContinuationToken från den senast mottagna uppdateringen och skickar den till en senare strömningskörning med agent.WithContinuationToken(token) och agent.Stream(true).

Använda A2A-fjärragenter som verktyg

Lös varje fjärragent, omslut den med a2aprovider.NewAgentoch konvertera den till ett verktyg med agenttool.New.

tools := make([]tool.Tool, 0, len(agentURLs))

for _, agentURL := range agentURLs {
    card, err := agentcard.DefaultResolver.Resolve(ctx, agentURL)
    if err != nil {
        panic(err)
    }

    client, err := a2aclient.NewFromCard(ctx, card)
    if err != nil {
        panic(err)
    }

    remoteAgent := a2aprovider.NewAgent(client, a2aprovider.AgentConfig{
        Config: agent.Config{
            Name:        card.Name,
            Description: card.Description,
        },
    })

    tools = append(tools, agenttool.New(remoteAgent, agenttool.Config{}))
}

Tips/Råd

Se A2A-providerexemplet och A2A-agenter som verktygsexempel för fullständiga körbara exempel.

Nästa steg

Gå djupare: