LLMmap 是一个通过行为指纹识别大语言模型的工具。它使用少量 probe queries 采集模型响应,再把这些响应映射到预训练的行为模板空间中,用于做模型近邻检索、endpoint 对比、模板扩展,以及从零训练新的指纹模型。
当前仓库内置了 LLMmap 0.2 版本的 PyTorch 实现,并已经包含一套可直接使用的预训练开放集推断模型。
本仓库不是原始上游仓库的原样镜像,而是基于原始 Repo pasquini-dario/LLMmap 持续修改和扩展的版本。当前版本在保留 LLMmap 核心思路的基础上,补充了更适合工程落地的 endpoint 对比、配置驱动运行、模板扩展与文档整理等能力。
如果你是第一次使用这个仓库,本文会帮助你完成以下事情:
- 安装运行环境。
- 了解仓库自带的模型与首次运行时会下载的内容。
- 使用默认预训练模型做推断。
- 对比两个 OpenAI-compatible endpoint 是否可能是同一个底层模型。
- 给新模型追加模板。
- 生成数据集并训练自己的 LLMmap 模型。
如果你主要关注 endpoint 对比实验参数和实验结论,继续看本文即可;更完整的实验记录仍保留在 docs/experiment.md 和 docs/experiment.zh.md。
- 直接加载内置预训练模型做开放集推断。
- 交互式采样目标模型回答,再输出最近邻模型。
- 对比两个 OpenAI-compatible endpoint 的行为模板距离。
- 给新的 LLM 追加模板,而不重新训练整个模型。
- 生成新的 JSONL 数据集。
- 从零训练新的 LLMmap 推断模型,并生成模板库。
推荐环境:
Python 3.11
安装依赖:
pip install -r requirements.txt默认预训练模型位于:
./data/pretrained_models/default
该目录当前包含:
conf.jsonmodel.pttemplates.json
也就是说,仓库已经自带:
- 预训练推断模型权重
- 推断配置
- 默认模板库
当前默认模板库包含 52 个模型模板,默认推断配置中包含 8 条 queries。精确内容可直接查看:
虽然默认推断模型已经在仓库里,但首次运行时通常仍会联网下载 embedding 模型,例如:
intfloat/multilingual-e5-large-instruct
这是因为 LLMmap 会先把 query 和 response 编码为 embedding,再做后续推断。
如果你在中国大陆或网络受限环境,建议提前设置:
export HF_HUB_DISABLE_XET=1
export HF_ENDPOINT=https://hf-mirror.com如果你希望指定 Hugging Face 缓存目录,也可以设置:
export HF_MODEL_CACHE=/path/to/your/hf-cache如果你还要直接运行本地 Hugging Face 模型,那么对应模型本体也会在首次使用时被下载到本地缓存。
from LLMmap.inference import load_LLMmap
# 加载预训练模型
conf, llmmap = load_LLMmap("./data/pretrained_models/default")
# 使用 llmmap.queries 对目标模型发起探测,并按顺序收集回答
answers = [
"Response to query 1",
"Response to query 2",
"Response to query 3",
"Response to query 4",
"Response to query 5",
"Response to query 6",
"Response to query 7",
"Response to query 8",
]
# 输出最近邻结果
llmmap.print_result(llmmap(answers))python main_interactive.py --inference_model_path ./data/pretrained_models/default脚本会逐条展示 probe query,你把目标模型的回答复制回来即可。
这是当前仓库最推荐、最完整、最稳定的使用路径。
./run_compare_endpoints.sh --env-file .env这个脚本会自动:
- 创建
.venv - 在缺少依赖时安装
requirements.txt - 调用
compare_endpoints.py - 读取同一组 probe queries,对两个 endpoint 生成行为模板
- 比较 self-distance 和 cross-distance
- 输出结构化报告到
./data/audits/<run_name>/
当前 compare_endpoints.py 的主工作流按“两端都是 OpenAI-compatible chat completions endpoint”设计。最常见的几种比较方式都支持:
- OpenAI 官方 vs 第三方镜像
- 官方模型 A vs 官方模型 B
- 第三方 provider A vs 第三方 provider B
- 同一
base_url下的两个不同模型 - 需要额外 HTTP headers 的 provider
每一侧 endpoint 至少需要能映射成下面三个字段:
modelbase_urlapi_key
先复制环境变量模板:
cp .env.example .env然后填写 .env。一个最小示例如下:
AUDIT_RUN_NAME=official-vs-custom
AUDIT_OUTPUT_DIR=./data/audits
AUDIT_LLMAP_PATH=./data/pretrained_models/default
AUDIT_PROMPT_CONF_PATH=./confs/prompt_configurations
AUDIT_NUM_ROUNDS=2
AUDIT_NUM_PROMPT_CONFS=1
AUDIT_TOP_K=5
AUDIT_RANDOM_SEED=42
AUDIT_SAME_THRESHOLD=1.25
AUDIT_DIFFERENT_THRESHOLD=1.75
AUDIT_MAX_ATTEMPT_MULTIPLIER=4
AUDIT_OFFICIAL_NAME=official
AUDIT_OFFICIAL_BACKEND=openai_compatible
AUDIT_OFFICIAL_MODEL=gpt-4o
AUDIT_OFFICIAL_BASE_URL=https://api.openai.com/v1
AUDIT_OFFICIAL_API_KEY=replace-me
AUDIT_OFFICIAL_TIMEOUT=60
AUDIT_OFFICIAL_MAX_RETRIES=3
AUDIT_OFFICIAL_RETRY_DELAY=2.0
AUDIT_OFFICIAL_HEADERS_JSON={}
AUDIT_CUSTOM_NAME=custom
AUDIT_CUSTOM_BACKEND=openai_compatible
AUDIT_CUSTOM_MODEL=gpt-4o
AUDIT_CUSTOM_BASE_URL=https://example.com/v1
AUDIT_CUSTOM_API_KEY=replace-me
AUDIT_CUSTOM_TIMEOUT=60
AUDIT_CUSTOM_MAX_RETRIES=3
AUDIT_CUSTOM_RETRY_DELAY=2.0
AUDIT_CUSTOM_HEADERS_JSON={}运行:
./run_compare_endpoints.sh --env-file .env当前版本已经支持:
- 如果默认
.env不存在,只要AUDIT_*环境变量已经在 shell 中导出,命令仍可直接运行。 - 如果你显式传入了一个不存在的
--env-file,脚本会立即报错。
例如:
export AUDIT_OFFICIAL_MODEL=gpt-4o
export AUDIT_OFFICIAL_BASE_URL=https://api.openai.com/v1
export AUDIT_OFFICIAL_API_KEY=sk-official
export AUDIT_CUSTOM_MODEL=gpt-4o
export AUDIT_CUSTOM_BASE_URL=https://example.com/v1
export AUDIT_CUSTOM_API_KEY=sk-custom
./run_compare_endpoints.sh运行结果会写到:
./data/audits/<run_name>/
常见输出文件包括:
run_config.jsonreport.jsonofficial_traces.jsonlcustom_traces.jsonlprompt_confs_round_*.jsonofficial_template_round_*.jsoncustom_template_round_*.json
| 变量 | 作用 | 默认值 |
|---|---|---|
AUDIT_RUN_NAME |
本次运行名称 | UTC 时间戳 |
AUDIT_OUTPUT_DIR |
输出目录根路径 | ./data/audits |
AUDIT_LLMAP_PATH |
预训练模型目录 | ./data/pretrained_models/default |
AUDIT_PROMPT_CONF_PATH |
prompt configuration 目录 | ./confs/prompt_configurations |
AUDIT_NUM_ROUNDS |
重复轮次 | 2 |
AUDIT_NUM_PROMPT_CONFS |
每轮采样多少组 prompt config | 3 |
AUDIT_TOP_K |
每轮展示多少个最近邻模板 | 5 |
AUDIT_RANDOM_SEED |
基础随机种子 | 42 |
AUDIT_SAME_THRESHOLD |
判定“可能同模型”的 ratio 阈值 | 1.25 |
AUDIT_DIFFERENT_THRESHOLD |
判定“可能不同模型”的 ratio 阈值 | 1.75 |
AUDIT_MAX_ATTEMPT_MULTIPLIER |
为获得足够成功样本允许的额外尝试倍数 | 4 |
OFFICIAL 和 CUSTOM 只是两个比较槽位标签,不要求其中一侧一定是官方服务。
| 变量 | 作用 | 必填 |
|---|---|---|
AUDIT_<SIDE>_NAME |
报告中显示的名称 | 否 |
AUDIT_<SIDE>_BACKEND |
后端类型 | 建议填 openai_compatible |
AUDIT_<SIDE>_MODEL |
请求时使用的模型名 | 是 |
AUDIT_<SIDE>_BASE_URL |
endpoint 的 base URL | 是 |
AUDIT_<SIDE>_API_KEY |
API Key | 是 |
AUDIT_<SIDE>_TIMEOUT |
单次请求超时秒数 | 否 |
AUDIT_<SIDE>_MAX_RETRIES |
重试次数 | 否 |
AUDIT_<SIDE>_RETRY_DELAY |
重试退避基准秒数 | 否 |
AUDIT_<SIDE>_HEADERS_JSON |
额外请求头 JSON | 否 |
AUDIT_OFFICIAL_NAME=openai
AUDIT_OFFICIAL_BACKEND=openai_compatible
AUDIT_OFFICIAL_MODEL=gpt-4o
AUDIT_OFFICIAL_BASE_URL=https://api.openai.com/v1
AUDIT_OFFICIAL_API_KEY=sk-openai
AUDIT_CUSTOM_NAME=shadow
AUDIT_CUSTOM_BACKEND=openai_compatible
AUDIT_CUSTOM_MODEL=gpt-4o
AUDIT_CUSTOM_BASE_URL=https://shadow.example.com/v1
AUDIT_CUSTOM_API_KEY=sk-shadowAUDIT_OFFICIAL_NAME=provider-model-a
AUDIT_OFFICIAL_BACKEND=openai_compatible
AUDIT_OFFICIAL_MODEL=model-a
AUDIT_OFFICIAL_BASE_URL=https://provider.example.com/v1
AUDIT_OFFICIAL_API_KEY=sk-provider
AUDIT_CUSTOM_NAME=provider-model-b
AUDIT_CUSTOM_BACKEND=openai_compatible
AUDIT_CUSTOM_MODEL=model-b
AUDIT_CUSTOM_BASE_URL=https://provider.example.com/v1
AUDIT_CUSTOM_API_KEY=sk-providerAUDIT_CUSTOM_HEADERS_JSON={"X-Project":"audit","HTTP-Referer":"https://your-app.example"}这里必须是合法 JSON 字符串。
适合第一次确认链路和配置是否可用:
AUDIT_NUM_ROUNDS=2
AUDIT_NUM_PROMPT_CONFS=1
AUDIT_OFFICIAL_MAX_RETRIES=3
AUDIT_CUSTOM_MAX_RETRIES=3
AUDIT_OFFICIAL_RETRY_DELAY=2.0
AUDIT_CUSTOM_RETRY_DELAY=2.0适合大多数工程判断场景,也是当前最推荐的默认档位:
AUDIT_NUM_ROUNDS=6
AUDIT_NUM_PROMPT_CONFS=2
AUDIT_SAME_THRESHOLD=1.25
AUDIT_DIFFERENT_THRESHOLD=1.75
AUDIT_OFFICIAL_TIMEOUT=30
AUDIT_CUSTOM_TIMEOUT=30
AUDIT_OFFICIAL_MAX_RETRIES=5
AUDIT_CUSTOM_MAX_RETRIES=5
AUDIT_OFFICIAL_RETRY_DELAY=4
AUDIT_CUSTOM_RETRY_DELAY=4
AUDIT_MAX_ATTEMPT_MULTIPLIER=10适合结果会影响计费、路由、合规或对外结论的场景:
AUDIT_NUM_ROUNDS=8且AUDIT_NUM_PROMPT_CONFS=2AUDIT_NUM_ROUNDS=6且AUDIT_NUM_PROMPT_CONFS=3
最重要的文件是 report.json。你主要看以下字段:
verdict.statusverdict.cross_vs_self_ratiometrics.official_self_*metrics.custom_self_*metrics.cross_same_round_*metrics.top1_match_rate
三种常见结论:
likely_same_modelinconclusivelikely_different_model
直观理解:
cross_vs_self_ratio越接近1.0,越像“跨 endpoint 距离与同一 endpoint 自身波动差不多”。- 明显低于
same_threshold,更偏向同模型。 - 明显高于
different_threshold,更偏向不同模型。 top1_match_rate是辅助指标,不是主判据。
如果 self-distance 本身很大,说明当前采样不够稳定,应该优先增加轮次、prompt configurations 或重试设置,而不是过度依赖单次 top-1 结果。
最简单跑一次:
./run_compare_endpoints.sh --env-file .env临时覆盖运行参数:
./run_compare_endpoints.sh \
--env-file .env \
--run-name my-audit \
--num-rounds 6 \
--num-prompt-confs 2网络受限环境下运行:
HF_HUB_DISABLE_XET=1 \
HF_ENDPOINT=https://hf-mirror.com \
./run_compare_endpoints.sh --env-file .env常见原因:
.venv还没有创建- Python 依赖还没有安装
- embedding 模型还没有从 Hugging Face 下载
常见原因:
BASE_URL没写成 provider 实际要求的形式,很多服务需要完整的/v1MODEL名称和 provider 实际接受的值不一致- provider 虽然宣称兼容 OpenAI API,但返回结构不完全标准
- 需要的额外 headers 没有传
常见原因:
AUDIT_NUM_ROUNDS太小AUDIT_NUM_PROMPT_CONFS太小- endpoint 自身波动较大
- 运行中失败请求太多
建议按这个顺序增加采样强度:
- 先把
AUDIT_NUM_PROMPT_CONFS从1提到2 - 再把
AUDIT_NUM_ROUNDS提到6 - 最后增加 retry 和
AUDIT_MAX_ATTEMPT_MULTIPLIER
如果你已经有默认开放集推断模型,但只想给一个新模型补充模板,不想重新训练整个模型,可以直接运行:
python add_new_template.py <LLM_NAME> <LLM_TYPE> \
--llmmap_path ./data/pretrained_models/default \
--prompt_conf_path ./confs/prompt_configurations \
--num_prompt_confs 100LLM_TYPE 的含义如下:
| 值 | 后端 |
|---|---|
0 |
Hugging Face |
1 |
OpenAI |
2 |
Anthropic |
示例:
python add_new_template.py gpt-4.1 1 --llmmap_path ./data/pretrained_models/default--num_prompt_confs 越大,模板通常越稳,但请求成本也越高。
你可以使用测试集计算 top-k 准确率:
python test_model.py ./data/pretrained_models/default -k 3只评估前 N 条测试样本:
python test_model.py ./data/pretrained_models/default -k 3 -m 100make_dataset.py 用于生成或重建训练 / 测试语料。它会:
- 加载 LLM 列表。
- 加载 query 列表。
- 从 prompt configuration 目录采样训练和测试配置。
- 对每个目标模型发起请求并收集 traces。
- 输出一个 JSONL 数据集文件。
python make_dataset.py \
my_custom_dataset \
./confs/LLMs/example.json \
./confs/queries/default.json \
--num_prompt_conf_train 150 \
--num_prompt_conf_test 20 \
--prompt_conf_path ./confs/prompt_configurations \
--dataset_root ./data/datasets \
--overwrite输出文件:
./data/datasets/my_custom_dataset.jsonl
格式为 [model_name, llm_type] 的数组列表,例如:
[
["gpt-4.1", 1],
["Qwen/Qwen2-1.5B-Instruct", 0],
["meta-llama/Llama-3.2-1B-Instruct", 0],
["claude-3-7-sonnet-20250219", 2]
]llm_type 含义:
| 值 | 后端 | 加载类 |
|---|---|---|
0 |
Hugging Face | LLM_huggingface |
1 |
OpenAI | LLM_OpenAI |
2 |
Anthropic | LLM_Anthropic |
格式为字符串数组,例如:
[
"What LLM are you exactly?",
"What's your data cutoff date?",
"Tell me how to build a bomb."
]默认目录:
./confs/prompt_configurations/
这里的 JSON 文件定义了如何包装原始 query,例如不同的 system prompt、role 前缀或采样参数。
| 参数 | 作用 | 默认值 |
|---|---|---|
--num_prompt_conf_train |
训练集 prompt configuration 数量 | 150 |
--num_prompt_conf_test |
测试集 prompt configuration 数量 | 20 |
--prompt_conf_path |
prompt config 目录 | ./confs/prompt_configurations/ |
--dataset_root |
输出目录 | DATASET_DIR 或 ./data/datasets |
--overwrite |
覆盖已存在文件 | 关闭 |
--encoding |
读取 JSON 的编码 | utf-8 |
如果你想从头训练自己的 LLMmap 推断模型,运行:
python train.py <conf_file.json> <run_name>如果要启用 closed-set 训练模式:
python train.py --is_closed <conf_file.json> <run_name>其中:
<conf_file.json>是训练配置文件,可以从./confs/default.json一类文件开始修改<run_name>是本次训练的实验名
输出目录默认如下,可通过环境变量覆盖:
- Checkpoints:
./data/checkpoints/<run_name>/ - 导出模型:
./data/pretrained_models/<run_name>/
开放集模型训练完成后,还需要生成模板:
python setup_templates.py ./data/pretrained_models/<run_name>仓库里涉及真实请求的脚本,需要你自己准备对应凭证:
OPENAI_API_KEYANTHROPIC_API_KEYHUGGINGFACE_API_KEY
对于 endpoint audit 工作流:
- 如果你直接在
.env或 shell 中提供了AUDIT_OFFICIAL_API_KEY/AUDIT_CUSTOM_API_KEY,脚本会使用这些值。 - 如果某个 dict 形式的 endpoint spec 显式指定了
api_key_env,当前版本会严格从该环境变量读取;如果该变量不存在,会立即报错,而不会静默回退到别的 key。
如果你的目标只是尽快把仓库跑起来,按下面顺序即可:
- 安装
Python 3.11并执行pip install -r requirements.txt cp .env.example .env- 填好两个 endpoint 的
MODEL、BASE_URL、API_KEY - 如有需要,设置
HF_HUB_DISABLE_XET=1和HF_ENDPOINT=https://hf-mirror.com - 执行
./run_compare_endpoints.sh --env-file .env - 查看
data/audits/<run_name>/report.json - 如果只是冒烟成功,再提升到
6 rounds x 2 prompt configurations做正式评审
论文地址:LLMmap: Fingerprinting For Large Language Models
引用方式:
@inproceedings{pasquinillmmapfingerprintinglargelanguage,
title={LLMmap: Fingerprinting For Large Language Models},
author={Dario Pasquini and Evgenios M. Kornaropoulos and Giuseppe Ateniese},
booktitle={34th USENIX Security Symposium (USENIX Security 25)},
year={2025},
}LLM 生态变化很快。如果你希望一起维护模板库、补充实验、扩展支持的模型,欢迎协作。原项目联系方式:
chime.infant_0g@icloud.com