sokudan-ja-310m

日本語 System One 意思決定モデル。 日本語テキスト(state)と型付き質問(questions)を受け取り、テキストを一切生成せずに 単一フォワードパスで型付き回答と確率を返します。生成しないので、 パースするものがなく、ハルシネーションする余地もありません。

この モデルカードの数値はすべて公開リポジトリのコードで再現できる実測値です。 未測定のものは「測定していない」と明記します。


使い方

PyPI には上げていないので、リポジトリから入れてください:

pip install git+https://github.com/hiroki-abe-58/sokudan.git
import sokudan

# リポジトリ ID を渡せば重みと temperatures.json を取得します。
# 未較正で使う場合は temperatures を渡さないでください(下の Limits)。
agent = sokudan.load("GeneLab/sokudan-ja-310m", temperatures="temperatures.json")
result = agent.predict(
    {"body": "先月の請求で同じ金額が二回引き落とされています。至急ご確認ください。"},
    {
        "department": {"type": "choice",
                       "instructions": "この問い合わせはどの部署が担当すべきか",
                       "criteria": {"請求": "支払い・返金", "技術": "不具合・障害",
                                    "営業": "料金・新規契約", "その他": "上記以外"}},
        "urgency":    {"type": "score",
                       "instructions": "この依頼の緊急度は",
                       "criteria": ["急がない", "早めに", "業務が止まっている"]},
        "churn":      {"type": "noul", "instructions": "解約を示唆しているか"},
    },
)

質問タイプは choice / score / boolnoul はエイリアス)。 スキーマはリクエストごとに自由で、再学習は要りません。


何を狙ったモデルか

作る前に、既存の System One 系モデルが日本語でどう振る舞うかを実測しました (bench_ja 300件、docs/baseline_ja.md)。

対象 choice acc score RPS↓ bool acc bool AUROC
laya-multilingual (ja) 0.747 0.232 0.543 0.523
多数決クラス 0.380 0.197 0.703
ランダム 0.253 0.201 0.513
  • choice は日本語でも既に動いていた(多数決の約2.0倍)。ここは狙っていません
  • score は多数決以下。原因はスキーマだけ変えた5条件すべてで 提示順の第1選択肢が300件中0〜1件しか選ばれない位置バイアス
  • bool は AUROC 0.523 で順位付けができていない

このモデルは scorebool を狙っています。


評価結果

3 シードの平均 ± 標準偏差bench_ja 300 件、同一条件、同一メトリクス実装)。 bench_ja 300件、同一条件、同一メトリクス実装で測定したものだけを載せること。

対象 choice acc choice ECE score RPS↓ score acc score MAE bool acc bool ECE bool AUROC
sokudan-ja-310m 0.847 ± 0.009 0.147 ± 0.003 0.090 ± 0.023 0.763 ± 0.088 0.258 ± 0.086 0.788 ± 0.010 0.202 ± 0.013 0.789 ± 0.043
sokudan-ja-310m + 温度較正 0.847 ± 0.009 0.092 ± 0.036 0.149 ± 0.032 0.763 ± 0.088 0.258 ± 0.086 0.788 ± 0.010 0.129 ± 0.009 0.789 ± 0.043
laya-multilingual (ja) 0.747 0.148 0.232 0.443 0.620 0.543 0.352 0.523
多数決クラス 0.380 0.000 0.197 0.460 0.540 0.703 0.000
ランダム 0.253 0.003 0.201 0.403 0.777 0.513 0.013

配布している重みについて

このリポジトリのメイン revision は seed 0 の重みです。 seed 0 は 3 本を学習する前から既定として staging していたもので、 結果を見てから選んだものではありませんseed 1 / seed 2 は同じリポジトリの revision seed1 / seed2 に置いてあります。

下の表は seed 0 単独の実測3 シードの平均 ± 標準偏差を併記します。 ダウンロードした重みが出す数値は前者です。

指標 seed 0(配布している重み) 3 シード平均 ± SD
choice acc 0.843 0.847 ± 0.009
choice ECE↓ 0.148 0.147 ± 0.003
score RPS↓ 0.117 0.090 ± 0.023
score acc 0.663 0.763 ± 0.088
score MAE↓ 0.357 0.258 ± 0.086
bool acc 0.793 0.788 ± 0.010
bool ECE↓ 0.198 0.202 ± 0.013
bool AUROC 0.837 0.789 ± 0.043
bool mean P(true) 0.135 0.125 ± 0.012

score はシード間の振れが大きい指標です(acc 0.663 / 0.800 / 0.827)。 平均 0.763 はどのシードの実測値でもありません。seed 0 を使う場合の実測は 0.663 です。

温度較正について

temperatures.json を同梱していますが、既定は未較正ですsokudan.load(..., temperatures=...) を明示的に渡したときだけ適用されます。

3 シード平均での効果:

指標 較正前 較正後
choice ECE↓ 0.147 0.092 改善
bool ECE↓ 0.202 0.129 改善
score RPS↓ 0.090 0.149 悪化

score の RPS は較正で悪化します。 同梱の温度は合成の検証セットでフィットしたもので、 bench_jascore 分布とは一致していません。 利用者自身のデータで再フィットすることを推奨しますscripts/calibrate.py)。 choicebool の較正だけを使い、score は未較正のままにするのも妥当な選択です。

レイテンシ

項目
1問 p50 / p95 11.9 ms / 29.5 ms
10問 / 50問 未測定(joint は質問数に比例。1問あたりの実測から外挿しないこと)
questions/sec 229.4 ± 0.6

位置バイアスの検証(このモデルの主目的)

laya-multilingual が失敗した5条件(選択肢の順序・表記・段階数を変えたもの)で 同じ測定を行った結果:

同じ 300 件・同じ質問で、選択肢の表記と順序だけを変えた 5 条件。 提示順そのまま(remap なし)で第 1 選択肢が argmax になった件数です。

条件 提示した選択肢 sokudan 第1選択肢(3シード) Laya 第1選択肢 sokudan acc
A 原文 急がない / 早めに / 業務が止まっている 92 ± 13 0 0.761 ± 0.085
B 逆順 業務が止まっている / 早めに / 急がない 81 ± 20 0 0.788 ± 0.070
C 言い換え 低 / 中 / 高 98 ± 19 1 0.697 ± 0.009
D 言い換えの逆順 高 / 中 / 低 92 ± 12 1 0.733 ± 0.048
E 4段階 全く急がない / 急がない / 早めに / 業務が止まっている 45 ± 25 0 0.427 ± 0.072

Laya は 5 条件すべてで第 1 選択肢が 300 件中 0〜1 件しか選ばれません (「第1選択肢スロットが構造的に選ばれない」位置バイアス)。 sokudan は 3 シード・5 条件すべてで 15〜35% の頻度で選んでいます。

ただし E(K=4)は acc 0.427 と、3 段階の A〜D(0.697〜0.788)から明確に落ちます。


学習

データ

すべて合成データです。 ラベル条件付き生成(生成条件=正解ラベル)で作っています。

生成した文書 4,833 文書
ラベル付き (文書, 質問) ペア 31,243 ペア
スキーマ拡張後のビュー 79,552 ビュー

「79,552 ビュー」を「79,552 例」と読み替えないでください。 同じ文書・同じラベルをスキーマ表記だけ変えて複数回見せたものを含みます。 独立な事例数は「ラベル付きペア」の段です。

  • 生成モデル: qwen3:30b-a3b-instruct-2507-q4_K_M(Apache-2.0, ollama 経由)、temperature 0.9
  • カタログ: 14 ドメイン / 28 属性 / choice は4〜6択 / scoreK=2〜7 / bool 10属性
  • bool のラベル偏りは属性ごとに向きを混ぜています(false寄り4 / ほぼ均衡3 / true寄り3)
  • train / val は文書単位で分割

スキーマランダム化

選択肢の順序シャッフル、表記ゆれ、ディストラクタ混入、選択肢の削除、 指示文の言い換え、順序尺度の反転。正解ラベルは全変換に追従します。

設定

項目
Stage 1 損失 choice/bool は CE、score は RPS
Stage 2 (質問タイプ, 選択肢数) ごとに温度を1つ、検証セットでフィット
Stage 3 (RLCD) 未実施
エポック 2
バッチサイズ 24
学習時間 661 秒 / シード(RTX 5090、3 シード)
シード 1つのみ
attention sdpa(FA2 はこの環境でビルド不可)

Limits(正直に)

ここを盛ると死にます。以下はすべて現時点で確定している制約です。

測定の限界

  • 単一シードです。 3シード以上の平均±標準偏差が本来の要件ですが、 1日スプリントのため1シードに落としました。この数値に分散は付いていません。 シードを変えたときにどれだけ動くかは測定していません
  • 評価は bench_ja の 3 スキーマのみ(部署ルーティング4択 / 緊急度3段階 / 解約示唆)。 300件、1ドメイン(日本語の業務問い合わせ文)です。 他のタスク・他の文書種での性能は測定していません
  • bench_ja も合成データです。 実際の業務メールの分布とは異なります。
  • bench_ja を生成したモデルと、比較対象の LLM-as-classifier ベースラインは 同一モデル(qwen3)です。そのベースラインは公平な比較対象ではなく、 「生成条件がどれだけ文面に現れているか」の上限の目安として読んでください。

アーキテクチャと運用上の限界

  • bool は true を過少予測します。 bench_ja での mean P(true) は 0.125 ± 0.012、 対して gold の陽性率は 0.297 です。AUROC 0.789 なので順位付けは機能していますが、 閾値の位置がずれています。argmax をそのまま使うと true を取りこぼします。 利用者側の事前確率に合わせて閾値を決めてください。 これは温度スケーリングでは補正されません(温度は順位も argmax も変えないため。 較正後の mean P(true) は 0.170 で、依然として gold より低いままです)。 このずれは bench_ja の陽性率に対するもので、モデルの大域的な性質ではありません: 陽性率 0.513 に再バランスした held-out では mean P(true) 0.437 とほぼ整合します (docs/benchmarks.md §4 の追試)。 logit のバイアス項 1 つで補正でき、AUROC は 1e-6 未満しか動きませんが、 フィットすべき相手は検証セットではなく配備先の事前確率です。
  • 選択肢が 4 段階の score で精度が落ちます。 位置バイアス検査の E 条件(4段階)は acc 0.427 ± 0.072 で、3 段階の A〜D(0.697〜0.788)から明確に落ちます。 ただし原因は K ではありません: held-out を K 別に分解すると K=4 は学習ビュー最多 (24.4%)で acc も K=3 より高く、K に対して単調でもありません (docs/benchmarks.md §5 の追試)。 残る説明はその条件固有の選択肢の並びですが、未検証の仮説です。 いずれにせよ K≥4 の性能を K=3 から外挿しないでください。
  • レイテンシは質問数に比例します。 v0.1 は joint encoding で、質問ごとに state を 再エンコードします。N 問のリクエストは backbone を N 回通ります。 「state は 1 リクエストにつき 1 回」という当初の主張は撤回しました (https://github.com/hiroki-abe-58/sokudan/blob/main/docs/architecture.md §1.2)。質問側エンコードのキャッシュも joint では効きません。
  • state が長くなると未知スキーマの精度が下がります。 backbone の local_attention は 128 です。 held-out の AUROC はトークン数で 0–200: 0.904 / 200–400: 0.882 / 400–600: 0.866 / 600–: 0.730 と単調に低下します(docs/benchmarks.md §6 の追試)。 学習済み属性は 600 トークンまでほぼ平坦(0.997)です。 600 トークン超は n=33 で標準誤差が約 0.09あり、そこでの急落は断定できません。 学習データの state は平均 134 トークン・p95 237 トークンです。
  • 位置に依存する質問は苦手です。 held-out の位置依存属性 「文末が問いかけで終わっているか」は AUROC 0.688 にとどまり、 意味を問う属性(意図推論 0.786、明示的要求 0.995)より明確に低く出ました。
  • エンコーディングは [CLS] 指示 [SEP] 選択肢+マーカー [SEP] state [SEP] の joint 方式で、 これは Laya と同じ配置です。state と質問を別系列にする方式も実装して A/B しましたが、 未知スキーマへの意図推論が転移しませんでした(held-out AUROC 0.506 対 0.872)。

学習データの限界

  • 学習データは合成データのみです。JGLUE などの実データは、 ライセンスの一次確認に時間を要するため当日は採用していません。
  • 生成者は単一モデル(qwen3:30b-a3b-instruct-2507-q4_K_Mです。 そのモデルの語彙・言い回しの癖が学習データ全体に乗っています。 別のモデルが書いた日本語、まして人間が書いた日本語での性能は測定していません
  • 学習カタログは 14 ドメインで、いずれも「業務文書」です。 文学・会話・専門文書などは含みません。

訂正(2026-09-21)。 bench_jabool 質問(「送信者は解約・契約終了を示唆しているか」)は 学習データに一度も現れていません。ただし当日の bench_ja リーク検査は不完全で、 解約 が train+val の質問文 718 行、解除 が 868 行に含まれていました。 いずれも choice 質問の選択肢説明(criteria の値)と選択肢ラベルとしての出現です (survey_freetext の「申込や解約などの手順」、contract_clause の選択肢「解除」)。 当時の検査が criteriaキーしか読んでおらず値を検査していなかったこと、および 解除 が語彙リストに入っていなかったことが原因です。 カタログと検査は scripts/check_catalog_leak.py で修正済み。 2026-09-20 の s0 / s1 の数値は訂正しません——bool 質問は未出現であり、 語彙が入っていてもなお bool が転移しなかったという事実は変わらないためです。

bool は未知スキーマでは多数決以下

bool(yes/no 質問)は、学習で見ていないスキーマに対して多数決ベースラインを下回ります。 学習したスキーマ系統では機能しますが、新しい言い回しの yes/no 質問に移すと崩れます。 2択の choice として問い直す経路も試しましたが改善せず、 選択肢の提示順を入れ替えるだけで精度が大きく動く状態でした。

bool を未知のスキーマで使わないでください。使う場合は自分のデータで必ず検証してください。 原因の切り分けは継続中です。

目標にしていないこと

  • choicelaya-multilingual を上回ることは目標にしていません。 事前の実測で choice は既に実用水準(多数決の約2.0倍)だったためです。 choice の数値は報告しますが、そこを改善する設計はしていません。
  • 英語その他の言語は対象外です。日本語のみで学習・評価しています。

実装上の制約

  • 温度を渡さない限り確率は較正されていません。
  • act / escalate ヘッドはありません。 学習信号(交差適合)を用意できないなら 作らない、という判断です。confidence 閾値で運用してください。
  • RLCD (Stage 3) は未実施、ONNX / TensorRT も未対応です。
  • FlashAttention-2 は使っていません(この環境でビルド不可: CUDA Toolkit 13.1 と torch の 12.8 の不一致)。sdpa + 長さバケット化で動かしています。
  • decision head 内に RoPE を入れていません。backbone からコピーした attention 重みは 学習時に隣にあった位置信号なしで動いています。アブレーションは未実施です。
  • head は 2 層固定です。2層 vs 4層のアブレーションは未実施です。

やってはいけない使い方

  • 人間の最終判断を置き換える用途(採用、与信、懲戒、医療、法務の決定)には使わないでください。 合成データのみで学習された 314.6M のモデルです。
  • 確率をそのまま業務上の期待値計算に入れる前に、自分のデータで較正し直してください。

TypeSafe Jev について

TypeSafe の利用規約(Master Customer Agreement 2.3(b))が、同サービスおよびその出力を類似製品の開発に用いることを禁じているため、本プロジェクトでは Jev を実測していません。 このリポジトリには Jev を呼ぶコードが存在しません。


引用

バックボーン:

@misc{modernbert-ja,
  title  = {{ModernBERT-Ja}},
  author = {SB Intuitions},
  year   = {2025},
  url    = {https://huggingface.co/sbintuitions/modernbert-ja-310m}
}
Downloads last month
29
Safetensors
Model size
0.3B params
Tensor type
F32
·
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support

Model tree for GeneLab/sokudan-ja-310m

Finetuned
(17)
this model