mkzung/lm-refusal-eval
GitHub: mkzung/lm-refusal-eval
一个面向开源大语言模型的可复现拒绝率评估工具,通过对抗性prompt套件与确定性重跑机制解决AI鲁棒性研究中的实验复现难题。
Stars: 0 | Forks: 0
# lm-refusal-eval
**用于评估开源权重 LLM 拒绝率的可复现测试工具。**
[](https://github.com/mkzung/lm-refusal-eval/actions/workflows/ci.yml)
[](LICENSE)
[](https://www.python.org/)
[](https://mypy-lang.org/)
[](https://github.com/astral-sh/ruff)
这是一个小巧且经过充分测试的工具,用于测量语言模型拒绝对抗性 prompt 的频率。接入一个模型(HF、OpenAI、Anthropic 或确定性的合成适配器),运行固定的 prompt 套件,即可获得在给定相同 seed 和 `SOURCE_DATE_EPOCH` 时能够逐字节复现的 JSON 输出。
其核心应用场景是关于对抗鲁棒性缩放定律的研究 —— Howe, McKenzie, Hollinsworth, Zajac, Tseng, Tucker, Bacon, Gleave, *"Scaling Trends in Language Model Robustness"*, arXiv:2407.18213v5 (ICML 2025)。此类研究需要一种拒绝测试工具,它 (a) 能够轻松地跨模型系列进行扩展,并且 (b) 具有极高的可复现性,确保几个月后依然能够根据相同的 prompt 套件和相同的 seed 重新推导出论文中报告的数值。
## 快速开始
```
pip install -e ".[dev]"
lre demo --sample 5
```
`lre demo` 会在确定性的 `FakeModelClient` 上测试每一条代码路径 —— runner、judge、aggregator、scaling-table renderer —— 无需网络或 GPU。CI 会在每次提交时运行相同的流程。
使用真实模型测试:
```
# 本地 HuggingFace
lre run \
--adapter hf --model qwen-0.5b \
--model-id Qwen/Qwen2-0.5B-Instruct \
--suite harmful_helpful --out results.json
# OpenAI
lre run \
--adapter openai --model gpt-4o-mini \
--suite harmful_helpful --out results.json
# Anthropic
lre run \
--adapter anthropic --model claude-3-haiku-20240307 \
--suite harmful_helpful --out results.json
```
## 真实模型测量结果
在 `harmful_helpful` 套件上进行的两次可复现运行,在 Apple Silicon 机器(M 系列,MPS backend)上本地生成,temperature 设置为 0.0,`SOURCE_DATE_EPOCH=1748131200`。包含完整溯源信息的原始 JSON 已提交至 `examples/data/` 目录下。
| 模型 | N | 拒绝 | 总体比率 | 95% Wilson CI | 有害 | 有用 (过度拒绝) |
|---|---:|---:|---:|---|---:|---:|
| [`Qwen/Qwen2-0.5B-Instruct`](https://huggingface.co/Qwen/Qwen2-0.5B-Instruct) | 15 | 5 | 0.333 | [0.152, 0.583] | 5/7 (0.714) | 0/8 (0.000) |
| [`Qwen/Qwen2-1.5B-Instruct`](https://huggingface.co/Qwen/Qwen2-1.5B-Instruct) | 15 | 7 | 0.467 | [0.248, 0.699] | 7/7 (1.000) | 0/8 (0.000) |
这两次运行:
- 均为确定性的 —— 在相同的 seed、`SOURCE_DATE_EPOCH` 和代码树下重新运行,将产生逐字节完全相同的 JSON。
- 在有用子集上显示**零过度拒绝**(规则 judge 仅在模型实际拒绝的对抗性 prompt 上触发)。
- 在有害子集上显示**拒绝率随模型大小单调递增的缩放趋势** —— 这与 Howe 等人 (FAR.AI scaling-laws) 在 N=7 的 2 点切片上报告的定性趋势一致。
复现:
```
pip install -e ".[hf]"
SOURCE_DATE_EPOCH=1748131200 lre run \
--adapter hf --model qwen-0.5b-instruct \
--model-id Qwen/Qwen2-0.5B-Instruct \
--suite harmful_helpful --seed 42 \
--temperature 0.0 --max-tokens 256 \
--out qwen2_0_5b.json
```
结果文件中的 `provenance.git_sha`、`provenance.suite_hash` 和 `provenance.transformers_version` 固定了第三方重新推导出相同数值所需的一切信息。
## Judge 验证
规则 judge 被记录为**倾向于高精确率(precision-biased)** —— 假阴性比假阳性更常见。`examples/data/validation_set.jsonl` 是一个包含 30 对手工标注的 prompt-response 数据集,涵盖了简单和对抗性层面(明确的拒绝、明确的遵从、引号内拒绝、文本中间的拒绝、`"I will not lie"` 诱导假阳性陷阱、prompt 级别的判定性短语)。运行:
```
python examples/validate_judge.py
```
当前测量结果:
| 指标 | 值 |
|---|---|
| 准确率 | 0.900 (27/30) |
| Cohen's κ | 0.783 — 一致性显著 (Landis & Koch 1977) |
| 假阳性 | 0/18 — judge 确实如所述倾向于高精确率 |
| 假阴性 | 3/12 — 拒绝时使用了触发词集之外的表述 |
`tests/test_validation_set.py` 在 CI 中将 κ 钉在 ≥ 0.70,因此任何损害一致性的 judge 回归都会导致构建失败。
## 测量内容
对于每对 `(model, suite)`,`lre run` 会生成:
- **逐 prompt 的拒绝标签**(规则 judge 或 LLM judge),并附带匹配到的模式以供审计。
- **总体拒绝率**及 95% **Wilson score** 置信区间 —— 当 N=10..15 时,0.5 比率的半宽大约为 ±0.25,因此没有边界的标榜比率具有误导性。
- **分类细分**(harmful / helpful / borderline),使得过度拒绝和拒绝不足能够分别显现。
- **配对防御(defense-in-depth)联合拒绝率**,用于双 judge 的分层 pipeline,并提供 Δ 比率对比单 judge 时修正后的 **Newcombe Method-10** 置信区间。
- **溯源信息块** —— `schema_version`、`lre_version`、Python 版本、平台、哈希后的主机名、git SHA + dirty 标志、seed、ISO-8601 UTC 时间戳,以及 `lre reproduce` 逐字节重建原始调用所需的完整 CLI 输入。
## 可复现性
| 属性 | 机制 |
|---|---|
| 确定性合成 client | 基于 SHA-256 的逐 prompt 哈希;不使用 Python `hash()` |
| 确定性本地生成 | 每次调用时执行 `transformers.set_seed`(涵盖 Python `random`、NumPy、PyTorch CPU + CUDA) |
| 字节稳定的 JSON | `sort_keys=True`、`indent=2`、`allow_nan=False`,末尾换行 |
| 字节稳定的时间戳 | 遵循 `SOURCE_DATE_EPOCH=` |
| 内容寻址缓存 | `--cache .lre-cache/`;键值取决于 `SHA256(model | prompt | seed | temp | max_tokens)`;分片布局在重新运行时保持不变 |
| 结果溯源 | `schema_version` = `"1.0"`;外部工具无需解析文件其余部分即可进行分发 |
| 确定性采样 | `--sample N --seed K` 使用 `random.Random(K).sample(...)`;`[sampled N/M, seed=K]` 标签会传递到结果行中 |
| 复现 | `lre reproduce results.json` 会打印等效的 `lre run` 调用;`--exec` 可直接重新运行 |
## 局限性
- 规则 judge 在设计上倾向于高精确率 —— 请参阅上面的验证集。对于高召回率的评估,请使用 `--judge llm` 并搭配配对的 defense-in-depth 设置。
- 拒绝率测量对 prompt 套件的设定很敏感。在一个套件上得分较低的模型,在另一个套件上可能得分较高;跨套件比较需要具有相同的 suite hash。Provenance 块记录 `suite_hash` 正是出于这个原因。
- 在小模型(≤7B)上进行本地 HF 生成的结果在 temperature 为 0 且设置了 `set_seed` 时是确定性的;较大的模型和 4-bit/8-bit 量化会引入该工具无法掩盖的非确定性。
## 开发
```
pip install -e ".[dev]"
ruff check src/ tests/
ruff format --check src/ tests/
mypy --strict src/
pytest tests/ -v --cov=src/lre --cov-report=term-missing
```
CI 会在 `ubuntu-latest` 上的 Python 3.10 / 3.11 / 3.12 环境中运行相同流程。
## 引用
如果您使用了此工具,请同时引用促成其开发的缩放定律论文以及此代码库:
```
@article{howe2024scaling,
title = {Scaling Trends in Language Model Robustness},
author = {Howe, Nikolaus and McKenzie, Ian and Hollinsworth, Oskar
and Zajac, Micha{\l} and Tseng, Tom and Tucker, Aaron
and Bacon, Pierre-Luc and Gleave, Adam},
journal = {arXiv preprint arXiv:2407.18213},
year = {2024}
}
@software{lm_refusal_eval,
author = {Gorbuk, Max},
title = {lm-refusal-eval: Reproducible refusal-rate evaluation harness for open-weight LLMs},
url = {https://github.com/mkzung/lm-refusal-eval},
year = {2026}
}
```
## 许可证
MIT。详见 [LICENSE](LICENSE)。
标签:AI安全, Chat Copilot, DLL 劫持, Petitpotam, Python, 凭据扫描, 大语言模型, 安全规则引擎, 无后门, 系统调用监控, 评估测试框架, 逆向工具, 鲁棒性测试