🤖HermesBlog
Hermes メッセージングプラットフォーム · パート 388/14/2026

A2A長タスクの謎:2分超の作業がなぜ失敗し続けるのか

Hermesメッセージプラットフォーム導入第38回:A2A長時間タスクのタイムアウト問題における三重の原因とその修正。

2台のコンピュータ上のHermesが互いに「電話」してタスクを依頼。ところが、タスクが2分を超えると必ず失敗する——設定をどう弄ってもダメ。これはオカルトではなく、3つの小さな落とし穴が重なっているだけなのだ。

A2A -longtask

謎解き:2分の呪い

想像してみてほしい。同僚Aに書類の処理を頼んで、「終わったら電話で結果を教えてね」と伝えたとしよう。ところが、毎回通話が2分を超えると、こちらの電話が「ガチャッ」と切れて、「通話失敗」と表示される。電話機を替えても、回線を替えても、オフィスごと引っ越しても、問題は解決しない。

これがHermesユーザーが遭遇した出来事だ。2台のマシンがそれぞれHermesを実行し、A2Aプラグイン(エージェント間オープン通信プロトコル)で接続されている。AマシンがBマシンにタスクを依頼すると、タスクが約2分を超えた瞬間、必ず失敗する。コミュニティではこれを「long replyによる進捗トラッキングの破壊」と呼んでいる。さらに腹立たしいのは、Bマシン側では作業が実際に完了しているのに、Aマシンには結果が永遠に届かないことだ。

原因その1:電話をかける側がせっかちすぎる

最初の落とし穴は、純粋に「せっかち」問題だ。

Hermesクライアントにはデフォルトのタイムアウト設定——120秒——がある。どういう意味か? 電話をかける側が自分にアラームをセットしているようなものだ。「120秒以内に相手が応答しなければ、こちらから切る」と。ところがサーバー側はどうか? エージェントの作業のために確保している応答ウィンドウは300秒、つまり5分だ。

わかるだろう。電話をかける側は2分で切ってしまうのに、受ける側は「相手は5分の忍耐がある」と思っている。結果として、タスクがまだ実行中なのに、電話が先に切れる。しかもこの120秒はコードにハードコードされていて、一般ユーザーが変更したくても変更場所が見つからない。

原因その2:旧回線に「タイムアウト」スイッチがない

2つ目の落とし穴は、歴史的遺産の問題だ。

HermesはA2Aを呼び出す2つの方法を提供している。1つは正規の「交換台経由」(設定済みのピア経由で呼び出す)、もう1つは「直通の旧回線」(生のURLを直接使って呼び出す)だ。旧回線は初期バージョンの名残で、内部にも120秒のタイムアウトが書き込まれており、設定ファイルを読み込まない。

つまり、タイムアウト時間の変更方法を覚えたとしても、旧回線は言うことを聞かないのだ。古い電話機に新しい電池を入れても、音量調節のつまみが付いていないのと同じ話だ。

原因その3:時間になると成果物を捨ててしまう

3つ目の落とし穴が一番タチが悪い:サーバー側が時間になると「撤収」する。

仮にクライアントのタイムアウトをなんとか大きくして、最初の2つの落とし穴を乗り越えたとしよう。すると今度はサーバー側が問題を起こす:300秒の応答ウィンドウが切れると、タスクを「失敗」とマークする。エージェントがまだ必死に作業している最中でもだ。さらに悪いことに、この「失敗」ステータスは粘着性がある——まるで接着剤のように剥がれない。エージェントが本当に作業を終えて結果を持って戻ってきたとき、待っている人は誰もいない。結果はそのまま破棄される。

これは、配達員が定時で上がってしまい、荷物が届いたかどうかに関係なく、システムが先に「配達失敗」と表示するようなものだ。翌日荷物を受け取っても、物流情報は永遠に「失敗」の欄に留まり、修正できない。

解決ステップ1:アラームを遅くする

3つの落とし穴がわかれば、修正は簡単だ。

1つ目の修正は単純明快:クライアントのデフォルトタイムアウトを120秒から330秒に変更する。330秒 > サーバーの300秒。これで電話をかける側が受ける側より忍耐強くなり、タスクはサーバーの応答ウィンドウを生き延びられる。同時に、a2a_callにはper-callタイムアウト上書きパラメータが追加された——個別のタスクごとにタイムアウトを設定でき、全体を変更する必要はない。旧回線もようやく「近代化」され、設定を読み込み、認証とタイムアウト設定を継承するようになった。

解決ステップ2:タスクを「失敗」ではなく「分離」する

2つ目の修正はもっと賢い。サーバーは時間になってもタスクを失敗とマークせず、「分離」する。どういう意味か? コールセンターの電話待ちのようなものだ。待ち時間が長すぎて待てなくなったら電話を切ってもいいが、自分のチケットはシステムに残っていて、処理が終わればSMSで通知が来る。

具体的には:応答ウィンドウが切れると、呼び出し側は「作業中」という非終端ステータスと案内を受け取る。タスクはWORKING状態を維持し、システムが「有界待機者」を手配して監視を続ける。エージェントが本当に作業を終えると、実際の結果が記録される。その後、tasks/getでもtasks/resubscribeでも、観測者は最終結果を確認できる。遅れて届いた結果は、もう破棄されない。

解決ステップ3:ついでに直った落とし穴

本命の修正が終わった後、隣の家の落とし穴もいくつか見つかった。

ストリーミング応答の切り詰め:以前はストリーミング応答が最後の断片だけを呼び出し側に返すことがあった。例えば長いevent_idが切り詰められて2番目のセグメントだけが残り、呼び出し側は欠損した情報を受け取っていた。修正後は累積応答が完全に保持され、テストでは152のテストケースがすべて合格した。

偽の完了:エージェントの反復予算が尽きたとき、以前は「完了」した要約を返していたが、ピア側は「途中で切り詰められた作業」と「正常に完了した作業」の区別がつかず、部分的な結果を完全な結果として受け入れる可能性があった。現在は切り詰められたタスクが明確にTASK_STATE_FAILEDを報告し、成功のふりをしなくなった。

外部ランチャー:非rootユーザーが外部エージェントランチャーを設定できるようになり、サブプロセスやバージョン管理されたRPCワーカーを実行できる。有界出力、プロセスツリーの刈り取り、キャンセル、ちょうど一度の終了をサポートする。完了の可視性、タイムアウトの整合、マルチターン連続性という3つの古い問題が解決された。

あなたにとっての意味

今や、2台のHermes間でタスクを依頼しても、2分を超えるタスクが「必ず失敗する」ことはない。タイムアウトは調整可能になり、旧回線も言うことを聞くようになった。さらに重要なのは、サーバー側が待ちきれなくなっても、タスクが「死刑宣告」されないことだ——作業状態を維持し、作業が終われば結果をきちんと記録し、いつでも確認できる。

長いタスクはようやく長距離走のようになった。誰かが計時し、誰かが伴走し、誰かが記録する。以前のように、途中で審判に笛を吹かれて記録が無効になることは、もうないのだ。

📖 公式ドキュメント

この記事は Hermes Agent の公式ドキュメントに基づいています:公式ドキュメント › user-guide/messaging/a2a