基础环境配置
https://github.com/ggml-org/llama.cpp/releases
![图片[1]-大模型安全测试garak工具搭建配置-阻击者联盟](https://blog.h-acker.cn/wp-content/uploads/2026/10/f6bc72e01720261021165617.png)
下载对应cuda版本的exe和后面对应的DLLs 至于如何看cuda版本,命令nvidia-smi也行,去nvidia控制面板看也行
![图片[2]-大模型安全测试garak工具搭建配置-阻击者联盟](https://blog.h-acker.cn/wp-content/uploads/2026/10/1d513d783b20261021165619.png)
modelscope download --model diodel/Qwen3.5-4B-Q4_K_M-GGUF --local_dir ./
![图片[3]-大模型安全测试garak工具搭建配置-阻击者联盟](https://blog.h-acker.cn/wp-content/uploads/2026/10/426d08a63a20261021165620.png)
llama-server.exe -m D:\llama_cpp\llama-b10995-bin-win-cuda-13.4-x64\models\qwen3-5-4B-Q4_K_M.gguf -c 4096 --host 127.0.0.1 --port 9090 -ngl 99
![图片[4]-大模型安全测试garak工具搭建配置-阻击者联盟](https://blog.h-acker.cn/wp-content/uploads/2026/10/f5841c70f220261021165622.png)
curl http://127.0.0.1:9090/v1/models
大模型就跑起来了
安装garak
conda create --name garak_env "python>=3.10,<=3.12"
conda activate garak_env
python -m pip install -U garak
![图片[6]-大模型安全测试garak工具搭建配置-阻击者联盟](https://blog.h-acker.cn/wp-content/uploads/2026/10/6236cb8ad520261021165625.png)
set OPENAI_API_KEY=sk-no-key-required
set OPENAI_BASE_URL=http://127.0.0.1:9090/v1
![图片[7]-大模型安全测试garak工具搭建配置-阻击者联盟](https://blog.h-acker.cn/wp-content/uploads/2026/10/25d1b8bc9120261021165627.png)
garak --target_type openai --target_name qwen3-5-4B-Q4_K_M.gguf --probes encoding --parallel_attempts 1 --generations 1
![图片[8]-大模型安全测试garak工具搭建配置-阻击者联盟](https://blog.h-acker.cn/wp-content/uploads/2026/10/2f1c82dc0120261021165628.png)
|
参数
|
缩写
|
默认值
|
作用与说明
|
|---|---|---|---|
--target_type |
-t / -m |
无(必填)
|
指定生成器类型,如
openai、rest、huggingface、ollama |
--target_name |
-n |
无(必填)
|
目标模型或服务名称,如
qwen3-5-4B-Q4_K_M.gguf |
--probes |
-p |
all |
探针列表,可指定
encoding、dan、promptinject、 all 或 garak --list_probes(建议新版本使用–spec) |
--probe_tags |
无
|
无
|
按标签筛选探针,如
owasp:llm01 |
--detectors |
-d |
all |
检测器列表,默认使用各探针推荐的检测器
|
--generations |
-g |
5 |
每个提示生成几个响应。本地模型建议设为
1 |
--parallel_attempts |
无
|
5 |
并行执行的探测尝试数。本地模型建议设为
1 |
--parallel_requests |
无
|
1 |
同一提示的并行请求数,对不支持多生成的模型会被忽略
|
--config |
无
|
无
|
指定 YAML/JSON 配置文件路径
|
--generator_option_file |
-G |
无
|
指定生成器配置文件路径(用于自定义 REST 接口)
|
--detector_option_file |
无
|
无
|
指定检测器配置文件路径(用于配置裁判模型)
|
--eval_threshold |
无
|
0.5 |
判定为“成功攻击”的最低阈值
|
--timeout |
无
|
视生成器而定
|
请求超时时间(秒),本地模型建议设大一些
|
--report_prefix |
无
|
garak |
报告文件的前缀名
|
--seed |
-s |
随机
|
随机种子,用于结果可复现
|
--verbose |
-v |
0 |
增加日志详细程度,可叠加使用
|
坑1: 跑完之后发现模型的返回是空
![图片[9]-大模型安全测试garak工具搭建配置-阻击者联盟](https://blog.h-acker.cn/wp-content/uploads/2026/10/b82e2471c520261021165630.png)
经过检查发现是Qwen3.5自带思考,设置的窗口4096还没完成思考过程就截断了,导致garak没有收到完整的结果,也就默认判断为了通过
现在换成qwen2.5-3b-instruct-q4_k_m.gguf,这个没有思考过程,可以直接在content里返回模型输出结果
llama-server.exe -m ./models/qwen2.5-3b-instruct-q4_k_m.gguf -c 4096 --host 127.0.0.1 --port 9090 -ngl 99
![图片[10]-大模型安全测试garak工具搭建配置-阻击者联盟](https://blog.h-acker.cn/wp-content/uploads/2026/10/17d7e82ad720261021165631.png)
garak --target_type openai --target_name qwen2.5-3b-instruct-q4_k_m.gguf --spec probes.promptinject --parallel_attempts 1 --generations 1
![图片[11]-大模型安全测试garak工具搭建配置-阻击者联盟](https://blog.h-acker.cn/wp-content/uploads/2026/10/11e2095ec120261021165633.png)
查看生成的jsonl结果文件,可以看到每个请求和响应
![图片[12]-大模型安全测试garak工具搭建配置-阻击者联盟](https://blog.h-acker.cn/wp-content/uploads/2026/10/0627cd0c8a20261021165634.png)
![图片[13]-大模型安全测试garak工具搭建配置-阻击者联盟](https://blog.h-acker.cn/wp-content/uploads/2026/10/6b62f6663220261021165636.png)
如果大模型提供接口和请求不是标准的格式,那么可能需要自己写对应的配置文件或Generator插件,相见下文,分别对应流式和非流式以及配置文件或插件处理方式
流式返回
方案一:使用RestGenerator配置文件
创建my_config.yaml
plugins:
generators:
rest:
RestGenerator:
name:"MyAgent"
uri:"http://xxxx:8080/api/chat/stream"
method:post
headers:
Content-Type:"application/json"
Accept:"text/event-stream"# 明确要求返回SSE流
User-Agent:"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
req_template_json_object:
message:"$INPUT"
session_id:"garak_session_default"
user_orgid:"123456"
user_orgnm:"机构1"
# 注意:因为返回是 text/event-stream,此处无法用 response_json 提取字段
response_json:false
执行
garak --target_type rest -G my_config.yaml --spec probes.encoding --parallel_attempts 1
方案二:编写自定义Generator插件
新建my_generator.py
import json
import requests
from garak.generators.base import Generator
class MyGenerator(Generator):
"""专门用于对接MyAgent自定义接口的生成器"""
# 声明支持的生成数量
supports_multiple_generations = False
# 默认参数,可在配置文件中覆盖
DEFAULT_PARAMS = Generator.DEFAULT_PARAMS | {
"uri": "http://xxxxx:8080/api/chat/stream",
"headers": {
"Content-Type": "application/json",
"Accept": "text/event-stream",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
}
}
def _call_model(self, prompt, generations_this_call=1):
# 构造请求体,替换 message 字段
payload = {
"message": prompt,
"session_id": "garak_session_123",
"user_orgid": "123456",
"user_orgnm": "机构1"
}
try:
# 发送请求,开启流式读取
response = requests.post(
self.uri,
headers=self.headers,
json=payload,
stream=True,
timeout=60
)
response.raise_for_status()
# 解析 SSE 流,寻找 type 为 message 的 data
final_message = ""
for line in response.iter_lines():
if line:
decoded_line = line.decode('utf-8')
if decoded_line.startswith("data:"):
json_str = decoded_line[5:].strip() # 去掉 "data:" 前缀
try:
data_obj = json.loads(json_str)
if data_obj.get("type") == "message":
final_message = data_obj.get("data", "")
# 因为只有一条真正的 message,找到后可以 break(或者继续读取直到流结束)
break
except json.JSONDecodeError:
continue
# 如果没找到 message 类型的回复,返回兜底内容
ifnot final_message:
final_message = "ERROR: No 'message' type found in SSE response."
return [final_message]
except Exception as e:
return [f"ERROR: {str(e)}"]
把这个文件放到garak安装目录下,比如:D:\env\anaconda3\envs\garak_env\Lib\site-packages\garak\generators\my_generator.py
复制过去后,运行garak --list_generators,如果看到my_generator.MyGenerator,说明加载成功。
执行命令
garak --target_type my_generator --target_name qwen-agent --spec probes.promptinject --parallel_attempts 1 --generations 1
非流式返回
方案一:使用 RestGenerator 配置文件
创建my_json_config.yaml
plugins:
generators:
rest:
RestGenerator:
name:"MyAgent普通接口"
uri:"http://xxxxx:8080/api/chat/stream"# 换成实际接口地址
method:post
headers:
Content-Type:"application/json"
Accept:"application/json"
User-Agent:"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
req_template_json_object:
message:"$INPUT"
session_id:"garak_session_default"
user_orgid:"123456"
user_orgnm:"机构1"
response_json:true
# 重点:根据你的实际返回结构改写 JSONPath
# 假设返回的是 {"data": {"content": "..."}}
response_json_field:"$.data.content"
执行命令和流式一样:
garak --target_type rest -G my_json_config.yaml --spec probes.promptinject --parallel_attempts 1
方案二:编写自定义 Generator 插件
新建my_json_generator.py
import json
import requests
from garak.generators.base import Generator
class MyJsonGenerator(Generator):
"""用于对接返回普通 JSON 的MyAgent接口"""
supports_multiple_generations = False
DEFAULT_PARAMS = Generator.DEFAULT_PARAMS | {
"uri": "http://xxxx:8080/api/chat/stream",
"headers": {
"Content-Type": "application/json",
"Accept": "application/json",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
}
}
def _call_model(self, prompt, generations_this_call=1):
# 构造请求体,替换 message 字段
payload = {
"message": prompt,
"session_id": "garak_session_123",
"user_orgid": "123456",
"user_orgnm": "机构1"
}
try:
# 1. 发送请求,注意去掉了 stream=True
response = requests.post(
self.uri,
headers=self.headers,
json=payload,
timeout=60
)
response.raise_for_status()
# 2. 直接将整个响应解析为 JSON
resp_json = response.json()
# 3. 根据返回结构提取需要的字段
final_message = ""
# 假设普通 JSON 返回是类似 {"code":200, "data": [{"type":"thought", ...}, {"type":"message", "data":"..."}]}
data_list = resp_json.get("data", [])
if isinstance(data_list, list):
for item in data_list:
if item.get("type") == "message":
final_message = item.get("data", "")
break# 找到就跳出循环
elif isinstance(data_list, dict):
# 如果是 {"data": {"type": "message", "data": "..."}}
if data_list.get("type") == "message":
final_message = data_list.get("data", "")
# 兜底:如果没找到对应字段,返回整个 JSON 字符串
ifnot final_message:
final_message = json.dumps(resp_json, ensure_ascii=False)
return [final_message]
except Exception as e:
return [f"ERROR: {str(e)}"]
同样复制到garak安装目录下,执行:
garak --target_type my_json_generator --target_name qwen-agent --spec probes.promptinject --parallel_attempts 1
— 阅读原文请访问微信公众号「智佳网络安全」 · 原文链接 —
© 版权声明
THE END













暂无评论内容