Hermes Agent で A2A を動かす:Docker Gateway リファレンススタック
本番環境でA2Aを実行するということは、互いに通信するように設計されていなかった2つのプロトコルをブリッジすること — そしてトークンを落とさずに認証、テナント分離、ストリーミングを処理するゲートウェイの背後でそれを行うことを意味します。このリファレンススタックはA2Aデプロイメントをブロックする3つの問題を解決します:プロトコル変換(JSON-RPC 2.0からOpenAI互換のchat completions)、ストリーミング調整(A2AアーティファクトSSEからHermes実行イベントSSE)、マルチテナントセキュリティ(すべてのクエリでのPostgreSQL Row-Level Security)。異なるフレームワーク上のエージェントが互いに作業を委任する必要がある場合、ここでのパターンがデプロイメントパスです。
主要なポイント
- 3 層・1 つの Docker Compose スタック — SilvaEngine Gateway がトランスポートと認証を担い、A2A Daemon Engine がプロトコルロジックを処理し、HermesAgentHandler が Hermes Agent の OpenAI 互換 API への橋渡しを行います。docker-a2a-hermes-agent-gateway リポジトリがこの 3 つをまとめてパッケージ化します。
- 1 つのポートで 5 つのプロトコルサーフェス — JSON-RPC 2.0、GraphQL、SSE ストリーム、SSE プッシュ、Agent Card ディスカバリのすべてが、ポート 8765 上の単一ゲートウェイの背後で JWT または AWS Cognito 認証により提供されます。
- PostgreSQL の行レベルセキュリティがテナント分離を強制 —
partition_key = "{endpoint_id}#{Part-Id}"複合キーは、アプリケーションコードだけでなく、データベースレベルで RLS ポリシーにより 4 つの A2A テーブルすべてに適用されます。 - A2A SDK v2 の単一メッセージ制約がストリーミングアーキテクチャを形作る — ブリッジはトークンチャンクを SSE にリアルタイムで送出し、ストリーム完了後に 1 つの累積 Message を SDK EventQueue へ送出することで、
InvalidAgentResponseErrorを回避します。 - 5 つのスクリプトで 15 項目の E2E テストチェック — 非ストリーミングのスモークテストから HTTP フォールバック検証を含む完全な SSE ストリーミングパイプラインまで、すべて
pip install requestsで実行可能です。
Agent2Agent Protocol(A2A)は、AI エージェントが JSON-RPC 2.0 経由で互いに検出、委譲、タスクのストリーミングを行う方法を定義します。Hermes Agent(Nous Research 製)は /v1/chat/completions で OpenAI 互換 API Server を、/v1/runs と /v1/runs/{id}/events で runs ベースの SSE ストリーミングインターフェースを公開します。両者は同じ言語を話しません。A2A は構造化された parts を伴う message/send を送信し、Hermes はチャット完了ペイロードを受信します。A2A は SSE 経由でタスクアーティファクトをストリーミングし、Hermes は run イベント経由でトークンデルタをストリーミングします。
docker-a2a-hermes-agent-gateway リポジトリは、そのギャップを単一のコンテナイメージと docker compose スタックで橋渡しします。a2a_daemon_engine モジュールのみを登録した SilvaEngine Gateway を稼働させ、A2A プロトコルの全サーフェスを公開しつつ、HTTP + SSE 経由で Hermes Agent API Server インスタンスへ A2A タスクを橋渡しします。状態はテナント分離のための Row-Level Security を備えるバンドル済み PostgreSQL バックエンドに永続化されます。
本記事は、3 層アーキテクチャ、A2A クライアントから Hermes へ、そして戻るまでのリクエストライフサイクル、設定とデプロイのパターン、および本番環境で Hermes Agent 上に A2A を稼働させるための運用上の懸念事項を整理します。これはリファレンスデプロイの解説です — 一般的なパターン(任意のエージェントフレームワークへのゲートウェイ媒介 A2A ブリッジ)が主題であり、Docker スタックは実装例です。
3 層アーキテクチャ
このスタックは関心を 3 つの層に分離し、それぞれが独立したコンポーネントが所有します。
ゲートウェイは唯一の常時稼働サービスです。Hermes と PostgreSQL はどちらもプロファイルで制御される兄弟です — 自己完結型スタックとしてバンドルするか、プロファイルをオフにして HERMES_API_URL と PG_HOST を外部インスタンスに向けることができます。これは本番環境で重要です。ゲートウェイを自社 VPC で稼働させ、マネージド Postgres(RDS、Cloud SQL)と、別の場所の GPU ノードで稼働する Hermes インスタンスに向けることができます。
層 1:SilvaEngine Gateway — トランスポートと認証
SilvaEngine Gateway は、認証済みのインプロセスアクセスをインストール済みモジュールに提供する FastAPI ゲートウェイです。設定可能な YAML ルートマニフェストを通じてモジュールの GraphQL と REST ルートを公開します。新しいモジュールの追加はマニフェストの変更のみで済み、ゲートウェイの Python コードは一切不要です。本スタックでは A2A Daemon Engine のみが登録されています。
ゲートウェイは以下を所有します。
- 認証 —
GATEWAY_AUTH_PROVIDERで選択されるローカル JWT(HS256)または AWS Cognito(RS256 + JWKS) - ルーティング — YAML マニフェストが URL パスをモジュールディスパッチ関数にマッピング
- SSE クライアントライフサイクル —
sse_managerがモジュールごとに解決され、長寿命のクライアント接続を管理 - レート制限 — IP ごとのインメモリレート制限(
GATEWAY_RATE_WINDOW秒あたりGATEWAY_RATE_LIMITリクエスト) - スレッドプールディスパッチ — 同期モジュールディスパッチ関数は設定可能なスレッドプール(
GATEWAY_DISPATCH_WORKERS、Docker イメージではデフォルト 32)で実行
ゲートウェイは URL パスセグメントと Part-Id リクエストヘッダーから partition_key = "{endpoint_id}#{Part-Id}" を構築します。テナントスコープのすべてのリクエストにはこのヘッダーが必須です。/{ep}/.well-known/agent-card.json の Agent Card エンドポイントは A2A 仕様に従い公開(認証不要)ですが、カードはパーティションごとに解決されるため Part-Id は依然として必須です。
層 2:A2A Daemon Engine — プロトコルロジック
a2a_daemon_engine はスタンドアロンサービスではありません。main.py の deploy() を経由して登録済みゲートウェイモジュールとして読み込まれ、ゲートウェイ向けの 3 つのエントリポイントを宣言します。
| エントリポイント | ゲートウェイルート | メソッド | 目的 |
|---|---|---|---|
a2a_core_graphql |
POST /{ep}/a2a_core_graphql |
POST | agents、tasks、messages、settings の GraphQL CRUD |
a2a |
POST /{ep}/a2a |
POST | A2A JSON-RPC プロトコル(message/send、tasks/get、tasks/cancel、tasks/list) |
sse_message |
POST /{ep}/a2a_sse |
POST | A2A JSON-RPC メッセージ + SSE クライアントへのプッシュ |
ゲートウェイはさらに SSE ストリーム用に GET /{ep}/a2a_sse を公開します。デーモンは本番環境では自身のポートでリッスンしたり独自の HTTP サーバーを稼働したりしません。すべてのトランスポート、認証、SSE クライアントライフサイクルはゲートウェイが所有します。
デーモンは以下を提供します。
- A2A SDK v1.0 — HTTP 経由の JSON-RPC、公式 A2A SDK サーバーパターンに基づいて構築
- 公開 Agent Card —
/.well-known/agent-card.jsonで ETag と Last-Modified をサポート - タスク状態機械 —
submitted→working→input-required|completed|failed|canceled - デュアルバックエンド永続化 — DynamoDB(PynamoDB)または PostgreSQL(SQLAlchemy + Alembic)。Docker イメージは PostgreSQL を強制します。
- マルチテナント分離 — 複合パーティションキー(
{endpoint_id}#{part_id})と PostgreSQL Row-Level Security - プラグ可能な LLM ハンドラ — エージェントレジストリでのエージェントごとの
module_name/class_name選択
層 3:HermesAgentHandler — ブリッジ
Hermes ブリッジハンドラ(a2a_daemon_engine/handlers/a2a_hermes_handler.py)は唯一のフレームワーク固有コードです。ask_model() インターフェースを実装します。A2A メッセージ parts とコンテキストを受け取り、Hermes Agent API Server を呼び出し、レスポンスを A2A メッセージ parts に変換し、ストリーミングの場合はトークンデルタを SSE チャネルに転送します。
ハンドラは 2 つの実行モードをサポートします。
非ストリーミング は Hermes API Server の POST /v1/chat/completions — OpenAI 互換エンドポイントにマッピングされます。リクエストは変換された A2A メッセージ parts をチャット完了ペイロードとして運びます。Hermes はリクエストを処理し、単一のレスポンスを返します。ハンドラはレスポンスを ROLE_AGENT を持つ A2A Message に変換し、SDK EventQueue へ送出します。クライアントはエージェントの完全なテキストを含む単一の JSON-RPC レスポンスを受け取ります。
ストリーミング は run を作成するために POST /v1/runs にマッピングされ、その後 GET /v1/runs/{id}/events への SSE 接続を開きます。Hermes はイベントが発生するたびにストリーミングします。トークンデルタ(message.delta)、推論メタデータ(reasoning.available)、ツール呼び出し/結果通知、承認リクエスト(approval.required)、ライフサイクルイベント(run.created、run.completed、run.failed)。ハンドラはバックグラウンドスレッドでドレインループを実行します。各 message.delta イベントは接続済みクライアントへのリアルタイム配信のためゲートウェイの SSE マネージャにプッシュされます。run.completed が到着すると、累積されたテキストは単一の A2A Message として SDK EventQueue へ送出されます。
リクエストライフサイクル
stream=true を指定した単一の message/send は 8 つのステップを経由します。
1. クライアント POST /{ep}/a2a {jsonrpc, method:"message/send", params}
ヘッダー: Authorization: Bearer *** Part-Id:
2. ゲートウェイ 認証 (ローカル JWT / Cognito) → routes.yaml からルートマッチ
→ partition_key = "{ep}#{Part-Id}"
3. a2a_daemon dispatch_a2a → A2ADaemonExecutor
→ resolve_agent(): エージェントメタデータ (DB) > 設定 dict > Config (env)
4. ハンドラ HermesAgentHandler (A2A_AI_AGENT_MODULE / _CLASS)
5. Hermes POST {HERMES_API_URL}/v1/runs (Bearer HERMES_API_KEY)
GET {HERMES_API_URL}/v1/runs/{id}/events (SSE)
6. ブロードキャスト トークンチャンク → GET /{ep}/a2a_sse のサブスクライバへ
7. 永続化 task + messages が PostgreSQL に書き込み (a2a_* テーブル、RLS スコープ)
8. レスポンス 累積された返信も HTTP JSON-RPC 結果として返却 ステップ 8 が重要です。ストリーミング時でも HTTP レスポンスは完全な返信を運びます。SSE フレームを見逃したクライアントは HTTP レスポンスにフォールバックできます。E2E テストスイート(test_hermes_sse_live.py)はそのフォールバックをステップ 06 で明示的に検証します。
エージェント解決の優先順位
設定の解決は優先順位チェーンに従います。エージェントメタデータ(DB)→ 設定 dict → Config デフォルト(env vars)。エージェントごとのオーバーライドがグローバルデフォルトより優先されます。2 つのエージェントを異なるフレームワークに向けることができます — 片方を推論重視タスク用に Hermes へ、もう片方をワークフロー編成タスク用に別のハンドラへ — そして A2A プロトコルサーフェスは呼び出し元エージェントにとって同一に見えます。
Hermes バックエンドのエージェントの場合、a2a_agents テーブルに格納されるメタデータは次のようになります。
{
"module_name": "a2a_daemon_engine.handlers.a2a_hermes_handler",
"class_name": "HermesAgentHandler",
"hermes_api_url": "http://127.0.0.1:8642",
"hermes_api_key": "hermes-local-key",
"hermes_model": "hermes-agent",
"hermes_timeout": 300.0
}env var デフォルト(HERMES_API_URL、HERMES_API_KEY、HERMES_MODEL)により、DB エージェントレコードがなくてもブリッジは Hermes に到達できます — a2a_ai_agent_utility.py の resolve_agent() 関数は、エージェントレコードが存在しない場合 env var にフォールバックします。これはスタックを起動し、エージェントを一切登録せずに message/send を送信すると、env デフォルトを使って Hermes にルーティングされることを意味します。
A2A 状態マッピング
ブリッジは Hermes SSE イベントを A2A タスク状態にマッピングします。このテーブルがブリッジの中核です — すべてのフレームワーク統合は同等のテーブルを生成します。
| Hermes SSE イベント | A2A タスク状態 | ブリッジのアクション |
|---|---|---|
run.created(run_id 返却) |
WORKING |
キャンセルサポート用に run_id を登録 |
message.delta |
WORKING |
トークンを累積、チャンクごとに SSE へ送出 |
reasoning.available |
WORKING |
推論メタデータ — トークン送出なし |
tool.call / tool.result |
WORKING |
ツール実行メタデータのみ |
approval.required |
INPUT_REQUIRED |
承認チャンクを送出、pending_approval を格納 |
run.completed |
COMPLETED |
ストリームイベントを設定、最終テキストを累積 |
run.failed |
FAILED |
エラーチャンクを送出、FAILED 状態を設定 |
POST /v1/runs/{id}/stop |
CANCELED |
tasks/cancel による外部キャンセル |
POST /v1/runs/{id}/approval |
(run を継続) | operation="approval_response" で解決 |
a2a_daemon_engine リポジトリの HERMES_INTEGRATION.md ドキュメントに、Hermes イベントフォーマット、設定キー、エンドツーエンドのフロー詳細が記録されています。
エージェント境界をまたぐ human-in-the-loop 承認
Hermes は human-in-the-loop の承認ゲートをサポートします — エージェントが機密性の高いアクションの実行許可を必要とする場合、一時停止して承認リクエストを送出します。ブリッジはこれを A2A の INPUT_REQUIRED 状態に変換し、入力が必要であることを呼び出し元エージェント(または人間のオペレータ)に通知します。レスポンスは POST /v1/runs/{id}/approval 経由で戻り、run が継続します。
ここがブリッジパターンの価値が示される部分です。A2A は INPUT_REQUIRED をファーストクラスのタスク状態として定義します。Hermes には独自の承認メカニズムがあります。ブリッジが一方を他方にマッピングし、呼び出し元エージェント — それ自体が完全に異なるフレームワークで稼働する A2A クライアントかもしれない — は Hermes 固有の詳細ではなく標準的なプロトコル状態遷移を見ます。エージェントの委譲チェーンに人間の承認を必要とするステップ(購入承認、データアクセス判断、見積もり承認)を含めることができ、A2A プロトコルがそのゲートをフレームワーク境界を越えて透過的に運びます。
A2A SDK v2 の制約とデュアルパスの解決策
A2A SDK v2(a2a-sdk==1.0.2)は on_message_send パスに 2 つの制約を課し、これがブリッジの実装を形作りました。
- 単一 Message のみ。 SDK EventQueue に複数の
Messageオブジェクトを送出するとInvalidAgentResponseError: Multiple Message objects received.が発生します。 - TaskStatusUpdateEvent 不可。 ステータスイベントは
InvalidAgentResponseError: Received TaskStatusUpdateEvent in message mode.を発生させます。
素朴なブリッジはトークンデルタごとに 1 つの Message を送出するでしょう — 自然なストリーミングパターンです。SDK はこれを拒否します。また message/send パスでのステータスイベント(WORKING、COMPLETED)も拒否します。
解決策はデュアルパスの出力チャネルです。
- SSE(ゲートウェイ管理): トークンチャンクはリアルタイムで SSE にプッシュされます。接続済みクライアントはストリーミング出力をそのまま確認します。ステータスイベント(WORKING、COMPLETED、FAILED)も SSE のみに送られます。
- SDK EventQueue: ストリーム完了後、完全なレスポンステキストを含む単一の累積
Messageが SDK EventQueue へ送出されます。これが JSON-RPCmessage/sendレスポンスとして返される内容です。
クライアントは SSE 経由でリアルタイムストリーミングを、SDK 経由でクリーンな単一メッセージ JSON-RPC レスポンスを受け取ります。両チャネルとも機能し、いずれも SDK 制約に違反しません。
1 つのポート上のプロトコルサーフェス
ゲートウェイは単一ポート(デフォルト 8765)で 5 つのプロトコルサーフェスを公開します。
| プロトコル | ルート | 認証 | 目的 |
|---|---|---|---|
| GraphQL | POST /{ep}/a2a_core_graphql |
あり | A2A コアクエリ/ミューテーション(agents、tasks、messages、settings) |
| JSON-RPC 2.0 | POST /{ep}/a2a |
あり | A2A プロトコル:message/send、tasks/get、tasks/cancel、tasks/list |
| SSE(ストリーム) | GET /{ep}/a2a_sse |
あり | パーティションごとの長寿命 A2A タスクイベントストリーム |
| SSE(プッシュ) | POST /{ep}/a2a_sse |
あり | JSON-RPC メッセージ + 接続済み SSE クライアントへのプッシュ |
| Agent Card | GET /{ep}/.well-known/agent-card.json |
公開 | A2A ディスカバリドキュメント(Part-Id ヘッダーは依然必須) |
テストハーネスが使用する JSON-RPC message/send パラメータの構造は次のとおりです。
{
"message": {
"role": "ROLE_USER",
"parts": [{ "text": "Say hello from A2A" }]
},
"metadata": {
"operation": "task_execution",
"agent_uuid": "a2a-hermes-agent",
"stream": true,
"task_data": { "task_id": "my-task-001", "task_type": "hermes_test" },
"system_prompt": "You are a concise assistant.",
"conversation_history": []
}
}metadata.operation フィールドが実行パスを選択します。ストリーミングサポート付きのエージェント実行には task_execution、非ストリーミングチャットには message_response。agent_uuid はレジストリ内の特定のエージェントを指定します。stream フラグが SSE ブロードキャストを有効にします。task_data.task_id は tasks/get と tasks/cancel で使用される呼び出し元提供の id です。
SSE はタスクごとではなくパーティションごとです。{ep}#{Part-Id} 内のすべてのタスクは、そのパーティションのすべてのサブスクライバにブロードキャストされます。操作順序が重要です。メッセージを送信する前に SSE リスナーを接続してください。そうしないと初期のトークンチャンクが見逃されます。
永続化とマルチテナンシー
Docker イメージは db_backend=postgresql を強制します — DynamoDB はサポートされません。デーモンはリテラルでプレフィックスなしのテーブル名を使用します。
| テーブル | 保持するもの |
|---|---|
a2a_agents |
エージェントレコード + エージェントごとのハンドラ/モデルメタデータ |
a2a_tasks |
タスクライフサイクル + ステータス |
a2a_messages |
タスクごとのメッセージターン |
a2a_settings |
パーティションごとの設定 dict |
名前はプレフィックスなしのため、同じ名前を使用する他のモジュールと PG_DB を共有しないでください。
テナント分離には PostgreSQL Row-Level Security を使用します。セッション変数 app.tenant_id がリクエストの partition_key("{endpoint_id}#{Part-Id}")に設定され、RLS ポリシーがすべてのクエリをそれにスコープします。テーブルとポリシーは initialize_tables=1 の場合にゲートウェイ起動時に自動作成されます。これはアプリケーションコードで忘れられた partition_key フィルタがテナント間の行を漏洩できないことを意味します — データベースが境界を強制します。
RLS 実装は a2a_daemon_engine/utils/rls.py(set_rls_context と create_rls_policies)とマイグレーション 0005_enable_rls_policies にあります。set_rls_context 関数は接続上でリクエストごとに SET app.tenant_id を実行し、create_rls_policies は 4 つの A2A テーブルすべてに tenant_isolation ポリシーで RLS を有効化・強制します。RLS は DynamoDB モードでは不活性です。
Docker Compose によるデプロイ
スタックは 1 つの常時稼働サービスと 2 つのオプションのプロファイル制御兄弟で構成されます。
| サービス | コンテナ名 | 常時稼働? | プロファイル | 目的 |
|---|---|---|---|---|
a2a-gateway |
a2a-hermes-gateway |
はい | — | SilvaEngine Gateway(A2A 専用ルート)+ Hermes ブリッジ |
postgres |
a2a-postgres |
オプション | postgres |
バンドル済み PostgreSQL 永続化バックエンド |
hermes |
container-hermes |
オプション | hermes |
バンドル済み Hermes Agent(OpenAI 互換 API + ダッシュボード) |
COMPOSE_PROFILES が両兄弟の単一スイッチです。
| 値 | 起動するサービス |
|---|---|
| 空 | ゲートウェイのみ(外部 Postgres + 外部 Hermes) |
postgres |
ゲートウェイ + バンドル済み Postgres |
hermes |
ゲートウェイ + バンドル済み Hermes(外部 Postgres) |
postgres,hermes |
ゲートウェイ + バンドル済み Postgres と Hermes(デフォルト) |
兄弟をバンドルする場合、ホスト参照をサービス名に向けたままにしてください。PG_HOST=postgres、HERMES_API_URL=http://hermes:<API_SERVER_PORT>。兄弟を外部にする場合、それらを自社インスタンスに向けます(例:PG_HOST=host.docker.internal、HERMES_API_URL=http://host.docker.internal:8642)。
クイックスタート
cp .env.example .env
# 記入: JWT_SECRET_KEY, ADMIN_PASSWORD, API_SERVER_KEY,
# HERMES_API_KEY (= API_SERVER_KEY), HERMES_MODEL_PROVIDER + プロバイダキー, HERMES_MODEL
mkdir -p www/hermes www/projects
DOCKER_BUILDKIT=1 docker compose build
docker compose up -d # COMPOSE_PROFILES=postgres,hermes がデフォルト
docker compose ps # (healthy) を待機
curl -f http://localhost:8765/health
pip install requests
python test_hermes_hello.py # エンドツーエンドのスモークテストsilvaengine_gateway と a2a_daemon_engine はどちらも git からイメージに pip インストールされます(ホストソースマウントなし)。イメージは汎用で完全に env 駆動です — シークレットは一切 baked-in されません。モジュールは ideabosque 配下の公開 GitHub リポジトリから git+https 経由でクローンされます — 認証情報や SSH deploy キーは不要です。
.env のインラインコメントの罠
Docker Compose の env_file パーサーはインラインコメントを除去しません。次のような行は
HERMES_API_KEY=hermes-local-key # token for HermesHERMES_API_KEY をリテラル文字列 hermes-local-key # token for Hermes(コメント込み)に設定し、認証を黙って壊します。ルールは、どの KEY=value 行でも値の後に何も置かないことです。メモは変数の上の独立立した # コメント行に記述してください。
検証:5 つのスクリプットで 15 項目の E2E チェック
スタックにはスタンドアロンの Python テストハーネスが同梱されています(唯一の依存関係:requests)。これらは ./.env を読み込み、ゲートウェイ JWT を解決または発行し、稼働中のスタックと通信します。
| スクリプト | 種類 | 実行内容 |
|---|---|---|
test_hermes_hello.py |
スモーク | 非ストリーミング message/send、返信を出力 |
test_hermes_hello_sse.py |
スモーク | 1 プロンプトを SSE 経由でストリーミング |
test_hermes_gateway_live.py |
E2E スイート | 9 項目:Hermes ヘルス、ゲートウェイヘルス、エージェントカード、GraphQL ping、message/send、tasks/get、tasks/list、tasks/cancel、失敗パス |
test_hermes_sse_live.py |
E2E スイート | 6 項目:ヘルス x2、SSE 接続、ライブトークンチャンク、COMPLETED ステータス、HTTP フォールバック |
test_hermes_chatbot.py |
インタラクティブ | ライブ SSE ストリーミング付きの A2A サーフェスに対する REPL |
非インタラクティブなスクリプトはすべてステップごとに PASS/FAIL を出力し、失敗時に非ゼロで終了するため、CI ゲートとして機能します。ユニットテストスイート(test_hermes_handler.py)は httpx.MockTransport 経由のモック HTTP で 24 のテストを実行します — サービスは不要です。
運用パターン
リビルド不要のルート変更
routes.yaml はコンテナにリードオンリーでバインドマウントされています。ホストファイルを編集し、ゲートウェイプロセスを再起動するだけです — リビルドは不要です。
make restart上流変更後
silvaengine_gateway と a2a_daemon_engine はビルド時に git から pip インストールされるため、上流の変更には --no-cache でのリビルドが必要です。これにより git レイヤーが最新の @main を再クローンします。
DOCKER_BUILDKIT=1 docker compose build --no-cache
docker compose up -d --force-recreateバージョンピン留めはありません — @main は移動するターゲットです。再現性が必要な場合は requirements-modules.txt でタグまたはコミットをピン留めしてください。
1 ワーカーを超えるスケーリング
インメモリのタスク状態、レート制限カウンタ、SSE クライアントレジストリはプロセスごとです。GATEWAY_WORKERS > 1 の場合、共有バックエンドに切り替え(GATEWAY_TASK_BACKEND=dynamodb、GATEWAY_RATE_LIMIT_BACKEND=dynamodb、region_name と aws_* 認証情報を追加)、SSE にスティッキーセッションを使用してください。デフォルト設定は 1 つの Uvicorn プロセスを起動します。
変更すべきセキュリティのデフォルト
JWT_SECRET_KEY=change-me-in-production—openssl rand -hex 32で置き換えてくださいADMIN_PASSWORD=change-me— 本物のパスワードに置き換えてくださいPOSTGRES_PASSWORD=silvaengine— 本物のパスワードに置き換えてくださいGATEWAY_CORS_ORIGINS=*は認証情報なしで任意のオリジンを許可します。Cookie/認証情報が必要な場合は明示的なリストを設定してください。- バンドル済み Hermes はホストの Docker ソケット(
/var/run/docker.sock)をマウントします。これはそのコンテナ内のあらゆるものにとってホスト上の実質的な root です。hermesプロファイルは制御下のホストでのみ実行し、エージェントがコンテナを起動する必要がない場合はマウントを削除してください。 - Hermes ダッシュボードはデフォルトでポート 9119 にて空の basic-auth 認証情報で有効化されます。ホストを公開する前に
HERMES_DASHBOARD_BASIC_AUTH_*を設定するか、ポートを localhost にバインドしてください。 - RLS がテナント境界です。任意の
Part-Idを設定できる呼び出し元は、そのパーティションのデータを読み取れます — このゲートウェイの前に配置するあらゆるフロントエンドでPart-Idを認証関連の入力として扱ってください。
これがもたらすもの
3 層スタックは、ゼロから組み立てるのが困難な 3 つの能力をもたらします。
1. Hermes を書き直すことない A2A プロトコル準拠。 任意の A2A クライアントは Agent Card 経由で Hermes バックエンドのエージェントを検出し、message/send でタスクを送信し、SSE 経由でレスポンスをストリーミングし、標準的な A2A 状態でタスクライフサイクルを追跡できます。クライアントはリモートエージェントが Hermes を稼働していることを知りません — JSON-RPC インターフェースを持つ A2A エンドポイントとして見えます。
2. 1 つのゲートウェイからのマルチテナントエージェント提供。 Part-Id ヘッダーと PostgreSQL RLS の組み合わせにより、1 つのゲートウェイインスタンスがハードなデータベースレベルの分離で複数テナントにサービスを提供します。各テナントは独自のエージェントレジストリ、タスク履歴、メッセージストアを持ちます — すべて同じ 4 つのテーブル内に、partition_key でスコープされます。
3. エージェント境界をまたぐ human-in-the-loop 承認。 Hermes の承認ゲートは A2A の INPUT_REQUIRED 状態にマッピングされます。エージェントの委譲チェーンに人間の承認を必要とするステップを含めることができ、A2A プロトコルがその状態遷移をチェーン内の各エージェントが稼働するフレームワークに関わらず、起点のエージェントまたはオペレータに運び戻します。
リファレンス実装はさらに、サーバーレス A2A 向けの AWS Lambda ディスパッチ、双方向ストリーミング付きの実験的 gRPC トランスポート、デュアルバックエンド永続化(DynamoDB または PostgreSQL)をサポートします。a2a_daemon_engine リポジトリ とその Hermes 統合ガイド に完全な実装、設定リファレンス、状態マッピングの詳細が含まれます。SilvaEngine Gateway リポジトリ がルートマニフェストシステム、認証プロバイダ、モジュールの自動初期化を文書化しています。
関連読物
- MCP + A2A:すべての本番エージェント AI システムの背後にある 2 つのプロトコル — 2 層プロトコルスタックにおける MCP(エージェントからツールへ)と A2A(エージェントからエージェントへ)の補完的な役割
- 既存エージェントフレームワークとの A2A 統合:Hermes Agent デモンストレーション — 一般的なブリッジパターンと、OpenClaw を含む Hermes 以外のフレームワークへの適用方法
- MCP モジュールコード標準 — 本番対応エージェントモジュールの構造パターン、A2A ハンドラコードにも適用可能
中堅ディストリビュータには、カタログエージェントと話す見積もりエージェント、在庫エージェントと話すカタログエージェントが必要です — それぞれ異なるフレームワークに支えられ、それぞれ異なるチームが所有します。A2A はそれらのエージェントに共有プロトコルを与えます。ブリッジレイヤーにより Hermes Agent は内部を書き直すことなく参加できます。docker-a2a-hermes-agent-gateway がそのブリッジを、PostgreSQL 永続化、RLS マルチテナンシー、15 項目の E2E テストチェックとともに単一のコンテナイメージにパッケージ化します。
スコープ済みビルドを依頼
1 週間のディスカバリ。システムインベントリ、ワークフローマップ、固定スコープを入手 — 当社と一緒に構築するかどうかにかかわらず。
あなたのシステムのためにこれを構築したいですか?
ここの各ドキュメントは実際の本番作業から来ています。ターゲットシステムとワークフローがあれば、1週間でスコープを定義できます。
スコープ付き構築を依頼1週間のディスカバリ。システムインベントリ、ワークフローマップ、固定スコープを提供します — 私たちと構築するかどうかにかかわらず。