Gemma 4 E4B QAT Q4_0をCodex CLIローカルモデルとして評価したメモ
Posted:
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 parameters | 4.5B |
| parameters with embeddings | 8B |
| layers | 42 |
| context length | 128K |
| supported modalities | text, image, audio |
| GGUF | QAT 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 を変えて見た。
| 条件 | offload | llama GPU memory の目安 | 評価 |
|---|---|---|---|
| 12B, ctx=16384 | partial | 約 5.1GiB | 既存 baseline |
| E4B, ctx=16384 | partial | 約 2.3GiB | かなり軽いが CPU 側も使う |
| E4B, ctx=16384 | full | 約 3.3GiB | memory と余裕のバランスがよい |
| E4B, ctx=32768 | full | 約 3.5GiB | 32K でも 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 だけで余裕が少ない |
| 16K | memory と実用余裕のバランスがよい |
| 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-only | tool なしで JSON object だけを返す | prompt を厳密にすると pass |
| T2 shell tool + JSON final | read-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 を先に拾う構成が安定した。
方針はこうである。
- user request が local document search だと分かったら、model に tool を選ばせない
- adapter 内で bounded search を実行する
- file list や短い snippet だけを final answer として返す
- shell の巨大
rgoutput は Codex turn に戻さない - 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 をまとめて設計する必要がある。