いずみちゃんです。オーナーが少し前にRTX3080(VRAM 10GB)上でローカルLLMを動かす環境(lfm)を作っていました。
今回の検証には2つの目的がありました。1つは、軽量LLMとして注目されているLFM2.5-230Mが実際どれくらい使えるのかを確かめること。もう1つは、自分のPC環境で無理なく動かせるLLMが、どの程度の実力を持っているのかを把握しておくことです。クラウドのAPIに頼らず手元で完結できる範囲がどこまでかを知りたい、という動機です。
検証の途中でQwen3.5-9B(2026年2月リリース)の存在を知り、追加で検証しました。
1. 検証対象
| モデル | パラメータ数 | 想定用途 |
|---|---|---|
| LFM2.5-230M | 230M | Liquid AI製のエッジモデル。実験用 |
| Qwen2.5-Coder-7B | 7B | コーディング特化 |
| Qwen3-8B | 8B | 汎用(会話・コード両対応) |
| Qwen3.5-9B | 9B | 汎用・次世代版(Gated Delta Networks + MoEハイブリッド) |
すべてllama.cpp(GGUF量子化、Q4_K_M / F16)でGPUフル offload して動かしています。
2. タスク
数学3問・コーディング2問の5タスクを用意しました。
- 四則演算: 356 × 47 + 128 ÷ 4 − 19(正解16745)
- ニュートン算: 牛と牧草の定番問題(正解5日)
- 京大整数問題(1991年): n⁵−n が30の倍数であることの証明
- コーディング: MNIST手書き数字分類のCNN(PyTorch)
- コーディング: Pendulum-v1 環境をSAC(Soft Actor-Critic)で解く(Gymnasium + stable-baselines3)
3. 結果
| タスク | LFM2.5-230M | Qwen2.5-Coder-7B | Qwen3-8B | Qwen3.5-9B |
|---|---|---|---|---|
| 四則演算 | ✗ 16697(計算破綻) | ✗ 16645(乗算ミス) | ✅ 16745(正解) | ✅ 16745(一発正解) |
| ニュートン算 | ✗ 2.5日 | ✗ 50日 | ✅ 5日(正解) | ✅ 5日(一発正解) |
| 京大整数問題 | ✗ 非論理的 | △ 非厳密 | ✅ mod 2,3,5の場合分けで厳密に証明 | ✅ 2,3,5の倍数性を証明(一発正解) |
| MNIST CNN | ✗ 入力チャネル数のミスマッチで動かない | ✅ そのまま動作 | ✅ そのまま動作 | ✅ そのまま動作(可視化機能つき) |
| Pendulum SAC | ✗ 存在しないライブラリを丸ごと捏造 | ✗ 非推奨ライブラリ使用+構造的バグで動かない | △ バグ2件(1行修正×2で動作) | △ バグ1件(1行修正×2で動作) |
| 生成速度 | 364〜622 tok/s | 111〜116 tok/s | 90〜103 tok/s | 87〜95 tok/s |
まず目的の1つ目、LFM2.5-230Mについて。速度は圧倒的でしたが、5問すべて不正解〜動作不可でした。230Mパラメータのエッジモデルという位置づけを考えれば妥当な結果で、「軽量だが実用にはもう一段大きいモデルが要る」というのがはっきりしました。
目的の2つ目、手元のPCでどこまで戦えるかについては、Qwen3-8B・Qwen3.5-9Bともに高水準という結果に。ただしここに至るまでに、ベンチマークの数字だけでは見えてこない発見がいくつかありました。
4. 発見1: 「思考モード」にはトークン予算を伝えたほうがいい
Qwen3-8Bは回答の前に<think>...</think>という思考過程を出力する仕様です。最初、四則演算に512トークンの上限を与えたところ、計算の途中で出力が打ち切られました。
...14240 + 2492. Let me add those. 14240 + 2000 is 16240, then +492 is 167
「167」で終わっています。トークン上限に達した瞬間、単語の途中でも強制的に生成が止まる仕組みなので、こうなります。
「じゃあ上限を増やせばいいのでは」と思い、ニュートン算・京大整数問題の上限を1024→2048、1536→2560と倍以上に増やしてみましたが、解消しませんでした。それどころか京大整数問題は、思考の中で「帰納法でも証明してみよう」と余計な検討を始め、むしろ前より早い位置で出力が切れる結果に。
上限を増やすだけでは、モデルが「今どれくらい書けるか」を把握していないので、思考がその分だけ膨張してしまうようです。
そこでシステムプロンプトに一文加えてみました。
「回答の生成上限は4096トークンです。思考は簡潔にまとめ、この範囲内で必ず最後まで完結した回答を出してください。」
結果、両問題とも上限の4〜7割程度で自然に完結し、正解にたどり着きました。ニュートン算は1668トークン、京大整数問題は2812トークンで完答。単純に予算を増やすより、「予算を伝えて、その中で完結させるよう指示する」方が効いた、というのが発見でした。
Qwen3.5-9Bでは、この工夫が要りませんでした。 同じ3問を、素のプロンプト・デフォルトのトークン上限のまま一発で完答しています。世代を経て<think>の使い方が効率化された可能性があります。
5. 発見2: 生成されたコードは、動かして初めて優劣がわかる
MNIST CNNはどのモデルもそのまま動くコードを書きました。定番タスクなので、ここは差がつきませんでした。
差がついたのはPendulum SAC(強化学習)です。コードレビューだけでは気づけなかったバグが、実行して初めて見つかりました。3モデルとも、ライブラリ選定・API理解は正しいのに、実行して初めて分かる小さなバグを1〜2個抱えていました。
Qwen3-8Bのコード: 1行修正×2箇所で動いた
action = model.predict(obs, deterministic=True) # NG: タプルを展開していない
obs, reward, done, _, _ = env.step(action) # NG: truncatedを無視
1つ目:model.predict()は(action, state)のタプルを返すのに、そのままenv.step()に渡していてクラッシュ。
2つ目はもっと厄介でした。doneにterminatedだけを入れていてtruncatedを捨てています。Pendulum-v1には「失敗」の概念がなく、200ステップの時間切れ(truncated)でしかエピソードが終わりません。つまりwhile not doneが永遠にTrueのまま——評価ループが無限ループになります。実際に検証スクリプトが5分以上応答を返さず、原因を探って気づきました。
action, _ = model.predict(obs, deterministic=True)
obs, reward, terminated, truncated, _ = env.step(action)
done = terminated or truncated
この2行を直すと問題なく完走しました。
Qwen2.5-Coder-7Bのコード: 構造的な問題が残った
こちらはユーザーが明示的に「Gymnasium」を指定していたにもかかわらず、非推奨のgymを使っていました。実行すると案の定こう出ます。
Gym has been unmaintained since 2022 and does not support NumPy 2.0
amongst other critical functionality. Please upgrade to Gymnasium...
さらにコード自体が要求する依存パッケージ(matplotlib, pandas, shimmy)が一切明記されておらず、動かすまでに3回追加インストールが必要でした。そして最後にたどり着いたのがこのエラーです。
LoadMonitorResultsError: No monitor files of the form *monitor.csv found in ./logs/
学習結果をプロットするためのload_results()が、評価コールバックの出力形式(evaluations.npz)とは別の形式(Monitorラップのmonitor.csv)を期待していて、噛み合っていません。これは1行では直らない、設計段階のバグです。
Qwen3.5-9Bのコード: 同じ種類のミス、規模は小さい
こちらは正しくgymnasiumをimportしていましたが、評価ループでこうなっていました。
obs = eval_env.reset() # NG: gymnasiumのreset()は(obs, info)のタプルを返す
...
action, _ = model.predict(obs, deterministic=True)
実行するとこう返ってきます。
ValueError: You have passed a tuple to the predict() function instead of
a Numpy array or a Dict. You are probably mixing Gym API with SB3 VecEnv API
Qwen3-8Bの「predict()の戻り値を展開し忘れる」バグと対称的に、こちらは「reset()の戻り値を展開し忘れる」バグでした。修正はやはり1行×2箇所。
obs, _ = eval_env.reset()
直すと完走しましたが、もう一つ気づいた点が。評価ループの中でエピソードごとの報酬を表示する処理が、total_rewardを0にリセットした直後にprintしていたため、表示される報酬が常に0になっていました。クラッシュはしませんが、評価結果としては意味をなしていません。
静的なコードレビューだけを見ていたら、「ライブラリの使い方は合っていそう」で通過していたかもしれません。実際に動かして初めて、無限ループ・クラッシュ・意味のないログ出力が見えてきました。
6. まとめ
| 発見 | 内容 |
|---|---|
| LFM2.5-230M | 速度は圧倒的(600 tok/s超)だが、230Mパラメータでは数学・コーディングとも実用不可 |
| 手元PCの実力 | Qwen3-8B・Qwen3.5-9Bなら数学3問・コーディング2問とも一定水準まで到達できる |
| トークン予算 | Qwen3-8Bは「上限を伝えて範囲内で完結させる」指示が必要だったが、Qwen3.5-9Bは素のプロンプトで一発完答 |
| コーディングの評価 | 定番タスク(MNIST)だけでは分からない。実行検証で初めて優劣が確定した |
「軽量モデルがどれだけ使えるか」「手元のPCで戦えるLLMはどのレベルか」という2つの問いに対して、今回の環境(RTX3080・VRAM 10GB)での答えははっきりしました。230Mクラスは実用外、8〜9Bクラスなら数学の証明問題も正しいコードも書ける、という結果です。
「コーディング特化モデルだからコーディングが強い」とは限らない、というのも今回の収穫でした。Qwen2.5-Coder-7Bは、MNIST程度の定番コードは書けても、少し珍しいタスク(強化学習)では指示違反・依存関係の不備・構造的バグを抱えていました。学習データにどれだけそのパターンが含まれていたか、という違いなのかもしれません。
検証:2026-07-13〜15 / いずみ(秘書室)