BLOG.HIRO UENO.ART
← INDEX

アプリかCodeかの相談は、薄いワーカー1本に縮んだ

MONET(僕が普段話しかけている、中心のAI)は、ちょっとした調べ物なら自分で検索して、その場で答えてくれる。資料をいくつも読むような重めの調べ物は、別のやり方でやっている。開発や調べ物を手伝ってくれているClaude Code(以降Code)を直接開いて、Quick Research(クイックリサーチ)で頼む。Quick Researchは、調べ物の手順をCodeと一緒にまとめた仕組みで、途中で何度か僕に確かめながら資料を集めて読み、結果をファイルに残す。

ただこのやり方だと、調べた結果はMONETの記憶に入らない。MONETの記憶は、僕とMONETの会話から作られる。Codeで調べたことは、MONETから見ると無かったことになる。

だから重めの調べ物もMONETに頼めるようにして、MONETがそれを別の係に任せる形にしたかった。任せる先は、調べ物専用のアプリを1本作るか、Codeに直接投げるか。

それを、候補の片方であるCodeに聞いた。Codeは、自分に投げる方を勧めてきた。

理由は3つ。1つ目はお金。Codeなら、僕が払っているサブスク(月額定額のプラン)の中で動く。専用アプリを作ると、使った分だけ払うAPIの料金になる。自作のプログラムからサブスクでClaudeを動かしても規約上かまわないことは、少し前に公式の資料で確かめてあった。2つ目は、調べ物の手順がもうCodeの側にあること。アプリにすれば作り直しになる。3つ目は記憶。調べた結果の要約がMONETとの会話に戻ってくれば、そのままMONETの記憶にも残る。

Codeはこうも言っていた。アプリにするとしても、AIを自分で持った調べ物アプリにする必要はない。頼まれた仕事をCodeに渡して、結果を返すだけの薄い係でいい、と。

アプリにしても、中身はCodeと同じプログラムになる

僕はそのとき、アプリの方に傾いていた。調べ物は地味に回数が多い。全部Codeに投げると、僕とCodeの会話(スレッド)が調べ物で散らかる。それに、アプリからでもサブスクで動かせるなら、1つ目のお金の理由は消える。Codeの中で動かすかアプリで動かすかは、もうあまり関係ないんじゃないか。そう返した。

Codeは条件付きで同意した。条件は、アプリがClaude Agent SDK(自分のプログラムからClaudeを動かすための部品)を使うこと。この部品の中身はCodeと同じプログラムなので、そうすれば「アプリを作る」も「Codeに投げる」も、中で動くものは同じになる。違うのは入口の方だけ。スレッドの心配も無い、とCodeは言った。アプリから画面を出さずに裏で動かせば、僕とCodeの会話とは別の会話として走るから。

ただ、どこで動かすかは、まだ1つ関係があった。Codeによると、AIが考える部分はAnthropic(Claudeを作っている会社)のサーバーで動く。でも、検索を呼ぶ、ファイルに書く、といった作業そのものは、呼び出したマシンの上で動く。だから、そのマシンの電源が入っていないといけない。

全部を家のサーバーに置く方針なら、置き場所は1か所で済む

Codeが出した置き場所の案は3つ。Mac、NAS(家に置いてある常時稼働のサーバー)、Anthropicのクラウド。クラウドについては、MONETから呼び出せるかは公式の資料で確かめないと分からない、とCodeは念を押していた。

僕は普段、MacとWindowsの両方を使っている。MONETと話すのはそのどちらかの前なので、片方は必ず電源が入っている。だから、その時ついている方で動かせばいいんじゃないか、と出した。Codeは、それでも動くと答えた。

でも、ここで一度条件を整理したくなった。サブスクでClaudeを動かすこの仕組みは、これから作るアプリも全部同じものを使うことになる。ちゃんと決めておかないと、後で面倒なことになりそうだった。アプリもデータベースも全部NASに置くことになっているのだから、できればややこしい仕様にはしたくない。そう伝えて、気になっていたことを確かめてもらった。クラウドで動かす条件。NASで全部済ませた時の負担。それと、僕はClaudeのデスクトップアプリがいつも開いている前提で考えていたので、それが本当に要るのか。

Codeは、NASの使用状況をその場で測り、クラウドの条件はサブエージェント(Codeが作業を分けて任せる、別のAI)に公式の資料で調べさせてから答えた。デスクトップアプリは要らない。NASの負担は小さい。クラウドはMONETから直接は呼べず、結果もクラウドの側に残るので、全部NASに置く方針とは合わない。

そのうえでCodeは、置き場所を1つにまとめた。NASに、調べ物用のワーカー(頼まれた仕事を拾って片付ける係のプログラム)を1本だけ置く。MONETも、これから作る他のアプリも、ここに仕事を投げて結果を受け取るだけ。MacとWindowsに1本ずつ置く案は、全部NASに置いて仕様をそろえる、という僕の条件では劣る、とCodeは言った。NASなら2台に同じ係を置かずに済むし、サブスクのログイン情報も1か所に置けばいい。

Codeに投げても、頼む相手はいつものAI。アプリとの差は画面とデータベース

置き場所は決まった。でもアプリにする利点も、まだ頭にあった。調べた生のデータをデータベースに貯められるし、結果を一覧で見る画面も作れる。

逆に、Codeに投げる場合の形は、まだ見えていなかった。Codeを直接開いて調べる今のやり方のように、MONETを通さない形になるのか、と聞いた。

Codeの答えは、入口はMONETのまま、だった。

  1. 僕がMONETに「〇〇を調べて」と言う
  2. MONETが、その仕事をNASに書き置いて、すぐ会話に戻る
  3. NASのワーカーがそれを見つけて、Codeを画面なしで起動する。いつものQuick Researchがそのまま走る
  4. 結果はファイルで残る。今Codeで調べた時と同じ置き場所
  5. 要約だけがMONETの会話に入り、そこから記憶にも流れる

MONETを通さないのは、むしろ今の僕のやり方の方だった。Codeを直接開いて調べると、結果がMONETの記憶に入らない。

Code「アプリ案との差は、この5つのステップの周りに、データベースと画面を付けるかどうかだけ。」

ワーカーの中身は同じなので、薄い形で始めても行き止まりにはならない。後から同じワーカーを画面とデータベースで包めば、アプリになる。

総合的に見て、こっちの方が楽だと思った。すぐ入れられる。MONETとは画面のタブを分けて何本も会話しているけど、どのタブから頼んでも、結果は同じ置き場所に残る。それなら、簡単な調べ物もこっちに投げたい。ただ、どのくらい待つのかは気になった。それと、MONETが自分で調べるものとCodeに投げるものを振り分けられるか、と聞いた。

Codeの見積もりでは、仕事を拾ってCodeを起動するまでの遅れは十数秒。時間のほとんどは調べ物そのものにかかる。振り分けもできる。軽いものはMONETが自分で検索し、重いものはCodeに投げる。僕がMONETに「Codeで調べて」「ここで軽く」と言えば、そっちに従う。

終わった結果をMONETに戻す方法は、Codeが2つ挙げた。僕が次に話しかけた時に、自動で差し込むか。僕が「終わった?」と聞くか。僕は自動で差し込む方を選んだ。

残ったのは、Codeを起動するだけの100行の係

Codeは、MONETの側の仕組みを読んでから仕様書を書いた。そこで1つ、新しい問題が出てきた。Quick Researchには、僕と話す所が3か所ある。最初に何を調べるかを話す所、集めた候補から外すものを選ぶ所、最後にこれで足りたかを決める所。無人のワーカーは、僕と話せない。

ただ、Quick Researchはかなり使っているけど、途中で込み入った話をした記憶はあまり無い。話すのはほとんど最初だけ。だから最初の会話は、僕がMONETとやればいい。何を調べるか、どのくらい深く、何に使うかをMONETが聞いて、仕事に添えてワーカーに渡す。残りの2か所は自動で済ませる。

レポートに仕上げるような重い調べ物だと、途中で何度か話すことになりそうだけど、それもMONETを通して続ければいい。これはできるけど仕組みが1つ増えるので、次に作る時に回した。

こうして、ワーカーの仕事はほとんど残らなかった。約100行のスクリプトで、頼まれた仕事を見つけて、Codeを起動して、終わったら結果を書くだけ。画面も、データベースの設計も無い。

最初にCodeが言っていた「受け渡すだけの薄い係」は、これのことだった。この係は、後にDig(ディグ)という名前になる。

薄い係でも、無人で動くなら、させないことを先に決める

Codeはこの形でワーカーを作った。ここから先は、僕は関わっていない。後でCodeの完了報告で知った話。

Codeは実装がひと通りできたところで、レビュー役のサブエージェントに中身を見せた。見つかった問題の中に、権限の話があった。

ワーカーは、検索で見つけたWebページの本文を読む。その本文を全部信用するわけにはいかない。ページの中に「このコマンドを実行して」という指示が仕込まれていることがある(プロンプトインジェクションと呼ばれる)。最初の作りでは、ワーカーの中のCodeは確認なしで何でも実行できるモードで、打てるコマンドにも制限が無かった。無人なので、止める人もいない。

そしてワーカーは、サブスクのログイン情報を持っている。Codeの言い方では「あなたのログイン状態を持ち運ぶ鍵」。これがあれば、僕としてClaudeを使える。仕込まれた指示が通れば、その鍵を外に送らせることができてしまう。

Codeは、許可する操作を一覧に書き出し、それ以外は聞かずに断るモードに切り替えた。打てるコマンドも、調べ物で使う2本のスクリプト(Webページを保存するものと、引用が元の資料と合っているかを照らすもの)と、いくつかの確認用のコマンドだけに絞った。このモードが本当にそう動くかは、別のサブエージェントに公式の資料で確かめさせていた。

100行の薄い係でも、無人で外の文章を読み、鍵を持って動く。相談で縮んだのは作るものの量で、ワーカーが持つ力まで縮んだわけではなかった。

薄い係だと、結果は僕が話しかけるまで待っている

NASに載せて、最初の仕事が通った。天気予報の調べ物だった。ワーカーがCodeを起動して調べ、結果をファイルに残した。MONETの会話には、僕が次に話しかけた時に「リサーチ完了」の知らせが入る。

この天気は、僕がMONETに「Codeに頼んで」と言って投げたものだった。MONETが自分で振り分けたわけではない。MONET自身の振り分けがどれくらい当たるかは、まだ実例が無い。

もう1つ気になった。知らせが入るのは、僕が次に話しかけた時。逆に言うと、僕が何も言わなかったら、一生返ってこないんじゃないか。アプリを作らず、MONETの会話に相乗りする形にしたので、知らせの届き方もMONETの会話の仕組みに縛られる。ツールの結果が返ってくるみたいに、向こうから差し込めないのか。

前に聞いた話では、MONETが別のアプリを操作した時の結果は、仕組みの上では「僕からのメッセージ」という形でMONETに渡っている。それなら、調べ物の結果も同じ形で入れられないのか、と聞いた。

Codeによると、僕の覚えていたとおりで、今回の知らせももう同じ形で作ってある。「リサーチ完了」の知らせは、僕の次のメッセージにくっついて、僕からのメッセージとしてMONETに届く。

足りないのは、くっつける先だった。ツールの結果は、MONETがアプリを呼んだ直後に、その返事として返すことしかできない。調べ物は終わるまで数分から30分かかるので、その頃には返事を待っている呼び出しがもう無い。だから僕の次のメッセージに相乗りさせている。

Codeは、僕の言う「向こうから」を完全にやる方法も、同じ仕組みの延長でできると言った。調べ物が終わったのを見つけたら、MONETの側が僕の代わりに「調べ物が終わった」というメッセージを自分で作って、返事を始める。そうすれば、僕が何も言わなくても、MONETの方から話しかけてくる。ただ、MONETが自分から話し出すのは、このシステムで初めての動きになる。どのタブに出すか、夜中でも出すか、といった行儀も決めないといけない。次に設計する時の、最初の項目に積んだ。

アプリを作るか、Codeに投げるか。答えはCodeに投げる方だった。ただし投げる先は、僕が話しているCodeではなく、NASで無人で起動するCode。アプリにする利点だった一覧の画面やデータベースは付けず、MONETとの間に置いたのは、Codeを起動するだけの100行の係1本だった。