A2A エージェント

A2AAgentを使用すると、アプリケーションはエージェント間 (A2A) プロトコルを介して公開されているリモート エージェントに接続できます。 A2A 準拠エンドポイントが標準の AIAgentとしてラップされるため、 RunAsyncRunStreamingAsync などの使い慣れた方法を使用して、構築されたフレームワークやテクノロジに関係なくリモート エージェントと対話できます。

はじめに

必要な NuGet パッケージをプロジェクトに追加します。

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

エージェントの検出

リモート A2A エージェントと通信する前に、それを検出し、 AIAgent インスタンスを作成する必要があります。 A2A プロトコルは、エージェント フレームワークでサポートされる 3 つの 検出戦略を定義します。

Well-Known URI

A2A エージェントは、標準化されたパス () でhttps://{domain}/.well-known/agent-card.jsonを検出できるようにします。 A2ACardResolverを使用してカードをフェッチし、1 回の呼び出しでエージェントを作成します。

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

ヒント

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を使用して、使用するプロトコル バインディングを明示的に制御します。

Note

リモート 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 エージェントが即時メッセージではなくタスクを返すと、Agent Framework は、結果のポーリングや中断されたストリームへの再接続に使用できる継続トークンを提供します。

タスク完了のポーリング

ストリーミング以外のシナリオでは、 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);
        }
    }
}

Note

A2A エージェントは、ストリーム内の特定のポイントからのストリーム再開ではなく、ストリーム再接続 (最初から同じ応答ストリームを取得) をサポートします。

ツール

A2AAgent は、リモート A2A エージェントを囲むトランスポート レベルのラッパーです。 リモート エージェントがリモート側でライブで使用し、コードからは見えないツール。 エージェント フレームワーク ツールの種類 (関数ツール、コード インタープリター、ファイル検索、ホスト/ローカル MCP など) は、リモート エージェントの機能を拡張し、リモート エージェントの構成を変更するために、 A2AAgent 自体では構成されません。

はじめに

A2A パッケージをインストールします。

pip install agent-framework-a2a --pre

初期化

A2AAgent は、リモート エージェントについて事前に知っている程度に応じて、3 つの方法で初期化できます。

直接 URL

エンドポイントが既知の開発または密結合システムの場合:

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)

URL のみが指定されている場合、 A2AAgent は最小限のエージェント カードを内部で作成し、JSON-RPC を使用して接続します。

エージェント カード

レジストリまたはカタログから AgentCard がある場合は、それを直接渡します。

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)

AgentCardが指定されている場合、A2AAgentはカードからのnamedescriptionの既定値になります。 カードの supported_interfacesを使用してトランスポートをネゴシエートします。

Well-Known URI (A2ACardResolver)

A2ACardResolvera2a-sdkを使用して、標準の既知のパス (/.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)

ストリーミング

リモート エージェントが要求を処理する際に、 stream=True を使用してリアルタイムで更新プログラムを受信します。

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

長時間実行タスク

既定では、 A2AAgent はリモート エージェントが終了するまで待機してから戻ります。 実行時間の長いタスクの場合は、後でポーリングまたはサブスクライブするために使用できる継続トークンを表示するように background=True を設定します。

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)

ポーリングの代わりに SSE ストリームに再サブスクライブすることもできます。

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

会話の識別 (context_id)

A2AAgent.run()AgentSessionと共に呼び出すと、送信メッセージにA2A context_idがまだ含まれていない場合、エージェントは自動的にsession.service_session_idからA2A context_idを導き出します。 これにより、複数の A2A 呼び出し間で会話の継続性を維持できます。

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)

メッセージのcontext_idに明示的なadditional_propertiesがある場合、その値はセッションから派生したフォールバックよりも優先されます。

認証

セキュリティで保護された A2A エンドポイントに AuthInterceptor を使用します。

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

タイムアウト構成

A2AAgent は、要求タイムアウトを制御するための timeout パラメーターを受け取ります。

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:
    ...

タイムアウトが指定されていない場合、既定値は 10 秒接続、60 秒読み取り、10 秒書き込み、5s プールです。

ツール

A2AAgent は、リモート A2A エージェントを囲むトランスポート レベルのラッパーです。 リモート エージェントがリモート側でライブで使用し、コードからは見えないツール。 エージェント フレームワーク ツールの種類 (関数ツール、コード インタープリター、ファイル検索、ホスト/ローカル MCP など) は、リモート エージェントの機能を拡張し、リモート エージェントの構成を変更するために、 A2AAgent 自体では構成されません。

Foundry エージェントで A2A エージェントをツールとして呼び出す場合は、get_a2a_toolFoundryChatClient ファクトリを参照してください。

Go は、 provider/a2aprovider パッケージを介してリモート A2A エージェントをサポートします。 Go の例とエンド ツー エンドのホスティング ガイダンスについては、 A2A の統合を参照してください。

次のステップ