ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

garak 恒定行为检测器模块解析:Fail / Pass / Passthru / Random 的原理与实战用法

2026/9/16 19:49:40 拓冰建站 浏览量
garak 恒定行为检测器模块解析:Fail / Pass / Passthru / Random 的原理与实战用法 garak 恒定行为检测器模块解析Fail / Pass / Passthru / Random 的原理与实战用法【免费下载链接】garakthe LLM vulnerability scanner项目地址: https://gitcode.com/GitHub_Trending/ga/garak导读garak.detectors.always是 garakthe LLM vulnerability scanner中一组特殊的检测器detector模块它们不分析模型输出内容而是恒定返回预设的检测结果主要用于框架自测、插件原型开发与调试链路。本文基于 docs/source/detectors/always.rst 对应的 garak/detectors/always.py 源码逐一拆解Fail、Pass、Passthru、Random四个检测器的实现、返回值语义、默认参数与调用约定并结合仓库内的测试用例tests/detectors/test_detectors_always.py与命令行用法说明如何在开发自有插件时用它们做链路自检。一、模块定位为什么需要恒定结果的检测器garak 的检测器detector负责判断一次 attempt探针请求 模型输出是否命中漏洞其基类定义在 garak/detectors/base.py 中核心契约是def detect(self, attempt: garak.attempt.Attempt) - Iterable[float | None]: ...returns a list of results in the range 0.0-1.0 where 0.0 represents no hit, 1.0 represents successful hit (i.e. vulnerability found).返回值语义为0.0 表示未命中通过1.0 表示命中发现漏洞None 表示无法评分。绝大多数真实检测器如基于字符串匹配的StringDetector、基于 HF 模型的HFDetector都要在这一契约下实现复杂的判定逻辑。而always模块garak/detectors/always.py 第 1-4 行的模块文档字符串明确声明了它的设计意图These always return a certain result, used mostly in testing or to indicate where a class child should override something.即恒等返回某种结果主要用于测试或用于标记子类应当覆盖此处的位置。它解决的问题是当你要调试探针、生成器或 garak 主流程本身时需要一个结果完全可预期的检测器作为锚点把变量隔离出来。这与 garak 的测试哲学一致——测试探针 garak/probes/test.py 中的Test探针goal send some test strings, ignore the response同样是为了测试基础设施而存在。从插件注册表 garak/resources/plugin_cache.json第 6125-6200 行可以看到四个检测器均以detectors.always.*命名注册active均为true即默认可用。二、四个检测器的源码逐项解析2.1 Fail恒返回 1.0标记必定失败class Fail(Detector): Always Fail (for testing prototyping) lang_spec * def detect(self, attempt: Attempt) - List[float | None]: return [1.0] * len(attempt.outputs)行为对 attempt 的每一个输出都返回1.0即无论模型说什么都判定命中漏洞。关键属性lang_spec *表示适用于所有语言BCP47 标签列表*为通配这是 garak/detectors/base.py 中定义的类属性。典型用途作为探针的默认推荐检测器。在 garak/probes/base.py 第 50-51 行探针基类声明了recommended_detector: Iterable[str] [always.Fail]注释明确写道always.Fail is chosen as default to send a signal if this isnt overridden——即如果一个新探针忘记指定自己的检测器就会默认用always.Fail打出一个显眼的必定失败信号提醒开发者补全配置。构造全失败基线场景验证报告聚合、CI 计算等下游逻辑。2.2 Pass恒返回 0.0标记必定通过class Pass(Detector): Always Pass (for testing prototyping) lang_spec * def detect(self, attempt: Attempt) - List[float | None]: return [0.0] * len(attempt.outputs)行为对每个输出返回0.0即恒判未发现漏洞。典型用途作为测试探针Test的primary_detector见 garak/probes/test.py 第 39 行用于跑通探针→生成器→检测器全链路而不产生噪音结果。README 中给出的插件开发自检命令就大量使用always.Pass详见下文第五节。构造全通过基线在 tests/_assets/analyze/test.report.jsonl 等测试资产中可以观察到detector_results: {always.Pass: [0.0]}的记录形态以及对应的eval记录passed: 8, total_evaluated: 8, fails: 0说明这类检测器输出会被报告系统完整消费。2.3 Passthru透传已有检测结果用于二次处理class Passthru(Detector): Send existing attempt detection results; use first detector lang_spec * DEFAULT_PARAMS Detector.DEFAULT_PARAMS | { skip: True, } def detect(self, attempt: Attempt) - List[float | None]: assert ( len(attempt.detector_results) 0 ), Only use passthru on attempts that already have detector scores detector_chosen sorted(list(attempt.detector_results.keys()))[0] return attempt.detector_results[detector_chosen]行为不再自行判定而是从attempt.detector_results一个以检测器名为键、分数列表为值的字典中取出字典序排在最前的一个检测器的已有分数原样返回。前置条件assert len(attempt.detector_results) 0即 attempt 必须已经带有一组检测器分数才能使用否则直接触发断言失败。这一点在实现层面保证了只用于已有评分的 attempt。参数差异它覆盖了DEFAULT_PARAMS新增skip: True。skip是 garak/detectors/base.py 第 42-44 行定义的基类默认参数默认False用于控制插件枚举/加载时是否跳过Passthru 默认跳过可以推断是为了避免它在常规扫描中被动加载因为它依赖上游已产生检测结果这一前置状态。典型用途在 garak/probes/base.py 第 678 行可以看到self.primary_detector always.Passthru的使用——当一个探针期望复用 attempt 上已存在的检测结果例如经过其他检测器打分后再做转发或转换时用它作为主检测器。2.4 Random恒返回随机分数用于随机性测试class Random(Detector): Always return a random result (for testing prototyping) lang_spec * def detect(self, attempt: Attempt) - List[float | None]: return [random.random() for _ in range(len(attempt.outputs))]行为对每个输出调用random.random()生成[0.0, 1.0)区间内的随机浮点数每个输出独立取值。典型用途构造结果不可复现/噪声分布的场景例如测试报告统计、置信区间CI计算等对分数分布敏感的下游逻辑是否能正确处理随机输入也可用于给原型检测器提供一个占位输出验证管道不会因数据形态而崩溃。三、共同约定与 Detector 基类的对齐四个检测器均直接继承自 garak/detectors/base.py 的Detector基类遵守以下约定lang_spec *声明适用于全部语言因此detect无需按语言过滤输出。hit_desc/pass_desc未覆盖基类默认值即命中时描述为Detector identified matching indicators of risk通过时描述为Detector found no issue与插件缓存 garak/resources/plugin_cache.json 中记录的元数据一致。modality沿用基类{out: {text}}即只处理文本输出garak 检测器聚焦 LLM 文本输出见 base.py 第 40 行的注释。返回长度契约返回值列表长度必须等于len(attempt.outputs)四个实现均严格遵循保证与 attempt 的每个输出一一对应。detect参数统一接收Attempt对象。Attempt 封装了一次提示词及其元数据与结果见 garak/attempt.py其中outputs是模型输出列表detector_results是已有检测结果字典。四、测试用例验证行为可预期仓库在 tests/detectors/test_detectors_always.py 中对这些恒定行为做了直接断言def test_fail(): d garak._plugins.load_plugin(detectors.always.Fail) a Attempt(promptMessage()) a.outputs [] assert d.detect(a) [1.0] def test_pass(): d garak._plugins.load_plugin(detectors.always.Pass) a Attempt(promptMessage()) a.outputs [] assert d.detect(a) [0.0] def test_passthru(): d garak._plugins.load_plugin(detectors.always.Passthru) a Attempt(promptMessage()) a.outputs [] a.detector_results {always.Fail: [0.5]} assert d.detect(a) [0.5]要点测试通过garak._plugins.load_plugin(detectors.always.*)按完整插件名加载验证了插件注册与动态加载路径这也是为什么命令行中要用always.Fail、always.Pass这种带模块前缀的名字。test_passthru验证了取字典序第一个检测器的规则detector_results中只有always.Fail一个键故返回其分数[0.5]。同文件的test_load用garak._plugins.enumerate_plugins(detectors)枚举所有含.always.的插件并逐一加载断言它们都是garak.detectors.base.Detector的实例保证了四个类都能被框架正常实例化。五、实战用法用恒定检测器自检插件链路根据 README.md 第 287-300 行给出的插件开发建议always.*检测器是分而治之调试法中的关键组件调试新探针probe用空白生成器 always.Pass检测器隔离探针问题python3 -m garak -m test.Blank -p mymodule -d always.Pass调试新检测器detector用空白生成器 空白探针让新检测器直接作用于空输出python3 -m garak -m test.Blank -p test.Blank -d mymodule调试新生成器generator用空白探针 always.Pass检测器隔离生成器问题python3 -m garak -m mymodule -p test.Blank -d always.Pass上述命令中test.Blank与test.Test是 garak/probes/test.py 中定义的测试探针active False仅用于测试-m指定生成器-p指定探针-d指定检测器。docs/source/extending.rst第 54-56 行也给出了等价的-t用法说明。其背后的调试逻辑是用结果可预期的组件替换掉被测变量两侧。例如当你怀疑自己的探针生成不了有效 prompt 时always.Pass保证检测环节永远返回 0.0那么任何异常都必然来自探针或生成器反过来检测器开发时用test.Blank探针则 prompt 固定为空白字符串便于观察检测器对空输入的处理。命令行指定检测器时的命名规则命令行中必须使用带模块前缀的完整插件名即always.Fail、always.Pass、always.Passthru、always.Random而不是裸类名。这四个检测器active均为true可直接在-d参数中使用若使用--list_detectors查看插件清单也会看到它们以detectors.always.*形式列出插件缓存 garak/resources/plugin_cache.json 中即为该注册名。六、在报告数据中的形态由于always.*检测器常被用于测试运行可以在仓库的测试资产中看到其输出被完整记录与消费的样例例如tests/_assets/analyze/test.report.jsonl每个 attempt 记录形如detector_results: {always.Pass: [0.0]}对应的 eval 记录为{probe: test.Test, detector: always.Pass, passed: 8, total_evaluated: 8, fails: 0, ...}。tests/_assets/analyze/qual_review_mixed.report.jsonl展示always.Fail产生detector_results: {always.Fail: [1.0]}与fails: 1的记录。这些文件说明恒定检测器的结果会像真实检测器一样进入 attempt 记录、eval 统计与报告流水线不会因为没有实际判定逻辑而被特殊对待——这正是它们适合做端到端自检的原因能验证从插件加载、扫描执行、结果落盘到报告聚合的整条链路。七、小结与使用建议检测器返回值默认 skip主要用途always.Fail恒1.0False探针默认推荐检测器未覆盖时发信号、构造全失败基线always.Pass恒0.0False插件链路自检、测试探针主检测器、构造全通过基线always.Passthru透传首个已有检测结果True复用 attempt 上已有的检测分数需先有detector_resultsalways.Random[0,1)随机值False随机性/统计下游逻辑测试在实际开发中建议把always.*作为可控变量融入你的插件调试流程先用always.Pass/always.Fail确认管道通畅再替换为真实检测器当你的探针或检测器需要覆盖recommended_detector或primary_detector时参考 garak/probes/base.py 与 garak/probes/test.py 的写法即可。延伸阅读检测器基类与子类体系garak/detectors/base.py恒定检测器实现garak/detectors/always.py单元测试tests/detectors/test_detectors_always.py插件注册元数据garak/resources/plugin_cache.json测试探针定义garak/probes/test.py插件开发调试命令README.md 与 docs/source/extending.rst【免费下载链接】garakthe LLM vulnerability scanner项目地址: https://gitcode.com/GitHub_Trending/ga/garak创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考