
Herramienta única para la toma de huellas digitales de Modelos de Lenguaje de Gran Tamaño basada en sus tokenizadores y comportamiento.

Identifica la pila de servicio que hay detrás de un endpoint de chat compatible con OpenAI.
Registra el cálculo de tokens del tokenizador, el desplazamiento oculto de la plantilla, el texto de validación, la forma de JSON/SSE, la aceptación de roles, los límites nombrados y las cabeceras de la puerta de enlace. No carga pesos, no almacena claves de API ni le pregunta al modelo quién es.
| Import | lm_fingerprint |
| CLI | lm-fingerprint |
| Qué es | Sondas de infraestructura versionadas contra /chat/completions. Librería sintética sin conexión. Verificación local de tokenizadores de Hugging Face (sin pesos). |
| Qué no es | No es un ataque de gradientes. No es un jailbreak. No es identidad por mapa de codificación (tokprint). No es “qué binario hay en este puerto” (Julius). |
Solo para uso autorizado: endpoints que te pertenecen, laboratorios que controlas, programas de recompensas dentro del alcance, pruebas de penetración por escrito. Ver SECURITY.md.
--api-key-envnombra una variable de entorno. La clave nunca se registra en los registros.
El chat compatible con OpenAI es un cable común. vLLM, SGLang, una puerta de enlace de laboratorio y un
revendedor pueden hablar todos con /chat/completions. El campo model es una etiqueta.
El host puede cambiar el backend, envolver el tokenizador o poner un router delante.
Las sondas de personalidad se mueven cuando se mueve el prompt del sistema.
Lo que permanece fijo es la fontanería: cómo cuenta tokens el servidor, cuántos tokens ocultos de plantilla
añade, la prosa que escribió su validador, el dialecto SSE, qué roles acepta, el número que nombra cuando
max_tokens es absurdo, las cabeceras Server / de proveedor.
Esa es la pregunta que responde esta herramienta: ¿qué pila está gestionando esta ruta de chat? No qué checkpoint, no qué proceso está vinculado al puerto, no quién escribió una finalización.
ModelPrint hizo la misma pregunta en un navegador con nueve sondas. Este paquete es la forma CLI y de librería: sondas versionadas, librería inscribible, evidencia por pares, deriva y una ruta local de tokenizadores que nunca llama a una API de inferencia alojada.
Una huella es un registro JSON versionado de values de sonda. Cada sonda
debe devolver el mismo valor cuando se golpea la misma pila dos veces. Las marcas de tiempo, los ids de
solicitud, la latencia y las claves se eliminan.
Los recuentos de tokenizador reutilizan los textos de ModelPrint 1.0.0 (MIT, unclecode/modelprint),
byte a byte, menos una línea base de un carácter "a" para que una plantilla oculta se cancele. Esos cuatro
números son una proyección del mapa de codificación (T).
Recuentos iguales no significan (T_1 \equiv T_2). GPT-2 y OPT coinciden en
ellos; el hash de la canalización rust no.
hf_identity (solo ruta HF local) es SHA-256 de ese compromiso de canalización
más el hash de la plantilla de chat. El mismo (T) y la misma plantilla coinciden
(tiny-gpt2 / gpt2). Eso es familia + plantilla, no un checkpoint.
Distribución:
src/lm_fingerprint/
cli.py argparse. Solo --api-key-env. Sin --api-key.
client.py HttpTransport, InProcessTransport, redact_secrets
probes.py 23 filas de ProbeSpec (tokenizador / errores / forma / roles / límites / proxy)
engine.py ejecuta el conjunto → Fingerprint
schema.py schema_version=1, probe_suite_version=lm-fingerprint-probes-v1
similarity.py coincidencia exacta ponderada, cobertura, confianza, rango de librería, deriva
library.py inscribir / coincidir. Las filas empaquetadas son fixtures sintéticos
synthetic.py pilas en proceso para pruebas y la librería distribuida
hf.py AutoTokenizer local + perfil de validación nombrado. Sin pesos
localmap.py compromiso encode-pipeline-v2 (tokenizer.json de rust)
proof.py identidad medida de 9 sondas de ModelPrint
report.py informes de texto
data/library.json
Dos rutas hacia el mismo conjunto de sondas:
endpoint en vivo tokenizador local del Hub (opcional [hf])
| |
HttpTransport.chat HfChatTransport
POST /chat/completions encode / chat_template para recuentos
| perfil sintético para errores/forma
+------------------+----------------------+
|
engine.run_probes
|
Fingerprint (JSON, sin claves)
|
compare | match | drift | enroll
Autoría de sondas: docs/PROBES.md. Mapa de módulos: docs/ARCHITECTURE.md.
Una coincidencia es infraestructura compartida. Un laboratorio puede servir dos checkpoints en una pila. Un router puede responder con su propio envoltorio de errores. El acuerdo en los recuentos no es identidad de (T).
Python 3.10+. El núcleo en tiempo de ejecución es la biblioteca estándar.
git clone https://gitlab.com/WattoCyber/lm-fingerprint.git
cd lm-fingerprint
pip install -e ".[dev]"
PYTHONPATH=src python3 scripts/repro.py
Espera REPRO_OK. Esa puerta funciona sin conexión: sin GPU, sin API de producción.
Las pruebas HF locales se omiten si el tokenizador no está en caché.
pip install -e ".[hf]" # transformers, para fingerprint-hf / verify-hf
lm-fingerprint list-probes
lm-fingerprint list
list imprime las pilas empaquetadas: openai-chat-strict, glm-compat,
router-openai, permissive-compat. Son fixtures, no proveedores extraídos.
Compara dos de ellas sin red:
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"])
Mismo tokenizador de palabras, distintos errores y cabeceras. La puntuación ronda
0.58. Los cuatro recuentos de ModelPrint coinciden; esta herramienta no llama a eso
una pila compartida.
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
No pases la clave por la línea de comandos. No extraigas API de producción para llenar una librería pública.
lm-fingerprint fingerprint-hf --model sshleifer/tiny-gpt2 --local-files-only
lm-fingerprint verify-hf --local-files-only
Los recuentos provienen de apply_chat_template cuando existe una plantilla; si no,
de encode(..., add_special_tokens=False). La taxonomía de errores proviene de un
perfil sintético nombrado (por defecto openai-chat-strict) para que la ejecución siga
sin conexión. Los identificadores remotos (https://, api://, …) se rechazan.
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
No existe la opción --api-key. Los JSON antiguos de wireprint-fingerprint /
stackprint-fingerprint todavía se cargan.
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.
Comparación: coincidencia exacta ponderada sobre las sondas que están ok y stable en
ambos lados. La confianza es score × coverage. La coincidencia de librería informa
certainty (exact / strong / possible / unknown) y el margen
con respecto al segundo vecino.
Re-ejecución:
lm-fingerprint prove --local-files-only
Mismo residuo que ModelPrint
(nueve sondas en probes/index.js). Su README es la regla de puntuación:
las huellas coincidentes demuestran infraestructura compartida, no identidad.
Explicación: docs/PROOF.md.
fingerprint-hf nunca carga pesos y nunca llama a Inference alojada.--api-key-env. Los artefactos no deben contener sk- ni
Authorization.scripts/repro.py es la puerta del producto. No declares verde a menos que
acabes de ejecutarlo.MIT. Ver LICENSE. Los textos del tokenizador de ModelPrint siguen siendo MIT (unclecode/modelprint) y byte a byte exactos.
| Tú posees | Lo que puedes observar | Lo que hace esta herramienta |
|---|
| Una URL base de OpenAI-compat autorizada + clave | Chat HTTP: uso, errores, cabeceras, SSE | fingerprint / compare / match / drift |
| Archivos de tokenizador locales | encode y chat_template | fingerprint-hf / verify-hf. Los pesos permanecen en el disco |
| Nada más que un host:puerto | Banner / /health / /api/tags | Fuera de alcance. Usa Julius |
| Campo | Significado |
|---|
kind | lm-fingerprint |
target.model / target.base_url_host | A qué se apuntó. Solo host; sin clave |
features.tokenizer_norm | Cuatro recuentos de clase ModelPrint (inglés, chino, código, emoji) |
features.template_offset | Tamaño oculto de la plantilla de servicio |
probes.<id>.value | Celda comparable. Debe ser estable |
probes.<id>.weight | Contribución a la similitud |
keys_stored | Siempre false |
weights_loaded | Siempre false |
| Prueba | ModelPrint | Esta herramienta |
|---|
Mismo tokenizador, distinta pila (openai-chat-strict vs router-openai) | tokenizador 4/4 + coincidencia de plantilla | puntuación 0.58, etiquetado como contabilidad compartida |
gpt2 vs facebook/opt-125m | los cuatro recuentos y la plantilla coinciden | encode_commitment los separa |
| Qwen2 / 2.5 / 3 | tokenizador 4/4 coincide; la plantilla separa | hf_identity separa |
tiny-gpt2 vs gpt2 | coincidencia (mismo (T)) | coincidencia (requerida) |
| Conjunto de sondas | 9 | 23 + compromisos HF de encode/plantilla |
logprobs, forma de stream, rol de sistema | enumerados como ideas | incluidos |
| Herramienta | Objeto |
|---|
| ModelPrint | Mismo residuo, navegador, nueve sondas |
| tokprint | ID local de familia por mapa de codificación. Vive en gradient-untangler |
| gradient-untangler | Gradientes a través de pesos locales |
| Julius | Qué software de servidor hay en un puerto |
| TokenPrint / LLMmap / UTF | Texto generado, linaje o tokens implantados |