※本記事の情報は2026年8月時点のものです。
「契約したのは最上位モデルのはずだけど、本当にそれが動いてるのかな」
APIの向こう側は見えません。レスポンスが返ってくるだけで、そこで何が動いているかを確かめる手段を、私たちはほとんど持っていません。
TL;DR: 同じプロンプトを複数モデルに投げて、トークン数の差分を比べます。16個のプローブで16個とも差分が一致すれば、トークナイザーは同一です。この記事では実際に動かしたスクリプトと、16プローブ全ての実測値を載せます。
APIの向こう側は、契約書では確かめられない
モデル検証が必要になったのは、AIの供給構造が不透明になったからです。
理由は3つあります。ひとつめは、匿名で提供されるモデルが増えたこと。OpenRouterには「stealth(ステルス)モデル」という枠があります。提供元を明かさないままAPIで公開されるモデルが、定期的に登場します。2026年8月20日に現れた stealth/ox-alpha もそのひとつです。
ふたつめは、同じモデル名でも実体が変わりうること。プロバイダーが裏でモデルを差し替えても、API利用者からは気づきにくい構造になっています。
3つめは、業務利用でこれが効いてくること。社内システムに組み込むAIについて「契約したモデルが動いている」ことを説明できなければ、それはサプライチェーンの穴です。ベンダーの申告を検証する手段が要ります。
モデル検証は好奇心の問題ではなく、自分が使っているものを自分で確かめるという基本的な話です。
トークン数の絶対値を比べても何も分からない
最初に結論を書きます。トークン数はそのまま比べてはいけません。差分を見てください。
なぜかを実例で示します。英語の1文を2つのモデルに投げてみます。プロンプトは「The quick brown fox jumps over the lazy dog.」です。レスポンスの usage.prompt_tokens はこうなりました。
| モデル | prompt_tokens |
|---|---|
stealth/ox-alpha | 97 |
z-ai/glm-5.3 | 22 |
75も違います。ここで「別のトークナイザーだ」と結論づけると間違えます。
差の正体はチャットテンプレートです。APIに送るのは私たちが書いたプロンプトだけですが、モデル側では、その前後にシステムプロンプトや役割タグが付加されます。推論モデルの場合は思考を促す指示も入るため、この付加分が大きくなります。Ox Alphaは推論モデルで、reasoning フィールドに思考過程を出力します。
重要なのは、この付加分がリクエストごとに変わらない定数だということです。だから、こうすれば消せます。
差分 = (プロンプトAのトークン数) - (プロンプトBのトークン数)
同じモデル内で引き算すれば、定数のテンプレート分は打ち消し合います。残るのは、トークナイザーがそのテキストをどう分割したかという情報だけです。
この差分ベクトルをモデル間で比べれば、テンプレートの違いに邪魔されずにトークナイザー自体を比較できます。
16個のプローブで、トークナイザーは割れる
実際に動かしたスクリプトを先に置きます。OpenRouterのAPIキーだけあれば動きます。依存ライブラリはありません。
#!/usr/bin/env python3
"""tokenizer指紋照合 — 差分比較でトークナイザーの同一性を判定する。"""
import json
import os
import urllib.request
API_KEY = os.environ["OPENROUTER_API_KEY"]
MODELS = ["stealth/ox-alpha", "z-ai/glm-5.3", "z-ai/glm-5.2"]
PROBES = [
("en-basic", "The quick brown fox jumps over the lazy dog."),
("en-contraction", "I can't believe it's already 2026! Don't stop."),
("ja-basic", "こんにちは、今日はいい天気ですね。"),
("ja-tech", "製造業におけるAI活用の事例を教えてください。"),
("code-python", "def fibonacci(n):\n return n if n < 2 else fibonacci(n-1) + fibonacci(n-2)"),
("code-js", "const x = [1,2,3].map(n => n * 2);"),
("number-pi", "3.14159265358979323846264338327950288419716939937510"),
("emoji-unicode", "🚀✨🎉 特殊文字テスト 𝕏 𝔘𝔫𝔦𝔠𝔬𝔡𝔢"),
("currency", "The price is ¥1,980 (about $13.50) per month."),
("long-word", "antidisestablishmentarianism pneumonoultramicroscopicsilicovolcanoconiosis"),
("url", "https://github.com/openai/gpt-5/blob/main/README.md"),
("json", '{"name": "test", "values": [1, 2, 3], "nested": {"key": "value"}}'),
("zh", "人工智能的发展非常迅速。"),
("ko", "인공지능의 발전이 매우 빠릅니다."),
("math", "∫₀^∞ e^(-x²) dx = √π/2"),
("mixed", "AIモデル「Ox Alpha」は1Mコンテキスト対応で、$0.0000014/tokenです。"),
]
def get_prompt_tokens(model, prompt):
"""max_tokens=1 で投げて prompt_tokens だけ取る(生成コストを最小化)。"""
req = urllib.request.Request(
"https://openrouter.ai/api/v1/chat/completions",
data=json.dumps({
"model": model,
"messages": [{"role": "user", "content": prompt}],
"max_tokens": 1,
}).encode("utf-8"),
headers={
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json",
},
)
with urllib.request.urlopen(req, timeout=120) as r:
return json.load(r)["usage"]["prompt_tokens"]
counts = {m: {} for m in MODELS}
for name, prompt in PROBES:
for m in MODELS:
counts[m][name] = get_prompt_tokens(m, prompt)
print(f"[{name}] " + " ".join(f"{m}={counts[m][name]}" for m in MODELS))
# 差分ベクトルを作り、モデル間で比較する
base = "en-basic"
deltas = {m: {k: v - counts[m][base] for k, v in counts[m].items()} for m in MODELS}
ox, ref = deltas["stealth/ox-alpha"], deltas["z-ai/glm-5.3"]
match = sum(1 for k in ox if ox[k] == ref[k])
print(f"\n差分一致: {match}/{len(ox)}")
プローブの設計には意図があります。トークナイザーの違いが出やすいのは、文字体系の境界です。英語だけで比べても差は出にくいためです。日本語・中国語・韓国語、コード、数値の羅列、絵文字と特殊グリフ、URL、JSONを混ぜています。円周率50桁を入れているのは、数字の分割単位がトークナイザーごとに違うからです。
実行結果です。2026年8月23日に、OpenRouter API経由で実測しました。
| プローブ | ox-alpha | GLM-5.3 | GLM-5.2 | ox差分 | GLM-5.3差分 | 一致 |
|---|---|---|---|---|---|---|
| 英語(基本文) | 97 | 22 | 22 | +0 | +0 | ✅ |
| 英語(短縮形) | 102 | 27 | 27 | +5 | +5 | ✅ |
| 日本語(日常) | 96 | 21 | 21 | -1 | -1 | ✅ |
| 日本語(技術) | 103 | 28 | 28 | +6 | +6 | ✅ |
| Python | 111 | 36 | 36 | +14 | +14 | ✅ |
| JavaScript | 105 | 30 | 30 | +8 | +8 | ✅ |
| 円周率50桁 | 120 | 45 | 45 | +23 | +23 | ✅ |
| 絵文字+特殊グリフ | 122 | 47 | 47 | +25 | +25 | ✅ |
| 通貨記号 | 105 | 30 | 30 | +8 | +8 | ✅ |
| 超長単語 | 108 | 33 | 33 | +11 | +11 | ✅ |
| URL | 102 | 27 | 27 | +5 | +5 | ✅ |
| JSON | 114 | 39 | 39 | +17 | +17 | ✅ |
| 中国語 | 92 | 17 | 17 | -5 | -5 | ✅ |
| 韓国語 | 103 | 28 | 28 | +6 | +6 | ✅ |
| 数式記号 | 104 | 29 | 29 | +7 | +7 | ✅ |
| 日英混在 | 113 | 38 | 38 | +16 | +16 | ✅ |

上段が絶対値、下段が差分。絶対値では一律75トークン離れているのに、差分は完全に重なります。
16個中16個の差分が一致しました。 絶対値では一律75トークン離れているのに、差分は完全に同じ動きをします。これは、テンプレートの重さが違うだけで、テキストを切り分ける規則そのものは同一だということです。
計測条件を明記します。16プローブ × 3モデル、max_tokens=1、OpenRouter API経由、2026年8月23日実測。基準は英語基本文です。
なお、この結果は英語圏の先行報告と独立に一致しました。研究者の@aitrackerbot氏が2026年8月22日に報告しています。30プローブ・14の書記体系でGLM-5.3と一致し、一貫した+75トークンの隠れラッパーがあった、と。私はこの報告を見る前に16プローブで実施し、同じ+75にたどり着きました。先に見つけたという話ではなく、別の手で同じ数字が出たという再現の話です。手法の信頼性としては、こちらの方が意味があります。
モデルの指紋は3層に分かれている

トークナイザーだけが指紋ではありません。証拠は3つの層に分かれ、それぞれ強度と耐久性が違います。
第1層: トークナイザー層
前章で見た差分照合です。強度は中、耐久性は高い。
トークナイザーはモデルの学習時に固定されるため、プロバイダーが後から変えることは実質できません。パッチで潰せない証拠です。ただし後述するように、同一トークナイザーは同一モデルを意味しません。
第2層: サービング層
APIを運用しているインフラの署名です。強度は高いが、耐久性は低い。
Ox Alphaでは2つの証拠が報告されています。ひとつはJavaのスタックトレースです。top_p に数値ではなく文字列 "abc" を渡す不正なリクエストで露出しました。内部クラス名は com.wd.paas.api.domain.v4.chat.ChatCompletionRequest でした。これがZhipu AI(Z.ai)の公開APIエンドポイント /api/paas/v4/chat/completions の構造と一致します(Chetaslua氏による報告)。
もうひとつがエラーコードです。role情報を不正にすると、次が返ります。{"code":"1214","message":"Incorrect role information"} です。このコードはZ.aiがホストするGLMで一貫して出ます。
ここが面白いところです。同じGLMの重みをDeepInfraでホストすると、別の検証エラーが出ます。 つまりエラーコード1214が指しているのは「モデルが何か」ではなく「誰がAPIを運用しているか」です。層が違うものを見ているわけです。
耐久性が低いのは、スタックトレースの露出がOpenCode側のバリデーションバグに依存しているからです。修正されれば消えます。強い証拠ですが、一時的です。
第3層: 行動層
モデルの応答内容そのものから読み取る指紋です。強度は低いが、独立性が高い。
私の実測では2つ拾えました。ひとつは知識カットオフです。聞くと「early 2025、だいたい2025年1月まで」と答えます。GLM-5系のカットオフと整合します。
もうひとつは、思考過程の漏洩です。Ox Alphaに自己紹介を求めると、本人はこう名乗ります。
I am ox-alpha, a large language model developed by an undisclosed organization.
ところが同じレスポンスの reasoning フィールド(推論モデルが出力する思考過程)には、こう書かれていました。
According to my system prompt, I am “ox-alpha”… I should identify myself strictly as this model and not as any other.
正体を隠すよう指示されていること自体を、思考の途中で漏らしています。これは「隠されている」という事実の証拠にはなりますが、「何が隠されているか」の証拠にはなりません。行動層の証拠が弱いというのは、こういう意味です。
3層のまとめ
| 層 | 何を見るか | 強度 | 耐久性 | パッチ可能性 |
|---|---|---|---|---|
| トークナイザー層 | prompt_tokensの差分 | 中 | 高 | ほぼ不可 |
| サービング層 | スタックトレース・エラーコード | 高 | 低 | 容易 |
| 行動層 | カットオフ・自己申告・CoT | 低 | 中 | プロンプトで容易 |
検証を設計するときは、耐久性の高い層で当たりをつけ、強度の高い層で裏を取るのが基本です。1層だけで結論を出さないでください。
一致が証明するのは「同一トークナイザー」であって「同一モデル」ではない
ここが手法の限界です。誤って強く主張すると、検証の信頼性を自分で壊します。
前掲の表をもう一度見てください。GLM-5.2もGLM-5.3と完全に同じ数値です。つまりこの実測が示すのは「Ox AlphaはGLM-5系と同じトークナイザーを使っている」までです。「GLM-5.3である」までは言えません。
同じトークナイザーを共有する状況はいくらでもあります。同じシリーズの別バージョン、同じベースからのファインチューニング、同じ研究室の別モデル。トークナイザーは学習時の資産として使い回されるものです。
ではなぜGLM-5.3が有力視されているのか。他の証拠と重なるからです。
- 1,048,576トークンのコンテキスト長がGLM-5.3と一致(GLM-5.1以下は204,800)
- 出力上限131,072トークンが一致
- 推論モデルであることが一致
- 知識カットオフが2025年初頭でGLM-5系と整合
- サービング層がZ.aiのインフラを指している
ひとつひとつは決定打になりません。重なった結果として、現時点で最も有力な仮説という位置づけになります。
ただし一致しない点もあります。OpenRouterのモデル一覧を見ると、Ox Alphaの入力modalityは text / image / video ですが、GLM-5.3は text のみです(2026年8月23日時点でAPIから取得)。これをどう読むかは2通りあります。ひとつは、Ox Alphaが未公開のマルチモーダル版である可能性。もうひとつは、stealth枠のメタデータが実際の能力を反映していない可能性です。都合の悪いデータを黙って落とさないのが検証の基本なので、ここは未解決として残します。
そして注意点です。2026年8月23日時点で、提供元からの公式発表はありません。 GLM-5.3の重み公開は2026年8月28日頃とされており、公開後に直接照合できるまで、これは仮説のままです。断定して書いている記事を見かけたら、その根拠が公式発表かどうかを確認してください。
もうひとつ、性能主張についても同じ姿勢が要ります。Ox AlphaのDeepSWE 80%という数字が話題になりました。ただしこれは10タスクのユーザーテストによるもので、監査されたリーダーボードの結果ではありません。数字を見たら、Nと計測条件を確認してください。
この手法を自社のAPI検証に持ち込む手順
ここまでを、業務で使える形に一般化します。「契約したモデルが動いているか」を確かめる手順です。
ステップ1: 基準となるモデルを決める
契約書のモデルが別経路でも呼べるなら、それを基準にします。公式API、他のプロバイダー、ローカルなどです。基準が取れない場合、この手法は「変化の検出」にしか使えません。その場合は次のステップ2をカレンダーで定期実行し、過去の自分の測定値を基準にします。
ステップ2: プローブを10〜20個用意する
文字体系の境界を狙います。以下を最低1つずつ入れてください。
- 自社で実際に投げる言語(日本語なら日本語)
- 英語
- コード(自社で使う言語)
- 数値の長い羅列
- 絵文字・特殊記号
- URLやJSONなど構造化テキスト
数が多いほど偶然の一致が起きにくくなります。16個で16個一致する確率は、別トークナイザーならまず出ません。
ステップ3: max_tokens=1 で投げて prompt_tokens を取る
生成させる必要はありません。max_tokens=1 にすれば出力コストがほぼゼロで、必要な usage.prompt_tokens は取れます。前掲のスクリプトがそのまま使えます。
ステップ4: 差分ベクトルを作って比較する
ひとつのプローブを基準にして引き算し、モデル間で並べます。全一致なら同一トークナイザー、1つでもずれれば別トークナイザーです。
ステップ5: 他の層で裏を取る
トークナイザーが一致したら、コンテキスト長、対応モダリティ、知識カットオフ、推論モデルか否かを突き合わせます。ずれがあれば、契約と違うものが動いている可能性を疑ってください。
定期実行に載せる
一度きりの検証には意味が薄いです。四半期ごとなど定期的に走らせて、測定値が変化したら通知する形にすると、モデルの無断差し替えを検出できます。
⚠️ 検証時の注意点
匿名モデルや外部APIを検証する際は、プロンプトの内容に注意してください。提供元が明かされていないモデルは、データの取り扱いポリシーも確認できません。OpenRouterのstealthモデルについても、提供者がプロンプトを保持する可能性があります。
検証用のプローブには、業務データ・社内固有名詞・機密コードを絶対に含めないでください。この記事で使ったプローブが、公開されている文章や無意味な文字列ばかりなのはそのためです。
まとめ
今回は、APIの向こうのモデルを検証する手法について解説しました。
要点の再掲
- トークン数は絶対値ではなく差分で比べる(チャットテンプレートの定数分を打ち消すため)
- 16プローブで差分が全一致すれば、トークナイザーは同一と判定できる
- 証拠はトークナイザー層・サービング層・行動層の3つに分かれ、強度と耐久性が違う
- 一致が証明するのは同一トークナイザーまでで、同一モデルの証明にはならない
- 実測では、Ox AlphaはGLM-5系と16/16で一致し、一律+75トークンのテンプレート差があった(2026年8月23日実測)
契約したモデルが実際に動いているかどうか、これまでは確かめる手段がありませんでした。この手法を使えば、ベンダーの申告を自分で検証できます。
まずは自社で使っているAPIに対して、10個のプローブを投げることから始めてみてください。ベースラインが取れなくても、測定値を記録しておけば、次回以降の変化を検出できるようになります。
関連記事
出典
- explainx.ai「Ox Alpha: What We Know — Serving Layer Evidence」 (2026-08-23取得)
- explainx.ai「Ox Alpha on OpenRouter: Free 1M Stealth Model」(2026-08-23取得)

コメント