
Strumento unico per il fingerprinting di Grandi Modelli Linguistici basato sui loro tokenizzatori e sul loro comportamento.

Rileva l'impronta dello stack di servizio dietro un endpoint chat compatibile con OpenAI.
Registra la contabilità del tokenizer, l'offset nascosto del template, il testo di validazione, la forma JSON/SSE, l'accettazione dei ruoli, i limiti dichiarati e gli header del gateway. Non carica pesi, non memorizza chiavi API e non chiede al modello chi sia.
| Import | lm_fingerprint |
| CLI | lm-fingerprint |
| Cosa | Sonde infrastrutturali versionate verso /chat/completions. Libreria sintetica offline. Verifica locale del tokenizer Hugging Face (senza pesi). |
| Cosa non è | Non è un attacco ai gradienti. Non è un jailbreak. Non è identità tramite encode-map (tokprint). Non è “quale binario è su questa porta” (Julius). |
Solo uso autorizzato: endpoint di tua proprietà, laboratori che controlli, bounty in scope, pentest autorizzati per iscritto. Vedi SECURITY.md.
--api-key-envindica una variabile d'ambiente. La chiave non viene mai registrata.
La chat compatibile con OpenAI è un protocollo comune. vLLM, SGLang, un gateway di laboratorio e un rivenditore possono tutti parlare /chat/completions. Il campo model è un'etichetta. L'host può sostituire il backend, incapsulare il tokenizer o mettere un router davanti. Le sonde di personalità si spostano quando si sposta il system prompt.
Ciò che resta fermo è l'infrastruttura: come il server conta i token, quanti token di template nascosti aggiunge, il testo scritto dal suo validatore, il dialetto SSE, quali ruoli accetta, il numero che riporta quando max_tokens è assurdo, gli header Server / del provider.
Questa è la domanda a cui risponde lo strumento: quale stack sta gestendo questo percorso di chat? Non quale checkpoint, non quale processo è in ascolto sulla porta, non chi ha scritto una completion.
ModelPrint si è posto la stessa domanda in un browser con nove sonde. Questo pacchetto ne è la forma CLI e libreria: sonde versionate, libreria registrabile, confronto a coppie, drift e un percorso tokenizer locale che non chiama mai un'API di Inference ospitata.
Un'impronta è un record JSON versionato dei value delle sonde. Ogni sonda deve restituire lo stesso valore quando lo stesso stack viene colpito due volte. Timestamp, id di richiesta, latenza e chiavi vengono rimossi.
I conteggi del tokenizer riutilizzano i testi di ModelPrint 1.0.0 (MIT, unclecode/modelprint), identici byte per byte, meno una baseline di un carattere "a" così un template nascosto si annulla. Quei quattro numeri sono una proiezione della mappa di encode (T). Conteggi uguali non significano (T_1 \equiv T_2). GPT-2 e OPT collidono su di essi; l'hash della pipeline rust no.
hf_identity (solo percorso HF locale) è lo SHA-256 di quel commitment della pipeline più l'hash del chat-template. Stessa (T) e stesso template corrispondono (tiny-gpt2 / gpt2). È famiglia + template, non un checkpoint.
Struttura:
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
Due percorsi verso la stessa suite di sonde:
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
Scrittura delle sonde: docs/PROBES.md. Mappa dei moduli: docs/ARCHITECTURE.md.
Una corrispondenza è infrastruttura condivisa. Un laboratorio può servire due checkpoint su un unico stack. Un router può rispondere con il proprio wrapper degli errori. L'accordo sui conteggi non è identità di (T).
Python 3.10+. Il runtime principale è la libreria standard.
git clone https://gitlab.com/WattoCyber/lm-fingerprint.git
cd lm-fingerprint
pip install -e ".[dev]"
PYTHONPATH=src python3 scripts/repro.py
Attenditi REPRO_OK. Questo gate è offline: niente GPU, niente API di produzione. I test HF locali vengono saltati se il tokenizer non è in cache.
pip install -e ".[hf]" # transformers, for fingerprint-hf / verify-hf
lm-fingerprint list-probes
lm-fingerprint list
list stampa gli stack inclusi: openai-chat-strict, glm-compat, router-openai, permissive-compat. Sono fixture, non provider raccolti. Confrontane due senza rete:
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"])
Stesso tokenizer di parole, errori e header diversi. Il punteggio si attesta intorno a 0.58. I quattro conteggi di ModelPrint corrispondono; questo strumento non lo definisce uno stack condiviso.
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
Non passare la chiave da riga di comando. Non fare scraping di API di produzione per riempire una libreria pubblica.
lm-fingerprint fingerprint-hf --model sshleifer/tiny-gpt2 --local-files-only
lm-fingerprint verify-hf --local-files-only
I conteggi provengono da apply_chat_template quando esiste un template, altrimenti da encode(..., add_special_tokens=False). La tassonomia degli errori proviene da un profilo sintetico nominato (default openai-chat-strict) così l'esecuzione resta offline. Gli handle remoti (https://, api://, …) vengono rifiutati.
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
Non esiste il flag --api-key. I JSON più vecchi di wireprint-fingerprint / stackprint-fingerprint vengono ancora caricati.
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.
Confronto: exact-match pesato sulle sonde che sono ok e stable su entrambi i lati. La confidenza è score × coverage. Il match con la libreria riporta certainty (exact / strong / possible / unknown) e il margine rispetto al secondo vicino.
Esegui di nuovo:
lm-fingerprint prove --local-files-only
Stesso residuo di ModelPrint (nove sonde in probes/index.js). Il loro README è la regola di punteggio: impronte corrispondenti provano infrastruttura condivisa, non identità.
Approfondimento: docs/PROOF.md.
fingerprint-hf non carica mai pesi e non chiama mai Inference ospitata.--api-key-env. Gli artefatti non devono contenere sk- o Authorization.scripts/repro.py è il gate del prodotto. Non dichiarare verde se non l'hai appena eseguito.MIT. Vedi LICENSE. I testi del tokenizer di ModelPrint restano MIT (unclecode/modelprint) e identici byte per byte.
| Cosa possiedi | Cosa puoi osservare | Cosa fa questo strumento |
|---|
| Un URL base compatibile OpenAI autorizzato + chiave | HTTP di chat: usage, errori, header, SSE | fingerprint / compare / match / drift |
| File tokenizer locali | encode e chat_template | fingerprint-hf / verify-hf. I pesi restano su disco |
| Solo un host:porta | Banner / /health / /api/tags | Fuori scope. Usa Julius |
| Campo | Significato |
|---|
kind | lm-fingerprint |
target.model / target.base_url_host | Cosa è stato puntato. Solo host; nessuna chiave |
features.tokenizer_norm | Quattro conteggi di classe ModelPrint (english, chinese, code, emoji) |
features.template_offset | Dimensione nascosta del template di servizio |
probes.<id>.value | Cella confrontabile. Deve essere stabile |
probes.<id>.weight | Contributo alla similarità |
keys_stored | Sempre false |
weights_loaded | Sempre false |
| Test | ModelPrint | Questo strumento |
|---|
Stesso tokenizer, stack diverso (openai-chat-strict vs router-openai) | tokenizer 4/4 + template corrispondente | punteggio 0.58, etichettato come contabilità condivisa |
gpt2 vs facebook/opt-125m | quattro conteggi e template collidono | encode_commitment li separa |
| Qwen2 / 2.5 / 3 | tokenizer 4/4 collidono; template li separa | hf_identity li separa |
tiny-gpt2 vs gpt2 | corrispondenza (stessa (T)) | corrispondenza (richiesta) |
| Set di sonde | 9 | 23 + commitment HF di encode/template |
logprobs, forma dello stream, ruolo system | elencati come idee | implementati |
| Strumento | Scopo |
|---|
| ModelPrint | Stesso residuo, browser, nove sonde |
| tokprint | ID famiglia tramite encode-map locale. Si trova in gradient-untangler |
| gradient-untangler | Gradienti attraverso i pesi locali |
| Julius | Quale software server è in ascolto su una porta |
| TokenPrint / LLMmap / UTF | Testo generato, provenienza o token impiantati |