14
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

国産LLM llm-jp-4 32Bを実務で検証: 業務活用できる精度 — vLLMパーサーとGGUFの罠

14
Posted at

はじめに

GMOコネクトの永田です。

日本語の業務文書から約50項目のメタデータをJSONで抽出する仕事をしています。gpt-oss:20bで95%前後の精度は出ているのですが、もっと良いモデルがないか定期的にウォッチしていました。

2026年4月3日にNIIから公開された「LLM-jp-4」はApache 2.0、日本語MT-BenchでGPT-4o超え。期待して飛びついたのですが、Ollamaで動かそうとして異常出力、vLLMでもパーサーの設定を見落として出力が壊れる、と一筋縄ではいきませんでした。

最終的にはgpt-oss相当の精度を安定して実現できたので、その過程を共有します。

先にまとめ

llm-jp-4-32b-a3bは、50項目のJSON抽出タスクで93%の精度が5回安定して出ました。gpt-oss:120bの約97%には及びませんが、国産LLMとして実用圏内です。

モデル 推論エンジン 精度 (5回AVG) 処理時間AVG
gpt-oss:120b llama-server 96.8% ~81秒
gpt-oss:120b Ollama (基準) 95.8% ~78秒
gpt-oss:20b llama-server 94.7% ~92秒
llm-jp-4-32b-a3b vLLM + Harmonyパーサー 93.0% ~145秒

ただし以下の2点でハマりました:

  • vLLMでは公式cookbookのカスタムreasoningパーサーが必須
  • Ollama/llama.cppはトークナイザ非互換で現時点では動作しない

LLM-jp-4の概要

モデルスペックは既に多くの記事で紹介されているので、検証に必要な情報だけまとめます。

項目 llm-jp-4-32b-a3b-thinking
アーキテクチャ Qwen3-MoE
パラメータ数(総数 / 推論時に活性化) 320億 / 38億
トークナイザ Unigram byte-fallback (196,608語彙)
コンテキスト長 65,536
ライセンス Apache 2.0

詳細はNII公式プレスリリースHuggingFaceモデルカードをご参照ください。

検証環境と手法

ハードウェア・ソフトウェア

項目
ハードウェア NVIDIA DGX Spark (Grace Blackwell, 119GB統合メモリ)
llama-server llama.cpp build 8423 (3fee84e15)
vLLM 0.19.1rc1 (Docker: vllm/vllm-openai:nightly-aarch64)
Ollama 0.20.2 (GGUF非互換確認用)
Temperature 0
MAX_TOKENS 8,192
コンテキスト長 16,384

タスク内容

プロジェクトサマリー(Markdown形式、数千文字の日本語文書)から約50項目のメタデータをJSON形式で抽出するタスクです。項目には自由記述、パイプ区切りの選択肢(日本語名|English name)、日付、配列、条件分岐など多様な形式が含まれます。

評価方法

gpt-oss:120b(Ollama 0.20.2実行)の出力をベースに、各項目の正答をClaudeで判定して基準データを作成しました。各モデルの出力をこの基準データと突き合わせ、57項目の完全一致率を算出しています。各モデル5回ずつ実行し、平均と安定性を評価しました。

精度検証の結果

5回追試の結果

3モデルとも5回中4回以上は同一結果で、出力は安定していました。llm-jp-4は5回とも完全に同一です。

モデル 推論エンジン Run1 Run2-5 AVG 処理時間AVG
gpt-oss:120b llama-server 56 55, 55, 55, 55 55.2/57 (96.8%) ~81秒
gpt-oss:120b (基準) Ollama 57 54, 54, 54, 54 54.6/57 (95.8%) ~78秒
gpt-oss:20b llama-server 34 ※ 54, 54, 54, 54 54/57 (94.7%) ~92秒
llm-jp-4-32b-a3b vLLM+Harmony 53 53, 53, 53, 53 53/57 (93.0%) ~145秒

※ gpt-oss:20b Run1は*サフィックス欠落によるフォーマット差異。内容は他Runと同等

3モデルはどこを間違えたか

差分を横断比較すると、モデル共通で間違えやすい項目と、モデル固有の間違いが見えてきます。

差分のある項目 llm-jp-4 (53/57) gpt-oss:120b (55/57) gpt-oss:20b (54/57) 傾向
解析対象データ(時系列を推測追加) 2モデル共通: LLMにとって汎用的に難しい
リポジトリURL(空欄にする) 2モデル共通: 本文中のURLを転記するか判断が分かれる
目的の記述(冗長になる) 2モデル共通: 要約の粒度が基準と合わない
データセット名称(冗長になる) llm-jp-4固有: 名称を説明文のように長く書く
実験状況の説明(冗長になる) llm-jp-4固有: 上記と同パターン
ライセンス(英語部分の欠落) gpt-oss:20b固有: パイプ区切りの英語部分を落とす

「解析対象データへの時系列推測追加」はgpt-oss:120bとgpt-oss:20bの両方で発生しており、llm-jp-4だけが正解しています。逆に「名称や説明が冗長になる」のはllm-jp-4に特有のパターンです。

つまり、数値上の差(53 vs 54 vs 55)ほど3モデルの能力差は大きくなく、間違えるポイントが異なるというのが実態です。どのモデルもLLMにとって汎用的に難しい項目(要約の粒度、推測の抑制)でつまずいています。

なおllm-jp-4の8bモデル(denseアーキテクチャ、86億パラメータ)も試しましたが、必須フィールドの*サフィックス欠落や選択肢のパイプ区切り形式を守れないなど、精度が約61%となり実用に至りませんでした。

ハマり1: vLLMのHarmonyパーサーを見落として出力が壊れた

llm-jp-4はThinkingモデルで、応答の前に「思考トークン」を生成します。この思考トークンはOpenAI Harmonyフォーマットのanalysisチャネルに格納される設計です。

HuggingFaceのモデルカードには公式cookbookへのリンクがあり、cookbookのvLLMサンプルにはカスタムreasoningパーサーの指定方法が記載されています。最初これを見落として素のvLLMで起動したところ、思考トークンが最終出力に生テキストとして混入しました。

# パーサーなしの出力例(先頭部分)
analysis We need to extract values from memo according to schema...
Memo header: "プロジェクトデータセットのメモ 2026年3月5日"
作成: 仮名株式会社 仮名 太郎 ...

JSONのキー名がスキーマと全く異なる内容になるため、メタデータ抽出は完全に破綻します。

公式のllm-jp-4-cookbookにはvLLM用のカスタムreasoningパーサー(llmjp4_reasoning_parser.py)が同梱されており、これを使って起動する必要があります。

# cookbookのexample_cli.py経由で起動
python example_cli.py serve /model \
  --served-model-name llm-jp-4-32b-a3b-thinking \
  --reasoning-parser llmjp4 \
  --trust-remote-code \
  --dtype bfloat16 \
  --gpu-memory-utilization 0.85 \
  --max-model-len 16384

--reasoning-parser llmjp4 がないと、思考トークンが分離されません。--trust-remote-code もllm-jp-4のカスタムトークナイザ(llmjp4_tokenizer.py)のロードに必須です。

ハマり2: GGUF/Ollama非互換

「Ollamaで動くなら統一運用できるのに」と思って試した結果です。

GGUF版 結果
Q4_K_M (mmnga版, 21.4GB) 異常出力(数式ループ 2+1は?3+1は?... の繰り返し)
MXFP4_MOE (mmnga版, 18.1GB) クラッシュ(出力なし。ARM/aarch64でのNVFP4 CPUバックエンド問題)

根本原因

LLMのトークナイザ(テキストをトークンに分割するアルゴリズム)には主にBPE(頻出するバイト列のペアを統合していく方式)とUnigram(確率モデルで最適な分割を選ぶ方式)の2種類があります。GGUFに変換する際は、モデルが使っているトークナイザの方式を正しく指定する必要があります。

llm-jp-4-32b-a3b のアーキテクチャ: Qwen3-MoE
Qwen3-MoE の標準トークナイザ:      BPE
llm-jp-4 の実際のトークナイザ:     Unigram (byte-fallback)
                                    ↑ ここが想定外

llama.cppのGGUF変換ツール(convert_hf_to_gguf.py)は、モデルのアーキテクチャからトークナイザ方式を自動判定します。Qwen3-MoEなら通常はBPEなので、BPEとして変換します。しかしllm-jp-4はQwen3-MoEアーキテクチャなのに独自のUnigramトークナイザを使っているため、変換結果が壊れます。

手動でUnigram(UGM)として変換する方法もありますが、llama.cppのUGM実装はGoogleのSentencePieceライブラリが出力する.modelファイルを前提としています。llm-jp-4はHuggingFace形式のtokenizer.jsonのみで.modelファイルを同梱していないため、この方法でも正しく動作しませんでした。

まとめ

検証したタスクでの推奨構成

実施するタスクによって最適なモデル・推論エンジンは異なるため、参考まで。

用途 モデル 推論エンジン 精度 処理時間
精度重視 gpt-oss:120b llama-server 96.8% ~81秒
メモリ効率重視 gpt-oss:20b llama-server 94.7% ~92秒
国産LLM llm-jp-4-32b-a3b vLLM + Harmonyパーサー 93.0% ~145秒

llm-jp-4を使うにはcookbook同梱のカスタムreasoningパーサーが必須で、Ollama/llama.cppはトークナイザ非互換のため現時点では動きません。
なお、93%〜97%の差はモデル間で間違えるポイントが異なるためで、プロンプト見直しで改善の余地がありそうです。

検証環境の詳細(再現用メモ)

項目
llama.cpp build 8423 (3fee84e15)
gpt-oss:120b GGUF ggml-org/gpt-oss-120b-mxfp4 (60GB, 3分割)
gpt-oss:20b GGUF ggml-org/gpt-oss-20b-mxfp4 (12GB)
vLLM 0.19.1rc1 (vllm/vllm-openai:nightly-aarch64)
llm-jp-4-cookbook llm-jp/llm-jp-4-cookbook main
Ollama 0.20.2
llm-jp-4 GGUF mmnga-o/llm-jp-4-32b-a3b-thinking-gguf Q4_K_M / MXFP4_MOE

参考リンク


最後に、GMOコネクトではサービス開発支援や技術支援をはじめ、
幅広い支援を行っておりますので、何かありましたらお気軽にお問合せください。

お問合せ:https://gmo-connect.jp/contactus/

14
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?