
Einzigartiges Tool zum Fingerprinting großer Sprachmodelle anhand ihrer Tokenizer und ihres Verhaltens.

Erstellt einen Fingerabdruck des Serving-Stacks hinter einem OpenAI-kompatiblen Chat-Endpunkt.
Es erfasst Tokenizer-Zählung, versteckten Template-Offset, Validierungsprosa, JSON/SSE-Form, Rollenakzeptanz, benannte Limits und Gateway-Header. Es lädt keine Gewichte, speichert keine API-Schlüssel und fragt das Modell nicht, wer es ist.
| Import | lm_fingerprint |
| CLI | lm-fingerprint |
| Was | Versionierte Infrastruktur-Sonden gegen /chat/completions. Offline-synthetische Bibliothek. Lokale Hugging-Face-Tokenizer-Verifikation (keine Gewichte). |
| Was es nicht ist | Kein Gradientenangriff. Kein Jailbreak. Keine Encode-Map-Identität (tokprint). Nicht „welches Binary auf diesem Port läuft“ (Julius). |
Nur für autorisierte Nutzung: Endpunkte, die dir gehören, Labore, die du kontrollierst, Bounties im Rahmen, schriftlich beauftragte Pentests. Siehe SECURITY.md.
--api-key-envbenennt eine Umgebungsvariable. Der Schlüssel wird nie protokolliert.
OpenAI-kompatibler Chat ist ein gängiges Protokoll. vLLM, SGLang, ein Labor-Gateway und ein Wiederverkäufer können alle /chat/completions sprechen. Das model-Feld ist ein Label. Der Host kann das Backend austauschen, den Tokenizer wrappen oder einen Router davor schalten. Persönlichkeits-Sonden verschieben sich, wenn sich das System-Prompt verschiebt.
Was bleibt, ist die Infrastruktur: wie der Server Token zählt, wie viele versteckte Template-Tokens er hinzufügt, die Prosa, die sein Validator geschrieben hat, der SSE-Dialekt, welche Rollen er akzeptiert, die Zahl, die er nennt, wenn max_tokens absurd ist, die Server-/Provider-Header.
Das ist die Frage, die dieses Tool beantwortet: Welcher Stack behandelt diesen Chat-Pfad? Nicht welcher Checkpoint, nicht welcher Prozess an den Port gebunden ist, nicht wer eine Vervollständigung geschrieben hat.
ModelPrint hat dieselbe Frage in einem Browser mit neun Sonden gestellt. Dieses Paket ist die CLI- und Bibliotheksform: versionierte Sonden, erweiterbare Bibliothek, paarweise Belege, Drift und ein lokaler Tokenizer-Pfad, der nie eine gehostete Inference-API aufruft.
Ein Fingerabdruck ist ein versionierter JSON-Datensatz von Probe-values. Jede Probe muss denselben Wert zurückgeben, wenn derselbe Stack zweimal getroffen wird. Zeitstempel, Request-IDs, Latenz und Schlüssel werden entfernt.
Tokenizer-Zählungen verwenden ModelPrint-1.0.0-Texte (MIT, unclecode/modelprint), bytegenau, abzüglich einer Ein-Zeichen-"a"-Basislinie, sodass ein verstecktes Template sich aufhebt. Diese vier Zahlen sind eine Projektion der Encode-Map (T). Gleiche Zählungen bedeuten nicht (T_1 \equiv T_2). GPT-2 und OPT kollidieren bei ihnen; der Rust-Pipeline-Hash nicht.
hf_identity (nur lokaler HF-Pfad) ist SHA-256 dieses Pipeline-Commitments plus dem Chat-Template-Hash. Gleiches (T) und dasselbe Template stimmen überein (tiny-gpt2 / gpt2). Das ist Familie + Template, kein Checkpoint.
Layout:
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
Zwei Pfade in dieselbe Sondensuite:
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
Probe-Erstellung: docs/PROBES.md. Modulzuordnung: docs/ARCHITECTURE.md.
Ein Treffer ist gemeinsame Infrastruktur. Ein Labor kann zwei Checkpoints auf einem Stack bedienen. Ein Router kann mit seinem eigenen Fehler-Wrapper antworten. Übereinstimmende Zählungen sind keine Identität von (T).
Python 3.10+. Die Kernlaufzeit ist die Standardbibliothek.
git clone https://gitlab.com/WattoCyber/lm-fingerprint.git
cd lm-fingerprint
pip install -e ".[dev]"
PYTHONPATH=src python3 scripts/repro.py
Es wird REPRO_OK erwartet. Dieses Gate ist offline: keine GPU, keine Produktions-APIs. Lokale HF-Tests werden übersprungen, wenn der Tokenizer nicht gecacht ist.
pip install -e ".[hf]" # transformers, for fingerprint-hf / verify-hf
lm-fingerprint list-probes
lm-fingerprint list
list gibt die mitgelieferten Stacks aus: openai-chat-strict, glm-compat, router-openai, permissive-compat. Das sind Fixtures, keine abgescrapten Anbieter. Vergleiche zwei davon ohne Netzwerk:
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"])
Derselbe Wort-Tokenizer, andere Fehler und Header. Die Punktzahl liegt bei etwa 0.58. ModelPrints vier Zählungen stimmen überein; dieses Tool bezeichnet das nicht als gemeinsamen Stack.
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
Gib den Schlüssel nicht auf der Kommandozeile an. Scrape keine Produktions-APIs, um eine öffentliche Bibliothek zu füllen.
lm-fingerprint fingerprint-hf --model sshleifer/tiny-gpt2 --local-files-only
lm-fingerprint verify-hf --local-files-only
Zählungen stammen aus apply_chat_template, wenn ein Template existiert, andernfalls aus encode(..., add_special_tokens=False). Die Fehlertaxonomie stammt aus einem benannten synthetischen Profil (Standard openai-chat-strict), damit der Lauf offline bleibt. Remote-Handles (https://, api://, …) werden abgelehnt.
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
Es gibt kein --api-key-Flag. Ältere wireprint-fingerprint- / stackprint-fingerprint-JSON-Dateien werden weiterhin geladen.
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.
Vergleich: gewichteter Exakt-Match bei Sonden, die auf beiden Seiten ok und stable sind. Konfidenz ist score × coverage. Bibliothekstreffer melden certainty (exact / strong / possible / unknown) und den Abstand zum zweiten Nachbarn.
Führe erneut aus:
lm-fingerprint prove --local-files-only
Gleicher Rest wie ModelPrint (neun Sonden in probes/index.js). Deren README ist die Bewertungsregel: übereinstimmende Fingerabdrücke belegen gemeinsame Infrastruktur, keine Identität.
Ausarbeitung: docs/PROOF.md.
fingerprint-hf lädt nie Gewichte und ruft nie gehostete Inference auf.--api-key-env. Artefakte dürfen kein sk- oder
Authorization enthalten.scripts/repro.py ist das Produkt-Gate. Bezeichne es nicht als grün, außer du
hast es gerade ausgeführt.MIT. Siehe LICENSE. ModelPrint-Tokenizer-Texte bleiben MIT (unclecode/modelprint) und bytegenau.
| Du besitzt | Was du beobachten kannst | Was dieses Tool tut |
|---|
| Eine autorisierte OpenAI-kompatible Basis-URL + Schlüssel | Chat-HTTP: Nutzung, Fehler, Header, SSE | fingerprint / compare / match / drift |
| Lokale Tokenizer-Dateien | encode und chat_template | fingerprint-hf / verify-hf. Gewichte bleiben auf der Festplatte |
| Nichts als Host:Port | Banner / /health / /api/tags | Außerhalb des Anwendungsbereichs. Nutze Julius |
| Feld | Bedeutung |
|---|
kind | lm-fingerprint |
target.model / target.base_url_host | Worauf gezeigt wurde. Nur Host; kein Schlüssel |
features.tokenizer_norm | Vier Zählungen der ModelPrint-Klasse (englisch, chinesisch, Code, Emoji) |
features.template_offset | Größe des versteckten Serving-Templates |
probes.<id>.value | Vergleichbare Zelle. Muss stabil sein |
probes.<id>.weight | Beitrag zur Ähnlichkeit |
keys_stored | Immer false |
weights_loaded | Immer false |
| Test | ModelPrint | Dieses Tool |
|---|
Gleicher Tokenizer, anderer Stack (openai-chat-strict vs router-openai) | Tokenizer 4/4 + Template-Match | Punktzahl 0.58, als gemeinsame Zählung gekennzeichnet |
gpt2 vs facebook/opt-125m | vier Zählungen und Template kollidieren | encode_commitment trennt |
| Qwen2 / 2.5 / 3 | Tokenizer 4/4 kollidieren; Template trennt | hf_identity trennt |
tiny-gpt2 vs gpt2 | Match (gleiches (T)) | Match (erforderlich) |
| Sondensatz | 9 | 23 + HF-Encode/Template-Commitments |
logprobs, Stream-Form, Systemrolle | als Ideen gelistet | ausgeliefert |
| Werkzeug | Zweck |
|---|
| ModelPrint | Gleicher Rest, Browser, neun Sonden |
| tokprint | Lokale Encode-Map-Familien-ID. Lebt in gradient-untangler |
| gradient-untangler | Gradienten durch lokale Gewichte |
| Julius | Welche Serversoftware auf einem Port läuft |
| TokenPrint / LLMmap / UTF | Generierter Text, Herkunft oder implantierte Tokens |