Gemma 4 E4B QAT Q4_0をCodex CLIローカルモデルとして評価したメモ

Gemma 4 E4B QAT Q4_0 GGUF を、Codex CLI の text-only local model backend 候補として試した。

比較対象は、先に評価していた Gemma 4 12B Q4_K_M である。見たかったのは、単なる短文応答ではなく次の 4 点だった。

  • 12B より GPU memory が下がるか
  • Codex CLI の agent prompt を現実的な context に収められるか
  • JSON final answer と read-only shell tool use が成立するか
  • 広い文書検索や MCP tool selection で破綻しないか

先に結論を書くと、E4B は memory / speed 面では 12B よりかなり扱いやすい。 一方で、Codex CLI の tool routing まで含めると、12B の単純な置き換えではない。特に MCP tool を model に直接選ばせる構成は不安定で、検索 intent は adapter / router 側でルールベースに拾う方が堅い。

評価対象

対象にしたのは Google の Gemma 4 E4B QAT Q4_0 GGUF である。

評価時点の model card では、E4B は dense model として次のように説明されていた。

項目
effective parameters4.5B
parameters with embeddings8B
layers42
context length128K
supported modalitiestext, image, audio
GGUFQAT Q4_0

今回は text-only backend として見るため、image / audio / video と mmproj は評価範囲から外した。

E4B は「4B 級」と見たくなるが、embeddings 込みでは 8B と説明されている。そのため 12B Q4_K_M より軽い可能性は高いが、VRAM が単純に半分以下になるとは仮定しない方がよい。

構成

抽象化すると構成はこうなる。

flowchart LR
    Codex[Codex CLI] --> Proxy[OpenAI-compatible proxy]
    Proxy --> Adapter[ルールベースの adapter / router]
    Adapter --> Llama[llama-server]
    Llama --> Model[Gemma 4 E4B QAT Q4_0 GGUF]
    Adapter --> Search[bounded document search]
    Codex --> Tools[Codex tool executor]

最初は adapter なしで llama-server + proxy + Codex CLI を試した。 短い JSON / tool smoke は通ったが、広い検索や MCP selection で崩れたため、最終的には proxy と model の間にルールベースの前段ルータを挟む構成を本命にした。

重要なのは、adapter がすべての作業を実行するわけではないことだ。 read-only shell tool の実行境界は Codex CLI 側に残し、adapter は「巨大出力になりやすい request を抑制する」「文書検索 intent を bounded search に寄せる」層として使う。

12B baselineとの比較

12B baseline は次の条件だった。

ctx=16384
n-gpu-layers=28
reasoning=off

評価に使った Ubuntu Desktop は、DMI では MSI MS-7817 v2.0 Haswell 世代のデスクトップで、CPU は Intel Core i7-4790 の 4 cores / 8 threads、GPU は NVIDIA GeForce RTX 3060、VRAM は 12288 MiB である。 この条件では、短い JSON-only、read-only shell tool + JSON final、strict JSON shape の smoke は通っていた。 ただし RTX 3060 12GB class GPU では、GPU memory はおおむね 5GiB 前後を使っていた。

E4B では同じ ctx=16384 から始め、GPU offload と context size を変えて見た。

条件offloadllama GPU memory の目安評価
12B, ctx=16384partial約 5.1GiB既存 baseline
E4B, ctx=16384partial約 2.3GiBかなり軽いが CPU 側も使う
E4B, ctx=16384full約 3.3GiBmemory と余裕のバランスがよい
E4B, ctx=32768full約 3.5GiB32K でも VRAM に余裕は残る

数値は手元環境の目安で、GPU 常駐 process や build、driver、batch 設定で変わる。 ただし方向性としては明確で、E4B は 12B より memory 面で扱いやすかった。

full offloadでもCPUは使う

E4B の layer 数から --n-gpu-layers 42 で full offload になると予想していたが、実測では output layer まで含めて 43/43 にする必要があった。

ただし full offload は CPU 0% を意味しない。 model buffer の一部は CPU mapped として残り、Codex CLI 経由の推論中は CPU も短時間で 1 core 近く使うことがあった。

GPU だけを見ていると「完全に GPU に載ったのになぜ CPU が動くのか」と見えるが、local LLM の実行では tokenizer、HTTP proxy、adapter、Codex CLI、JSON 変換、prompt cache なども含めて CPU 側の仕事が残る。

context sizeの見方

E4B では 8K / 16K / 32K を試した。

context評価
8K短い smoke は通るが、Codex CLI の agent prompt だけで余裕が少ない
16Kmemory と実用余裕のバランスがよい
32K長めの task に使えるが、広い検索結果を戻すとまだ溢れる

32K にしても、Codex CLI の AGENTS、tool schema、会話履歴、検索結果が重なると context overflow は起きる。 これは model crash ではなく、単に次 turn へ戻す情報量が多すぎる問題である。

特に repository 横断検索を shell の rg 結果としてそのまま返すと、32K でも簡単に上限へ近づく。 小型 local model では、検索そのものよりも「検索結果をどれだけ小さく返すか」が先に問題になる。

JSON/tool smoke

Codex CLI 経由では、12B と同系統の smoke を試した。

Test目的結果
T1 JSON-onlytool なしで JSON object だけを返すprompt を厳密にすると pass
T2 shell tool + JSON finalread-only shell tool を 1 回使い、結果を JSON に入れるpass
T3 strict JSON shape指定 key / type の JSON object を返すpass

注意点は、E4B は prompt phrasing に敏感だったことだ。 弱い テストプロンプト(T1) では JSON に余計な拒否文が混じった。一方、出力形式を強く指定した プロンプトでは JSON object のみになった。

T2 では、final answer に「tool を呼んだ」と書いてあるだけでは不十分である。 実際に command_execution event が出たか、tool result が返ったかを確認する必要がある。 E4B では、短い tool smoke は通っても、実 task に近づけると tool event が出ずに model が推測だけで答えることがあった。

このため、E4B の tool 評価では final text ではなく event stream を見る方がよい。

MCP tool selectionの失敗

文書検索の context overflow を避けるため、出力上限つきの local document search MCP を用意した。 tool surface は file list、snippet、短い slice 取得だけに絞り、検索 root と出力 byte 数も制限した。

それでも、E4B に MCP tool を直接選ばせる構成は安定しなかった。

観測した failure class は次の通り。

  • 目的の検索 tool ではなく、MCP resource listing helper を選んでしまう
  • resource API を tool API と混同する
  • prompt で resource API を禁止しても再発する
  • 起動 MCP server を文書検索だけにしても、架空の shell command へ流れる

これは MCP server の実装が壊れているというより、小型 model に見える tool / helper の選択問題だと思う Codex 側で MCP server tool の allowlist を絞っても、client が持つ resource helper が別枠で見える場合、model はそこへ流れることがある。

adapter / routerで検索intentを拾う

結論として、E4B 級の小型 model では「MCP tool を直接選ばせる」より、adapter / router が検索 intent を先に拾う構成が安定した。

方針はこうである。

  1. user request が local document search だと分かったら、model に tool を選ばせない
  2. adapter 内で bounded search を実行する
  3. file list や短い snippet だけを final answer として返す
  4. shell の巨大 rg output は Codex turn に戻さない
  5. unbounded log、full diff、full JSON、full YAML も同じ class として抑制する

この構成では、検索 request は bounded file list として完了し、command_execution や MCP resource helper へ流れなかった。 また、長くなりやすい docker logs のような request も、adapter 側の suppressed response で止められた。

MCP は不要になるわけではない。 MCP server は、検索範囲と出力量を強制的に絞る read-only の小さな部品として持ち、adapter / router から呼べるようにするのがよい。 小型 model に「どの MCP tool を使うか」を毎回選ばせるのが危ない、という整理である。

adapterとrouterを分けるか

この検証では、model 固有の adapter と、ルールベースで処理を振り分ける前段ルータを同じ前段 process に入れた。 短期検証ではこの方が速い。proxy、health check、context metadata、tool suppression、bounded search を 1 箇所で見られるからだ。

ただし、長く運用するなら責務の名前を分けた方がよい可能性がある。

方針向いている状況注意点
既存 adapter に router を同居PoC、単一 host、local model を頻繁に差し替える段階名前と実責務がずれやすい
generic router process に改名複数 model で同じ bounded search / suppression を使う段階unit 名、設定名、test fixture、docs の移行が必要
router core を library 化し、model adapter は薄く分けるHermes、Gemma、別 model で parser / prompt だけを差し替えたい段階抽象化が増え、初期実装量も増える
model ごとに別 adapter を持つmodel 固有の prompt / parser が大きく違う段階suppression / search policy の重複に注意

現時点の判断では、E4B で必要だったのは「Gemma 固有 parser」ではなく、model に tool selection させないルールベースの前段ルータだった。 そのため、長期的には model 名を冠した adapter より、Codex local router のような中立的な境界に寄せる方が自然である。

この評価では、運用上の service 名も generic router に寄せる方針にした。 一方で、既存の parser / canary 資産はすぐ捨てず、router process から再利用できるものは残した。

次に見るべきことはまだある。

  • bounded document search 以外にも、log、diff、JSON、YAML で同じ router policy が必要になるか
  • Hermes 系 model と Gemma 系 model の両方で同じ router が使えるか
  • write policy 付き profile を作る必要があるか
  • proxy の readiness と context metadata を router 経由で安定して扱えるか
  • test fixture が model 固有名ではなく policy 名で読めるか

評価のまとめ

E4B は、12B より軽い local Codex backend 候補として残す価値がある。

良かった点:

  • 12B より GPU memory が明確に少ない
  • 16K / 32K context でも短い Codex smoke は通る
  • full offload まで持っていける
  • --reasoning off で短文の本文応答は安定した
  • ルールベースの前段ルータを挟むと local document search が扱いやすくなる

弱かった点:

  • prompt phrasing に敏感
  • final answer の自己申告だけでは tool 実行を信用できない
  • 32K でも広い検索結果を戻すと context overflow する
  • MCP tool selection を model に任せると resource API と混同しやすい
  • full offload でも CPU 負荷は残る

実運用での注意

E4B を Codex CLI backend として使うなら、次の方針がよい。

  • まず ctx=16384 を安定寄りの基準にする
  • 長めの検証では ctx=32768 を使うが、広い検索結果を戻さない
  • --reasoning off を server 側で指定する
  • tool task では final answer ではなく tool event を確認する
  • document search は MCP 直接選択ではなく adapter / router でルールベースに処理する
  • unbounded log / diff / JSON / YAML は suppress か summary-first にする
  • router / proxy だけでなく、背後の model server lifecycle も同じ運用単位で管理する

今回の評価で分かったのは、E4B が「軽いが、そのまま agent に任せるには rough edge がある」model だということだ。 model 単体の短文応答ではなく、Codex CLI、tool schema、MCP、proxy、adapter、context hygiene をまとめて設計する必要がある。