← 一覧へ
連載 Agentic OS:技術スタックを下から読む の一部です ―― 目次を見る →

Agentic OS 技術スタックを下から読む 第13回:一体から複数へ ―― 難所は「間」にあり、実行ツリーで見る

この記事の読み方
前回まで見てきたのは、一体のエージェントをどう安全に走らせるかだった。

一体の運行時から、複数の編成へ

前回まで見てきたのは、一体のエージェントをどう安全に走らせるかだった。

外の環境からどう隔離するか。
必要な記憶をどう持たせるか。
長く続く仕事の途中で、どこまでを状態として残すか。

これは、エージェントを実用に近づけるうえで避けられない層である。一度の応答で終わるなら、話は比較的単純で済む。だが、実際の仕事は途中で道具を呼び、結果を読み、方針を変え、また実行する。そのためには、閉じ込める仕組みと、覚えておく仕組みが要る。

しかし、一体のエージェントには限界がある。

長く複雑な仕事を、すべて一つの文脈に詰め込むと、文脈は太っていく。調査も計画も実行も確認も、同じ主体が抱えることになる。最初は柔軟に見えるが、しだいに役割が曖昧になる。どの判断がどの結果につながったのかも追いにくくなる。

そこで自然に、仕事を分けたくなる。

調べる係。
計画する係。
実行する係。
確認する係。

それぞれに違う役割を持たせ、必要な情報だけを渡す。大きな仕事を小さな単位に分ける。これは、人間の組織でも、計算機のシステムでも、ごく普通の考え方である。

ただし、ここで一つ注意が要る。

一体を複数に分けると、問題が消えるわけではない。問題の場所が変わる。

今回から扱うのは、その層である。複数のエージェントをどう束ねるか。つまり、編成の層である。今回はその入口として、複数にした瞬間に何が難しくなるのか、そしてそれを見るにはなぜ実行ツリーが必要なのかを考える。

複数にすると、新しい問題が生まれる

一体のエージェントを複数に分けることには、明らかな利点がある。

一つひとつの仕事は小さくなる。役割もはっきりする。調査をするエージェントは調査に集中できる。実行するエージェントは、与えられた手順を進めることに集中できる。確認するエージェントは、結果の妥当性を見ることに集中できる。

これは、文脈を細く保つうえでも有効である。一体のエージェントにすべてを持たせるより、それぞれの役割に必要な情報だけを渡したほうが、判断の範囲を制御しやすい。

ここまではよい。

だが、分けた瞬間に、前は存在しなかった問題が生まれる。

エージェント同士は、どう情報を渡すのか。
どの順番で動くのか。
あるエージェントの判断を、別のエージェントはいつ信じてよいのか。
同じ対象に、二つのエージェントが同時に手を出したらどうするのか。

仕事は分かれても、結果は一つでなければならない。

たとえば、調査係が情報を集め、計画係が手順を作り、実行係がその手順を進めるとする。このとき、調査係の情報が途中で更新されたらどうなるか。計画係は古い情報をもとに計画を立てるかもしれない。実行係はその計画を信じて動くかもしれない。確認係が最後に失敗を見つけても、どこでずれたのかはすぐには分からない。

一体の中では、少なくとも状態は一つの流れの中にあった。もちろん、それでも誤りは起きる。だが、複数に分けると、状態は場所ごとに分かれる。判断も場所ごとに分かれる。時間の進み方も、完全にはそろわない。

ここで初めて、「間」の問題が出てくる。

本当の難所は、一体の中ではなく「間」にある

複数エージェントの不具合は、ある一体のエージェントの中だけを見ても見つからないことが多い。

それぞれを単体で見れば、妥当な判断をしている。調査係は、手元にある情報から自然な結論を出している。計画係は、その結論を前提に筋の通った手順を作っている。実行係も、渡された手順どおりに動いている。

それでも、全体としては壊れる。

なぜか。

一つの典型は、古い状態をもとに判断してしまうことである。

あるエージェントが、対象の状態を読み取る。その直後に、別のエージェントが同じ対象を書き換える。最初のエージェントは、その書き換えを知らないまま判断を続ける。本人にとっては正しい判断である。だが、前提がもう古い。

もう一つは、同じ資源への同時操作である。

二つのエージェントが、同じファイル、同じ設定、同じ記録、同じ外部の対象に手を出す。片方は追記するつもりで動き、もう片方は書き換えるつもりで動く。どちらの操作も単体では間違っていない。だが、同時に走ると、片方の結果が消えたり、途中状態を読んだりする。

この種の不具合は、エージェントの能力不足とは少し違う。

問題は、個々の判断の中にあるとは限らない。むしろ、二つの判断がいつ出て、どの順で実行され、どの状態を共有していたかにある。

つまり、バグはエージェントの中ではなく、エージェントとエージェントの間にある。

ここを見落とすと、直し方を間違える。単体の指示文をいくら整えても、同時に走る二つの操作が衝突しているなら、根本は変わらない。必要なのは、より丁寧な言い回しではなく、間にある状態と順序を見ることである。

平らなログでは、間が見えない

では、その「間」をどう見るか。

最初に思いつくのはログである。実行時刻、呼び出し内容、応答、エラー。こうした出来事を順番に記録する。これは必要である。ログがなければ、何も追えない。

ただ、時系列に並んだ一本のログだけでは足りない。

複数のエージェントが並行して動くと、ログにはいろいろな出来事が混ざる。調査係の出力のあとに、実行係の道具呼び出しがあり、その次に確認係の判断があり、さらに調査係の別の出力が来る。時間順には正しい。だが、それだけでは構造が分からない。

知りたいのは、単に「何が先に起きたか」ではない。

どの判断が、どの行動を生んだのか。
どの枝とどの枝が、同時に走っていたのか。
どの道具の呼び出しが、失敗の引き金になったのか。
誰が、すでに古くなった状態をもとに判断したのか。

平らなログは、出来事を一列に並べる。そのかわり、親子関係や並行関係を潰してしまう。

親子関係とは、ある判断が次の行動を生んだ、というつながりである。たとえば、計画係が「この資料を確認する」と決めたから、実行係が検索の道具を呼ぶ。この二つは、ただ時間的に近いだけではない。前者が後者の理由になっている。

並行関係とは、二つ以上の枝が同じ時間帯に進んでいた、という関係である。片方が外部の結果を待っているあいだに、もう片方が別の対象を書き換えている。失敗の原因は、この重なりにあるかもしれない。

一本のログでは、この形が見えにくい。

何が起きたかは並ぶ。だが、なぜそうなったかの形が消える。

複数エージェントの不具合を追うとき、本当に必要なのは、この形である。

だから、実行を木として見る

そこで、実行を木として見る。

木というのは、単に見た目の話ではない。ある出来事から、別の出来事が生まれる。そのつながりを、親と子として表すということである。

最初に、全体の仕事がある。そこから、調査、計画、実行、確認といった枝が生まれる。調査の枝の下には、情報を読む操作がある。実行の枝の下には、道具の呼び出しがある。確認の枝の下には、結果を比べる判断がある。

それぞれの節点には、種類がある。

ただ考えたのか。
道具を呼んだのか。
別のエージェントを呼び出したのか。
外部の結果を待っていたのか。
失敗して止まったのか。

こうして分けておくと、実行はただ流れていく文字列ではなくなる。読んで推論できる構造になる。

たとえば、ある失敗が最後に見つかったとする。平らなログでは、最後のエラーから上にさかのぼっていくしかない。だが、実行ツリーでは、そのエラーがどの枝に属しているかが分かる。さらに、その枝を生んだ判断も見える。別の枝が同じ時間に何をしていたかも見える。

すると、問いの立て方が変わる。

「このエージェントはなぜ失敗したのか」ではなく、「この枝は、どの前提から生まれ、どの枝と重なっていたのか」と見られる。

これは大きい。

複数エージェントの実行では、全体を一度に理解するのが難しい。関係者が増え、道具が増え、待ち時間も増える。そこに必要なのは、すべてを細かく読む努力ではなく、構造を先に見せる工夫である。

実行ツリーでは、見出しの付け方そのものが説明になる。

「調査の枝」
「計画の枝」
「実行中の道具呼び出し」
「確認で見つかった不一致」

こうしたまとまりが見えるだけで、初めて読む人でも全体の動きをつかみやすくなる。長いログを上から下まで追うより、どこを見るべきかを早く決められる。

もちろん、実行ツリーは魔法ではない。記録していないものは見えない。節点の粒度が粗すぎれば、原因はぼやける。細かすぎれば、今度は木そのものが読みにくくなる。

それでも、平らなログだけに比べれば、見えるものは大きく変わる。

とくに見えるようになるのは、間である。

多くの不具合は、モデルの不具合ではない

複数エージェントがうまく動かないとき、つい考えたくなることがある。

指示の出し方が悪かったのではないか。
もっと賢い判断ができれば防げたのではないか。
役割の説明を詳しくすればよいのではないか。

もちろん、そういう場合もある。曖昧な指示が、曖昧な行動を生むことはある。役割がぼやけていれば、余計なことまで始めることもある。

だが、実行を構造として見ると、別の原因が見えてくることが多い。

古い状態を読んでいた。
同じ資源に同時に手を出していた。
片方の操作が終わる前に、もう片方が判断していた。
失敗した道具呼び出しの結果を、成功したものとして扱っていた。

これらは、賢さだけの問題ではない。

むしろ、調停の問題である。

調停とは、複数の動きがぶつからないように、順序や権限や待ち方を決めることである。ある操作が進行中なら、終わるまで待たせる。重要な資源には、同時に一つの枝しか触れないようにする。衝突しやすい操作は、並行ではなく順番に行う。失敗した道具呼び出しは、その場で分かる形にして、後続の判断に混ぜない。

こうした設計は、指示文を少し直すだけでは代替できない。

見えないまま指示文をいじり続けると、時間を使うわりに原因に届かない。ある日はうまく動き、別の日にまた壊れる。なぜ直ったのかも、なぜ壊れたのかも分からない。

実行ツリーがあると、直す場所を決めやすくなる。

失敗が一つの枝の内部に閉じているなら、そのエージェントの判断や道具の扱いを見る。複数の枝の重なりで起きているなら、順序や排他を見直す。古い状態を前提にしているなら、状態の読み直しや確認の場所を変える。

原因の形が違えば、直し方も違う。

ここを混ぜてしまうと、すべてを「モデルの問題」として扱ってしまう。だが実際には、多くの不具合は、モデルの中ではなく、モデルを含む実行の組み方にある。

Agentic OS への含意

オペレーティングシステムで複数のプロセスを動かすとき、必要になるのは実行そのものだけではない。

何が動いているのか。
何が待っているのか。
どこで詰まっているのか。
どの処理が、どの資源を使っているのか。

こうしたことが見えなければ、調停も最適化もできない。動いているものが見えないままでは、順序を変えることも、待たせることも、止めることも難しい。

複数のエージェントでも同じである。

一体のエージェントを安全に走らせる段階では、隔離と記憶が中心だった。何に触れてよいか。何を覚えるか。どこまでを実行環境として閉じるか。これは運行時の問題である。

そこから複数の編成へ進むと、中心は「間」に移る。

エージェント同士がどうつながるか。どの判断がどの行動を生むか。どの枝が同時に走るか。どの状態を共有するか。どこで待ち、どこで進めるか。

この層では、束ね方を考える前に、まず見えるようにしなければならない。

実行ツリーは、そのための土台である。複数のエージェントを、ただの呼び出し列としてではなく、構造を持った実行として扱う。これによって初めて、失敗の場所を分けられる。単体の判断の問題なのか。道具の扱いの問題なのか。枝どうしの衝突なのか。古い状態を前提にした問題なのか。

見える化は、後付けの観察機能ではない。

編成の前提である。安全の前提でもある。評価の前提でもある。何が起きたかを構造として見られなければ、複数エージェントの良し悪しを判断することもできない。

今回見たのは、編成そのものの入口である。

一体から複数へ進むと、仕事は分けられる。だが、難しさは消えない。難しさは、分けられたものの間に移る。そして、その間を見るには、平らなログだけでは足りない。実行を木として見なければならない。

次回は、この見える化を前提に、複数のエージェントをどんな形に束ねるかへ進む。役割をどう分けるか。誰が誰を呼ぶか。段数が増えるほど、信頼性にどんな崖が現れるか。編成の具体的な形は、そこから考える。

← 一覧へ