2026-09-19 · 研究ノート
JevPick — AIに「選ばせる」を、
文章生成そのものの高速化に使う
openvons は「AI に文章を書かせず、有限の選択肢に確率で答えさせる」層です。同じ考え方で、AI が文章を書く速さを上げられないか。3 日間で検証した結果、ツール呼び出しでは予測モデルなしで 3〜5 倍、出力は 1 文字も変わりませんでした。長い文脈では、いま流行りの高速化手法がむしろ遅くなることも分かりました。
先読み (speculative decoding) とは
LLM は 1 語ずつしか書けません。1 語書くごとに、モデル全体を 1 回動かします。ところが「次の数語」を誰かが仮置きしてくれれば、モデルはそれをまとめて 1 回で検算できます。当たっていれば数語ぶん一気に進み、外れていれば外れた所から普通に書き直す。だから出力は変わらず、速くなるだけです。これを先読みと呼びます。
問題は「誰が仮置きするか」。ふつうは小さな予測モデルを別に学習して使います (MTP、EAGLE、DFlash など)。学習が要り、モデルごとに作り直しで、長い文脈では重くなります。
JevPick のしくみ
候補メニューを作る
次に出そうな数語の候補を、学習なしで集めます。ツール呼び出しならツール定義から関数名・引数名・値の並びを機械的に展開する。過去の出力や入力文に同じ語の並びがあれば拾う。モデルに同梱の予測器 (MTP) があればそれも候補に入れる。
JevPick が選ぶ
本体モデルが次の語を考えるときに持っている内部状態 (hidden state) を見て、メニューの中から「いま一番当たりそうな候補」と「何語まで当たりそうか」を出します。openvons の「状況 → 選択肢 → 確率」と同じ形です。パラメータ 500 万、学習は 1〜2 分。
本体が検算する
選んだ候補を本体モデルに一括で検算させ、当たった分だけ採用します。当たりそうな候補が無いときは、JevPick が「先読みしない」と判断して普通に書きます。
分かったこと
1. ツール呼び出しは、予測モデルなしで 3〜5 倍速くなる
AI エージェントが出すツール呼び出し (関数名と引数の JSON や XML) は、形が決まっています。ツール定義と過去の出力から機械的に作った候補メニューの中に、正解の続き (4 語) が 90% 入っていました。初めて見るツールでも 70〜80%。あとは選ぶ精度の問題で、単純な頻度順だと 64% しか当たらないところを、JevPick は 88% 当てます。
| モデル | 精度 | 何もしない | JevPick (予測モデルなし) | 出力の一致 |
|---|---|---|---|---|
| Qwen3-4B | bf16 | 1.0 倍 | 3.8 倍 (候補を 16 語にすると 4.8 倍) | 100% |
| Qwen3.8-27B | bf16 | 1.0 倍 | 3.9 倍 | 数値誤差のみ* |
| Qwen3.8-27B | FP8 | 1.0 倍 | 3.5 倍 | 数値誤差のみ* |
| Qwen3.8-27B | 4-bit (NF4) | 1.0 倍 | 3.2 倍 | 数値誤差のみ* |
* 半精度演算では「まとめて検算」と「1 語ずつ」で丸め誤差が異なり、ごく近い確率の 2 語が入れ替わることがあります。単精度 (fp32) では 4B で全 token 一致を確認しました。既存の先読み手法も同じ性質です。
量子化への強さも確認しました。bf16 で学習した JevPick を、FP8 版・4-bit 版のモデルの内部状態にそのまま使っても、精度の低下は 0.5〜3 ポイントです。量子化ごとに学習し直す必要はほぼありません。
2. 長い文脈では、先読みそのものが逆効果になる
今年注目の DFlash (ブロック拡散型の予測モデル) を vLLM で測ると、300 語の文脈では 5.4 倍でしたが、16k 語の文脈では 1.0 倍、つまり効果が消えました。よく使われる n-gram 方式は 0.7 倍と、逆に遅くなります。
理由は 2 つ。長い文脈では 1 回の検算が高くつくのに、候補の当たり幅が半分に落ちる (ツール定義 100 個を渡すと予測器が迷う) からです。この条件では「どの予測器が賢いか」より「いま先読みすべきか」の判断が結果を決めます。JevPick をその判断役に使うと 1.0 倍で踏みとどまり、常時先読みする方式は 0.6 倍まで落ちました。
3. Qwen3.5 系に同梱の MTP は、ツール呼び出しではほぼ完璧
Qwen3.8-27B や Qwen3.8-Flash-Next には MTP という小さな予測器が同梱されています。これがツール呼び出しで次の語を 99.7% 当て、7 語まとめても平均 6.3 語当たります。4-bit の 27B で 6 倍 (vLLM)、Flash-Next で 5.8 倍、llama.cpp (GGUF) でも 2 倍。エージェント用途なら、まず MTP を有効にする価値があります。
この条件では JevPick を上に乗せても上積みは 4〜8% にとどまります。MTP が外す 3% の位置を候補メニューで拾う、予測器を呼ぶかどうかを判断する、という役割に寄ります。
正直に言うと
- コードの補完には弱い。候補メニューが 3 割しか当たりません。ここは学習済み予測モデルの領分です。
- 速度の絶対値は簡易実装 (Hugging Face の推論ライブラリ transformers) で測った比です。製品級の推論エンジン (vLLM / SGLang) への組み込みは次の課題で、そこでは既存手法が 4〜8 倍出ています。
- 1 モデル系列 (Qwen)・1 タスク (ツール呼び出し) での結果です。
- Qwen3.8-Flash-Next は内部状態を取り出す経路が現時点で無く (推論ライブラリ transformers が FP8 の MoE 重みを読めない)、候補メニューと MTP までの確認です。
全手法 × モデルの一覧 (ツール呼び出し、何もしない = 1.0 倍)
| モデル・精度 | 実行環境 | JevPick (予測モデルなし) | DFlash / DFlash2 | MTP | JevPick + 予測器 |
|---|---|---|---|---|---|
| Qwen3-4B bf16 | transformers | 3.8〜4.8 倍 | 2.9 倍 (vLLM 5.4 倍) | — | 4.0〜4.8 倍 (hybrid) |
| Qwen3-4B bf16、16k 文脈 | transformers / vLLM | 1.0 倍 (損なし) | 0.6 倍 (vLLM 0.99 倍) | — | 1.0 倍 |
| Qwen3.8-27B bf16 | transformers / vLLM | 3.9 倍 | 4.9 倍 (vLLM 8.3 倍) | 4.3 倍 (vLLM 7.1 倍) | 4.7 倍 |
| Qwen3.8-27B NVFP4 | vLLM | 未統合 | 4.6 倍 | 6.0 倍 | — |
| Qwen3.8-27B AWQ-INT4 | vLLM | 未統合 | 6.2 倍 | 4.3 倍 | — |
| Qwen3.8-27B GGUF Q4_K_M | llama.cpp | 未統合 | 3.75 倍 | 2.0 倍 | — |
| Qwen3.8-27B NF4 | transformers | 3.2 倍 | 3.9 倍 | 3.3 倍 | 3.9 倍 |
| Qwen3.8-Flash-Next FP8 | vLLM (4 GPU) | 未統合 | — | 5.8 倍 (590 tok/s) | — |
| Qwen3.8-Flash-Next GGUF Q4 | llama.cpp (1 GPU、エキスパートは CPU) | 32 GB 級で動く: VRAM 7 GB で 38 tok/s、25 GB で 47 tok/s (128 コア機)。MTP 併用は本家 llama.cpp では未対応 | |||
すべて手元の RTX PRO 6000 Blackwell、1 リクエストずつ、greedy。JevPick を含む列は同一の検算コードで方式だけを変えて比べたもの。詳しい表・ログ・再現手順は docs/jevpick にあります。
これまでの openvons と、この結果の位置づけ
openvons はこれまで、音声 (数千の地点名から 50 ms で 1 つ選ぶ)、画像 (小さな出力層で大モデルを上回る)、テキスト (8 問まとめて 40 ms) で「選ばせる」を実装してきました。JevPick はその 4 つ目の入口で、選ぶ対象が「AI 自身が次に書く数語」になったものです。文章生成を速くするだけでなく、「いま先読みすべきか」という判断まで確率で扱える点が、他の高速化手法との違いです。