Gemma 4のtool callingが崩れた理由、LocalLLaMAが突き止めた小さなJinjaバグ

LocalLLaMAが強く反応するのは、ふわっとした不満が再現可能なbug reportに変わる瞬間だ。今回のGemma 4のtool callingスレッドはまさにそれだった。出発点はよくある不満だ。custom MCP toolをいくつかのinference engineで回すとGemma 4だけ挙動が不安定で、Qwen3.5やgpt-oss-20bは問題ない。普通ならここで「Gemmaはなんとなく弱い」で終わる。だが投稿者はverbose logを比べ、prompt renderingを追い、最後はchat templateの中にある小さな失敗点まで持っていった。

核心はJinja templateが一般的なJSON Schemaの形をどう扱うかにあった。tool parameterがanyOf: [$ref, null]のような形を取ると、意味の本体はanyOfや$defsの中にある。ところがtemplateはtop-levelのtypeを前提にしていた。その結果、rendered promptではparameterの意味が空のtype fieldのように潰れ、modelがtool callに必要な情報を受け取れなくなる。投稿者によれば、templateの小さな修正でこの情報は回復し、その後の更新ではoneOf、allOf、$defs、enum、const、type array、null valueまで保持対象を広げた。

コメント数は多くないが、なぜ価値があったかは十分に見える。人々がすぐに聞いたのは、「Gemma 4がagent setupでQwen3.6より不安定に見えた理由はこれか」「全Gemma 4系に効く問題なのか」「ローカルpatchで普通に戻るのか」という点だった。こういう議論はbenchmark screenshotよりずっと役に立つ。model preferenceの話をvibesから検証可能なsoftware bugへ移せるからだ。同時に、subredditが何度もぶつかっているパターンも見える。見た目はmodel qualityの差でも、実際の原因はweightsの下にあるtemplate、runtime、formatting、toolingに潜んでいることが多い。

この投稿が広がった理由もそこにある。すぐ試せる手が残るからだ。tool schemaがpromptでどうrenderされるかを確認する。nested JSON Schemaの意味がtemplateで勝手に守られると考えない。失敗するmodelと通るmodelを出力だけでなくprompt段階で見比べる。LocalLLaMAがこういう投稿を好むのは、体感の不満と実際の修正の距離を一気に縮めるからだ。benchmark noiseが多い場所ほど、小さくても鋭いbug reportは目立つ。