本地小模型审计:用来分流,别当裁判
作者先用五项确定性检查扫描交易策略代码,再让本地 Qwen2.5-Coder-1.5B 对有限上下文中的发现作二元判断。CPU 上每次判断约需 12 秒,因此将其用于后台报告排序,并强调模型判断的边界。
AI 深度解读
把小模型接进代码审计,最容易走偏的地方,是让它决定某个问题到底存不存在。作者给交易策略仓库做了一个本地审计工具,测完之后收紧了定位:规则负责发现问题,模型只提供一次范围很窄的复核,供人决定先看哪里。
这篇值得读的地方,是作者把耗时、答复翻转和没测过的部分都摊开了。对想给代码检查加一层 AI 的程序员来说,这比一句「小模型也能审代码」更有参考价值。
十二秒一次提问,决定了模型该放在哪里
工具先对源码执行五项确定性检查,再把每条发现交给本地模型。默认模型是 Qwen2.5-Coder-1.5B-Instruct,采用 Q4_K_M 量化,通过 llama.cpp 在笔记本 CPU 上运行。不需要 API key、上传代码或注册账号,内容留在机器上。
在附带样例中,四次模型检查耗时约 48 到 50 秒,平均每次约十二秒;加上 --no-llm,只跑规则则不到一秒。
这组数字决定了它适合什么工作流。逐文件循环询问模型,等待会不断累积;放在保存按钮后面,也会打断工作。作者选择让它在夜间或喝咖啡时执行,回来再读已经排好序的报告。
模型的价值是帮助安排阅读顺序,最终判断仍要回到代码。
这里的耗时是作者那台笔记本上的测量,原文没有给出硬件配置,不能直接当成所有 CPU 的性能结论。但在这个环境里,十二秒足以排除「让模型随便看看哪里有问题」的宽泛提问:等这么久,作者想得到的是一个检查线索,而非一段还要逐句核实的文字。
把问题压到六行,仍然不能把回答当裁决
模型看不到整个仓库,只能看到证据行及周边五行,共六行上下文。它需要回答一个具体判断,输出限定为 YES、NO 或 UNSURE,不负责生成文件名、行号或摘要。
这个限制来自一次失败。早期版本让模型总结文件,得到的文字流畅而具体,却把函数职责说错了。读者必须逐句验证,审计工具反而增加了阅读负担。作者因此让代码负责定位,让模型只判断「眼前这条指控是否成立」。
即便任务已经缩得这么窄,回答也会翻转。
作者用 Gemma 2 2B IT Q4_K_M,在 temperature 0.2 下,对同一段代码、同一个问题,在隔离上下文中提问三次,得到 NO、NO、YES。作者确认费用缺陷存在,检查器也已经打印出缺少费用项的账本代码行,但模型前两次都否认了它。
作者还比较过两个模型的回答:两次审计分别出现 3/4 和 4/4 的一致率。不过,两次运行之间调整过代码,把上下文窗口移到了证据行,因此不能把差异单纯归因于采样波动。
这份自我约束很关键。三次提问不足以估计整体错误率,两次有变量变化的运行也算不上严格对照。它们能支持的结论更窄:在作者测过的任务里,这个 2B 模型的判断不稳定,不能直接拿来当可靠测量。
报告必须保留证据,模型不能撤销发现
作者据此划出了几条明确边界。
检查器拥有发现的控制权。报告里的每个 path:line 都来自代码匹配,模型不能新增、移动或删除发现。即使模型回答 NO,原始线索仍然保留。
UNSURE 和「没有补充」都是合法结果,模型不必为了完成任务硬给答案。两个模型意见一致,也只说明它们都没有反对检查器,不能据此生成一个未经计算的置信度。
报告还会原样打印证据行。对于「某个东西不存在」这样的检查,则必须交代搜索过程。例如,报告应明确说明在 214 行中没有匹配到 fee、commission、slippage 或 spread,而不能只写「文件没有费用项」。前一种表达让人能检查搜索范围和关键词是否充分,后一种容易把搜索遗漏包装成业务结论。
工具的盲区也用固定文字说明:它不运行策略,不读取用户数据,无法判断交易优势是否真实存在。即使没有发现问题,报告也只说没有触发 v0 检查,不能据此宣告策略通过审计。
下面这些命令展示了完整运行、双模型对照和纯规则检查的入口:
pip install -e .
slothaudit audit samples/broken_lookahead # ~50s, four model checks
slothaudit audit samples/broken_lookahead --compare # both models, one report
slothaudit audit samples/broken_lookahead --no-llm # deterministic only, instant
python3 -m slothaudit audit samples/broken_lookahead # works without install
重点看带 --no-llm 的一行:关闭模型后,确定性检查仍可独立完成,模型没有成为整条流程的必经依赖。
我的判断
我赞成这套职责划分。相比让模型浏览仓库后自由写审计结论,规则定位、窄问题复核、人工看证据,更容易追溯每条发现的来处。尤其当模型能力有限时,限制它能改动什么,比要求它「务必准确」更具体。
但六行上下文也有代价。费用可能在其他函数里扣除,变量含义也可能依赖调用链;原文没有测量这种截断会造成多少误判。更大的模型或更多上下文是否值得额外成本,也没有对照数据。这里能借鉴的是设计取舍,不能据此认定六行就是最佳窗口。
作者自己指出,若要自动跳过模型否认的发现,还缺两类数据:真实问题与相近误报的分数分布,以及添加引用行、调整字段顺序等提示变化下的回答翻转率。当前流程又只输出离散答案,怎样得到可用于阈值分析的分数,原文也没说清。
自动执行审计,与自动采纳模型判断,是两种不同程度的授权。
目前材料支持前者加人工阅读。至于小模型能否稳定降低误报、节省多少总审阅时间,作者没有给出对照数据,应当保留问号。
能拿来做什么
- 给现有代码检查接入 AI 时,可以先保留规则产生的文件位置和证据,再让模型回答一个具体问题;模型否认也不要直接隐藏发现。
- 在本地仓库审阅流程中,先测单条提问的耗时,再决定采用交互运行还是后台批处理。报告很短、人工读完更快时,直接使用纯规则模式。
- 在考虑自动过滤之前,用已确认的问题和相近误报做评估,并对同一问题调整上下文、字段顺序和引用方式,记录答案是否翻转。
- 设计报告时,把命中的原始代码、未命中的搜索词和检查范围写清楚,同时明确「未触发规则」能证明到哪一步,避免让读者把空报告当成质量保证。