hyuntae's blog

AIにコーディングを任せ始めてから③ — AIサーバーが落ちたら自分も馬鹿になる

2026-06-30AI|閲覧数: 17
目次

AI適応記(全4部)

  1. さまざまなツールを試し、最後は自分で作るまで
  2. AIが「働く」システム — エンジニアリングと検証オーナーシップ
  3. AIサーバーが落ちたら自分も馬鹿になる — ローカルLLMとAI依存 ← 今読んでいる記事
  4. AIを追いかけながら、AIとともに — 学び方まで変わった

第2部の最後で触れたように、「AIに置き換えられるのではないか」という恐れが収まった場所に、別の恐れが育っていた。AIが止まれば自分も一緒に止まってしまうのではないかという、依存への不安だ。この記事は、その不安を減らそうとローカルLLMまで動かしてみた実験の記録だ。結論から言うと、ローカルLLMはその依存をゼロにしてくれる道具ではなかった。ただその過程で、それまでただ使うだけだったAIを、初めて自分の手で直接立ち上げ、触り、チューニングしてみた。ブラックボックスを開けてみたようなものだ。

ローカルLLMを作った本当の理由は「トークン」だった

まず誤解を解いておこう。ローカルLLMに手を出した最初の動機は、大それた「依存からの脱却」ではなかった。純粋にトークンを節約するためだった。第2部で見た生産性爆増の裏には、週に数億トークンを燃やして5時間・週間の上限を使い果たす現実があった。ちょうどGemma 4が登場し、「ローカルモデルの性能がすごい」という話が広まっていた時期でもあり、「軽い作業ならローカルで回せばトークンを節約できるのでは」という計算が自然に働いた。

肝心の「AI依存」という重い悩みは、始めた時ではなく、実験をしばらく回してから向き合うことになった。トークンを節約しようと始めたことが、いつのまにか*「AIにここまで頼っていいのか*」という問いの前に自分を連れてきていたのだ。

自宅のWindows PC: 12GB GPUの壁

まず自宅のWindows PCにローカルLLMを載せた。12GBメモリのGPUにOllamaを入れ、Gemma系のモデルを立ち上げた。起動時にログインなしで自動的に立ち上がるようバックグラウンドサービスとして登録し、Obsidianウィキと連携させていろいろな質問を投げてみた。

結論から言うと、12GBではコンテキスト容量が小さすぎて、実戦にはほとんど役立たなかった。せいぜい、ウィキを参照して質問に答えてくれる「秘書」レベルにとどまった。コーディングエージェントの代わりには到底ならなかった。

なぜ12GBが足を引っ張ったのかは、押さえておく価値がある。GPUメモリはまずモデルの重みを載せるのに使われ、その次にKVキャッシュ(アテンションが参照する、トークンごとに積み上がるキー・バリューのテンソル)に使われる。このKVキャッシュはコンテキスト長に比例して線形に膨らむ。最新モデルがGQA(Grouped-Query Attention)のような手法でKVキャッシュのサイズを減らしたとはいえ、コーディングエージェントが要求する32k・64kトークン台の長いコンテキストでは、KVキャッシュだけで数GBが消える。重みを載せた残りのわずかなメモリでそれをまかなうしかないので、実際に使えるコンテキストウィンドウが大きく縮んでしまう。コーディングエージェントはツール定義とファイルのコンテキストだけで簡単に数万トークンを消費するのに、そのウィンドウが小さければそもそも話にならない。

舞台を会社へ: 余ったMacBook 4台をつなぐ

自宅で単一マシンの壁にぶつかっていた頃、会社にはちょうど遊んでいるMacBookが4台あった。「余った機材でローカルLLMを組んでトークンを節約しよう」という話が自然に持ち上がり、自分が自宅で少し経験を積んでいたので、それを活かそうという流れになった。そこで自分を中心に、4台のMacBookと第2部で触れたKarpathy式Obsidian、そしてsyncthingを組み合わせて社内用ローカルエージェントクラスターを作り始めた。

ところが機材が1台から4台に増えると、自宅では見えなかった種類の壁が次々と現れた。以下は、その4台をセットアップする中でぶつかった問題だ。

実測はもっと痛かった — 初回応答60秒、そして二者択一の問題

期待は「クラウドなしでも似たように動く」だった。現実は数字で反論してきた。

初回応答が遅かった。フルのツールコンテキスト(約22kトークン)をprefillする最初のメッセージに約60秒かかった。クラウドの即答に慣れた身には長すぎる時間だった。prefillとは、モデルが最初のトークンを出す前に入力全体を一度なめてKVキャッシュを満たす段階で、入力が長いほど、そしてハードウェアが非力なほどこの区間は長くなる。

ここで最も痛いトレードオフにぶつかった。機材が4台あるのだから、自然と「負荷を複数台に分けて回そう」という考えになったが、実際には**「速い後続応答」と「複数台への分散」は同時には成立しなかった。**

  • Ollamaにはprefix KVキャッシュ機能がある。同じprefix(例: 毎回同じシステムプロンプト+ツール定義)を再利用すると、その部分のprefillを再計算せずキャッシュから取ってくる。実際に同じprefixを再利用したところ、prefillが約3.2秒から0.03秒に落ちた。100倍だ。
  • ところが負荷を4台に分散しようと毎回の呼び出しを新しいセッションとして投げると(ステートレスなディスパッチャー)、そのprefixキャッシュはそのたびに死んでしまう。つまり速くするにはキャッシュを生かす必要があり、キャッシュを生かすには一箇所に居続ける必要がある。分散とキャッシュが真っ向からぶつかったのだ。

しばらくは分散をあきらめる方向に傾いた。4台に分けるのをやめて1台がモデルを抱えたまま直接受けるようにすれば、少なくともキャッシュは生きるからだ。しかしそれは残りの機材を遊ばせる中途半端な解決策だった。

本当の解決はエンジンを乗り換えたことで訪れた。Ollamaはアイドル状態になるとモデルをメモリから下ろしてしまい、keep_alive=-1で固定しておいても、ツールが大量に付いたリクエストでは毎回~60秒が再発した。そこでOllamaを捨ててllama.cppllama-serverに乗り換えた。プロセスが立ち上がっている限りモデルを下ろさないので、アンロードでキャッシュがまるごと消える問題からしてなくなった。

分散も同じ作業の中で組み直した。毎回の呼び出しをステートレスにワーカーへばらまく代わりに、ゲートウェイ1箇所でペルソナ・検索・コンテキストをすべて付けた「完成したプロンプト」を作り、それをワーカーに渡すようにした。ワーカーがそれぞれプロンプトを組み立てると、改行1つ、空白1つの違いだけでもllama.cppのprefixキャッシュマッチング(最長共通prefixを探す方式)が崩れがちだ。ゲートウェイが単一の情報源としてプロンプトを決定論的に完成させて渡すことで入力フォーマットが統一され、複数台に分散しながらもキャッシュを高い確率で生かせるようになった。機材をワーカーとしてまとめ、そのうちの1台にゲートウェイを兼任させると、「分散かキャッシュか」というジレンマがようやく解けた。

トークンを少し節約しようと始めたことなのに、いつのまにか推論エンジンを差し替え、ゲートウェイを立て、キャッシュの動作を覗き込んでいた。

品質の天井と運用の細々とした手間

性能そのものにも天井があった。最初はもっと軽いGemma 12Bで十分だと思っていた。ところが12Bは26Bよりむしろ遅かった。使っていた26BがMoE(Mixture of Experts)モデルだったからだ。26Bはパラメータの総量こそ26Bだが、1トークンを処理する際に実際に起動するエキスパートは約4Bにすぎない(モデル名26b-a4ba4bは「アクティブ4B」を意味する)。一方12Bはdenseなので、1トークンごとに12B全体が演算に入る。しかもトークン生成はメモリ帯域幅がボトルネックになる作業(memory-bandwidth bound)であり、トークンごとにアクティブな重みをメモリから読み出す量が速度を左右する。26B-MoEはトークンあたり4Bだけ読めばよく、12B-denseは毎回12Bを丸ごと読み込まなければならないので、アクティブ4Bの26Bのほうが速かった。「小さいモデルほど速い」という直感は、dense同士のときにしか成り立たない。(量子化は26B全体をMacBookのメモリに載せるために使った手段にすぎず、速度が逆転した主役はMoE構造だった。)結局26Bにたどり着き、品質もそちらのほうが良かった。それでも複雑な推論や大規模なリファクタリングは、依然としてクラウドのほうが安定していた。「ローカルにすべて移す」ではなく「軽い作業だけローカルで」という当初の計算が、実測を前にさらに狭まった格好だ。

しかも4台のMacBookを同じ条件で動かすのは、「ただ電源を入れておけばいい」という話ではなかった。運用の細かな手間が絶えなかった。

  • モデルの量子化・バージョンの統一。同じモデルでも量子化方式やバージョンが機材ごとにバラバラだと、動作と品質が微妙に変わってしまう。4台の出力を揃えるには、まずここを統一する必要があった。
  • コンテキスト長の不一致によるインスタンスreload(スラッシング)。リクエストごとにコンテキスト設定が異なると、モデルを再度読み込むのに時間を食う。
  • バックグラウンドサービスがシェルの環境変数を読まない問題のような、些細だが人を消耗させる落とし穴の数々。

社内連携、しかしセキュリティで止まった

4台クラスターにインターネット検索を組み込み、ウィキを充実させ、社内の協業ツールと本格的に連携させようとしていた時期だった。ところがそこでセキュリティ問題にぶつかった。社内の協業ツールのあちこちに、認証情報が平文で露出していた問題が少なくなかった。ローカルLLMがそれらのツールをRAGやエージェントのコンテキストとしてそのまま取り込んでしまうと、誰かの質問に答える途中で平文の認証情報がそのまま流出したり、エージェントがそのトークンで権限外の操作をしてしまう危険があった。結局プロジェクトはひとまず保留になった。トークンを節約しようとした実験が、皮肉にも自分たちの組織のセキュリティ衛生をあぶり出した格好だ。

ここまでが自分のローカルLLMの話だ。

そして、AI依存と正面から向き合った

実験を続けるうちに、最初の問いが形を整えて戻ってきた。たまにクラウドAIが応答しなくなると、自分はただお手上げになってしまう。AIがないとコーディングができないわけではない。ただ効率がひどく落ちる。1行ずつ自分の手で打っている時間があるなら、むしろAIが復旧するのを待ちながらプロンプトを磨いていたほうがましだと感じるほどに。

そんな中、ふと怖くなった。いつのまにかここまで依存するようになっていた。

このツールが消えたら、自分はどうなるんだろう。

備えをしていなかったわけではない。1つのモデルが落ちたら別のモデルに乗り換えるというフォールバック戦略は、第1部で触れた「1つのモデルにすべて任せない」という原則の延長線上にある。片方が落ちている間はもう片方を使えばいい。しかし — もし両方とも落ちたら?そのときはまた別のモデルを使わなければならず、そのためにはClaude、Codex(GPT)、Antigravity(Gemini)の3製品をすべて用意しておく必要がある。普段は主力を1つだけ使いながらも、万一に備えて残りのツールの購読料やAPIの安全網コストまで毎月背負わなければならないということだ。使いもしない安全網に、律儀にお金を払い続けているようなものだ。そして本当に、3つのモデルが一斉に落ちたら?その瞬間、人にできることが何かあるだろうか。今のところ、答えは見えていない。

だから自分は、「AIサーバーが落ちたら自分も馬鹿になる」という感覚をしばしば覚えた。そしてこの言葉に、チームメンバーたちも深く共感した。自分だけの過敏さではなく、自分たち全員が同じ崖の上に立っていたのだ。

では、ローカルLLMは答えだったのか — 部分的にだけ

正直に言うと、部分的にそうだっただけだ。ローカルLLMはAI依存をゼロにしてくれる道具ではなかった。コスト削減、プライバシー、「切れても動く」という安心感は確かに実在したが、初回応答60秒と品質の天井は、はっきりとした壁だった。

ただ、この実験にはもっと価値のある収穫が別にあった。AIをブラックボックスではなく、自分が直接運用しチューニングする対象へと引き下ろせたことだ。KVキャッシュ、prefill、量子化、コンテキスト長といったものを自分の手で触っているうちに、皮肉にもAIへの依存ではなく理解が増えていった。そして気づいた — AI依存を減らすのは、より強いモデルではなく、自分が作ったシステムのほうだということに。第2部の検証手順と外部記憶、そしてこの記事でモデルの底まで直接触ってみた経験。サーバーが落ちても、自分の検証基準と記録、そして原理への理解は死なない。そこまで作っておくことが、今の自分が見つけた「AI依存を減らす方法」だ。

最後の記事では、こうした変化がすべて、仕事を超えて学び方まで変えてしまった話をする。そして、正直な告白を1つ — 今あなたが読んでいるこの記事を、実は誰が書いたのかについても。


続きの記事: ④ AIを追いかけながら、AIとともに — 学び方まで変わった

この記事が役に立ったら

コメント