# 交互:観察空間と動作空間の拡張 第一章で一つの主張を示しました。基盤モデルが固定されているとき、Agent のタスク性能を高める最も主要なシステム工学的手段は、多くの場合**観察空間**と**動作空間**を定義し直すか、拡張することだ、という主張です。第二章から第五章までは、この一文を実際に果たしてきました——コンテキストエンジニアリングは観察に何を入れるかを決め、メモリと知識ベースは観察をセッションを越えて延長し、ツールは Agent に何ができるかを定義し、コード生成はそれ自身に新しい動作を作らせます。 しかしこれらの拡張はすべて、同じ一つの前提のもとで起きていました。すなわち、**Agent と世界は交互に発言する**という前提です。ユーザーが一言話し終えると、Agent がしばらく考え、いくつかツールを呼び出し、そして返事をする。考えているあいだ、世界は静止していると暗黙に仮定されています。この前提はあまりに自然なので、仮定として書き出されることすらほとんどありません。 本章が取り払うのは、まさにこの前提です。 ## 二本の軸:モダリティとタイミング 観察空間と動作空間を広げてみると、それぞれに拡張しうる方向が二つあることが分かります。 - **モダリティ**は観察と動作の**形式**を決めます。Agent はテキストを読むだけなのか、それとも音を聞き、画面を見て、トルクを感じ取れるのか。トークンを出力するだけなのか、それとも発声し、クリックし、関節を駆動できるのか。 - **タイミング**は観察と動作の**リズム**を決めます。観察は Agent が能動的に取りに行くのか、それとも世界が押し込んでくるのか。動作は 1 ターン内に終えなければならないのか、それともターンをまたぎ、途中で割り込まれ、より緊急な事柄に横取りされうるのか。 これまでの章が拡張したのはこの二つの空間の**内容**であり、本章が拡張するのはその**モダリティ**と**タイミング**です。 | | 観察空間の拡張 | 動作空間の拡張 | |---|---|---| | **内容**(第二〜五章) | コンテキストエンジニアリング、メモリと知識ベース | ツール、コード生成 | | **モダリティ**(本章) | 音声、画面、物理センサー | 発話、クリック、関節運動 | | **タイミング**(本章) | 世界からのプッシュ、連続ストリーム | ターンをまたぐ、割り込み可能、横取り可能 | 本章の中核となる命題は一文に圧縮できます。**ターン制は訓練が残した仮定であって、環境の性質ではない。** モデルの訓練コーパスはほとんどがターン制です。質問の後に回答が続き、ツール呼び出しの後にツール結果が続き、片方が話し終えてからもう片方が始まります。そのため、モデルが学ぶ方策は、世界がモデルを待ってくれることを前提にしています。しかし現実の環境は、モデルの反応を待ってはくれません。考えているあいだにメールが届き、ユーザーは途中で口を挟み、2 枚のスクリーンショットのあいだにページはもう変わっており、ロボットアームが手を伸ばしている間にカップは倒れてしまいます。 | スケール | シーン | 観察側の変化 | 動作側の変化 | |---|---|---|---| | 秒 — 日 | 非同期とイベント駆動 | 世界が Agent を能動的に起こす(メール、タイマー、コールバック) | 動作がターンをまたぐ:先に起動し、後続はイベントで締める | | 10 ミリ秒 — 1 秒 | 音声 | 話しながら聞く。一文の終わりを待たない | 考えながら話す。割り込み可能で、途中で言い直せる | | 秒未満 — 秒 | Computer Use | 画面はフレーム間で変化し続ける | 動作の後、現実がまだ計画に合っているかを確認し直す必要がある | | ミリ秒 | ロボット | センサーが連続的に返ってくる | 動作をチャンク化:一度に少しだけ計画し、横取り可能にする | 四つの節は同じ原語群——**起動、セーフポイント、キャンセル、プリエンプション、速い/遅いの分離**——を共有しており、違うのはパラメータと失敗形態だけです。非同期イベント駆動における「セーフポイントでキャンセル信号を確認する」と、ロボットの動作チャンク化における「異常を見つけたら残りの動作を捨てて観察し直す」は、5 桁も離れた時間スケールにおける同一メカニズムの二度の実装です。この同型性が見えることは、個々のシーンの技術的細部を覚えることよりも重要です。 **読む順序について一つ意図的な配置があります。本章は音声に、後続の二つのシーンより明らかに多くの紙幅を割いています。** リアルタイム交互作用という進化の線上で、音声は最も遠くまで進み、参照系として最も価値のある一つです。「直列パイプラインは遅延が大きすぎる」という問題から出発し、エンドツーエンド、全二重、考えながら話すという一連の方策を経て、今日の比較的成型された終局まで、問題→方策→終局の全行程がすでに走り抜けられています。ですからこれを徹底的に論じ、後の Computer Use とロボットはこの筋道と照らし合わせて読めるようにします——それぞれがこの進化線のどこまで来て、どこで止まっているのかを。 ## 非同期とイベント駆動:世界のほうから訪ねてくるとき 第 4 章で扱った知覚・実行・協調の各ツールは、いずれも Agent が能動的に呼び出します。では、いつ到着するか分からない外部イベントにはどう応答すべきでしょうか。そのためにはイベント駆動の非同期アーキテクチャが必要です。第 1 章の残る 2 種類、イベントトリガーツールとユーザーコミュニケーションツールもこの構造に依存するため、ここで併せて扱います。 ### なぜ非同期が必要か まずたとえ話で、なぜ非同期が必要かを説明します。同期(Synchronous)は「1 つのことを終えてから次のことに取りかかる」ことを意味し、非同期(Asynchronous)は「複数のことを同時に進められる」ことを意味します。従来の同期 Agent アーキテクチャは、列に並ばせることしかできない窓口のようなものです——一度に 1 人の客しか処理できず、処理し終えてから次の番号を呼ぶのです。一方、真に賢いアシスタントは、柔軟な秘書のようなものです——机の上に複数の処理待ちの事項(メール、電話、来訪者)が並んでおり、秘書は緊急度に応じてどれを先に処理するかを決め、処理の途中でもより緊急のことがあれば一時停止して切り替えられます。同期モードでは、Agent はバックグラウンドタスクが完了するのを待ってからでないとユーザーと対話できないか、対話が終わってからでないと新たに届いたイベントを処理できず、真のアシスタントのシーンで求められるいくつかの核心的な能力に対応できません。 - **非同期実行が常態**——多くのタスクは長時間かかり、ユーザーとのインタラクションをブロックすべきではありません。 - **イベント優先度の動的な判断**——すべてのイベントが同等に重要なわけではなく、Agent は賢く処理戦略を選ぶ必要があります。現在の操作をキャンセルする(緊急)、キューに加える(通常)、あるいは並行処理する(独立した軽量なクエリ)。 - **割り込みと復帰のスムーズさ**——割り込まれた対話やタスクは、自然に復帰できるべきです。 そして非同期パラダイムを現在の LLM に落とし込む際に遭遇する根本的な矛盾は、こうです。LLM の訓練パラダイムは同期を前提としています——ツール呼び出しを発した後、次のメッセージは必ずツール結果でなければなりません。ところが真のデプロイは非同期を要求します——ユーザーはいつでも割り込む可能性があり、複数のタスクが並行して進む可能性があり、外部イベントはツールがまだ返っていないうちに到達する可能性があります。この「訓練は同期/デプロイは非同期」の矛盾が、本節の後続で論じるすべてのエンジニアリング上のトレードオフを貫いています。 そのために私たちには**イベント駆動の非同期 Agent アーキテクチャ**が必要です。技術的には、これはシステムがもはや能動的に「新しいメッセージがあるか」を繰り返し確認する(これをポーリングと呼び、効率が低い)のではなく、新しいメッセージが到達したときに自動的に処理ロジックをトリガーすることを意味します。すべての入力、出力、思考過程、外部とのインタラクションは、統一してイベントストリーム——1 本のタイムライン上に順に並ぶイベント記録——としてモデル化されます。図6-1 はイベント駆動の非同期 Agent の全体アーキテクチャを示し、イベントソース、イベントキュー、Agent の処理フローの間の関係を表しています。 ![図6-1 イベント駆動の非同期 Agent アーキテクチャ](images/fig6-1.svg) ### OpenClaw におけるイベント駆動機構の実装 オープンソースフレームワークの OpenClaw(第 5 章でそのアーキテクチャを詳しく紹介します)は、Gateway 制御プレーンを通じてマルチチャネルのメッセージを受信し、Agent ランタイムへルーティングします。それは 3 種類の組み込みの自動化機構を提供します。 - **Hooks(イベントフック)**:セッションの作成、リセットなど、Agent のライフサイクルにおけるイベントに応答するもので、GitHub Actions におけるイベントトリガーに似ています - **Cron(定時スケジューラ)**:cron 式(Unix システムで広く使われる定時タスクの構文で、`0 9 * * 5` は毎週金曜午前 9 時を表す)に従って周期的なタスクを実行するもので、毎週金曜に週報を生成する、毎月初にデータを集計するなど - **Heartbeat(ハートビートのデーモンプロセス)**:N 分ごとに一度 Agent を呼び覚まし、注目すべき事項があるかを確認するもので、判断力によってアラート疲れを避けます この 3 種類の機構は OpenClaw Agent に「自律的」な外観を与えます——ユーザーがオンラインでなくても、Agent は定時でレポートを生成し、システムの状態を確認し、ルーティンの事務を処理できます。しかし仔細に検討すると、1 つの根本的な限界に気づきます。まず一点整理しておく必要があります。Gateway が組み込みチャネル(IM、Web インターフェースなど)のメッセージを扱う仕方そのものは**プッシュ式**で、メッセージが届くとすぐに Agent へルーティングされます。3 種類の自動化機構のうち、ユーザーのメッセージがないときに Agent を本当に「自ら動かす」のは Cron と Heartbeat だけで、しかもそれらはいずれも**時間駆動**です——Heartbeat は一定間隔ごとに一度確認し、Cron は事前設定した時刻にトリガーし、Hooks はフレームワーク内部のライフサイクルイベントに受動的に応答するだけで、外部世界の新しい変化を持ち込むことはできません。真の弱点はこうです。組み込みチャネル以外の任意のサードパーティのイベントソース——1 通の新着メールの到達、1 つの外部 API のコールバックのプッシュ、直ちに処理すべき緊急通知——に対して、OpenClaw は即時に接続するチャネルを欠いており、Agent はイベント発生の瞬間に応答することができず、次の Cron/Heartbeat の周期を待ってはじめて気づける可能性があるのです。 この遅延は多くのシーンで受け入れられません。**PineClaw**(Pine AI の OpenClaw プラグイン)を例に取りましょう。Pine AI はユーザーに代わって実際の電話をかける AI アシスタントで、典型的なシーンには料金の交渉、サブスクリプションの解約、保険金請求の処理などがあります。ユーザーが OpenClaw Agent を通じて Pine の電話タスクを起動すると、Pine の音声 AI がユーザーに代わって電話をかけますが、通話の過程でいつでもユーザーの介入が必要になる可能性があります。 - **リアルタイムの本人確認**:カスタマーサービスがアカウント保持者の本人確認を求め、Pine はユーザーに直ちにセキュリティコードや OTP(ワンタイムパスワード)認証コードを提供してもらう必要がある - **三者通話の確認**:カスタマーサービスがアカウント保持者と直接話すことを求め、Pine はユーザーに数秒以内に電話に出てもらう必要がある - **進展の同期と意思決定の確認**:交渉が重要な節目(相手が値下げ案を提示するなど)に至り、Pine はユーザーに受け入れるかどうかを確認してもらう必要がある もし Heartbeat の定時ポーリングに頼るなら——ハートビート間隔が 5 分だと仮定すると——ユーザーはカスタマーサービスが認証コードを待っている間に通知をなかなか受け取れず、カスタマーサービスに電話を切られて通話が失敗する恐れがあります。一方、ポーリング間隔を秒レベルに短縮すると、大量の無効なリクエストとリソースの浪費を招きます。 PineClaw の解決策は **Channel 機構**を導入することです——OpenClaw の Gateway と Pine API の間にリアルタイムのイベントチャネルを確立します。電話が接続された、ユーザーの入力が必要、通話が終了した、といった重要なイベントが発生したとき、メッセージが即座に OpenClaw Agent へプッシュされ、Agent は直ちに処理してユーザーに通知し、応答遅延が分レベルから秒レベルへと下がりました。 この事例は、イベント駆動アーキテクチャが Agent フレームワークに対して持つ核心的な価値を明らかにします。**真の「能動的なサービス」は、Agent が定時で世界を確認できることだけでなく、世界が能動的に Agent へ通知できることをより一層必要とする**のです。すべての入力——ユーザーメッセージ、ツールの返り、外部のコールバック、定時のトリガー——を統一してイベントストリームとしてモデル化し、イベントループを通じて Agent の思考と行動を駆動することが、この目標を実現するアーキテクチャの基盤です。このアーキテクチャのもとで、以下ではまずイベントに直接関わる 2 種類のツール、および Agent の独立した行動を支える仮想アイデンティティと隔離された実行環境を紹介し、その後にイベント処理機構の具体的な設計を論じます。 ### イベントトリガーツール イベントトリガーツールは外部イベントが Agent の行動を駆動する入り口です。イベントトリガーツールがなければ、Agent は連続してループしながら思考し、ツールを呼び出し、最後に 1 つの結果を出力して、それからユーザーの次の入力を待つことしかできません。世界の変化を Agent が処理できるイベントへ転化させるために、よくあるイベントトリガーツールには 3 種類あります。 **タイマー**(set_timer)は物理的な時間に依存するイベントを処理します。例えば、メールを 1 通送ったが相手が返信しない場合、しばらくして進展を尋ねるメールをもう 1 通送るべきです。電話をかけたが相手が勤務時間外だった場合、次の勤務時間になってから再度かけ直す必要があります。そのために OpenClaw、Claude Code などのツールはいずれもタイマーツールをサポートし、指定した物理的な時刻に自らを呼び覚まします。**一度きりのタイマー**は明確な時点のあるタスクに使います。例えばユーザーが「DMV に電話して」と求めたが今が土曜日なら、Agent は「来週月曜午前 10:00 に DMV へ電話する」を設定し、タイマーがトリガーされると自動的にかけます。**繰り返しタイマー**は周期的なタスクに使います。例えば 1 時間ごとにサーバーの健全性を確認する、毎週金曜に進展報告を送る、などです。さらに、一部の外部サービスは能動的に進展をプッシュできず、能動的に進展を照会するしかないため、この場合は繰り返しタイマーで定時に繰り返し照会する必要があります——前節の OpenClaw の Heartbeat はまさにこの機構を体系化したもので、OpenClaw が「能動的なサービス」の能力を備える根源でもあります。 **バックグラウンドタスクの監視**(monitor_shell)は、非同期に実行されるツールやコマンドラインタスクから届くイベントを処理します。一部のコマンドラインタスクは長時間バックグラウンドで実行する必要があり、Agent は実行の進展を監視する必要があります。もし Agent に絶えず「コマンドラインを見張らせる」、つまり絶えずツールを呼び出して現在の進展を照会させれば、あまりに多くの token を浪費します。もしコマンドラインタスクが完全に実行し終えてから Agent に思考と行動を始めさせれば、Agent は実行過程の深刻な問題を適時に発見できず、それどころかコマンドラインが固まった場合に介入できず、タスク全体が固まってしまいます。Claude Code がこの問題を解決する方法は monitor(監視)ツールを導入することで、Agent がコマンドラインの新規出力や特定のキーワードを含む出力を監視できるようにします。 **外部イベントチャネル**(connect_channel)は、新着メールの到達、API のコールバック、IM メッセージなどの外部イベントを Agent へリアルタイムにプッシュします。前節の PineClaw の Channel 機構がまさに典型的な実装です。 設計のレベルでは、イベントトリガーツールは明確なトリガー条件とフィルタリングのルールを定義し、無関係なイベントが Agent を呼び覚まして計算力を浪費するのを避けるべきです。イベントのペイロード(payload)は十分なコンテキスト情報を含み、Agent が呼び覚まされた後にさらに追加で照会する回数を減らすべきです。 ### ユーザーコミュニケーションツール OpenClaw のセッションはユーザーから見えず、専用ツールで画像・ファイル・プッシュ通知を含むメッセージをいつでも交換できます。マルチモーダル通信や Generative UI も扱います。 ユーザーコミュニケーションツールは、Agent とユーザーのコミュニケーションチャネルが日増しに多様化する状況のもとで生まれたものです。多くの Agent(Claude Code、Manus、Genspark など)はネイティブな ReAct ループを採用しており、Agent が「話す」すべての言葉(すなわち assistant メッセージ)が直接ユーザーへ送られ、ユーザーは App で指定した session を開いてはじめて Agent と対話できます。OpenClaw はこの人機コミュニケーションのパラダイムを打ち破った汎用 Agent の最も影響力ある代表の 1 つです。その session はユーザーに対して透明です——ユーザーは session の存在を意識する必要もなく、Agent がツールを呼び出す細部を気にする必要もありません。ユーザーと Agent はどちらもいつでも相手にメッセージを送れ、ユーザーが 1 通送り、Agent が 1 通返すという形ではありません。そのため多くの人が OpenClaw は「生身の人間らしさ」を備えていると評し、まるで秘書のようにテキストメッセージを通じてユーザーと非同期にコミュニケーションします。このとき、これらのテキストメッセージは直接モデルが出力した assistant メッセージをユーザーへ出力するのではなく、専用のツールを使ってメッセージを送るもので、これらのメッセージには画像やファイルの添付を伴うこともでき、緊急度に応じてプッシュ通知リマインダーを伴うこともできます。 テキストの方式でユーザーとコミュニケーションするほかに、ますます多くの Agent がマルチモーダルなコミュニケーション能力を備えつつあります。例えば構造化カードメッセージの送信、リマインダーメールの送信などです。一部の Agent はすでに生成的 UI、すなわち HTML などの方式でインタラクティブなインターフェースを生成し、より親しみやすい方式で情報をユーザーに提示することを試み始めています。設計のレベルでは、ユーザーコミュニケーションツールは非同期メッセージのモード(ユーザーが必ずしもオンラインとは限らない)をサポートし、既読/未読の状態追跡を提供し、マルチチャネルのシーンでメッセージの一貫性を保つべきです。 **マルチチャネルのユーザーコミュニケーションと呼び戻し。** ここで混同しやすいカテゴリの境界を整理しておく必要があります。同じ「通知を送る」でも、通知の対象が承認者や協力者(管理者に承認を求める、協力 Agent に進展を報告する、など)であれば、そのツールは協調ツールに分類されます。通知の対象が最終ユーザー本人であってはじめて、ユーザーコミュニケーションツールに分類されます。両者の違いはチャネルにあるのではなく、「誰に、なぜ通知するのか」にあります。 **Agent の応答は単一のチャネルに限られるべきではなく、通知機構は同時にユーザー呼び戻しの機構でもあります**。メッセージの送信は、インスタントメッセージ、SMS、メール、電話、プッシュなど多様なチャネルへ拡張されます。Agent は緊急度、ユーザーの状態、内容の性質、ユーザーの選好を総合してチャネルの選択を決め、重要なメッセージを逃さないことを保証しつつ、重複した打診を避けます。 長時間実行のタスクについては、Agent は完了時に能動的にユーザーへ通知し、ユーザーの注意を呼び戻す必要があります。定期的なタスク(日次サマリー、週報など)については、通知はユーザーが固定的なインタラクションの習慣を築くのを助けられます。 ユーザーコミュニケーションツールは「いかにユーザーに到達するか」を解決しました。しかし Agent がどんなアイデンティティでこれらのチャネルに現れ、どんな環境でユーザーを代表して操作を実行するかには、なおアイデンティティと環境の一層の基盤インフラが必要です。これが次節のテーマです。 ### 仮想アイデンティティと隔離された実行環境 仮想コンピューターは 24 時間稼働でき、ローカルファイルへの自由なアクセスを防ぎ、Agent の誤操作の影響を仮想環境に閉じ込めます。データ交換は共有ファイルシステム上のパスで行います。 まず本節の位置づけを説明しておきます。仮想アイデンティティと隔離された実行環境は本質的に実行環境の基盤インフラの一種であり、前述の実行ツールの節で論じたサンドボックスと一脈相通じています。それをこの非同期アーキテクチャの節で展開するのは、独立して常駐実行でき、いつでもユーザーを代表して行動できる Agent こそ、それを最も切実に必要とするからです。 本章の冒頭で触れたように、『Her』の Samantha は独立したアイデンティティと操作環境を持っていました。このような汎用アシスタントを実現するには、まず 1 つの重要なアーキテクチャ上の選択に直面します。Agent はユーザーの個人アカウントを直接管理すべきか、それとも自分自身の仮想アイデンティティを持つべきか。直接管理は一見便利ですが、ひとたび Agent がエラーを起こしたり突破されたりすると、ユーザーのすべてのデジタルアイデンティティが露呈してしまいます。より穏当な方策は、Agent に一組の独立した仮想アイデンティティを与えることです——秘書が自分のオフィス電話とメールアドレスを持つように。この一組の仮想アイデンティティには専用の通信アカウント、ストレージ空間、計算環境が含まれ、Agent が透明なアイデンティティでユーザーを代表して働けるようにします。アイデンティティの明確さは信頼を削ぐどころか、かえってコミュニケーションの真正性を高めます。 仮想アイデンティティは隔離された実行環境の上に落とし込む必要があります。**仮想コンピュータ**(VM/コンテナ)と**仮想スマートフォン**(Android エミュレータ)は、Agent にオペレーティングシステムレベルの隔離と完全なデスクトップ/モバイルの操作能力を提供します。Agent はその中で自分のユーザーアカウント、ホームディレクトリ、ログイン認証情報を持ち、すべての操作は追跡・監査可能です。たとえ誤った操作を実行しても、ホストシステムやユーザーの実際のデバイスには影響しません。これは前述の実行ツールの節で論じたサンドボックスの思想を「デジタルアイデンティティ」の次元へ延伸したものです——サンドボックスが隔離するのはコードの実行ですが、仮想コンピュータと仮想スマートフォンが隔離するのはデジタルアイデンティティ全体です。 独立したアイデンティティは 2 つの現実的な課題ももたらします。1 つは**反自動化の機構**です。多くのウェブサイトは CAPTCHA 認証コードと IP レピュテーション検知で自動化アクセスを遮断し、データセンターの IP から来る仮想環境は容易に識別されるため、実践ではしばしば住宅プロキシネットワーク(実際の家庭の IP を使う)を設定してはじめて正常にアクセスできます。もう 1 つは**ユーザーの実際のアカウントにアクセスするシーン**です。タスクがどうしてもユーザー本人のアイデンティティでログインしなければならない場合は、Human-in-the-Loop 認証を採るべきです——VNC/RDP のリモートデスクトップを通じて、ユーザーが可視化された環境で自らログインを完了し、ユーザーは Agent が操作している完全なインターフェースを見られ、なぜ認証が必要かを理解できます。認証後のセッショントークンは有効期限内は再利用され、ユーザーを頻繁に中断させるのを避け、自律性と安全性の間でバランスを取ります。 主 Agent と仮想環境の間のデータ交換は**共有ファイルシステム**を通じて完了します。ボリュームマウントの方式(`/workspace/shared` など)で主 Agent、仮想コンピュータ、仮想スマートフォンを接続し、データは内容のコピーではなくファイルパスの参照として伝達され、コンテキストウィンドウを占めるのを避けます。データ分析タスクを例に取りましょう。ユーザーが CSV ファイルを共有ディレクトリにアップロードすると、仮想コンピュータの中の Agent がファイルを読み取り、分析を実行し、グラフを生成して共有ディレクトリに保存し直し、主 Agent はグラフのファイルパスをユーザーに返すだけでよいのです——各方面の間で伝達されるのは常に軽量なパス文字列だけです。 イベントトリガーツールは世界が Agent を呼び覚ませるようにし、ユーザーコミュニケーションツールは Agent がユーザーに到達できるようにし、仮想アイデンティティと隔離された実行環境は Agent が独立した、監査可能なアイデンティティで行動できるようにします。残る問題はこうです。複数のイベントが同時に同じ Agent インスタンスへ押し寄せたとき、どう処理すべきか。 ### イベント処理機構 1 つの Agent インスタンスは同時に複数のイベントに直面する可能性があります。ユーザーの新しいメッセージ、ツールが返した結果、タイマーの満了、別の Agent の協調リクエストです。これらのイベントをいかに効率的かつ正しく処理するかは、性能とユーザー体験を直接左右します。 この機構の骨格は、並行プログラミングにおける**イベントループ**(event loop)です。非同期 Agent は長期にわたって走り続けるループと見なせます。毎ラウンド、入力キューからいくつかのイベントを取り出して軌跡に追加し、1 回 LLM を呼び出し、それが決めたツールを実行し、そしてループの先頭へ戻って次のバッチのイベントを待つ——これは Go の goroutine が channel からメッセージを読み取り、`for { select { ... } }` の中で一ラウンドずつ処理するのと同じ構造です。このモデルには一つの鍵となる性質があります。**イベントは各ラウンドの境界でのみ消費される**のです。LLM が推論している最中、ツールが実行されている最中には、新たに到着したイベントが割り込んで現在のステップをかき乱すことはなく、まずキューで待機し、本ラウンドが**セーフポイント**(ひと区切りの推論の終わり、一度のツールの返り)に達してから一括して処理されます。キャンセルも同じ規律に従います。任意の時点で強引に断ち切るのではなく、セーフポイントで「停止を要求されているか」を確認する——これはまさに Go における `ctx.Done()` が担う役割です(第 10 章では同じ context の発想で、親 Agent がサブ Agent を連鎖的にキャンセルする話を論じます)。この点を理解すれば、以下の 3 つの処理戦略の違いは、セーフポイントの扱い方の違いに過ぎないとわかります。イベントを次に自然に訪れるセーフポイントまで待たせる(キュー式)、能動的にセーフポイントを前倒しで作り出す(キャンセル式)、あるいはいっそ別のループを立ち上げて主ループのセーフポイントを待たない(並列式)のいずれかです。 **イベントの構造化モデリング。** 処理の前提は理解です。汎用 Agent が直面する入力はユーザー 1 人から来るものだけではありません——サードパーティから届いたメッセージはユーザーが Agent に送ったものではありませんが、Agent はそれを理解し、その重要性を評価し、どう介入するかを決める必要があります。これは各入力を豊かな意味を含む**構造化イベント**としてモデル化することを要求します。 - **出所(誰)**:ユーザー本人、連絡先、見知らぬ相手、システム通知 - **チャネル(方式)**:電話音声、SMS、インスタントメッセージ、メール、ソーシャルメディア、タイマーのトリガー、非同期ツール呼び出しの結果、コマンドライン監視の状態更新 - **内容(何)**:メッセージのテキスト、感情の色合い、緊急度、返信が必要か否か - **コンテキスト(背景)**:以前のある対話への返信なのか新規に起こしたコミュニケーションなのか、現在のタスクとの関連 顧客の返金リクエストのメールを例に取ると、構造化イベントの具体的な形式は次のとおりです。 ```javascript { "source": {"type": "email", "sender": "client@example.com"}, "channel": "gmail_webhook", "content": {"subject": "退款请求", "body": "订单 #12345 希望退款..."}, "context": {"priority": "high", "customer_tier": "vip", "related_orders": ["#12345"]} } ``` これらの次元が明確に構造化イベントとしてモデル化されてはじめて、Agent は多者間の通信のなかで明晰な認知を保ち、ユーザー入力をツール結果と取り違えたり、指示の潜んだツール結果をユーザー指示と誤認してプロンプトインジェクションを招いたりするのを避けられます。マルチスレッドのコンテキスト管理の複雑さは、さらに Agent が複数の対話スレッドの間の関連を理解することを要求します——サードパーティから来たメッセージがいかにユーザーの感情に影響するか、複数の対話におけるユーザーの役割の転換、いつ異なるスレッドの情報を総合してアドバイスを提供すべきか。n8n などのワークフロープラットフォームのトリガーのエコシステムから見て取れるように、Webhook、タイマー、メール、データベースの変更、ファイルの監視——各種のトリガーはいずれも Agent が世界を知覚する 1 つの「感覚器官」です。これらの異種のイベントが統一して構造化形式にモデル化された後、Agent は異なる出所から来る刺激を一貫した方式で処理でき、以下の緊急度の判定と処理戦略もすべてこの統一モデリングの上に成り立っています。 **緊急度に基づく動的な処理戦略。** 人間は複数のタスクを処理するとき、緊急度に応じて異なる戦略を採ります。突発的な緊急事態に直面すると、直ちに手元の作業を止めます。通常の処理待ちの事項に直面すると、タスクリストに加えて後で処理します。Agent のイベント処理もこのような賢さを体現すべきです。 ![図6-2 非同期イベント処理の 3 つの戦略](images/fig6-2.svg) **キャンセル式処理(Cancellation-Based)**は緊急イベントに使います。その本質は、緊急イベントのために**セーフポイントを前倒しで作り出す**ことにあります。能動的に現在のステップを中断し、その瞬間を新しいイベントを消費できる境界に変えるのです。緊急イベントが到達したとき(ユーザーが「停止」をクリックする、または監督システムが高優先度の指示を送ってくるなど):(1) 現在の操作を停止する——LLM が推論中なら直ちにストリーミング応答をキャンセルし、同期ツールが実行中なら取消信号を送る。(2) 処理待ちキューを空にし、すべてのイベントを取り出す。(3) キュー内のイベントと緊急イベントを一緒に軌跡の末尾に追加する。(4) 直ちに LLM を再度呼び出し、更新後の完全な軌跡を入力として状況を評価する。例えば、Agent が誤りかもしれない操作を実行しているときにユーザーが「止めて! 言い間違えた」と入力すると、Agent は直ちにこの新しい入力を目にし、真の意図を理解し直し、誤った操作の実行を避けます。 **キュー式処理(Queued)**は通常のイベントに使います。非緊急のイベントが到達したとき(非同期ツールが結果を返す、またはユーザーが補足情報を送ってくるなど):(1) イベントをキューの末尾に入れ、現在の操作を中断しない。(2) 現在の操作の完了を待つ——LLM に推論を完了させ、同期ツールに実行を完了させる。(3) いずれかのツール呼び出しが完了して `tool.result` を返したとき、キューを確認し、キューが空でなければすべてのイベントを一度に軌跡へ追加する。(4) LLM が更新後の軌跡を総合的に処理する。これはバッチ処理を実現し、効率を高めます——例えば Agent が検索ツールを呼び出した後、待機中にユーザーが「直近 1 か月の結果だけ見て」と補足すると、この補足情報がキューに入り、検索結果が返ったときに 2 つのイベントが一緒に LLM に提示され、不要な往復を避けます。 **並行処理(Parallel)**は独立した軽量なクエリに使います。例えば Agent が大量のデータを分析している最中に、ユーザーが突然「今日の天気はどう?」と尋ねるような場合です。この種のクエリには 3 つの特徴があります。主タスクと無関係、素早い応答が必要、実行コストが低い。キャンセル式処理を使うべきでもなく(重要な主タスクを中断してしまう)、キュー式処理を使うべきでもありません(ユーザーを長く待たせてしまう)。システムはまずクエリの独立性と複雑さを判断し、それから 1 つの並行した推論セッションで独立して実行し、必要なツールを呼び出して応答を生成した後、直ちに返します。クエリと応答は主タスクの軌跡に追加され、「主タスクと並行して実行」と明確に標示され、LLM の混同を避けます。 **緊急度の判定。** 緊急イベント:ユーザー割り込み(`user.interrupt`)、監督指示(`supervisor.instruction`)、Agent 間割り込み(`agent.interrupt`)、緊急と標示された外部トリガー(システムアラート、決済失敗など)。 非緊急イベント:通常のユーザー入力(`user.input`)、Agent 入力(`agent.input`)、ツール結果(`tool.result`)、タイマーのトリガー(`timer.trigger`)、通常の外部トリガー。 ハードコードされたルールには限界があり、イベントの意味が処理方式を決めます——「すぐ止まって」はキャンセル式、「今日の天気はどう」は並行式、「レポートは中国語で送って」はキュー式です。**軽量な分類 LLM をイベントルーターとして使う**ことをお勧めします。イベントの到達時に、どの戦略を採るべきかを素早く判断させます。 以下では、イベント駆動のメール処理 Agent の実験を通じて、上述のイベント処理戦略を実行可能な実装へと落とし込みます。 > **実験 6-1 ★★★:イベント駆動のメール処理 Agent** > > > ![図6-3 実験 6-1 イベント駆動 Agent アーキテクチャ](images/fig6-3.svg) > > > 本実験では、最も単純なイベント駆動 Agent、すなわち**自動メール処理アシスタント**を構築します。Agent はメールの受信箱を監視し、新着メールを受け取るたびに自動的に処理フローをトリガーします——分類、要約、返信のドラフト作成、必要ならユーザーへの通知です。これはイベント駆動 Agent の最も直感的な入門シーンです。1 つの外部イベント(新着メールの到達)が 1 回の完全な Agent 思考ループをトリガーします。 > > **実験の目標**は、イベント駆動の核心的な概念を理解することです。Agent はもはや受動的にユーザー入力を待つだけの存在ではなく、外部イベントに応答して能動的に行動できるのです。この実験を通じて、読者はイベントソースの登録、イベントキュー、そして「イベントの到達 → Agent の処理 → 結果の出力」という基本的な閉ループを習得します。 > > **イベントソースとイベントキュー。** > > システムは多様なイベントソースの統一された接続をサポートします。 > > - **メールイベント** (`on_email_received`):受信箱を定期的に確認するか、プッシュ通知を受け取ることで、新着メールの到達時にトリガー > - **IM/SMS メッセージ** (`on_im_message`、`on_sms_message`):インスタントメッセージのトリガー > - **GitHub イベント** (`on_github_pr_update`、`on_github_issue_update`):PR review の意見、状態の変化 > - **タイマーのトリガー** (`on_timer_expire`):定時タスク(日次サマリー、週報生成など) > - **Webhook** (`on_webhook_received`):汎用の外部システムのコールバック > - **システムイベント** (`on_user_inactive`、`on_process_timeout`、`on_resource_alert`):内部状態の変化 > > すべてのイベントは統一された**イベントキュー**に入り、到達順に順次処理されます。各イベントは 1 回の独立した Agent 思考ループをトリガーします。Agent はイベントの内容を読み取り、関連するツール(知識ベースの照会、添付ファイルの読み取り、関連するメール履歴の検索など)を呼び出し、処理結果(分類ラベル、要約、ドラフト返信)を生成し、最後に通知ツールを通じてユーザーに知らせるか、直接操作を実行します。 > > **検証シナリオ**:Agent をテスト用メールアドレスの監視に設定します。3 通のメール——会議招待、顧客からのクレーム、マーケティング広告——を受け取ったとシミュレートします。Agent は順に処理します。会議招待にはカレンダーの衝突を自動的に確認して承諾/辞退の返信をドラフトし、顧客のクレームには重要な情報を抽出して高優先度に標示しユーザーに処理を通知し、マーケティング広告は自動的にアーカイブします。この過程全体でユーザーの介入は不要です。 実験 6-1 は最も単純なイベント駆動のパターン——イベントがキューに入り、Agent が順次処理する——を示しました。しかし Agent が長時間実行のツール実行の過程で割り込みに応答する必要がある場合、あるいは複数の並行タスクを同時に管理する必要がある場合には、単純なイベントキューでは足りなくなります。続いてより深いエンジニアリング上の課題を論じます。 ### エンジニアリング実装:いかに同期モデルに非同期割り込みをサポートさせるか 実験 6-1 は直列のイベントしか処理しません——イベントは順にキューに入り、Agent が 1 つずつ処理し終えます。ここで本節冒頭で提出した「訓練は同期/デプロイは非同期」の矛盾に戻ります。ツールがまだ返っていないときにユーザーが突然割り込んだら、同期の形式はそれをどう受け止めればよいのか。本節では現在の業界のエンジニアリング的な解法を示します。 まず具体的なシーンでこの矛盾を説明します。Agent がユーザーのためにメールをドラフトしている(ツール呼び出し:連絡先情報の検索)最中、検索がまだ結果を返していないときに、ユーザーが突然「ちょっと待って、先に明日の天気を調べて」と言ったとします。同期の ReAct ループでは、Agent は検索が返ってからでないと次のメッセージを処理できません——API が「ツール呼び出しを発した後、次のメッセージは必ずツール結果でなければならない」と要求するからです。しかし非同期の現実世界では、イベントはいつでも進行中のタスクに割り込む可能性があります。「同期の形式」の制約のもとで「非同期の割り込み」の意味論をいかに表現するか、これがまさに以下の一連のエンジニアリング方策が答えるべき問題です。 **エンジニアリング上の便法:同期を模擬する非同期実装。** 核心的な発想はこうです。**割り込みが起きない常態のもとでは、LLM に標準的な同期の軌跡を見せ、割り込みが起きたときにだけプレースホルダーを挿入して形式を修復する**。以下は 5 つの主要なルールです。 **ルール 1**:LLM が出力するとき、直ちに assistant message(thinking、content、tool call を含む)を記録する。 **ルール 2**:ツール呼び出しが完了したときにはじめて tool result を記録する。実行中の軌跡は「部分完了」の状態にある。 **ルール 3**:ツール実行中の割り込みにはプレースホルダーが必要。未完了のツールにプレースホルダーの応答(「ツールはバックグラウンドで実行中です。新しいイベントを優先して処理してください」など)を生成し、割り込みイベントを追加し、LLM を再度呼び出す。LLM の視点から見れば、assistant message にはなお対になった tool result がある。 **ルール 4**:LLM の思考中の割り込みは現在の思考を直接破棄する。軌跡には書き込まず、新しいイベントを直接追加してから新たな 1 ラウンドの思考を開始する。 **ルール 5**:非割り込みのイベントはキューに入れてバッチ処理を待つ。現在の周期が完了してからはじめて一度に追加する。 Agent がメールをドラフトしている最中にユーザーが割り込んで天気を尋ねる場合を例に、この 5 つのルールの動作の過程は次のとおりです。 1. Agent が `search_contacts` を呼び出して連絡先情報を検索し、assistant message が直ちに軌跡に書き込まれる(ルール 1)。 2. 検索ツールがまだ結果を返していないときに、ユーザーが「先に明日の天気を調べて」と送ってくる。これはユーザーの割り込みなので、システムは未完了の `search_contacts` のためにプレースホルダーの tool result(「ツールはバックグラウンドで実行中です。新しいイベントを優先して処理してください」、ルール 3)を生成し、それからユーザーの天気クエリを軌跡に追加し、LLM を再度呼び出す。この時点で LLM が見る軌跡の形式は完全に合法です——assistant message と tool result の対がきちんと保たれています。 3. 天気クエリが完了してユーザーに返信した後、先ほどの `search_contacts` の結果が到達し、新しいイベントとして軌跡に追加され(ルール 2)、Agent は連絡先情報を読み取った後、メールのドラフトを続けます。 この方策の核心的な利点はこうです。**常態のもとで LLM が見るのは完璧な同期の軌跡である**——assistant message と tool result が厳密に対になり、時間順が明晰で、いかなるプレースホルダーや異常状態もありません。これは現在の同期の訓練パラダイムに基づく LLM にとって最も親和的であり、思考の質を最大限に保証します。本当に割り込みが必要なときにだけ、プレースホルダーという「必要な妥協」を導入するのです。 しかしなおハルシネーションを助長するリスクが存在します。このシーンでは、プレースホルダーがツールが「まだ完了していない」ことを明確に説明していても、システムは後続の思考で 1 つのツール結果を「捏造」し、ツールがすでに有効なデータを返したと誤解し、この虚構の結果に基づいて不適切な意思決定を下してしまう可能性があります。これは、モデルが訓練時に見た大多数の軌跡では、ツール呼び出しの後にすぐ本物の結果が続いており、「結果がまだ返ってきていない」状況をどう処理するかを一度も学んでいないからです。したがって実践では、本当に緊急なとき(ユーザーが明確に停止を求めたとき)にだけ割り込み、非緊急のイベントはキューに入れてバッチ処理します。 **既存のモデルに適した非同期ツールインターフェース。** モデルの同期の前提を突破するのが難しい以上、より根本的な戦略は、**ツールインターフェースの設計のレベルから非同期の意味論を受け入れる**ことです。 従来のツール設計は「呼び出せば完了」という意味論を暗に含んでいました。例えば `phone_call` という名前は「呼び出せば電話をかけて通話の終了を待ち、通話記録を返す」ことを暗示します。非同期パラダイムでは「起動」と「完了」を分離すべきです。 - `initiate_phone_call`:電話の発信を起動し、直ちにタスク識別子と初期状態(「呼び出しを発起、ダイヤル中」など)を返す - 通話の進展はイベント通知(`phone_call_connected`、`phone_call_ended`)を通じて伝える 肝心なのは、ツールの名前と記述そのものが非同期の意味論を伝えることです。モデルが `initiate_phone_call` を見ると、その言語理解能力が自然に「起動」であって「完了」ではないと推論します。ツール記述はさらにこれを強化すべきです。「このツールはサブ Agent が処理する電話タスクを起動します。タスクが正常に発起されると直ちにタスク ID を返し、あなたは他の事項の処理を続けられます。通話が終了すると別途通知イベントを受け取ります。」 **キュー式処理における注意力の分散問題。** バッチのイベント処理では、モデルはしばしば最後の 1 つのイベントにしか注目しません。根源は、**モデルが最新の入力に反応するよう訓練されているのに、バッチのイベントがこの前提を破っている**ことにあります。 2 つのレベルから介入できます。 **プロンプトのレベル**:モデルに「複数の連続したイベントを受け取ったときは、すべての情報を漏れなく考慮するようにしてください」と告げる。 **Agent ステータスバーの標示**:各イベントの前に明示的な標示を加える。 ```text [未処理イベント 1/4] Tool result from database_query:... [未処理イベント 2/4] User の補足説明:北京地区のデータだけ見て [未処理イベント 3/4] システムリマインダー:レポートの締切まであと 30 分 [未処理イベント 4/4] User の質問:進捗はどう? ``` 末尾にまとめを加える。「上には 4 つの未処理イベントがあり、1 つのツール結果、2 通のユーザーメッセージ、1 つのシステムリマインダーを含みます。応答がすべての情報をカバーするようにしてください。」 ### 深層の矛盾と将来の方向 ![図6-4 同期の訓練パラダイムと非同期のデプロイの現実](images/fig6-4.svg) 突き詰めれば、前の各節のプレースホルダー、非同期ツールインターフェース、ステータスバーの標示は、いずれも同じ「訓練は同期/デプロイは非同期」の矛盾(図6-4)をプロンプトエンジニアリングで埋め合わせるものです——この矛盾の成因は本節の冒頭で詳述したのでここでは繰り返さず、その根本的な解法だけに焦点を当てます。 **モデルの進化への期待:同期から非同期へ。** 上述のエンジニアリングの技法は本質的に**プロンプトエンジニアリングでモデル訓練の不足を埋め合わせる**もので、過渡期の便法です。真の解決策はモデル訓練のレベルでパラダイムの転換が起こることを必要とします。 ロボット分野の VLA(Vision-Language-Action、視覚・言語・行動、第 6 章を参照)モデルはすでに類似の課題に直面し始めています。知覚と行動の間には避けられない遅延が存在するのです。VLA の成功は Agent モデルの進化に方向を指し示しました。次世代のモデルは非同期環境における強化学習を通じて 3 つの核心的な能力を獲得する必要があります。 1. **軌跡におけるイベントの非同期な差し込みを理解する**:これは最も核心的な能力の欠陥です。現在のモデルは厳密な同期のシーケンスを期待しますが、真の非同期環境では、tool call の後が tool result ではなく新しい user メッセージであるかもしれず、thinking が途中まで進んだところで割り込まれるかもしれませんが、その中間状態は軌跡に保持され、新しいメッセージを処理し終えた後に最初からではなく続きから思考すべきです。モデルはこのような「順序の乱れた」軌跡のなかで明晰な認知を保つ必要があります——どのツール呼び出しがまだ結果を待っているのか、どの思考が未完了の断片なのか。 2. **割り込まれたタスクと思考を復帰させる**:緊急イベントの処理のために割り込まれた後も、未完了のタスクを覚えている。例えば Agent がデータ分析ツールを実行している最中にユーザーが突然天気を尋ねたら、答えた後は自然にデータ分析の結果を待つべきであり、ツールがまだ動いていることを忘れるべきではありません。特に、割り込まれたツール呼び出しがすでに完了したと誤解するハルシネーションを避ける必要があります。 3. **バッチのイベントの総合的な処理**:複数のイベントがバッチで軌跡に追加されたとき、最後の 1 つだけに注目するのではなく、すべての未処理の情報を総合的に考慮しなければなりません。 このような非同期 RL 訓練を実現するには新しいインフラが必要です。非同期環境のシミュレータ(ツールの遅延返却、ユーザーのランダムな割り込みなどのシーンを生成する)と、非同期能力の専用の報酬(順序の乱れた軌跡を正しく理解する、割り込まれた思考を成功裏に復帰させる、ハルシネーションを避ける、バッチのイベントを総合的に処理する)です。 継続的思考は、次世代モデルを待たなくても実現できます。約 200 行のオーケストレーションで、**既存の**テキスト推論モデルを**連続時間** Agent に変え、先ほどの工学的な便法とモデル進化をつなげられます。これはルール 4 の拡張です。中断された思考を捨てず、対話全体を途切れない思考ストリームとして構成します。実行系はモデルが書いている `` ブロックを強制的に閉じ、到着したツール結果、ユーザー割り込み、認識更新などを通常のメッセージとして注入し、そのままデコードを続けます。 これは、しばしば無駄になる資源を使います。モデルは 1 秒に数百 token を生成できる一方、ツール呼び出しやユーザーの発話には数秒かかることがあります。その待ち時間を思考に使えます。したがって Agent は、部分的な情報から考え続け、次のツールを先に動かす**待ちながら考える**動作と、出力しながら推論を続け、行動の途中で自らを修正する**実行しながら考える**動作を行えます。 > **実験 6-2 ★★★:並行実行と割り込み能力を備えた非同期 Agent** > > > ![図6-5 実験 6-2 非同期 Agent の割り込みと復帰](images/fig6-5.svg) > > > 実験 6-1 の単純なイベントキューを土台として、本実験は非同期 Agent の深水域に入ります。**並行ツール実行、実行のキャンセル、状態管理**です。Agent はもはやイベントを 1 つずつ処理するだけではなく、複数の並行するタスクを同時に管理し、割り込みと復帰を処理し、リアルタイムの状態に応じて動的な意思決定を下す必要があります。 > > **1. 非同期ツール実行**:時間のかかるツールの非同期実行(少なくとも 3〜5 秒)をサポートし、起動後に直ちにプレースホルダーを返す。**検証シナリオ**:Agent が長時間のターミナルコマンドを実行し、その間にユーザーが「今何時?」と尋ねると、Agent は直ちに応答し、分析結果が返ってから改めて提示する。 > > **2. イベントキューとバッチ処理**:非緊急のイベントを蓄積し、バッチで軌跡に追加する。**検証シナリオ**:Agent が長いタスクを実行中、ユーザーが「日本語で返信するのを忘れないで」「ウェブページにまとめて」と連続して送り、タスク完了時にすべてのイベントを一度に処理し、日本語のウェブページを生成する。 > > **3. 割り込み機構**:ユーザーの「停止」が実行フローを直ちに終了させ、非同期ツールをキャンセルする。**検証シナリオ**:Agent が長いタスクを実行中、ユーザーが「キャンセル」を送ると、Agent は直ちに停止し、軌跡に割り込みイベントとキャンセル操作を記録する。 > > **4. 並行ツールのキャンセルと状態照会**:非同期ツールの完了後、新しいイベントを通じて本物の結果を対話に注入し、タスク ID を通じたキャンセルや進捗照会をサポートする。**検証シナリオ**:ユーザーが「この 3 つのスクリプトを同時に実行して、どれかが先に完了したら、残りのスクリプトの進捗を見て、まだ 50% を超えていなければキャンセルして」と要求する。3 つのスクリプトは分析プロセスをシミュレートし、実行中は絶えず進捗を出力し、速度はそれぞれ毎秒 3%、2%、1% とする。Agent は 3 つの非同期ターミナルコマンドを同時に起動し、毎秒 3% のスクリプトが約 33 秒後に完了すると、Agent は残り 2 つのターミナルの状態を照会し、1 つが約 66%、もう 1 つが約 33% まで実行されていることを発見し、そこで 50% を超えていないほうをキャンセルする。両方のターミナルが完了した後、結果を統合して完全なレポートを生成する。 > 非同期・イベント駆動の実行により、世界はいつでも Agent を起こせます。ただし、応答前にモデルが落ち着いて考え終えられることを前提としています。次の 3 節はこの前提を問い直します。環境がモデルの生成速度と同じかそれ以上の速さで変わるとき、「考え終えてから話す」こと自体が許容できない遅延になります。 ## 音声:最も自然な人間とコンピュータのインターフェース 音声は文字を音に変えるだけではない。発話はタイピングの約4倍速く、手と視線を使わないため、いつでも割り込まれ得る連続入出力ループに Agent を置くのに適している。音声入力は発話を文字にし、音声 Agent は利用者が Agent と直接協働できるようにする。どちらも序章の whisper coding を支える。 本節では、利用者が Agent に話す場合と、Agent が利用者に代わって外界に話す場合を扱う。音声モデルは何に答えられるかを、対話構造は聞き取り、応答、発話権の交代、確認とツール呼び出しを時間内に行えるかを決める。 ### 相互作用の時間構造:カスケードから全二重へ OpenAI は GPT-Live で、音声対話をカスケード、ターンベース、全二重の三パラダイムに整理した[^ch6-12]。これは新旧の順位ではなく、遅延・コスト・観測性のトレードオフである。 | パラダイム | 構造 | 利点 | 制約 | | --- | --- | --- | --- | | カスケード | VAD → ASR → LLM → TTS | 交換・デバッグしやすい明確なモジュール | 遅延の累積とパラ言語情報の欠落 | | エンドツーエンド Omni | ネイティブ音声入出力、ターン単位の対話 | 低遅延、声色・感情・環境音を保持 | ターン依存、訓練とデバッグが難しい | | 全二重 | ネイティブ音声入出力、継続的に聞き、話し、判断 | 重なり発話と自然な割り込み | 訓練・制御・評価が複雑 | 共通する課題は、交互に話す仮定と VAD による発話権の推測を越えることだ。全二重だけが発話権を継続的なモデル判断にする。 [^ch6-12]: OpenAI. *Introducing GPT-Live.* 2026-07-08. https://openai.com/index/introducing-gpt-live/。この三分類は ChatGPT Voice の三世代をまとめた同記事に由来し、本文の Omni は「turn-based voice models」に対応する。 ### パラダイム一・カスケードパイプライン(Cascading) 商用音声アシスタントの多くは直列パイプラインを使う(図6-6)。VAD が終了を判断し、ASR が音声を文字にし、LLM が回答を生成し、TTS が読み上げる。モジュール性は最適化を容易にするが、各境界が待ち時間を加える。 ![図6-6:直列音声 Agent パイプライン](images/fig6-6.svg) | モジュール | 役割 | ボトルネック | | --- | --- | --- | | VAD | 発話終了の判定 | 無音閾値による待機と誤分割 | | ASR | 音声を文字に変換 | 認識遅延と文脈欠落 | | LLM | 理解・思考・生成 | 最初の token の遅延、reasoning の追加待機 | | TTS | 文字を音声に変換 | 最初のパケットと再生バッファ | 短い回答でも段階の待機は直列に累積する(図6-7)。本番のキューイングは空載遅延をさらに増幅する(図6-8)が、容量計画は本章では扱わない。 ![図6-7:直列応答の遅延ウォーターフォール](images/fig6-7.svg) ![図6-8:キューイング遅延曲線](images/fig6-8.svg) > **実験 6-3 ★:従来型音声 Agent を構築する** > > マイク、Silero VAD、ローカル Whisper、ストリーミング LLM、Fish S1 TTS を WebSocket で接続し、カスケード方式のベースラインを構築します。 #### 直列からストリーミング知覚へ 図6-7 が描くのは VAD + ASR + LLM + TTS が完全に直列に動く場合であり、この直列知覚には三つの問題がある。 1. **遅延の累積:** 一定の無音を待たなければ発話終了を確認できない。 2. **情報損失:** 有声/無声の二値信号ではためらい、感情、相槌、環境音を表せない。 3. **文脈の分断:** メールアドレス、人名、固有名詞が分割して認識され誤りやすい。 これを解決する一つの最適化が、モジュールの分担を保ったまま各段階に増分結果を早く出させる**ストリーミング知覚**である: - **ASR 逐次転写:** VAD が発話開始を検出した時点から一定間隔でモデルを呼び、暫定転写を流し続ける。発話終了を検出してから最終テキストを確定する。 - **LLM 推測実行:** 暫定転写が出た時点で LLM を呼ぶ。最終テキストが暫定転写と一致すれば呼び直さず、異なれば先行する推測実行の思考を取り消して呼び直す。 - **LLM 分割出力:** 最初の読み上げに適した文ができ次第、完全な回答を待たずに TTS に渡す。 - **TTS 増分合成:** 音声チャンクを返し続け、後続の生成・合成・再生を重ねて進める。 真のストリーミング ASR にはモデル側の対応が要る。Whisper のデコードは自己回帰的だが、エンコーダは完全な音声区間を必要とするため、そのままストリーミングモデルとは言えない。LLM ベースのストリーミング聴覚モデルは連続音声からテキストと意味イベントを出力し、「認識」と「理解」の一部を同じモデルに収める。対話の開始から現時点までの文脈を保ち、ブランド名、人名、固有名詞には世界知識を利用できる。 終端判定を組み込む場合、ラベルは判断時点で見える情報だけから作る必要がある。speak_start/end、interrupt、emotion、laugh、sigh、noise のイベントを文字と一緒に出力すれば、音をすべてテキストに圧縮せず対話状態を扱える。 > **実験 6-4 ★:Qwen2-Audio でストリーミング音声知覚を模擬する** > > Qwen2-Audio 自体はストリーミングモデルではありません。本実験では、伸長する音声プレフィックスで連続知覚を模擬し、600 ms VAD + Whisper と比較します。 ### パラダイム二・エンドツーエンド全モダリティ(Omni) カスケードはストリーミング知覚を採っても、聞く・考える・話すが離散的なインターフェースで受け渡されるため、感情、抑揚、環境音などの情報は文字にする段階で失われ得る。Omni 方式は一つのモデルで音声を直接聞き、回答を生成し、音声を出力するため、これらの情報を保てる可能性があるが、訓練のコストは高い(図6-9)。パラダイム一のカスケード方式と比べると、Omni の利点は主に遅延と、非文字情報の理解と生成に現れる。 理解の面では、Omni モデルは声の中の間(ま)を理解できる。生成の面では、歌う、特別な語調で一文を言うといった、より豊かなパラ言語情報を伝えられる。 Omni モデルも交互に話すことを前提としており、発話権の区切りは通常 VAD に頼る。そのため、利用者が数字を読み上げる途中の無音を、発話終了と誤判定し得る。 ![図6-9:エンドツーエンド全モダリティ音声モデルの比較](images/fig6-9.svg) > **実験 6-5 ★★:MiniCPM-o 4.5 をローカルで実行し、エンドツーエンドと自己カスケードを比較する** > > MiniCPM-o 4.5 をローカルで実行し、thinking mode を無効にして、音声から直接答える経路と、同じモデルで先に文字起こししてから答える自己カスケードを比較します。測るのは音声情報が保持されるかであり、後述する**「話しながら考える」ではありません**。 ### パラダイム三・全二重インタラクティブモデル Omni は利用者とモデルの発話を分けるが、同時通訳などは重なりを要する。全二重モデルはターンを前提とせず、聞き、話し、続行・停止・割り込み・ツール呼び出しを連続的に判断する。Kyutai の Moshi は音声ストリームを並列にモデル化した初期例だ。 Thinking Machines Lab の Interaction Model[^ch6-14] は相互作用を VAD などの外部ハーネスではなくモデル内に持つ。短いマイクロターンで無音、重なり、割り込みを文脈として保ち、背景推論モデルに会話を委譲しながら話頭を維持できる。 [^ch6-14]: Thinking Machines Lab, “Interaction Models: A Scalable Approach to Human-AI Collaboration,” 2026-05. https://thinkingmachines.ai/blog/interaction-models/ ### 認知の時間構造:リアルタイム対話と深い思考 対話品質と知能の上限は別の次元である。前景モデルは利用者がオンラインの間に返答し、背景モデルは長く思考できる。三つの設計は線形の進歩ではなく取捨選択であり、最初の二つはカスケードまたは Omni に組み合わせられる。三つ目だけが深い思考とリアルタイムの表現を同じモデル内に統合する。 #### 解決策一:速い思考でつなぎ、遅い思考で回答する 速いモデルが数百ミリ秒で応答し、遅いモデルが深く推論すると、簡単な質問は二重処理され、難しい質問は矛盾し得る。二つの実体が独立に考えることが原因だ。 ![図6-10:速い/遅い思考の構造](images/fig6-10.svg) #### 解決策二:速い思考で対話し、遅い思考で助言する 背景モデルが専用インターフェースで助言を送り、前景モデルが会話を維持する。間接通信なので中間思考は見えず、真に考えながら話すことはできない。 #### 解決策三:思考と表現をエンドツーエンド統合する MGRD は音響特徴に基づく思考を蒸留し、MPS 双脳構造は計画と表現を並列化する。構想側の思考片を表現側が部分回答と結合して音声化するため、全推論を待たずに話せる。 #### 速い思考と遅い思考の分離と、エンドツーエンド思考のトレードオフ 統合モデルは「考えながら話す」を最も直接的に実現するが、思考とリアルタイム表現を一緒に再訓練しなければならない。分離型は背景モデルを交換しやすい。両者はトレードオフであり、単純な代替関係ではない。 最先端の推論モデルが急速に進歩する現在、速い思考と遅い思考を分離する構成には重要な工学上の利点がある。遅いモデルの世代更新による恩恵をそのまま取り込めるからだ。前景の速いモデルは低遅延で聞き、応答し、会話を維持することだけを担い、背景の遅いモデルが推論、計画、ツール呼び出しを担当する。より強力な推論モデルが登場したときは背景モデルだけを交換すればよく、リアルタイム音声システム全体を再訓練する必要はない。統合型では推論と対話が同じ訓練サイクルに結び付くため、更新のたびに知能、応答遅延、表現の自然さを再調整しなければならない。したがって速い思考と遅い思考の分離は、単なる遅延上の妥協ではなく、対話能力と知能の上限を別々に進化させるモジュール化の選択でもある。 この分離がタスク性能を必ず犠牲にするわけでもない。2026 年 8 月時点で、速い思考と遅い思考を分離した Pine AI の音声 Agent は τ³-Voice Leaderboard で首位となり、Grok Voice や GPT-Realtime-2 などのリアルタイム音声システムを上回った。この結果は少なくとも、深い推論とリアルタイム対話を同時に評価するタスクにおいて、分離型アーキテクチャがエンドツーエンドモデルに本質的に劣るわけではないことを示している。[^ch6-17] [^ch6-17]: Pine AI. “The Most Natural Human-Computer Interface Is Your Voice.” 2026-06-23(2026-08-06 更新). https://www.19pine.ai/blog/pine-ai-the-most-natural-human-computer-interface-is-your-voice ここで、「エンドツーエンドモデル」という語が一般に二つの意味で使われることを明確にしておく必要がある。第一は前節で扱った**音声経路のエンドツーエンド性**である。モデルが音声を直接受け取り、音声を生成し、複数のモデルを離散的なテキストでつながないことを指す。Omni と Interaction Model はどちらもこの意味ではエンドツーエンドだが、Omni は通常ターン単位で進み、Interaction Model は聞きながら話せるため、両者のアーキテクチャは大きく異なる。第二は本節で扱った**認知アーキテクチャのエンドツーエンド性**である。リアルタイム対話と深い思考が一つのモデル内で状態を共有して共同訓練されるのか、それとも前景の速いモデルと背景の遅いモデルに分けられるのか、という区別だ。この二つの軸は独立している。音声経路はエンドツーエンドでありながら、認知アーキテクチャでは速い思考と遅い思考を分離することもできる。Thinking Machines Lab が複雑なタスクを背景推論モデルへ委譲する構成は、その一例である。 ### より人間らしい音声合成 従来の TTS は、滑らかすぎたり間が少なすぎたりすると機械らしさを露呈します。人間の会話では、間、つなぎ言葉、時折の繰り返しが、迷いや思考を示します。 主 LLM はテキストに加えて、**THINKING**、**EMO:happy**、**SPEED:0.8x** などの制御マーカーを出力できます。TTS はそれらを間、韻律、話速、笑い、ため息、その他の非言語音声へとマッピングします。実装は、制御マーカーを理解するよう訓練された TTS でもよいですし、さまざまな感情やスタイルの参照クリップを使ったボイスクローニングでも構いません。 > **実験 6-6 ★★: Fish Audio を使った制御トークン駆動 TTS** > > Fish Audio S1 を使って多参照音声ライブラリを構築し、3 つの構成——制御マーカーなし、1 つの参照クリップ、複数の参照クリップ——を比較します。実行層は、マーカーに応じて感情、話速、スタイルを選択します。 ## Computer Use:GUI 自動化 Agent ここまで読んで、本章が音声に割いた紙幅が後の 2 つの場面より明らかに多いことに気づくかもしれません――これは意図的なものです。リアルタイム・マルチモーダルというこの進化の線上で、音声は最も完全に、最も参照系とするに値するかたちで進んだ一つです。「直列パイプラインは遅延が高すぎる」というこの問題から出発し、エンドツーエンド、全二重、考えながら話す、といった一連の方式を経て、今日の相対的にかたちを成した終局まで進んでおり、問題→方式→終局の全行程がすでに走り抜けられています。だからこそ私たちはそれを徹底的に論じました。続く Computer Use とロボットの 2 つの場面は、いずれも音声のこの脈絡と対照して見ることができます――それぞれこの進化の線のどの段まで進んだのか、どこで行き詰まっているのか。 この 3 つの場面は一見異なりますが、同じ中核の挑戦に直面しています。リアルタイム知覚、低遅延の意思決定、持続的な対話です。続いて、これらの技術的主題が視覚対話(Computer Use)と物理対話(ロボット)でどう再現されるかを見ましょう――まず視点を聴覚モダリティから視覚モダリティへと広げます。もし Agent が音声を理解できるだけでなく、画面を「見て理解」し、グラフィカルインターフェースを操作できるとしたら? Computer Use(GUI 自動化 Agent とも呼ぶ)は、AI に人間のように画面を観察し、マウスとキーボードを操作してソフトウェアを使わせます――たとえばブラウザを開いて情報を検索する、表計算ソフトにデータを記入する、システム設定で構成を調整する、といった具合です。その中核は **知覚-思考-行動** のループです(図6-11)。 1. Agent が現在の画面をスクリーンショットする 2. マルチモーダルモデルがスクリーンショットとタスク指示を受け取り、一段の思考と一つの具体的な動作を出力する 3. 実行層が現実の環境でその動作を実行する(マウスを動かす、クリックする、文字を入力する、など) 4. インターフェースの応答を待ってから再びスクリーンショットし、次のループに入る ここでは、**インターフェースを理解すること**と**タスクを完了すること**を区別する必要があります。前者はマルチモーダル理解に近く、1 枚のスクリーンショットへの質問応答で測れます。後者は、理解と動作生成を閉ループに入れ、ページの読み込み、状態変化、誤操作、不可逆な結果を扱うことを求めます。したがって Computer Use の難しさは、スクリーンショットについて正しく答えるだけでなく、各ステップの後に現実がなお計画どおりかを再確認することにあります。 ![図6-11 Computer Use Agent の知覚-思考-行動ループ](images/fig6-11.svg) このループには 3 つの鍵となる設計次元があります。**行動空間**(Agent がどんな操作を実行できるか)、**視覚グラウンディング**(スクリーンショットの中でいかに目標要素を見つけるか)、そして **モデルアーキテクチャ**(スクリーンショットからいかに正しい動作を生成するか)です。 ### 行動空間の設計 Anthropic のリファレンス実装は、完全な対話能力を 3 種類のツールに分けています(図6-12)。これは明快な行動空間の設計ですが、モデル提供者が従うべき独自プロトコルではありません。Harness が同じスクリーンショット、動作制約、実行結果を対象モデルの対応するメッセージと構造化出力へ変換できれば、Claude、オープンウェイトの視覚モデル、セルフホストしたエンドポイントのいずれでも同じ知覚-思考-行動ループを駆動できます。 ![図6-12 Computer Use の行動空間](images/fig6-12.svg) **GUI 操作ツール**(computer tool):マウス操作には移動(mouse_move)、左/右/中ボタンのクリック、ダブル/トリプルクリック、ドラッグ(left_click_drag)、そしてより細かい押下/解放(left_mouse_down/up)が含まれます。スクロール(scroll)は 4 方向をサポートし、修飾キーと組み合わせられます。キーボード操作には一字ずつの入力(type、各文字の間隔 12ms で本物のタイピングを模す)、組み合わせキー(key、Ctrl+C など)、長押し(hold_key)が含まれます。知覚動作:スクリーンショット(screenshot)、カーソル位置の取得(cursor_position)、待機(wait)。 **コマンド実行ツール**(bash tool):持続的な bash ターミナルセッションを提供し、120 秒のタイムアウトで、番兵文字列によってコマンドの実行完了を検出し、複数回の呼び出しの間で環境の状態を保ちます(あるディレクトリに cd した後、次の呼び出しでもそのディレクトリにいる、など)。 **ファイル編集ツール**(str_replace_editor):文字列マッチングによって安全な編集を実現し、閲覧、作成、置換、挿入、取り消しの操作をサポートします。ファイル全体を直接上書きするより正確で、他の内容を誤って書き換えにくくなります。 > **実験 6-7 ★: Computer Use を実行する(Anthropic 参照経路またはオープンモデル経路)** > > 経路 A は Anthropic Computer Use Demo を使います。コンテナには、ブラウザ、ターミナル、その他の一般的なツールを含む、完全な Ubuntu デスクトップ環境がパッケージされています。フロントエンドがタスクを受け取り、バックエンドが指示とスクリーンショットを Claude に送り、モデルが返したマウス、キーボード、ターミナル、編集操作を実行します。 > > 経路 B は [`chapter6/computer-use-open-model`](../chapter6/computer-use-open-model/) のサンプルコードを使います。既定では、ホスト型の OpenRouter API を通して、あるいはセルフホストの vLLM/SGLang などを通して、オープンウェイトの Qwen3-VL 32B Instruct モデルで browser-use を駆動します。 ### 視覚グラウンディング(Grounding) ループの各ラウンドで、モデルはスクリーンショットの中で目標要素を正確に特定する必要があります――「検索ボックスはどこか?」「送信ボタンの座標は何か?」。これが視覚グラウンディング(Grounding)の問題です。現在、主に **2 つの大きな考え方** があります。一つはグラウンディングを **選択問題** に変えるもの――先にインターフェースの要素に番号を振っておき、モデルはその中から一つ選ぶだけです。もう一つは **純粋な座標予測** ――モデルに人間のように直接スクリーンショットを「見て」座標を報告させます。そのうち選択問題の考え方にはさらに 2 つの実装方式があります。**純視覚アノテーション**(オリジナルの Set-of-Mark、セグメンテーションモデルでピクセル上に候補領域を切り出す)と **構造化要素インデックス**(DOM/Accessibility Tree、インターフェースが備える構造を直接読み取る)です。選択問題の考え方の共通の利点は、開放的な「スクリーンショットの中でボタンを見つけて座標を予測する」を、閉じた「アノテーション済みの要素から一つ選ぶ」へと変えることです。試験で選択問題が穴埋め問題より正解しやすいのと同じで、モデルは「画面の (350, 464) の位置にあるボタンをクリック」ではなく「[123] をクリック」と言えばよいのです。座標を出力すること自体がモデルにとってはとりわけ難しい課題で、正確にこなすには大量の訓練が必要ですし、解像度が変わると誤りやすくもあります。 **Set-of-Mark:視覚アノテーション法。** オリジナルの Set-of-Mark(SoM)は 2023 年にマイクロソフトリサーチが提案したもので、当初は GPT-4V の視覚グラウンディング能力を引き出すためのものでした。それは **純視覚** の手法です。画像セグメンテーションモデル(SAM、SEEM など)でスクリーンショット上に候補領域を自動で切り出し、各領域に番号マーカーを重ねます。モデルが見るのは番号付きの画像で、番号を報告するだけでよく、システムが対応する領域の中心座標へ換算します。全過程で DOM を必要とせず、いかなるインターフェース内部の構造も必要としないため、ネイティブのデスクトップソフトウェアやゲームのインターフェースにも同様に適用できます――セグメンテーションモデルが候補領域を切り出せさえすれば。 **構造化要素インデックス:SoM の思想を Web 上で構造化して実装したもの。** インターフェース自体が構造化された情報を提供できるとき、アノテーションはより精確に行えます。現代のウェブページはレンダリング前にすでに完全な要素構造(DOM ツリー)と意味的な役割(どれがボタンで、どれが入力ボックスか)を定義しています。無障害インターフェース(Accessibility Tree)は多くのデスクトップアプリに類似の情報を提供します。browser-use プロジェクトに代表される Web Agent の方式はまさにこうしています。DOM から対話可能な要素を列挙して番号を振るもので、SoM の思想を Web 上で構造化して実装したものと見なせます(図6-13)。流れは 4 ステップに分かれます。 1. ブラウザのデバッグインターフェース(CDP、Chrome DevTools Protocol)を通じてウェブページの構造化表現(DOM ツリー)と無障害情報を取得する 2. どの要素が対話可能か(ボタン、入力ボックス、リンクなど)を自動で検出する 3. 各対話可能要素に一意の ID を振り、スクリーンショット上に境界ボックスを描く 4. 同時に、各 ID に対応する要素を記述したテキストリストを生成する ```text Screenshot: [画像中の主要な要素に [1]、[2]、[3]、[4] などの ID が付されている] Elements: [1] [2]