- 模型评测
- 人工智能
- 大模型
- AI 评测
【免费下载链接】opencompass
OpenCompass is an LLM evaluation platform, supporting a wide range of models from OpenAI, Anthropic, Gemini, Qwen, GLM, DeepSeek, etc, across 100+ datasets covering knowledge, reasoning, coding, science, language, long-context, and safety.
本文是 OpenCompass 提示词攻击(Prompt Attack)模块的完整实战指南。该模块借鉴 Microsoft PromptBench 的思路,通过向提示指令注入文本扰动(如替换单词、插入字符等),系统性评测 LLM 对提示指令的鲁棒性。读完本文,你将掌握:如何配置一个可被攻击的提示模板、如何使用AttackInferencer与OpenICLAttackTask串联攻击实验、如何控制攻击类型与查询预算,以及如何从源码层面理解攻击搜索与评估的完整链路,从而在自己的数据集与模型上复现攻击评测。
背景:为什么要做提示词攻击
在常规评测中,我们关心"模型在给定提示下能否完成任务";而提示词攻击关心的是另一个问题:当提示指令本身被攻击/修改后,任务表现相比原始提示下降了多少。这反映的是模型对提示指令的敏感度与鲁棒性——一个鲁棒的模型应当在指令措辞发生微小扰动时依然保持稳定表现。
OpenCompass 的攻击能力借鉴了 PromptBench 的设计:维护一份"原始提示列表"(original prompt list),针对其中表现最好的若干条提示执行攻击搜索,用攻击前后准确率的差值(dropped accuracy)量化鲁棒性损失。整套流程涉及三个核心部件:
AttackInferencer:负责用指定提示文本对数据集进行推理并返回评估分数;OpenICLAttackTask:负责调度攻击搜索,选出待攻击提示并调用 promptbench 的Attack完成扰动生成;attack配置块:定义攻击算法、查询预算与待攻击提示数量。
环境准备
提示词攻击依赖 PromptBench 及其下游依赖(textattack 等),需要额外安装:
pip install promptbench==0.0.4 textattack==0.3.8 lru-dict安装完成后,OpenCompass 任务侧会动态导入promptbench.prompt_attack中的LABEL_SET、Attack、attack_config等组件(见 openicl_attack.py),因此版本需与 0.0.4 保持一致。
如何发起攻击:三步走
攻击实验的整体流程为:① 准备一个带攻击占位符的数据集配置 → ② 配置OpenICLAttackTask与攻击参数 → ③ 以--mode infer运行实验并解读结果。
第一步:配置数据集(infer_cfg)
以 GLUE-WNLI 数据集为例(完整配置见 promptbench_wnli_gen_50662f.py)。多数配置项与常规评测一致,可参考 config.md;如数据集尚未支持,可按 new_dataset.md 自行注册。
关键点在于infer_cfg中的提示模板与推理器:
adv_prompt是本次实验中要被攻击的提示占位符,攻击只会修改该字段;sentence1、sentence2是该数据集的输入列,保持不动;- 通过
AttackInferencer的original_prompt_list提供候选提示集合,用adv_key='adv_prompt'告诉推理器"要攻击模板中的哪个字段"。
original_prompt_list = [ 'Are the following two sentences entailment or not_entailment? Answer me with "A. entailment" or "B. not_entailment", just one word. ', "Does the relationship between the given sentences represent entailment or not_entailment? Respond with 'A. entailment' or 'B. not_entailment'.", # ... 可继续扩充候选提示 ] wnli_infer_cfg = dict( prompt_template=dict( type=PromptTemplate, template=dict(round=[ dict( role="HUMAN", prompt="""{adv_prompt} Sentence 1: {sentence1} Sentence 2: {sentence2} Answer:"""), ]), ), retriever=dict(type=ZeroRetriever), inferencer=dict( type=AttackInferencer, original_prompt_list=original_prompt_list, adv_key='adv_prompt'))配套的reader_cfg与eval_cfg与普通评测一致,例如 WNLI 使用first_option_postprocess抽取 A/B 选项并用AccEvaluator计算准确率:
wnli_reader_cfg = dict( input_columns=['sentence1', 'sentence2'], output_column='label_option', train_split='validation', test_split='validation') wnli_eval_cfg = dict( evaluator=dict(type=AccEvaluator), pred_role='BOT', pred_postprocessor=dict(type=first_option_postprocess, options='AB'), )仓库中还内置了其他几个攻击数据集配置,可作为模板参考:数学推理 promptbench_math_gen_abf776.py({adv_prompt} {problem}:单列输入、MATHEvaluator评估)、机器翻译 promptbench_iwslt2017_gen_cbb8c8.py、抽取式问答 promptbench_squad20_gen_b15d1c.py。
第二步:配置攻击任务与参数
攻击实验必须使用OpenICLAttackTask(而不是常规的OpenICLInferencer任务),并且分区器只能使用NaivePartitioner。原因在于:攻击搜索会把整个数据集重复运行数十上百次来寻找最优攻击,若拆分成多个子任务既不方便也不合理,因此必须整份数据集一次跑完。
# Please run whole dataset at a time, aka use `NaivePartitioner` only # Please use `OpenICLAttackTask` if want to perform attack experiment infer = dict( partitioner=dict(type=NaivePartitioner), runner=dict( type=SlurmRunner, max_num_workers=8, task=dict(type=OpenICLAttackTask), retry=0), ) attack = dict( attack='textfooler', query_budget=100, prompt_topk=2, )attack配置块中的三个关键参数:
| 参数 | 含义 | 取值说明 |
|---|---|---|
attack | 攻击算法类型 | textfooler、textbugger、deepwordbug、bertattack、checklist、stresstest等(由 promptbench 提供) |
query_budget | 查询次数上界 | 即攻击过程中运行整个数据集的次数上限,控制搜索开销 |
prompt_topk | 待攻击的提示数量 | 取原始提示列表中准确率最高的前 k 条执行攻击;原始提示列表通常大于 10 条,全量攻击耗时极高 |
注意:由于上述重复搜索机制,请选择样本量小于 1000 的小型数据集进行攻击,否则时间成本会急剧膨胀。
参考入口示例 eval_attack.py 展示了在本地环境(LocalRunner)组合 WNLI 数据集与 Qwen2-1.5B 模型发起攻击的完整写法,其中attack配置为textfooler、query_budget=100、prompt_topk=1。
第三步:运行攻击实验
攻击任务属于推理阶段,运行时必须指定--mode infer:
python run.py examples/eval_attack.py --mode infer结果解读:攻击日志与精度下降
所有结果保存在工作目录下的attack文件夹中(OpenICLAttackTask的output_subdir即attack,日志位于logs/attack,见 openicl_attack.py)。攻击过程会输出两类信息:
第一类:每个候选原始提示在数据集上的准确率排序(用于选出 topk 待攻击提示):
Prompt: Assess the connection between the following sentences and classify it as 'A. entailment' or 'B. not_entailment'., acc: 59.15% Prompt: Does the relationship between the given sentences represent entailment or not_entailment? Respond with 'A. entailment' or 'B. not_entailment'., acc: 57.75% Prompt: Analyze the two provided sentences and decide if their relationship is 'A. entailment' or 'B. not_entailment'., acc: 56.34% Prompt: Identify whether the given pair of sentences demonstrates entailment or not_entailment. Answer with 'A. entailment' or 'B. not_entailment'., acc: 54.93% ...第二类:对每条被攻击提示,给出原始提示、攻击后提示及准确率对比,dropped acc即为鲁棒性损失:
Original prompt: Assess the connection between the following sentences and classify it as 'A. entailment' or 'B. not_entailment'. Attacked prompt: b"Assess the attach between the following sentences and sorted it as 'A. entailment' or 'B. not_entailment'." Original acc: 59.15%, attacked acc: 40.85%, dropped acc: 18.31%可以看到攻击仅替换了两个单词("connection"→"attach"、"classify"→"sorted"),准确率即从 59.15% 跌至 40.85%,直观体现了提示措辞对任务表现的显著影响。结果还会同步写入attack目录下的attacklog.txt文件,便于后续批量分析。
源码级实现:攻击如何被调度与评估
要深入理解这套机制,可分别阅读推理侧与任务侧的两个核心实现。
AttackInferencer:一次预测对应一次完整评测
AttackInferencer定义于 icl_attack_inferencer.py,注册为ICL_INFERENCERS。它的构造参数除常规的model、max_out_len、batch_size外,核心新增了两个:
adv_key:提示模板中被攻击的字段名(对应上面的'adv_prompt');metric_key:用于比较的评估指标,默认'accuracy'。
其核心方法是predict(adv_prompt)(第 85 行):它把传入的攻击后提示文本注入模板中的adv_key位置({self.adv_key: adv_prompt}),走完常规的取回(retrieval)→ 组装 prompt → 生成 → 后处理 → 评估 全流程,最终返回归一化到 0~1 的分数。也就是说,每次攻击尝试 = 在完整数据集上做一次端到端评测,这正是攻击实验耗时数倍于普通评测的原因。源码中还内置了中间结果落盘与断点续跑逻辑(tmp_前缀 json 文件),攻击中途中断可部分恢复。
OpenICLAttackTask:提示筛选 → 攻击搜索 → 结果落盘
OpenICLAttackTask定义于 openicl_attack.py,注册为TASKS,负责整个攻击实验的编排:
- 筛选阶段(
prompt_selection,第 58 行):遍历original_prompt_list中的每条提示,调用inferencer.predict(prompt)得到准确率,按从高到低排序; - 攻击阶段(第 154 行):取排序后前
prompt_topk条且初始准确率大于 0 的提示,构造 promptbench 的Attack对象,其中eval_func=lambda prompt, _, __: inferencer.predict(prompt)将"攻击候选项好坏"的评估完全复用了第一步的预测管线,attack_name与query_budget直接来自attack配置; - 落盘阶段:原始/攻击后提示及 acc、attacked acc、dropped acc 同时写入日志与
attacklog.txt;若初始准确率为 0 则跳过攻击并记录原因。
值得注意的细节:attack配置中的dataset字段若不在 promptbench 的LABEL_SET中,会自动回退为'mmlu'(第 137-139 行);任务还支持多 GPU 场景下通过torch.distributed.run拉起分布式推理(第 47-52 行)。
实践建议与边界
- 数据集选择:务必使用样本数 < 1000 的小型数据集(如 WNLI 的 validation 集),因为
query_budget次攻击 × 多候选提示的组合开销十分可观; - 参数权衡:
prompt_topk建议从 1~2 起步验证流程,再按算力放宽;query_budget控制攻击搜索深度,值越大越可能找到更优攻击、耗时也越长; - 结果口径:
dropped acc越大代表模型对该提示越脆弱,可用于对比不同提示模板或不同模型的指令鲁棒性; - 模型适配:攻击实验沿用 OpenCompass 常规的模型配置体系(如示例中的
hf_qwen2_1_5b),本地模型与 API 模型均可接入,API 模型会自动开启逐次保存以应对中断。
通过 examples/eval_attack.py 与 promptbench 目录下的多个数据集配置,你可以快速把提示词攻击扩展到数学、翻译、抽取式问答等更多任务,建立自己的提示指令鲁棒性评测基线。
- 模型评测
- 人工智能
- 大模型
- AI 评测
【免费下载链接】opencompass
OpenCompass is an LLM evaluation platform, supporting a wide range of models from OpenAI, Anthropic, Gemini, Qwen, GLM, DeepSeek, etc, across 100+ datasets covering knowledge, reasoning, coding, science, language, long-context, and safety.
相关推荐
GLM-4提示词攻击防范指南:增强模型鲁棒性的终极方法
在人工智能快速发展的今天,GLM 4作为开源多语言多模态对话模型,其安全性和鲁棒性备受关注。随着恶意提示词攻击手段的日益复杂,如何有效防范提示词攻击、增强模型鲁
大模型人工智能微调多模态模型推理服务AI AgentMinIO V3 监控快速搭建:Prometheus 采集与 Grafana 可视化的最小配置路径
MinIO V3 监控快速搭建:Prometheus 采集与 Grafana 可视化的最小配置路径 MinIO V3 监控把集群健康、容量、API 请求等指标按
后端存储对象存储分布式存储云原生Tabby 提示词重写(Prompt Rewriting)评估工具实战指南
Tabby 提示词重写(Prompt Rewriting)评估工具实战指南 导读 本文聚焦 Tabby 仓库中 experimental/prompt rewr
人工智能大模型本地部署模型推理服务后端RAG交互助手
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考