27B のローカルモデルが 191 項目中 189 問正解した — 落とした 1 問は Gemma 4 と同じ場所だった¶
Alibaba が Apache 2.0 で公開した Qwen3.8-27B を、自作ベンチマークの全 9 テーマで実測しました。構造化出力ではローカル実行できる規模として過去最高でしたが、HTML の一括生成では別の弱点が出ます。
何を測ったか¶
OreOre-Bench は、同じプロンプトを各モデルに 1 回だけ投げて成果物を並べる個人用のベンチマークです。手直しは一切しません。
| 条件 | 値 |
|---|---|
| モデル | Qwen/Qwen3.8-27B(2026-08-05 公開、Apache 2.0) |
| 量子化 | unsloth の GGUF Q8_0(29GB) |
| 実行環境 | Ollama 0.30.6 / Mac Studio M3 Ultra 512GB |
| サンプリング | temperature 0.3、top_p 既定、max_tokens 65,000(全モデル共通) |
| テーマ | HTML 生成 7 種 + 構造化 JSON 2 種 |
アーキテクチャは 27B の dense で、Gated DeltaNet 3 層 + Gated Attention 1 層を 16 回反復する構成です。ネイティブ 262K コンテキストで、thinking がデフォルトで有効になっています。
構造化出力は明確に強い¶
json-ladder は、同じ短編小説から段階的に難しい JSON を抜き出させるテーマです。L1 のタイトル抽出から、L6 の「全文の段落冒頭を逐語で index 化する」まで 6 段階あります。
| レベル | 採点項目 | 一致 | accuracy |
|---|---|---|---|
| L1〜L4 | 41 | 41 | 100% |
| L5 | 54 | 53 | 98% |
| L6 | 96 | 95 | 99% |
| 合計 | 191 | 189 | 平均 99.5% |
191 項目中 189 一致。ローカル実行できる規模では過去最高で、これまで最高だった Gemma 4 31B(99%)を上回りました。
ただし「全問正解」ではありません。落とした 2 件はこれです。
L5 characters[0].relations got: 1 expected: 0
L6 sections[3].paragraph_openings[2]
got: "> 千鶴へ" expected: "千鶴へ"
L6 の方は、本文中に引用形式で挿入された手紙の冒頭行から、引用記号 > を取り除けなかったというものです。これは Gemma 4 31B が同じテーマで落としている箇所と完全に同一でした。モデルの規模や世代が変わっても、「原文の装飾をどこまで剥がすか」の判断は同じところで割れるようです。
PR トリアージのテーマ(10 件の PR を merge / fix / hold / close に分類)でも正解キー一致 90% で、Gemma 4 系 3 モデルの 85% を上回っています。しかもこのテーマは「JSON 単体で返す」ことを指示していますが、thinking を長く挟んだ上で指示どおり JSON だけを返しました。Claude Opus 4.8 が前置き文を付けて破っている指示です。
HTML 生成では前置きが混ざる¶
一方、HTML を 1 ファイルで書かせるテーマでは癖が出ます。
HTML 系 7 テーマのうち 6 テーマで、成果物の先頭に前置き文かコードフェンスが混入しました。
hasami-shogi `index.html` 1枚で完成した実装です。指定ルールセット(...
lp-fable5 絵本の世界観で「Fable 5」の発表ページを、水彩SVG・...
lp-nishibi # NISHIBI(西日)— 凍結プロンプト実装版
othello `index.html` 1枚で完成したオセロです。緑のフェルト盤面・...
phoenix-lp ```html
suminagashi 和紙の上で墨が渦を巻いて溶け合う、フルスクリーンの...
roguelike (混入なし。<!DOCTYPE html> で始まる)
末尾にも実装解説が付きます。ブラウザは寛容なので表示自体は成立しますが、「単一 HTML ファイルとして出力せよ」という指示に対しては不正確です。
面白いのは、構造化 JSON の 2 テーマでは混入がゼロだったことです。出力形式が JSON だと厳密に守り、HTML だと解説を付けたくなる、という非対称があります。
肝心の中身の完成度は高く、Fable 5 の LP は水彩 SVG のイラストと明朝の大見出し、スクロール演出まで作り込まれていました。オセロも合法手のハイライト、3D フリップ反転、パス処理まで実装され、Playwright で着手と CPU 応答を確認できています。
失敗したのは 2 テーマです。ローグライクはタイトル画面の作り込みが良い一方、ゲーム開始後に JS エラーが 6 件出ました。墨流し(WebGL の流体シミュレーション)はフラグメントシェーダーがコンパイルできず、ローカル勢が全滅しているこのテーマの傾向を踏襲しています。
18.8 tok/s は速いのか¶
生成速度は 8 テーマの加重平均で 18.8 tok/s でした。
| テーマ | completion | 秒 | tok/s |
|---|---|---|---|
| pr-triage | 12,004 | 616 | 19.5 |
| othello | 38,563 | 2,012 | 19.2 |
| lp-nishibi | 38,734 | 2,025 | 19.1 |
| hasami-shogi | 38,519 | 2,022 | 19.0 |
| lp-fable5 | 55,360 | 2,968 | 18.7 |
| suminagashi | 50,516 | 2,723 | 18.5 |
| phoenix-lp | 65,000 | 3,533 | 18.4 |
ブレが 18.4〜19.5 と極端に小さいのが特徴です。65,000 トークン出した phoenix-lp でも 18.4 を維持していて、KV キャッシュが増えても速度がほとんど落ちません。
ただし tok/s より効いたのは 1 リクエストあたりの総トークン量でした。thinking がデフォルトで有効かつ長いため、HTML 1 ページの生成に 32〜59 分かかります。9 テーマの completion 合計は 370,866 トークンでした。
phoenix-lp では 65,000 トークンの上限に到達し、末尾の JavaScript がコメントの途中で切れています。それでも canvas 描画とスクロール演出は動いたのでスモークテストは通ってしまいました。「テストが通る」と「出力が完成している」が一致しないケースです。
実運用の観点だと、この速度と thinking の長さは用途を選びます。対話的に使うには 1 応答 30 分は厳しく、バッチで構造化データを抽出する用途なら 191 項目中 189 という精度が効いてきます。
測定を 2 回やり直した¶
素直には終わりませんでした。
MLX サーバが 10 分で落ちる¶
最初は MLX で 8bit に自前変換して mlx_lm.server で回そうとしましたが、生成開始から約 10 分・1 万トークン前後で生成スレッドが落ちます。
499000 を「499GB のメモリ上限」だと読んで、メモリ枯渇を疑いました。しかし実測すると active 29GB で横ばい、swap の増加はゼロで、量的にはまったく余裕があります。仮説と観測が合いません。
これはバイト数ではなく Metal バッファの「個数」の上限でした。MLX の allocator は num_resources_ >= resource_limit_ で判定しています。桁が実測と合わないときは、単位の解釈を疑うべきでした。
切り分けで決定的だったのは、サーバ経由と直接生成を同条件で比較することです。
# 同じモデル・同じプロンプト・同じ max_tokens を直接流す
for _ in stream_generate(model, tokenizer, text, max_tokens=65000):
...
直接 stream_generate を叩くと 13,400 トークン / 644 秒を問題なく通過しました。サーバがクラッシュした地点を大きく超えています。これでモデルでもトークン数でもなく、mlx_lm.server の生成経路固有の問題だと確定しました。
厄介なのは、プロセスは生き続けて生成スレッドだけが死ぬことです。クライアントからは応答待ちのハングに見え、pgrep によるプロセス生存確認では異常を検知できません。監視条件にはサーバログの Exception を入れるべきでした。
最終的に llama.cpp(Ollama + 同等の Q8_0 GGUF)へ経路を変えて 9 テーマ完走しました。量子化水準を 8bit で揃えれば、比較条件は維持できます。MLX の直接生成は 21 tok/s と約 12% 速かったので、サーバが安定していれば MLX の方が良い選択でした。
検証スクリプトが正しい実装を FAIL にした¶
はさみ将棋のスモークテストが FAIL を返しました。「歩 10 枚・と 10 枚」で、初期配置は 9 枚ずつのはずです。
スクリーンショットを見ると盤面は 9 枚ずつで正しく、右側のスコアボードに置かれた「歩」「と」の 1 文字バッジまで駒として数えていました。検証スクリプトが、ページ全体の葉要素からテキストが「歩」「と」のものを数える実装だったためです。
盤面の座標からグリッドを推定し、その矩形内だけを数えるよう直したのですが、レビューでより悪い罠を指摘されました。
素朴に「等間隔が続く最長区間」を盤面とすると、配置を誤ったモデルほど盤面推定も一緒にずれ、過剰な駒が「盤外」に再分類されて逆に PASS してしまうのです。実際、列間隔が乱れた 10 列の盤(駒 10 枚)が 9/9 として通ることを再現できました。
判定基準を被検査対象そのものから導出すると、壊れた入力ほど基準が甘くなります。最終的に、列の採否を x 方向の距離ではなく「盤面の行に乗るか」で判定し、推定列数が 9 でなければ FAIL にする形にしました。
まとめ¶
- 構造化 JSON の抽出は 191 項目中 189 一致で、ローカル勢では過去最高
- ただし引用記号の除去など「原文の装飾をどこまで剥がすか」は Gemma 4 と同じ場所で落とす
- HTML 生成では 7 テーマ中 6 テーマで前置きが混入する。JSON では混入ゼロという非対称がある
- 18.8 tok/s は安定しているが、thinking が長く 1 ページ 30〜59 分かかる
- エラー番号の桁が実測と合わないときは、単位の解釈を疑う
- 判定基準を被検査対象から導出すると、壊れた入力ほど基準が甘くなる
全 9 テーマの成果物と生成条件は OreOre-Bench で公開しています。