

OpenAI互換のチャットエンドポイントの背後にあるサービングスタックをフィンガープリントします。
トークナイザーのカウント方法、隠れたテンプレートオフセット、検証プローズ、JSON/SSEの形状、ロールの受け入れ、明示される制限、ゲートウェイヘッダーを記録します。重みを読み込まず、APIキーを保存せず、モデルに自分が誰かを尋ねることもありません。
| インポート | lm_fingerprint |
| CLI | lm-fingerprint |
| 概要 | /chat/completions に対するバージョン管理されたインフラストラクチャプローブ。オフライン合成ライブラリ。ローカルHugging Faceトークナイザーの検証(重みなし)。 |
| そうではないもの | 勾配攻撃ではありません。ジェイルブレイクではありません。エンコードマップの同一性特定(tokprint)ではありません。「このポートでどのバイナリが動いているか」を特定するもの(Julius)でもありません。 |
許可された用途のみ:自分が所有するエンドポイント、管理下にあるラボ、スコープ内のバグ報奨金、書面によるペネトレーションテスト。SECURITY.md を参照してください。
--api-key-envは環境変数を指定します。キーがログに記録されることはありません。
OpenAI互換チャットは一般的なワイヤプロトコルです。vLLM、SGLang、ラボのゲートウェイ、リセラーはすべて /chat/completions を話すことができます。model フィールドは単なるラベルです。ホストはバックエンドを差し替えたり、トークナイザーをラップしたり、前面にルーターを配置したりできます。パーソナリティプローブは、システムプロンプトが変わると結果も変わります。
変わらずに残るのは配管(plumbing)です:サーバーがトークンをどう数えるか、隠れたテンプレートトークンをいくつ追加するか、バリデータが書いたプローズ、SSEの方言、受け入れるロール、max_tokens が非現実的な値のときに返す数値、Server / プロバイダーヘッダー。
このツールが答えるのは次の問いです:このチャット経路を処理しているスタックは何か? どのチェックポイントかでも、どのプロセスがポートにバインドされているかでも、誰が補完を書いたかでもありません。
ModelPrint はブラウザ上で9つのプローブを使って同じ問いを投げかけました。このパッケージはそのCLI版およびライブラリ版です:バージョン管理されたプローブ、登録可能なライブラリ、ペアワイズ証拠、ドリフト、そしてホスト型Inference APIを一切呼び出さないローカルトークナイザーパスを備えています。
フィンガープリントは、プローブの value を記録したバージョン管理されたJSONレコードです。各プローブは、同じスタックに対して2回実行した場合に同じ値を返さなければなりません。タイムスタンプ、リクエストID、レイテンシ、キーは除去されます。
トークナイザーのカウントは、ModelPrint 1.0.0のテキスト(MIT、unclecode/modelprint)をバイト単位で正確に再利用し、隠れたテンプレートが相殺されるように1文字の "a" ベースラインを差し引いています。この4つの数値はエンコードマップ (T) の射影です。カウントが等しくても (T_1 \equiv T_2) を意味するわけではありません。GPT-2とOPTはこれらのカウントで衝突しますが、rustパイプラインハッシュでは衝突しません。
hf_identity(ローカルHFパスのみ)は、そのパイプラインコミットメントとチャットテンプレートハッシュのSHA-256です。同じ (T) とテンプレートがあれば一致します(tiny-gpt2 / gpt2)。これはファミリー+テンプレートであり、チェックポイントではありません。
レイアウト:
src/lm_fingerprint/
cli.py argparse. --api-key-env only. No --api-key.
client.py HttpTransport, InProcessTransport, redact_secrets
probes.py 23 ProbeSpec rows (tokenizer / errors / shape / roles / limits / proxy)
engine.py run suite → Fingerprint
schema.py schema_version=1, probe_suite_version=lm-fingerprint-probes-v1
similarity.py weighted exact-match, coverage, confidence, library rank, drift
library.py enroll / match. Packaged rows are synthetic fixtures
synthetic.py in-process stacks for tests and the shipped library
hf.py local AutoTokenizer + named validation profile. No weights
localmap.py encode-pipeline-v2 commitment (rust tokenizer.json)
proof.py measured ModelPrint 9-probe identity
report.py text reports
data/library.json
同じプローブスイートへの2つの経路:
live endpoint local Hub tokenizer (optional [hf])
| |
HttpTransport.chat HfChatTransport
POST /chat/completions encode / chat_template for counts
| synthetic profile for errors/shape
+------------------+----------------------+
|
engine.run_probes
|
Fingerprint (JSON, keyless)
|
compare | match | drift | enroll
プローブの作成方法:docs/PROBES.md。モジュールマップ:docs/ARCHITECTURE.md。
一致はインフラストラクチャの共有を意味します。1つのラボが1つのスタック上で2つのチェックポイントを提供できます。ルーターは独自のエラーラッパーで応答できます。カウントの一致は (T) の同一性ではありません。
Python 3.10以上。コアランタイムは標準ライブラリのみです。
git clone https://gitlab.com/WattoCyber/lm-fingerprint.git
cd lm-fingerprint
pip install -e ".[dev]"
PYTHONPATH=src python3 scripts/repro.py
REPRO_OK が出力されるはずです。このゲートはオフラインです:GPUも本番APIも使用しません。ローカルHFテストは、トークナイザーがキャッシュされていない場合はスキップされます。
pip install -e ".[hf]" # transformers, for fingerprint-hf / verify-hf
lm-fingerprint list-probes
lm-fingerprint list
list は同梱のスタック(openai-chat-strict、glm-compat、router-openai、permissive-compat)を表示します。これらはフィクスチャであり、スクレイピングしたプロバイダーではありません。ネットワークなしでそのうち2つを比較できます:
from lm_fingerprint.client import InProcessTransport
from lm_fingerprint.engine import fingerprint_endpoint
from lm_fingerprint.similarity import compare_fingerprints
from lm_fingerprint.synthetic import SYNTHETIC_STACKS, handler_for
def fp(stack_id):
t = InProcessTransport(handler_for(stack_id), headers=SYNTHETIC_STACKS[stack_id].headers)
return fingerprint_endpoint(t, model=f"synthetic/{stack_id}", base_url=f"inprocess://{stack_id}")
print(compare_fingerprints(fp("openai-chat-strict"), fp("router-openai"))["note"])
同じワードトークナイザーでも、エラーとヘッダーは異なります。スコアは約 0.58 になります。ModelPrintの4つのカウントは一致しますが、このツールはそれを共有スタックとは呼びません。
lm-fingerprint fingerprint \
--base-url https://your-lab.example/v1 \
--model the-label \
--api-key-env OPENAI_API_KEY \
--out lab.json
lm-fingerprint match --fingerprint lab.json
lm-fingerprint enroll --fingerprint lab.json --stack-id my-lab --library my-lib.json
キーをコマンドラインで渡さないでください。公開ライブラリを埋めるために本番APIをスクレイピングしないでください。
lm-fingerprint fingerprint-hf --model sshleifer/tiny-gpt2 --local-files-only
lm-fingerprint verify-hf --local-files-only
カウントは、テンプレートが存在する場合は apply_chat_template から、それ以外の場合は encode(..., add_special_tokens=False) から取得されます。エラー分類は名前付き合成プロファイル(デフォルトは openai-chat-strict)から取得されるため、実行はオフラインのままです。リモートハンドル(https://、api://、…)は拒否されます。
lm-fingerprint list-probes
lm-fingerprint list [--library PATH]
lm-fingerprint fingerprint --base-url URL --model MODEL --api-key-env VAR [--out PATH]
lm-fingerprint fingerprint-hf --model HANDLE [--profile NAME] [--local-files-only]
lm-fingerprint verify-hf [--models a,b,c] [--local-files-only]
lm-fingerprint prove [--local-files-only]
lm-fingerprint compare --a a.json --b b.json
lm-fingerprint match --fingerprint a.json [--library PATH]
lm-fingerprint drift --baseline old.json --current new.json
lm-fingerprint enroll --fingerprint a.json --stack-id ID --library PATH
lm-fingerprint export --fingerprint a.json
--api-key フラグはありません。古い wireprint-fingerprint / stackprint-fingerprint のJSONも引き続き読み込めます。
from lm_fingerprint import (
StackLibrary,
compare_fingerprints,
fingerprint_endpoint,
fingerprint_hf,
match_library,
)
from lm_fingerprint.client import HttpTransport
fp = fingerprint_endpoint(HttpTransport(url, api_key=key), model="x", base_url=url)
hit = match_library(fp, StackLibrary.load())
local = fingerprint_hf("sshleifer/tiny-gpt2", local_files_only=True)
schema_version = 1、probe_suite_version = lm-fingerprint-probes-v1 です。
比較:両側で ok かつ stable なプローブに対する重み付き完全一致。信頼度は score × coverage です。ライブラリ照合は certainty(exact / strong / possible / unknown)と、2番目に近い隣接エントリとの差を報告します。
再実行:
lm-fingerprint prove --local-files-only
ModelPrint と同じ残差(probes/index.js 内の9つのプローブ)を使用します。ModelPrintのREADMEがスコアリングルールです:フィンガープリントの一致はインフラストラクチャの共有を証明するものであり、同一性を証明するものではありません。
解説:docs/PROOF.md。
fingerprint-hf は重みを決して読み込まず、ホスト型Inferenceも決して呼び出しません。--api-key-env から取得します。成果物に sk- や
Authorization を含めてはいけません。scripts/repro.py が製品ゲートです。実行した直後でない限り、
green を主張してはいけません。MIT。LICENSE を参照してください。ModelPrintのトークナイザーテキストはMIT(unclecode/modelprint)のままであり、バイト単位で正確です。
| あなたが保持するもの | 観測できるもの | このツールが行うこと |
|---|
| 認可されたOpenAI互換ベースURL+キー | チャットHTTP:使用量、エラー、ヘッダー、SSE | fingerprint / compare / match / drift |
| ローカルのトークナイザーファイル | encode と chat_template | fingerprint-hf / verify-hf。重みはディスク上に残ります |
| host:port のみ | バナー / /health / /api/tags | スコープ外。Juliusを使用してください |
| フィールド | 意味 |
|---|
kind | lm-fingerprint |
target.model / target.base_url_host | 指定された対象。ホストのみ。キーは含みません |
features.tokenizer_norm | ModelPrintクラスの4つのカウント(英語、中国語、コード、絵文字) |
features.template_offset | 隠れたサービングテンプレートのサイズ |
probes.<id>.value | 比較可能なセル。安定している必要があります |
probes.<id>.weight | 類似度への寄与 |
keys_stored | 常に false |
weights_loaded | 常に false |
| テスト | ModelPrint | このツール |
|---|
同じトークナイザー、異なるスタック(openai-chat-strict 対 router-openai) | トークナイザー4/4+テンプレート一致 | スコア 0.58、共有アカウンティングと判定 |
gpt2 対 facebook/opt-125m | 4つのカウントとテンプレートが衝突 | encode_commitment で分離 |
| Qwen2 / 2.5 / 3 | トークナイザー4/4で衝突、テンプレートで分離 | hf_identity で分離 |
tiny-gpt2 対 gpt2 | 一致(同じ (T)) | 一致(必須) |
| プローブセット | 9 | 23+HFのエンコード/テンプレートコミットメント |
logprobs、ストリーム形状、システムロール | アイデアとして記載 | 実装済み |
| ツール | 対象 |
|---|
| ModelPrint | 同じ残差、ブラウザ、9つのプローブ |
| tokprint | ローカルエンコードマップのファミリーID。gradient-untangler 内に存在 |
| gradient-untangler | ローカル重みに対する勾配 |
| Julius | ポート上で動作しているサーバーソフトウェアの特定 |
| TokenPrint / LLMmap / UTF | 生成テキスト、出自、または埋め込まれたトークン |