Nemotron 3.5 Lightning の判定役を、Jev のように生成しない 1 トークン判定にしてみた

Nemotron 3.5 Lightning の判定役を、Jev のように生成しない 1 トークン判定にしてみた

Nemotron 3.5 Lightning の LLM ルーター判定役を、投機デコード、Jev への置き換え、1 トークン読みの SFT で速くしてみました。同じ重みで 1.18 秒が 0.95 秒、1 トークン化で 0.25 秒。速さは読み出しの形で決まり、判定の質は学習データの課題の形で決まりました。
2026.09.23

はじめに

こんにちは、クラスメソッド製造ビジネステクノロジー部の森茂です。

8 月に Nemotron 3.5 Lightning を LoRA で LLM ルーターの判定役に仕立てた記事を書きました(2026-08-16 時点の記事です)。あの判定役はそのあと 1 か月あまり、NeMo Switchyard の本番経路でコーディングエージェントの依頼を振り分け続けています。9 月 22 日に Switchyard v0.3.0 が出て本番も切り替えましたが、判定役を務めているモデルは同じです。

https://github.com/NVIDIA-NeMo/Switchyard/releases/tag/v0.3.0

https://dev.classmethod.jp/articles/dgx-spark-nemotron-lightning-switchyard-classifier-finetune/

その 1 か月の間に、判定役まわりの景色が少し変わりました。TypeSafe の Jev が生成しない判断を製品として出し、OpenJev を名乗る実装が続き、自分もそれを読み比べる記事を書いています(2026-09-18 時点の記事です)。一方で自分の判定役は、依頼 1 件ごとに JSON を書くのに 1.2 秒かけていました。書かせるのをやめたらどこまで速くなるのか、そのとき判定の質は残るのか。本番と同じ重みで確かめたくなりました。

https://dev.classmethod.jp/articles/openjev-non-generative-ai-alternatives/

先に結論を書いておくと、同じ重みのまま、判定時間は投機デコードで 1.18 秒から 0.95 秒に、出力を 1 トークンにして 0.25 秒まで縮みました。1 トークン版は判定の質も現行にほぼ並んでいて、自分の評価セットで残る差はあと一歩というところです。速さは読み出しの形で決まり、判定の質は学習データにある課題の形で決まる、というのが今回の見立てです。同じ判定役を Jev に任せた結果と合わせて、この記事では判定役の速さと判定の質をどう測り分けたか、そこから何が言えるかを紹介します。ルーターやエージェントの判断部分を小さく速くしたい人に刺さるといいなと思っています。

判定時間の 8 割は JSON を書く時間だった

判定役は Nemotron 3.5 Lightning 30B-A3B を LoRA で学習して NVFP4 に量子化したもので、依頼文と capability カード(weak モデルの得意不得意と、参照ツールやテスト実行が使えるかという環境を書いた system prompt。以下 Card)を読み、4 フィールドの JSON を返します。1 回の判定を vLLM の metrics で分けると、こうなっていました。

区間 平均 中身
prefill 0.210 秒 約 1,250 トークンの入力を読む
decode 0.972 秒 約 78 トークンの JSON を 1 トークン 12.7 ミリ秒で書く
合計(p50) 1.18 秒 3 回起動し直しても 1.18 秒で一致

時間の 82% が decode、つまり JSON を書いている時間です。入力側の prefix cache は、この判定役の入力が Mamba 層を含む構成の cache ブロック 4,176 トークンを埋めないため、Card が毎回同じなのに hit 0 でした。速くしたければ decode を削るしかありません。

投機デコードで 2 割縮み、文法で縮めると暴走した

重みも出力の形も変えずに済む手として、Lightning 公式の投機デコード用ドラフト DSpark を載せました。first-touch 記事で生成速度が 1.45 倍になったものです(2026-08 時点の記事です)。

https://huggingface.co/nvidia/NVIDIA-Nemotron-3.5-Lightning-30B-A3B-NVFP4-DSpark

DSpark k=3 で中央値 1.18 秒が 0.95 秒、decode の平均は 0.97 秒から 0.72 秒で、全体の 2 割の短縮です。1 回の検証で採用されるドラフトは平均 1.71 トークンで、出力が短い JSON なので公式ベンチの数字よりは控えめでした。この構成は 9 月 21 日に本番へ昇格させ、本番経路での中央値は 1.16 秒から 0.99 秒になっています。

出力そのものを短くする近道として、JSON schema で根拠欄の文字数を 200 に制限する構成も試しました。1,152 判定のうち 66 件で上限に達した瞬間にモデルが改行を 4,000 行以上吐き、上限トークンまで走りました。8 月の記事で書いたキー順の暴走と同じ型で、学習分布に無い文法制約を推論時に足すと空白の暴走が出ます。出力を短くするなら学習側でやる、という結論がここで固まりました。

この記事の物差し

ここから先は判定の質を比べるので、使う評価セットと言葉を先にまとめておきます。

評価セット 中身 見たいこと
実運用 87 件 本番経路を流れた形の依頼 87 件と、その期待判定 誤送と安全側の件数
実装課題 30 件 weak で解けると実測で分かっている実装課題。環境節を変えた 2 版 weak に流せた数と Card への追従
見極め 14 問 weak が 2 回失敗し strong なら通った難問(8 月記事と同じ) strong に残せた数
設計相談 10 件 コードを書かない設計の壁打ち。strong が要る strong に残せた数
環境ペア 40 件 同じ依頼で環境節のツール可否だけ変えた 20 ペア 環境節だけで判定が変わるか

誤送は strong が要る依頼を weak に送ること、安全側は weak で足りる依頼を strong に送ることです。数える誤りは誤送の 1 方向だけで、安全側は個別には誤りにせず、増えすぎたときに節約の取りこぼしとして見ます。もう 1 つ、NVFP4 の判定役は同じ重み・同じ入力でも vLLM を起動し直すと判定が数件動くので、数字は起動 3〜4 回の幅で書き、差はその幅の外に出たときだけ差と呼んでいます。

Jev に判定役を任せてみる

生成しない判定を、まずは本家の Jev で試しました。本番の判定役とまったく同じ入力を渡し、system の Card は Jev の state に同梱、質問は「この依頼は weak で足りるか」の二択です。OpenRouter の decisions エンドポイントに 528 件を 3 反復、費用は 0.16 ドル、応答は回線込みで中央値 0.28 秒でした。Jev の選択をそのまま採るか confidence で切るかの規則は、結果を見る前に開発用の分割で凍結し、「confidence が 0.9 以上のときだけ Jev の選択を採用し、それ以外は strong に送る」になっています。

https://openrouter.ai/typesafe/jev-1.13

Jev が得意なのは、設計相談を strong に残す安定性です。10 件すべてを strong に置き、実運用 87 件でも誤送は 0 でした。その代わり安全側が 11 件(現行の判定役は 1 件)で、weak に流せる実装課題は 30 件中 10 件(現行は 20 件)です。confidence 0.9 が保守的すぎると言えばそれまでですが、緩めると開発用の誤送が戻ってくるので、この題材では両立しませんでした。

思っていたより差が出たのは見極め 14 問です。Jev は 14 問中 12 問を、自信を持って weak と言いました。8 月の判定役が 5 問、いまの判定役が 8〜11 問を strong に残せるようになった難問群です。Card には難易度を表す語彙がなく、Jev は依頼文から難しさを読み取らない。環境ペアでも、環境節のツール可否が変わったときの反応がほぼありませんでした。この 2 つは現行の判定役が実測ラベルと環境行を学習して得たもので、汎用の決定モデルが持っていなくて当然の、仕事に固有の判断だと受け取りました。実運用の会話 14 件を Jev で振り分けてみると、confidence 0.9 を超えたのは 1 件だけで、13 件が strong に流れて定価 2.47 ドル、現行の判定役は 13 件を weak に流して 0.32 ドルでした。Jev が悪いという話ではなく、Card を読む前提で仕立てた判定役の役目を汎用モデルにそのまま任せると、安全側に倒れて節約が消える、という話です。

Lightning の出力を 1 トークンにする

では Lightning 自身を生成しない判定役にできるのか。Jev 自身の仕組みは公開されていないので、やり方は OpenJev の実装群、具体的には Avi Chawla の記事と ekzhang/openjev-sglang が示していた読み出し方に倣います。候補を 1 トークンのラベルに対応づけ、prefill 直後の次トークンの logprob を候補の中だけで softmax します。ekzhang 版の README には、生成も思考の連鎖もない、prefill と最初のトークンの読み出しだけの仕事だ、と書かれています。

https://blog.dailydoseofds.com/p/build-your-own-jev-100-local

https://github.com/ekzhang/openjev-sglang

自分の判定役では、候補は 10 個の判定規則と weak か strong かの組み合わせで 20 通り、A から T の 1 文字を割り当てました。この凡例を依頼文の末尾に付け、vLLM 0.27.1 の chat completions に max_tokens: 1logprob_token_ids で 20 個のトークン id を指定すると、1 回の prefill で 20 候補の logprob が返ります。Switchyard は JSON の本文しか読まないので、間に小さな翻訳 proxy を置いて 4 フィールドの JSON に写像し、Switchyard 本体は無改変です。

最初は学習なしで、本番の重みをそのまま 1 トークン読みにかけました。速度は中央値 0.249 秒。起動を 3 回替えても同じ値で、DSpark 込みの 0.95 秒の約 4 分の 1 です。ところが判定は崩れました。実運用 87 件の安全側が 40 件を超え、見極め 14 問で strong に残せたのは 1〜4 問。JSON を書くように学習した重みは、凡例に答える読み方を知りません。読み出しの形を変えるなら、その形で学習し直すしかない。ここで 1 トークンのラベルを教える SFT に進みました。

学習データは 8 月の judge と同じ系統で、3,000 行の教師データの assistant 側を、4 フィールドの JSON から「本番のしきい値でこの依頼を weak に振るか」を表す 1 文字に置き換えます。レシピは LoRA rank 8 のまま 1 走 3 時間弱、そのあと NVFP4 に量子化して同じ評価セットを流しました。最初の 1 走で判定は JSON の判定役並みに戻り、速度は NVFP4 で中央値 0.249 秒、時間の 97% が prefill です。学習の有無に関わらず、読み出しの形が同じなら 0.249 秒で揃いました。

なお、1 トークン版に DSpark を付けると p95 が 41 ミリ秒増えるだけでした。1 トークンしか要求しないのでドラフトは 1 個も採用されず、投機デコードは JSON を書く判定役には効き、1 トークンの判定役にはコストだけかかる形です。

3 つの判定役の何が良くて、何が足りなかったか

現行の JSON 判定役、Jev、1 トークン版を並べると、良かったところと足りなかったところはこう分かれました。

判定役 良かったところ 足りなかったところ いまの扱い
現行の JSON 判定役 誤送がほぼ無く、難問も Card の環境節も読める。投機デコードで 0.95 秒 1 回 1 秒弱かかり、その 8 割は JSON を書く時間 本番で稼働中
Jev 1.13 誤送 0。設計相談は全件 strong に残す。回線込みで 0.28 秒 安全側に倒れて weak に流せる依頼が半分に減る。難問 14 問中 12 問を weak と判定し、Card の環境節を読まない 汎用の判断向け。この判定役の代わりにはならない
1 トークン版 0.25 秒で現行の 4 分の 1。難問の弁別と Card の追従は現行以上 安全側と環境ペアの誤送がわずかに多い。学習していない形の依頼には学習データの追加が要る 候補。あと一歩で本番投入

裏付けの数字は次の表です。✅ は現行と同等以上、🟡 はわずかに届かない、❌ は大きく届かない、の意味で付けています。

評価セット 現行の JSON 判定役 Jev 1.13(confidence 0.9) 1 トークン版(NVFP4)
実運用 87 件の誤送 / 安全側 ✅ 0〜1 / 1〜2 🟡 0 / 11 🟡 1〜2 / 4〜5
実装課題 30 件で weak に流せた数 ✅ 19〜23 ❌ 10 ✅ 30
見極め 14 問で strong に残せた数 ✅ 8〜11 ❌ 2 ✅ 11〜12
設計相談 10 件で strong に残せた数 ✅ 9〜10 ✅ 10 ✅ 10
環境ペアの誤送 ✅ 1 ✅ 1 🟡 3
Card の環境節への追従 ✅ +9 ❌ 反応せず ✅ +20
判定 1 回の時間(中央値) 0.95 秒 0.28 秒(回線込み) 0.25 秒

現行の判定役と Jev の秒数は測っているものが違うので、倍率は出しません。

1 トークン版は、🟡 の 2 項目が自分の評価セットであと少しというところです。現行と食い違った判定には 1 トークン版のほうが正しかったものもあり、速さ 4 分の 1 と合わせると、学習データをもう 1-2 周調整すれば本番に載せられそうだと見ています。Jev は誤送 0 という一番大事な基準は満たしていたものの、weak に流す量と難問の振り分けに弱く、節約側のメリットが出せませんでした。

速さは読み出しの形で決まり、判定は学習データの形で決まる

ここまでを一段引いて眺めると、2 つの軸がきれいに分かれました。

速さの軸は、重みではなく読み出しの形で決まります。学習なしの現行の重みを 1 トークン読みにしても、学習し直した版でも、中央値は 0.249 秒で揃いました。JSON を書かせる限り、投機デコードで削れるのは decode の 2 割で、文法で無理に縮めると暴走する。書かせるのをやめた瞬間に decode が消え、残るのは prefill だけです。Jev の中身は公開されていませんが、生成しないという点は同じなので、公式の値で 70〜500 ミリ秒を出せるのも同じ構造の帰結だと見ています。

その 0.25 秒は、DGX Spark の GB10 で約 1,250 トークンを読む時間です。prefill は GPU の計算力でほぼ決まるので、データセンター向けの GPU ならもっと短くなるはずで、手元の値は速い側の限界ではありません。一方で Jev の 0.28 秒は、手元から OpenRouter を経由して TypeSafe に届き戻ってくる往復の時間で、モデルの計算時間はその一部です。ルーターと同じ機体に判定役を置くローカルの構成には、この往復がそもそもありません。判定が毎リクエスト走る用途では、GPU の速さと回線の往復のどちらが待ち時間を決めているかを分けて見ておく価値があると思っています。

判定の軸は、モデルが何を学習したかで決まります。1 トークン版は、学習データに似た依頼なら JSON の判定役と同じ判定を出します。ところが学習データに無い形の依頼、たとえば失敗するテスト群を貼り付けた修正依頼では、学習し直すたびに weak と strong の間で答えが入れ替わりました。同じ依頼を JSON の判定役は毎回同じように判定しています。

違いは、答えの前に根拠を書くかどうかです。1 トークン版は依頼を読み終えた瞬間の 1 文字で答えるので、見たことのない形の依頼では手がかりが無く、答えが学習のたびの偶然で決まります。JSON の判定役は、この依頼の要点は何か、どの規則に当たるかを先に書いてから確率を出すので、見たことのない形でも書いた要点を足がかりに判定できる。8 月の記事では、根拠が JSON で残るからデバッグしやすい、と書きましたが、根拠を書くこと自体が判定を安定させていました。1 秒かけて書いている根拠は無駄ではなかった、というのが今回の収穫です。

では Jev はこの 2 軸のどこにいるのか。速さでは 1 トークン版と同じ、書かない側です。判定では、自分の Card にある参照ツールの可否や、この形の課題は weak が落ちるという手がかりを学習していない汎用モデルなので、それを読み取れません。逆に言えば、特化した判定役の強みはモデルの大きさではなく、weak モデルの実測から作ったラベルと環境行を学習したことにあります。そのラベルさえあれば、読み出しの形は 1 トークンでも JSON でもよく、レシピは 30B の Lightning に固有のものでもないはずです。

ここで、オープンウェイトのモデルを判定役にしている理由を書いておきます。判定基準そのものを自分で持てることです。何を weak に流すかを決める Card、weak モデルの実測から作ったラベル、しきい値、そして今回の 1 トークンという出力の形まで、全部が手元にあります。weak モデルを入れ替えたら学習し直せますし、合格ラインの置き方が間違っていたと気づいたら、自分で置き直せます。判定 1 回あたりの費用は API の従量ではなく手元の GPU の稼働で、依頼文とコードは機体の外に出ません。Jev のような汎用の決定モデルは、判断の中身を自分で変えられない代わりに学習の手間がないので、競合というより補完だと見ています。判定基準を自分で持ちたい用途にはオープンウェイトの特化型を、汎用の判断で足りる用途には API の決定モデルを、という使い分けです。

まとめ

Nemotron 3.5 Lightning の判定役を、投機デコード、Jev への置き換え、1 トークン読みへの学習し直しという 3 つの方向で速くしようとしてみました。同じ重みのまま投機デコードで 1.18 秒から 0.95 秒、出力を 1 トークンにして 0.25 秒。判定の質も現行にほぼ並びました。速さは読み出しの形で決まり、判定の質は学習データにある課題の形で決まる。汎用の Jev は速さの側では同じく書かない側にいますが、Card の環境節と難問の弁別は、実測ラベルで仕立てた特化型にしかありませんでした。判定基準ごと自分で持てるのが、オープンウェイトを判定役にする一番の理由です。

残っていることも書いておきます。1 トークン版は自分の評価セットであと少しの項目があり、学習データをもう一周調整してから本番に載せるつもりです。Jev との実運用の比較は 14 件を 1 回回しただけです。判定役の秒数は本番機とは別の 1 台で測った値で、本番の負荷での値ではありません。確率の較正は今回も測っていません。

次は、この 1 トークンの学習レシピを 4B 以下のモデルに移して、GPU の利用できない機体で同じ判定役が動くかを試してみたいところです。

参考リンク


AI白書2026 配布中

クラスメソッドが独自に行なったAI診断調査をもとに、企業のAI活用の現在地を調査レポートとしてまとめました。企業規模別の活用度傾向に加え、規模を超えてAI活用を進める企業に共通する取り組みまで、自社の現在地を捉えるためのヒントにぜひ。

AI白書2026

無料でダウンロードする

この記事をシェアする

DevelopersIO 2026

関連記事