Featured image of post Ornith-1.0-35BをHX370に導入する:DeepReinforceの自己改善エージェントモデルを試す

Ornith-1.0-35BをHX370に導入する:DeepReinforceの自己改善エージェントモデルを試す

前回、Qwen3.6-35B-A3BとGemma 4 26B-A4Bをベンチマークしたところで、DeepReinforce社からOrnith-1.0という新しいモデルファミリーがリリースされているのを見つけました。エージェント型コーディングに特化した自己改善型モデルで、しかもGemma 4とQwen 3.5の上に事後学習したものだそうです。前回試した2モデルの延長線上にある存在なので、これは試さない手はありません。

結論から言うと、pp(プロンプト処理)速度はQwen3.6とほぼ同一、tg(生成速度)は約22%速いという結果になりました。ただしチャットテンプレートに既知の不具合があり、そのままではツール呼び出しが動かないため、その対処も含めて残しておきます。

環境

  • マシン: MINISFORUM HX370
  • GPU: AMD Radeon 890M(RDNA 3.5 / gfx1150、UMA 64GB)
  • OS: CachyOS Linux
  • バックエンド: llama.cpp / Vulkan(version 9941)
  • 対象モデル: ornith-1.0-35b-Q4_K_M.gguf

Ornith-1.0の概要

  • 開発元: DeepReinforce(RLでコーディングエージェントを作る専業スタートアップ)
  • ライセンス: MIT
  • サイズ展開: 9B-Dense、31B-Dense、35B-MoE、397B-MoE
  • ベースモデル: Gemma 4とQwen 3.5の上に事後学習
  • 特徴: 解答そのものだけでなく、その解答を導く足場(スキャフォールド)自体もRLで同時最適化する自己改善フレームワーク

公称ベンチマークでは、SWE-bench Verified 75.6、Terminal-Bench 2.1で64.2を記録しており、Qwen3.5・Qwen3.6・Gemma4を上回るとされています。

アーキテクチャ

35B版はQwen3.6と同じhybrid構成を継承しています。

  • 全40層中、30層がGated DeltaNet(線形アテンション)、10層がFull Attention
  • MoE: 256エキスパート+共有エキスパート、実働3B相当(A3B)
  • Vision-language対応
  • コンテキスト: 256K(262,144)ネイティブ
  • Reasoning model(<think>...</think>ブロックを出力)

llama.cpp上でもqwen35moeとしてロードされます。事後学習のベースがQwen3.5系であることの裏付けです。

FP8版とGGUF版、どちらを選ぶか

公式配布にはOrnith-1.0-35B-FP8Ornith-1.0-35B-GGUFの2種類があります。

  • FP8版はデータセンター向けGPU(vLLM上でのA100/H100級)を前提にした形式で、Vulkan/RADV経由のRadeon 890Mでは使えません
  • GGUF版はllama.cppからそのまま扱えるので、HX370環境ではこちら一択です

ダウンロード

cd ~/src/llama.cpp/models
hf download deepreinforce-ai/Ornith-1.0-35B-GGUF \
  --include "*Q4_K_M*" \
  --local-dir .

Radeon 890Mの実効メモリ上限(VRAM 1GiB + GTT 30.7GiB ≒ 31.7GiB)を踏まえ、Q4_K_M(約19.7GiB)を選んでいます。

ベンチマーク結果

前回のQwen3.6-35B-A3B・Gemma 4 26B-A4Bと同条件(batch=512 / ubatch=512、--flash-attn on)で計測しました。

モデル サイズ 実働パラメータ pp1024 tg256
Qwen3.6-35B-A3B 20.60 GiB 3B 344.11 t/s 23.02 t/s
Gemma 4 26B-A4B(QAT) 13.26 GiB 4B 518.94 t/s 30.01 t/s
Ornith-1.0-35B(Q4_K_M) 19.70 GiB 3B 342.84 t/s 28.19 t/s

pp(プロンプト処理)速度はQwen3.6とほぼ同一(誤差範囲内)です。ファイルサイズ・アーキテクチャ表示(qwen35moe)が共通していることを踏まえれば妥当な結果でしょう。一方でtg(生成速度)はQwen3.6より約22%速く、同じ系統のモデルでも事後学習によって量子化後のメモリアクセス効率に差が出ることが見て取れます。

推奨サンプリングパラメータ

コミュニティで報告されている推奨値は以下の通りです。Qwen系の公式推奨サンプリング設定と一致しており、Ornithがその系譜であることを考えると妥当な数値です。

  • temperature: 0.6
  • top_p: 0.95
  • top_k: 20
  • min_p: 0.0
  • repeat_penalty: 1.0

起動コマンド

~/src/llama.cpp/build-vulkan/bin/llama-server \
  --model ~/src/llama.cpp/models/ornith-1.0-35b-Q4_K_M.gguf \
  --chat-template-file ~/src/llama.cpp/ornith_chat_template.jinja \
  --host 0.0.0.0 \
  --port 11434 \
  --ctx-size 32768 \
  --batch-size 512 \
  --ubatch-size 512 \
  --n-gpu-layers 99 \
  --flash-attn on \
  --temp 0.6 \
  --top-p 0.95 \
  --top-k 20 \
  --min-p 0.0 \
  --repeat-penalty 1.0 \
  --jinja

--chat-template-fileで指定しているのは、公式テンプレートに手を加えた修正版です(詳細は後述の補足を参照)。--host 0.0.0.0にしているので、Tailscale経由で他端末からもアクセスできます。

軽量ハーネスPiと接続する

Ornithはエージェント型コーディングに特化したモデルなので、その実力を体感するには軽量なツール呼び出しハーネスで動かすのが早道です。今回はPi(Mario Zechner氏による最小構成のターミナルコーディングハーネス)を使うことにしました。モデルに渡すツールはreadwriteeditbashの4つだけというシンプルな設計で、ローカルモデル向けのcontext engineeringに向いています。

インストール

npm install -g @mariozechner/pi-coding-agent

パッケージ名に紛らわしい兄弟パッケージ(@mariozechner/pi)があるので注意が必要です。今回欲しいのはターミナルハーネスの方で、こちらが正解です。

pi --version
# 0.73.1

モデル設定

~/.pi/agent/models.json:

{
  "providers": {
    "llama-cpp": {
      "baseUrl": "http://localhost:11434/v1",
      "api": "openai-completions",
      "apiKey": "none",
      "models": [
        { "id": "ornith-1.0-35b" }
      ]
    }
  }
}

起動

mkdir -p ~/ornith-test && cd ~/ornith-test
pi

/modelでllama-cpp/ornith-1.0-35bを選択すれば準備完了です。あとは通常のプロンプトでエージェント的なコーディングタスクを投げられます。

補足:既知の不具合

Ornithのモデル埋め込みチャットテンプレートには、システムメッセージが先頭以外に来ると例外を投げるハードコードされたチェックが入っています。

{%- if not loop.first %}
    {{- raise_exception('System message must be at the beginning.') }}
{%- endif %}

--jinjaでツール呼び出しを有効にすると、llama-server自身がツール定義をJSON形式で答えさせるための指示文をシステムメッセージとして追加で挿入します。これが「先頭ではない2つ目のシステムメッセージ」としてテンプレート側の例外チェックに引っかかり、毎回以下のエラーで起動・応答に失敗します。

API Error: 400 Unable to generate parser for this template. Automatic parser generation failed:
Error: Jinja Exception: System message must be at the beginning.

llama.cpp・LM Studio・Ollama・Claude Code経由など、--jinjaでツール呼び出しを使うあらゆる環境で同じ現象が報告されています。対処は、GGUFに埋め込まれたテンプレートを取り出し、該当箇所を削除した修正版を別ファイルとして用意し、--chat-template-fileで明示的に指定する方法です。

1. GGUFからテンプレートを取り出す

pip install gguf --break-system-packages
python3 -c "
import gguf
r = gguf.GGUFReader('./models/ornith-1.0-35b-Q4_K_M.gguf')
tmpl = r.fields['tokenizer.chat_template'].parts[-1].tobytes().decode('utf-8')
open('ornith_chat_template.jinja', 'w').write(tmpl)
"

2. 該当箇所を確認する

grep -n "raise_exception" ornith_chat_template.jinja

'System message must be at the beginning.''No user query found in messages.'の2箇所が対象です。それぞれを囲む{%- if ... %} ... {%- endif %}ブロックごと削除します。

修正前:

{%- if not loop.first %}
    {{- raise_exception('System message must be at the beginning.') }}
{%- endif %}

修正後(ブロックごと削除):

(何も残さない)

No user query found in messages.側も同様に、条件分岐ごと削除します。

3. 修正版を指定して起動する

~/src/llama.cpp/build-vulkan/bin/llama-server \
  --model ~/src/llama.cpp/models/ornith-1.0-35b-Q4_K_M.gguf \
  --chat-template-file ~/src/llama.cpp/ornith_chat_template.jinja \
  --jinja \
  ...(他のオプションは通常通り)

4. 動作確認

ツール呼び出しを含むリクエストを投げて、400エラーが出ずに応答が返れば修正完了です。

curl http://localhost:11434/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "ornith-1.0-35b",
    "messages": [{"role": "user", "content": "Hello, are you working?"}]
  }'

Qwen3.6と同一系統のアーキテクチャを持ちながら、生成速度で上回るという結果になりました。エージェント型コーディングに特化しているという触れ込み通りの実力かどうかは、Piハーネス経由での実タスク(テトリス実装など)で次回確認していきます。

Hugo で構築されています。
テーマ StackJimmy によって設計されています。