A2A 代理

这使 A2AAgent 应用程序能够连接到通过 代理到代理 (A2A) 协议公开的远程代理。 它将任何符合 A2A 的终结点包装为标准 AIAgent,因此可以使用熟悉的方法(例如 RunAsync ,并与 RunStreamingAsync 远程代理交互),而不考虑它们使用哪种框架或技术。

入门

将所需的 NuGet 包添加到项目:

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

代理发现

在与远程 A2A 代理通信之前,需要发现它并创建实例 AIAgent 。 A2A 协议定义了三种 发现策略,每个策略都受代理框架支持。

Well-Known URI

A2A 代理可以在标准化路径上发现其代理卡https://{domain}/.well-known/agent-card.json 使用 A2ACardResolver 提取卡片并在单个调用中创建代理:

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

Tip

GetAIAgentAsync还接受用于协议选择的可选A2AClientOptions参数。

Catalog-Based 发现

在企业环境或公共市场中,代理卡通常由中央注册表管理。 如果已 AgentCard 从此类注册表获取,请将其直接转换为 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."));

直接配置

对于提前知道代理终结点的紧密耦合系统或开发方案,请直接创建一个 A2AClient 并将其转换为 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?"));

协议选择

A2A 代理可以公开多个协议绑定,例如 HTTP+JSON 和 JSON-RPC。 默认情况下,HTTP+JSON 优先于 JSON-RPC。 用于 A2AClientOptions.PreferredBindings 显式控制使用哪种协议绑定:

注释

远程 A2A 代理必须在支持所选协议绑定的终结点上可用。

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

流媒体

A2A 支持通过 Server-Sent 事件进行流式处理响应。 用于 RunStreamingAsync 在远程代理处理请求时实时接收更新:

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

后台响应

A2A 代理支持 后台响应 来处理长时间运行的操作。 当远程 A2A 代理返回任务而不是即时消息时,代理框架提供了一个延续令牌,可用于轮询结果或重新连接到中断的流。

轮询任务完成

对于非流式处理方案,用于 AllowBackgroundResponses 接收延续令牌并轮询,直到任务完成:

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

流重新连接

在流式处理方案中,每个更新可能包含延续令牌。 如果流中断,请使用令牌重新连接并从头获取响应流:

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

注释

A2A 代理支持流重新连接(从头获取相同的响应流),而不是从流中的特定点进行流恢复。

注释

Python A2A 代理的文档即将推出。

后续步骤