Agentes de host com A2A

O protocolo Agente para Agente (A2A) permite a comunicação padronizada entre agentes criados com diferentes estruturas e tecnologias. Esta página aborda a exposição de agentes do Agent Framework como servidores A2A.

Para descobrir e invocar um agente A2A remoto, consulte o serviço de agente A2A.

O que é A2A?

A2A é um protocolo padronizado que dá suporte a:

  • Descoberta de agentes através de cartões de agentes
  • Comunicação baseada em mensagem entre agentes
  • Processos agentes de longa duração através de tarefas
  • Interoperabilidade entre plataformas entre diferentes estruturas de agente

Para obter mais informações, consulte a especificação do protocolo A2A.

A biblioteca Microsoft.Agents.AI.Hosting.A2A.AspNetCore fornece integração com o ASP.NET Core para expor seus agentes por meio do protocolo A2A.

Pacotes NuGet:

Example

Este exemplo mínimo mostra como expor um agente por meio do A2A. O exemplo inclui dependências OpenAPI e Swagger para simplificar o teste.

1. Criar um projeto de API Web do ASP.NET Core

Crie um novo projeto de API Web do ASP.NET Core ou use um existente.

2. Instalar dependências necessárias

Instale os seguintes pacotes:

Execute os seguintes comandos no diretório do projeto para instalar os pacotes NuGet necessários:

# 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. Configurar a conexão do Microsoft Foundry

O aplicativo requer uma conexão de projeto do Microsoft Foundry. Configure o endpoint e o nome da implantação usando dotnet user-secrets ou variáveis de ambiente. Você também pode simplesmente editar o appsettings.json, mas isso não é recomendado para os aplicativos implantados em produção, pois alguns dos dados podem ser considerados secretos.

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. Adicionar o código ao Program.cs

Substitua o conteúdo de Program.cs com o seguinte código e execute o aplicativo.

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

Warning

DefaultAzureCredential é conveniente para o desenvolvimento, mas requer uma consideração cuidadosa na produção. Em produção, considere o uso de uma credencial específica (por exemplo, ManagedIdentityCredential) para evitar problemas de latência, investigação de credenciais não intencionais e possíveis riscos de segurança de mecanismos de fallback.

Testando o agente

Depois que o aplicativo estiver em execução, você poderá testar o agente A2A usando o arquivo a seguir .http ou por meio da interface do usuário do Swagger.

O formato de entrada está em conformidade com a especificação A2A. Você pode fornecer valores para:

  • messageId - Um identificador exclusivo para esta mensagem específica. Você pode criar sua própria ID (por exemplo, um GUID) ou defini-la para null permitir que o agente gere uma automaticamente.
  • contextId - O identificador de conversa. Forneça sua própria ID para iniciar uma nova conversa ou continuar uma existente reutilizando uma anterior contextId. O agente manterá o histórico de conversas para o mesmo contextId. O agente também gerará um para você, se nenhum for fornecido.
# 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"
  }
}

Observação: substitua {{baseAddress}} por seu endpoint de servidor.

Essa solicitação retorna a seguinte resposta JSON:

{
	"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 resposta inclui o contextId (identificador de conversa), messageId (identificador de mensagem) e o conteúdo real do agente pirata.

Configuração do AgentCard

O AgentCard fornece metadados sobre seu agente para descoberta e integração.

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

Você pode acessar o cartão do agente enviando esta solicitação:

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

Observação: substitua {{baseAddress}} por seu endpoint de servidor.

Propriedades AgentCard

  • Nome: nome de exibição do agente
  • Descrição: breve descrição do agente
  • Versão: cadeia de caracteres de versão para o agente
  • URL: URL do ponto de extremidade (atribuída automaticamente se não for especificada)
  • Funcionalidades: metadados opcionais sobre streaming, notificações por push e outros recursos

Expondo vários agentes

Você pode expor vários agentes em um único aplicativo, desde que seus pontos de extremidade não colidam. Veja um exemplo:

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

O agent-framework-a2a pacote expõe um agente do Agent Framework pelo protocolo A2A.

pip install agent-framework-a2a --pre

Testar um ponto de extremidade seguro

Use um AuthInterceptor cliente de teste para verificar um ponto de extremidade A2A seguro:

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

Expondo um agente do Agent Framework pelo A2A

O pacote agent-framework-a2a fornece um A2AExecutor opinativo que adapta qualquer agente do Agent Framework ao protocolo A2A do lado do servidor. Ele executa o agente, mapeia o conteúdo de saída compatível em eventos e artefatos A2A e gerencia as atualizações de status da tarefa por meio da interface oficial a2a-sdk.

Seu aplicativo reúne os componentes do servidor do SDK A2A: o card do agente, DefaultRequestHandler o repositório de tarefas, as rotas ou o construtor da aplicação, a autenticação e a implantação. Para uma comparação entre os adaptadores pertencentes ao aplicativo e os auxiliares de conversão independentes em agent-framework-hosting-a2a, consulte Auto-hospedar agentes A2A.

import uvicorn
from a2a.server.request_handlers import DefaultRequestHandler
from a2a.server.routes import create_agent_card_routes, create_jsonrpc_routes
from a2a.server.tasks import InMemoryTaskStore
from a2a.types import AgentCapabilities, AgentCard, AgentInterface, AgentSkill
from agent_framework import Agent
from agent_framework.a2a import A2AExecutor
from agent_framework.openai import OpenAIChatClient
from starlette.applications import Starlette

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.",
    version="1.0.0",
    default_input_modes=["text"],
    default_output_modes=["text"],
    capabilities=AgentCapabilities(streaming=True),
    supported_interfaces=[
        AgentInterface(url="http://localhost:9999/", protocol_binding="JSONRPC"),
    ],
    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, stream=True),
    task_store=InMemoryTaskStore(),
    agent_card=public_agent_card,
)

server = Starlette(
    routes=[
        *create_agent_card_routes(public_agent_card),
        *create_jsonrpc_routes(request_handler, "/"),
    ]
)

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

A2AExecutor transmite atualizações do agente como artefatos A2A quando o agente subjacente oferece suporte a streaming e propaga o A2A context_id como o session_id da sessão do agente. Você pode criar uma subclasse de A2AExecutor e sobrescrever o método handle_events para implementar transformações personalizadas do formato de saída do seu agente em eventos do protocolo A2A.

Protocolo A2A

O Go Agent Framework dá suporte à hospedagem de agentes do Agent Framework por meio do protocolo Agente para Agente (A2A) com o provider/a2aprovider pacote e os manipuladores de servidor A2A Go oficiais.

Instale os pacotes do Agent Framework e do A2A no módulo Go:

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

Hospede um agente via A2A

Crie ou reutilize um agente do Agent Framework, descreva-o com um cartão de agente A2A e exponha-o por meio de uma das associações de transporte A2A. Neste exemplo, hostAgenté qualquer framework de agente*agent.Agent; o servidor hospeda um endpoint JSON-RPC em / e disponibiliza o cartão do agente no caminho A2A bem conhecido.

import (
    "fmt"
    "net/http"

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

url := "http://localhost:5000"

card := &a2a.AgentCard{
    Name:               "InvoiceAgent",
    Description:        "Handles requests relating to invoices.",
    Version:            "1.0.0",
    DefaultInputModes:  []string{"text"},
    DefaultOutputModes: []string{"text"},
    Capabilities: a2a.AgentCapabilities{
        Streaming: false,
    },
    SupportedInterfaces: []*a2a.AgentInterface{
        a2a.NewAgentInterface(url, a2a.TransportProtocolJSONRPC),
    },
}

mux := http.NewServeMux()
requestHandler := a2asrv.NewHandler(
    a2aprovider.NewExecutor(hostAgent, a2aprovider.ExecutorConfig{}),
    a2asrv.WithExtendedAgentCard(card),
)
mux.Handle("/", a2asrv.NewJSONRPCHandler(requestHandler))
mux.Handle(a2asrv.WellKnownAgentCardPath, a2asrv.NewStaticAgentCardHandler(card))

if err := http.ListenAndServe(":5000", mux); err != nil {
    panic(fmt.Errorf("A2A server failed: %w", err))
}

Encapsule o mesmo manipulador de solicitação com a2asrv.NewRESTHandler quando você quiser expor a associação de transporte HTTP+JSON. Defina ExecutorConfig.AllowBackgroundResponses como true se deve ser permitido ao agente hospedado retornar tarefas A2A para trabalhos de longa duração.

Consulte Também

Próximas Etapas