Overview
エージェント間(A2A)通信により、1 つのエージェントが実行時に同じプロジェクト内の他のエージェントを検出し、呼び出すことができます。クエリを実行することで、すべての呼び出しを中断します。
アクセスを検証します
子実行を作成します
リクエストをターゲットエージェントにディスパッチします
結果を返します
人間が開発したループ(HITL)での保証はエンドツーエンドで適用されます。人間のレビューのために一時停止するターゲットエージェントは、失敗を返す代わりに呼び出しを一時停止します。
有効にすると、A2A は次のシーケンスに従います。
agent.yamlファイルにa2a:ブロックを追加します。最初の実行で、プラットフォームはエージェントの構成を OA に登録し、同じプロジェクト内の他のエージェントによってエージェントを検出し、呼び出せるようにします。OA がエージェントに実行をディスパッチすると、有効期間の短いトークンが実行コンテキストに挿入されます。エージェントは、他のエージェントを呼び出すときにそのトークンを透過的に使用します。
エージェントコードから、
app.a2a_tools()を使用して A2A を LM ツールとして公開するか(推奨)、または決定的なルーティングのためにapp._runtime.a2aを介して A2Aクライアントを直接呼び出します。OA はアクセス制御を強制し、子の実行を親にリンクし、ターゲットにディスパッチして結果を返します。
エージェント.YAML で A2A を有効にする
agent.yamlファイルに a2a: セクションを追加して、エージェントを検出し、呼び出せるようにします。このセクションを省略するか、a2a.enabled を false に設定すると、エージェントはA2A 呼び出し元では表示されず、既存の配置と完全に下位互換性があります。
注意
A2A をローカルでテストするには、A2A を呼び出す、または呼び出されるすべてのエージェントの .envファイルで、A2A_JWT_SECRET 環境変数を同じ値に設定します。
次の例では、完全に構成された a2a: セクションを示しています。
name: insurance-agent entrypoint: insurance_agent.main:app a2a: enabled: true allowed_callers: - "ws-router-002" skills: - name: policy-lookup description: Look up insurance policy details example_input: '{"policy_id": "POL-123"}' example_output: '{"status": "active", "premium": 240}' - name: get-quote description: Generate an insurance quote input_modes: - "text/plain" output_modes: - "text/plain"
A2A フィールド
次の表は、agent.yamlファイルの a2a: セクション内のフィールドを説明したものです。
フィールド | タイプ | default | 説明 |
|---|---|---|---|
| ブール |
| A2A を通じてエージェントを検出し、呼び出せるようにします。 |
| list[str] |
| このエージェントを呼び出すために許可されたワークスペース ID。空のリストでは、同じプロジェクトで任意の A2A 有効エージェントが許可されます。空でないリストは許可リストとして機能します。 |
| list[object] |
| エージェントが検出のために公開するスキーム。各エントリには |
| list[str] |
| エージェントが受け入れる多目的インターネットメール拡張機能( MIME )の例( |
| list[str] |
| エージェントが生成するMIMEタイプ。検出フィルターとして使用されます。 |
注意
エージェントの name、skills、input_modes、output_modes、allowed_callers は、スタートアップ時に自動的に OA にプッシュされます。検出結果に表示される無料テキストの説明と機能タグは、agent.yaml ではなく、 API Gateway ワークスペース エンドポイントを通じて構成するワークスペースの Agentcard から取得されます。
他のエージェントを呼び出す
エージェントコードから他のエージェントを呼び出すには、A2A を LM ツールとして公開する(推奨)方法と、A2Aクライアントを直接使用する方法の 2 通りがあります。どちらも同じ 基礎となるクライアントを使用します。 LM を使用してルーティングの決定を行うか、決定的な制御が必要かに基づいてアプローチを選択します。
LM ツールとして A2A を使用
app.a2a_tools() メソッドは、2 つの Lgachein StructuredTool オブジェクト(discover_available_agents と invoke_a2a_agent )を返します。これらのオブジェクトを使用すると、LM は他のエージェントを単独で検出し、呼び出すことができます。既存のツールと一緒にこれらをバインドすることで、モデルは単独で他のエージェントにルーティングできます。
agent.yamlファイルで a2a.enabled が false の場合、app.a2a_tools() メソッドでは空のリストが返されるため、すべてのエージェントに を含めても安全です。
次の例では、A2A ツールを既存のツールと並行してバインドします。
from agent_engine_sdk_langgraph import App from langchain_openai import ChatOpenAI from langgraph.graph import StateGraph from langgraph.prebuilt import ToolNode app = App(app_name="router-agent") def build_agent(): llm = app.llm(ChatOpenAI(model="gpt-5.4")) a2a = app.a2a_tools() llm_with_tools = llm.bind_tools( app.get_tool_schemas() + a2a ) tool_node = ToolNode(app.get_tools() + a2a) graph = StateGraph(...) return graph.compile(checkpointer=app.checkpointer())
LM にバインドされると、モデルは 2 つのツールを名前で呼び出します。これらのツールは次の関数シグネチャを公開します。
discover_available_agents()は、呼び出しエージェントに表示されるエージェントのJSONリストを返します。各エントリには、agent_id、name、description、skills、capabilitiesが含まれます。呼び出しエージェントは、それ自体の結果からフィルタリングされます。invoke_a2a_agent(agent_id, message, custom_headers="")は、ターゲットエージェントを呼び出し、結果をJSONとして返します。custom_headersを指定する場合は、それらをJSON文字列(例:'{"x-tenant": "acme"}')として渡します。
A2A クライアントを直接呼び出す
決定的なルーティングを使用する場合、クライアントを公開する属性である runtime.a2a を介して AgentToAgentクライアントに直接アクセスできます。
次の例では、能力によってエージェントを検出し、最初の一致を呼び出します。
agents = app._runtime.a2a.discover_agents( skills=["policy-lookup"], limit=10, ) if agents: resp = app._runtime.a2a.invoke_agent( agent_id=agents[0].agent_id, message="Look up policy POL-123", skill="policy-lookup", timeout=120, ) if resp.status == "completed": print(resp.result)
runtime.a2aNone属性は、A2 A が利用できない場合に を返します。これがいつ発生するかについては、「 考慮事項 」を参照してください。次の例に示すように、クライアントメソッドを呼び出す前に、必ずこのケースを確認してください。
a2a = app._runtime.a2a if a2a is None: ...
注意
エージェントコード内の app._runtime.a2a を介して runtime.a2a にアクセスします。公開 app.a2a または app.runtime アクセス権は存在しません。ほとんどのユースケースでは、プライベート属性に依存しないため、代替として app.a2a_tools() が推奨されます。
A2クライアント SDK リファレンス
このセクションでは、エージェントコードからプログラムによってエージェントを検出して呼び出すメソッドを提供する A2AクライアントSDK について説明します。
クライアントSDK を使用するには、次の例に示すように、agent_engine_runner_shared.a2a から A2A タイプをインポートします。
from agent_engine_runner_shared.a2a import ( AgentToAgent, DiscoveredAgent, AgentSkill, AgentResponse, )
AgentToAgent クラス
AgentToAgent は、OU の /a2a/discover および /a2a/invoke エンドポイントと通信するHTTPクライアントです。エージェントコードでは、このクラスを直接構築するのではなく、runtime.a2a の事前認証済みインスタンスを使用します。
次の例は、 コンストラクターとそのパラメーターを示しています。
AgentToAgent(oe_url: str, auth_token: str = "")
以下の表では、AgentToAgent コンストラクター パラメーターを説明しています。
Argument | 説明 |
|---|---|
| OA HTTPベースURL(例: |
| A2 |
Discovery_ Agents() メソッド
discover_agents() メソッドは、呼び出し元が表示を許可されているエージェントを返します。 1 つのフィルター パラメーターに複数の値を渡すと、エージェントはそれらの値のいずれか 1 つを満たす場合は一致します。例、skills=["a", "b"] はいずれかの特権を紹介するエージェントを返します。複数のフィルターパラメーターを渡す場合、エージェントはそれらのすべてを満たす必要があります。 A2A が有効になっておらず、allowed_callers を通じて呼び出し元を除外しているエージェントは返されません。
次の例は、このメソッドとそのパラメーターを示しています。
discover_agents( project_id: str = "", skills: list[str] | None = None, capabilities: list[str] | None = None, input_modes: list[str] | None = None, limit: int = 50, ) -> list[DiscoveredAgent]
次の表では、discover_agents() メソッドのパラメータを説明しています。
Parameter | タイプ | 説明 |
|---|---|---|
| str | 検索するプロジェクト。空の string は呼び出し元のプロジェクトを使用します。 |
| list[str] | ルール名でフィルタリングします。リストされている特権のいずれかを持つエージェントを返します。 |
| list[str] | 機能タグでフィルタリングします。リストされている機能のいずれかを持つエージェントを返します。 |
| list[str] | 許容されるMIMEタイプでフィルタリングします。リストされているMIMEタイプのいずれかを受け入れるエージェントを返します。 |
| 整数 | 返される結果の最大数。デフォルトは |
invoice_agent() メソッド
invoke_agent() メソッドは、ターゲットエージェントを呼び出し、結果を待ちます。 OA は、トークンを検証し、アクセス制御をチェックし、子実行を作成し、エージェントが完了するまでポーリングします。
次の例は、このメソッドとそのパラメーターを示しています。
invoke_agent( agent_id: str, message: str, skill: str = "", timeout: float | None = None, custom_headers: dict[str, str] | None = None, ) -> AgentResponse
次の表では、invoke_agent() メソッドのパラメータを説明しています。
Parameter | タイプ | 説明 |
|---|---|---|
| str | ターゲット ワークスペースID。 |
| str | ターゲットエージェントに送信するプロンプトまたはメッセージ。 |
| str | 多くの特権を紹介するエージェントの、任意の特権のヒント。 |
| 浮動小数点数 |なし | タイムアウトするまでの待ち時間。 |
| dict[str, str] | None | ターゲット エージェントの実行コンテキストに転送されるキー値ヘッダー。キーでは予約された |
応答データ クラス
次の表は、すべて不変のデータクラスである応答タイプを示しています。
クラス | フィールド |
|---|---|
|
|
|
|
|
|
AgentResponse ステータスの処理
次の表は、AgentResponse.statusフィールドの各値について説明したものです。
ステータス | 意味 | 何をする |
|---|---|---|
| ターゲットエージェントが正常に終了しました。 |
|
| ターゲットエージェントがエラーを返しました。 |
|
| ターゲットエージェントは人間によるレビューのために一時停止されました。 | 一時停止をユーザーまたはフローに表示します。これを失敗として扱わないでください。 |
タイムアウトや OA からの 4x および 5x 応答などのネットワークおよびHTTPレベルのエラーでは、discover_agents() メソッドと invoke_agent() メソッドから httpx.HTTPError が発生します。 status 値が failed である AgentResponse は、呼び出しは OA に到達したが、ターゲットエージェント自体が失敗したことを示します。ネットワークエラーとエージェントの障害の両方を処理するには、呼び出しを try/except ブロックでラップし、status 値を確認します。
次の例では、3 つのステータス値がすべて処理されています。
resp = app._runtime.a2a.invoke_agent( agent_id="ws-billing-001", message="Process the payment", ) if resp.status == "completed": handle(resp.result) elif resp.status == "input-required": notify_user( "The billing agent needs human approval before continuing." ) else: log.error("A2A call failed: %s", resp.error)
カスタム ヘッダーの転送
A2A を使用して、テナントID 、トレース タグ、委任された OAuth トークンなど、リクエスト スコープのコンテキストを伝達するエージェント呼び出しに任意のキー値ヘッダーをアタッチできます。
呼び出されたエージェントにヘッダーを渡す
呼び出されるエージェントにヘッダーをアタッチするには、invoke_agent() の custom_headers パラメータを使用して dict を渡します。 invoke_a2a_agent LM ツールを使用する場合は、ヘッダーをJSON string として渡します。
次の例では、ダイレクトクライアントを使用してカスタム ヘッダーを渡します。
app._runtime.a2a.invoke_agent( agent_id="ws-billing-001", message="Charge the customer", custom_headers={ "x-tenant": "acme", "oauth-token": "<delegated-token>", }, )
次の例では、 LM ツールを使用してカスタム ヘッダーを渡します。
invoke_a2a_agent( agent_id="ws-billing-001", message="Charge the customer", custom_headers='{"x-tenant": "acme"}', )
ヘッダーキーでは、予約された a2a- 大文字と小文字を区別しない プレフィックスは使用できません。 UE は、いずれかのキーが a2a- で始まる場合、400 Bad Request 応答でリクエストを拒否します。 a2a- プレフィックスは、a2a-tokenや a2a-caller-workspace などのプラットフォーム ルーティングと ID ヘッダー用に予約されています。
呼び出し元からの読み取りヘッダー
呼び出しエージェントによって転送されたカスタム ヘッダーを読み取るには、agent_engine_runner_shared.contextクラスの get_current_custom_headers() メソッドを使用します。次の例では、このメソッドを呼び出します。
from agent_engine_runner_shared.context import get_current_custom_headers headers = get_current_custom_headers() tenant = headers.get("x-tenant")
get_current_custom_headers() は dict[str, str] を返します。メソッドは返される前にすべての a2a- プラットフォームのヘッダーを処理するため、エージェントコードでは A2A トークンやルーティングメタデータが表示されることはありません。呼び出し元がカスタム ヘッダーを送信しない場合、メソッドは空の辞書を返します。
アクセス制御の構成
agent.yamlファイルの a2a.allowed_callersフィールドは、次の動作を通じて を検出できるエージェントを制御します。
空のリスト(デフォルト):2 同じプロジェクト内の任意の A A 対応エージェントがエージェントを呼び出し、検出結果で確認できます。
空でないリスト: リストされているワークスペース ID のみがエージェントを呼び出すことができます。他のすべてのエージェントは
403応答を受け取り、検出結果にエージェントを表示できません。
プライマリは、ディスパッチする前に、呼び出し元のエージェントの ID を allowed_callers リストと照合します。エージェントではコードの変更は必要ありません。次の例では、呼び出しを単一の ルーターエージェントに制限しています。
a2a: enabled: true allowed_callers: - "ws-router-002"
UIで A2A 呼び出しを表示
すべての A2A 呼び出しはセッションのトレース パネルに自動的に表示されます。ツールは必要ありません。ターゲットエージェントのアクティビティは同じセッショントレース内にネストされて表示されるため、エージェント間の完全な呼び出しツリーを1つの場所で追跡できます。
各呼び出しは A2A: <target agent name> というラベルの付いたサブエージェントノードとしてレンダリングされ、表示名がない場合はターゲットのワークスペースIDにフォールバックします。ノードには、呼び出しのステータスと期間が表示されます。ステータスは running として始まり、成功すると done、失敗すると error に変わります。ノードを選択すると、名前、ステータス、期間、ディスパッチの説明、ストリーム出力、およびエラーが表示される詳細パネルが開きます。
ターゲット エージェント独自のツール呼び出し、LM ステップ、メモリ操作は サブエージェントノードの下にネストされ、エージェント間で完全な呼び出しツリーが再構築されます。
Considerations
runtime.a2 の場合、 は なし を返します
runtime.a2a では、次の条件が すべて 当てはまる場合にのみクライアントが返されます。
エージェントコードはエージェントサンドボックスで実行中。 A2A は、 ツール サンドボックスで実行されるコードからは使用できません。
UE URL が実行コンテキストに存在する。
受信ヘッダーに
a2a-tokenが存在する。 UE は、A2A が設定されている場合、すべてのディスパッチでこのトークンを自動的に挿入します。
いずれの条件も満たされない場合、runtime.a2a は None を返します。 app.a2a_tools() を使用する場合、例外が発生する代わりにツールは構造化エラーJSONを返します。
トークンの有効期間
A2A トークンは、デフォルトで 5 後に期限切れになります。一般的なリクエストと応答のフローでは、これが十分です。トークンの有効期間よりも長く実行されるエージェントは、A2A 呼び出しで 401 応答を受け取る場合があります。自動トークン更新はまだ実装されていません。長時間実行される呼び出しからの 401 応答を一時的な障害として扱います。
自己検出フィルター
discover_available_agents LM ツールは、呼び出しエージェントの独自のワークスペースの結果をフィルタリングして、モデルが自分自身を呼び出さないようにします。未加工の discover_agents()クライアントメソッドを使用する場合、OA は結果に独自のエージェントを含める可能性があります。必要に応じて、自分でフィルタリングします。
プロジェクト内スコープ
現在のリリースでは、 A2A の検出と呼び出しは、 同じプロジェクト内のエージェントに制限されています。プロジェクト間のルーティングはまだ実装されていません。
観察可能性
プラットフォームはすべての A2A 呼び出しを自動的にログに記録し、リンクします。ツールを追加する必要はありません。ターゲットは、parent_execution_id を介して呼び出し元にリンクされた子実行として実行されます。共有 root_session_id は、元のユーザー セッションの下に完全なクロスエージェント呼び出しツリーをグループ化します。
例: ルーターエージェント
次の例では、LVM を使用して検索し、専用エージェントに委任するルーターエージェントを示します。 agent.yamlファイルはA2A を有効にし、route 特権を宣言します。
name: router-agent entrypoint: router_agent.main:app a2a: enabled: true skills: - name: route description: Route a user request to the best specialist agent
次のエージェントコードは、A2A ツールを独自のツールとともにバインドし、LM がルーティングを処理できるようにします。
from agent_engine_sdk_langgraph import App from langchain_openai import ChatOpenAI from langgraph.graph import StateGraph, MessagesState from langgraph.prebuilt import ToolNode app = App(app_name="router-agent") def build_agent(): llm = app.llm(ChatOpenAI(model="gpt-5.4")) a2a = app.a2a_tools() llm_with_tools = llm.bind_tools( app.get_tool_schemas() + a2a ) def call_model(state: MessagesState): return { "messages": [llm_with_tools.invoke(state["messages"])] } graph = StateGraph(MessagesState) graph.add_node("model", call_model) graph.add_node("tools", ToolNode(app.get_tools() + a2a)) graph.set_entry_point("model") graph.add_conditional_edges( "model", lambda s: ( "tools" if s["messages"][-1].tool_calls else "__end__" ), ) graph.add_edge("tools", "model") return graph.compile(checkpointer=app.checkpointer())
実行時に、LM は一致する特権特権エージェントを検出し、invoke_a2a_agent を通じてそれを呼び出し、アクセス制御を強制し、呼び出しの両方をログに記録しながら、呼び出しを中断します。
LM に依存するのではなく、明確にルーティングするには、グラフノード内でクライアントを直接呼び出します。
def delegate(state): a2a = app._runtime.a2a if a2a is None: return {"messages": [("ai", "A2A is unavailable.")]} resp = a2a.invoke_agent( agent_id="ws-insurance-001", message=state["messages"][-1].content, skill="policy-lookup", custom_headers={"x-request-source": "router-agent"}, ) text = ( resp.result if resp.status == "completed" else f"({resp.status}) {resp.error}" ) return {"messages": [("ai", text)]}
次のステップ
エージェント間通信を有効にしたら、次のガイドを確認して、関連するタスクの詳細を学習できます。
エージェントのパフォーマンスと配置の健全性を監視するには、「 エージェントを監視する 」を参照してください。
配置されたエージェントを認証して呼び出すには、「 エージェントの呼び出し 」を参照してください。
エージェントをテストしてコードを反復処理するには、「 エージェントをテストする 」を参照してください。