Agentic OS 技術スタックを下から読む 第13回:一体から複数へ ―― 難所は「間」にあり、実行ツリーで見る
前回まで見てきたのは、一体のエージェントをどう安全に走らせるかだった。
一体の運行時から、複数の編成へ
前回まで見てきたのは、一体のエージェントをどう安全に走らせるかだった。
外の環境からどう隔離するか。
必要な記憶をどう持たせるか。
長く続く仕事の途中で、どこまでを状態として残すか。
これは、エージェントを実用に近づけるうえで避けられない層である。一度の応答で終わるなら、話は比較的単純で済む。だが、実際の仕事は途中で道具を呼び、結果を読み、方針を変え、また実行する。そのためには、閉じ込める仕組みと、覚えておく仕組みが要る。
しかし、一体のエージェントには限界がある。
長く複雑な仕事を、すべて一つの文脈に詰め込むと、文脈は太っていく。調査も計画も実行も確認も、同じ主体が抱えることになる。最初は柔軟に見えるが、しだいに役割が曖昧になる。どの判断がどの結果につながったのかも追いにくくなる。
そこで自然に、仕事を分けたくなる。
調べる係。
計画する係。
実行する係。
確認する係。
それぞれに違う役割を持たせ、必要な情報だけを渡す。大きな仕事を小さな単位に分ける。これは、人間の組織でも、計算機のシステムでも、ごく普通の考え方である。
ただし、ここで一つ注意が要る。
一体を複数に分けると、問題が消えるわけではない。問題の場所が変わる。
今回から扱うのは、その層である。複数のエージェントをどう束ねるか。つまり、編成の層である。今回はその入口として、複数にした瞬間に何が難しくなるのか、そしてそれを見るにはなぜ実行ツリーが必要なのかを考える。
複数にすると、新しい問題が生まれる
一体のエージェントを複数に分けることには、明らかな利点がある。
一つひとつの仕事は小さくなる。役割もはっきりする。調査をするエージェントは調査に集中できる。実行するエージェントは、与えられた手順を進めることに集中できる。確認するエージェントは、結果の妥当性を見ることに集中できる。
これは、文脈を細く保つうえでも有効である。一体のエージェントにすべてを持たせるより、それぞれの役割に必要な情報だけを渡したほうが、判断の範囲を制御しやすい。
ここまではよい。
だが、分けた瞬間に、前は存在しなかった問題が生まれる。
エージェント同士は、どう情報を渡すのか。
どの順番で動くのか。
あるエージェントの判断を、別のエージェントはいつ信じてよいのか。
同じ対象に、二つのエージェントが同時に手を出したらどうするのか。
仕事は分かれても、結果は一つでなければならない。
たとえば、調査係が情報を集め、計画係が手順を作り、実行係がその手順を進めるとする。このとき、調査係の情報が途中で更新されたらどうなるか。計画係は古い情報をもとに計画を立てるかもしれない。実行係はその計画を信じて動くかもしれない。確認係が最後に失敗を見つけても、どこでずれたのかはすぐには分からない。
一体の中では、少なくとも状態は一つの流れの中にあった。もちろん、それでも誤りは起きる。だが、複数に分けると、状態は場所ごとに分かれる。判断も場所ごとに分かれる。時間の進み方も、完全にはそろわない。
ここで初めて、「間」の問題が出てくる。
本当の難所は、一体の中ではなく「間」にある
複数エージェントの不具合は、ある一体のエージェントの中だけを見ても見つからないことが多い。
それぞれを単体で見れば、妥当な判断をしている。調査係は、手元にある情報から自然な結論を出している。計画係は、その結論を前提に筋の通った手順を作っている。実行係も、渡された手順どおりに動いている。
それでも、全体としては壊れる。
なぜか。
一つの典型は、古い状態をもとに判断してしまうことである。
あるエージェントが、対象の状態を読み取る。その直後に、別のエージェントが同じ対象を書き換える。最初のエージェントは、その書き換えを知らないまま判断を続ける。本人にとっては正しい判断である。だが、前提がもう古い。
もう一つは、同じ資源への同時操作である。
二つのエージェントが、同じファイル、同じ設定、同じ記録、同じ外部の対象に手を出す。片方は追記するつもりで動き、もう片方は書き換えるつもりで動く。どちらの操作も単体では間違っていない。だが、同時に走ると、片方の結果が消えたり、途中状態を読んだりする。
この種の不具合は、エージェントの能力不足とは少し違う。
問題は、個々の判断の中にあるとは限らない。むしろ、二つの判断がいつ出て、どの順で実行され、どの状態を共有していたかにある。
つまり、バグはエージェントの中ではなく、エージェントとエージェントの間にある。
ここを見落とすと、直し方を間違える。単体の指示文をいくら整えても、同時に走る二つの操作が衝突しているなら、根本は変わらない。必要なのは、より丁寧な言い回しではなく、間にある状態と順序を見ることである。
平らなログでは、間が見えない
では、その「間」をどう見るか。
最初に思いつくのはログである。実行時刻、呼び出し内容、応答、エラー。こうした出来事を順番に記録する。これは必要である。ログがなければ、何も追えない。
ただ、時系列に並んだ一本のログだけでは足りない。
複数のエージェントが並行して動くと、ログにはいろいろな出来事が混ざる。調査係の出力のあとに、実行係の道具呼び出しがあり、その次に確認係の判断があり、さらに調査係の別の出力が来る。時間順には正しい。だが、それだけでは構造が分からない。
知りたいのは、単に「何が先に起きたか」ではない。
どの判断が、どの行動を生んだのか。
どの枝とどの枝が、同時に走っていたのか。
どの道具の呼び出しが、失敗の引き金になったのか。
誰が、すでに古くなった状態をもとに判断したのか。
平らなログは、出来事を一列に並べる。そのかわり、親子関係や並行関係を潰してしまう。
親子関係とは、ある判断が次の行動を生んだ、というつながりである。たとえば、計画係が「この資料を確認する」と決めたから、実行係が検索の道具を呼ぶ。この二つは、ただ時間的に近いだけではない。前者が後者の理由になっている。
並行関係とは、二つ以上の枝が同じ時間帯に進んでいた、という関係である。片方が外部の結果を待っているあいだに、もう片方が別の対象を書き換えている。失敗の原因は、この重なりにあるかもしれない。
一本のログでは、この形が見えにくい。
何が起きたかは並ぶ。だが、なぜそうなったかの形が消える。
複数エージェントの不具合を追うとき、本当に必要なのは、この形である。
だから、実行を木として見る
そこで、実行を木として見る。
木というのは、単に見た目の話ではない。ある出来事から、別の出来事が生まれる。そのつながりを、親と子として表すということである。
最初に、全体の仕事がある。そこから、調査、計画、実行、確認といった枝が生まれる。調査の枝の下には、情報を読む操作がある。実行の枝の下には、道具の呼び出しがある。確認の枝の下には、結果を比べる判断がある。
それぞれの節点には、種類がある。
ただ考えたのか。
道具を呼んだのか。
別のエージェントを呼び出したのか。
外部の結果を待っていたのか。
失敗して止まったのか。
こうして分けておくと、実行はただ流れていく文字列ではなくなる。読んで推論できる構造になる。
たとえば、ある失敗が最後に見つかったとする。平らなログでは、最後のエラーから上にさかのぼっていくしかない。だが、実行ツリーでは、そのエラーがどの枝に属しているかが分かる。さらに、その枝を生んだ判断も見える。別の枝が同じ時間に何をしていたかも見える。
すると、問いの立て方が変わる。
「このエージェントはなぜ失敗したのか」ではなく、「この枝は、どの前提から生まれ、どの枝と重なっていたのか」と見られる。
これは大きい。
複数エージェントの実行では、全体を一度に理解するのが難しい。関係者が増え、道具が増え、待ち時間も増える。そこに必要なのは、すべてを細かく読む努力ではなく、構造を先に見せる工夫である。
実行ツリーでは、見出しの付け方そのものが説明になる。
「調査の枝」
「計画の枝」
「実行中の道具呼び出し」
「確認で見つかった不一致」
こうしたまとまりが見えるだけで、初めて読む人でも全体の動きをつかみやすくなる。長いログを上から下まで追うより、どこを見るべきかを早く決められる。
もちろん、実行ツリーは魔法ではない。記録していないものは見えない。節点の粒度が粗すぎれば、原因はぼやける。細かすぎれば、今度は木そのものが読みにくくなる。
それでも、平らなログだけに比べれば、見えるものは大きく変わる。
とくに見えるようになるのは、間である。
多くの不具合は、モデルの不具合ではない
複数エージェントがうまく動かないとき、つい考えたくなることがある。
指示の出し方が悪かったのではないか。
もっと賢い判断ができれば防げたのではないか。
役割の説明を詳しくすればよいのではないか。
もちろん、そういう場合もある。曖昧な指示が、曖昧な行動を生むことはある。役割がぼやけていれば、余計なことまで始めることもある。
だが、実行を構造として見ると、別の原因が見えてくることが多い。
古い状態を読んでいた。
同じ資源に同時に手を出していた。
片方の操作が終わる前に、もう片方が判断していた。
失敗した道具呼び出しの結果を、成功したものとして扱っていた。
これらは、賢さだけの問題ではない。
むしろ、調停の問題である。
調停とは、複数の動きがぶつからないように、順序や権限や待ち方を決めることである。ある操作が進行中なら、終わるまで待たせる。重要な資源には、同時に一つの枝しか触れないようにする。衝突しやすい操作は、並行ではなく順番に行う。失敗した道具呼び出しは、その場で分かる形にして、後続の判断に混ぜない。
こうした設計は、指示文を少し直すだけでは代替できない。
見えないまま指示文をいじり続けると、時間を使うわりに原因に届かない。ある日はうまく動き、別の日にまた壊れる。なぜ直ったのかも、なぜ壊れたのかも分からない。
実行ツリーがあると、直す場所を決めやすくなる。
失敗が一つの枝の内部に閉じているなら、そのエージェントの判断や道具の扱いを見る。複数の枝の重なりで起きているなら、順序や排他を見直す。古い状態を前提にしているなら、状態の読み直しや確認の場所を変える。
原因の形が違えば、直し方も違う。
ここを混ぜてしまうと、すべてを「モデルの問題」として扱ってしまう。だが実際には、多くの不具合は、モデルの中ではなく、モデルを含む実行の組み方にある。
Agentic OS への含意
オペレーティングシステムで複数のプロセスを動かすとき、必要になるのは実行そのものだけではない。
何が動いているのか。
何が待っているのか。
どこで詰まっているのか。
どの処理が、どの資源を使っているのか。
こうしたことが見えなければ、調停も最適化もできない。動いているものが見えないままでは、順序を変えることも、待たせることも、止めることも難しい。
複数のエージェントでも同じである。
一体のエージェントを安全に走らせる段階では、隔離と記憶が中心だった。何に触れてよいか。何を覚えるか。どこまでを実行環境として閉じるか。これは運行時の問題である。
そこから複数の編成へ進むと、中心は「間」に移る。
エージェント同士がどうつながるか。どの判断がどの行動を生むか。どの枝が同時に走るか。どの状態を共有するか。どこで待ち、どこで進めるか。
この層では、束ね方を考える前に、まず見えるようにしなければならない。
実行ツリーは、そのための土台である。複数のエージェントを、ただの呼び出し列としてではなく、構造を持った実行として扱う。これによって初めて、失敗の場所を分けられる。単体の判断の問題なのか。道具の扱いの問題なのか。枝どうしの衝突なのか。古い状態を前提にした問題なのか。
見える化は、後付けの観察機能ではない。
編成の前提である。安全の前提でもある。評価の前提でもある。何が起きたかを構造として見られなければ、複数エージェントの良し悪しを判断することもできない。
今回見たのは、編成そのものの入口である。
一体から複数へ進むと、仕事は分けられる。だが、難しさは消えない。難しさは、分けられたものの間に移る。そして、その間を見るには、平らなログだけでは足りない。実行を木として見なければならない。
次回は、この見える化を前提に、複数のエージェントをどんな形に束ねるかへ進む。役割をどう分けるか。誰が誰を呼ぶか。段数が増えるほど、信頼性にどんな崖が現れるか。編成の具体的な形は、そこから考える。
← 一覧へ