给 LLM 评审器加了句 "adversarial"
搞了个开源项目 PlannerCritic,双 LLM 协作:一个写执行计划,一个当评审员挑刺。原本想跑个 strict 模式,只拦截真正的安全隐患——乱序、回滚薄弱、依赖未验证、不可行这四类。结果评审员拿到 system prompt 里那六个词 You are an adversarial plan reviewer 后,16 个严格目标全触发了人工升级。
全是误报。
评审员不是在找安全缺陷,它在找"遗憾"。跨账号 VPC 对等连接方案,回滚逻辑写得清清楚楚,评审员非说"还得考虑 DNS 故障回切场景"——这是完整性建议,不是结构性缺陷。嵌入索引迁移方案,切换窗口可能有延迟,评审员给个笼统 risk 就判 blocker。这俩按设计本该是 warning,带着已知风险放行才对。
提示词单改不管用。我在 system prompt 里追加 "only block on concrete defects",跑下来仍有 30% 左右的 completeness 问题被判 blocker。LLM 对"严重到必须拦截"这条线根本没有稳定内化,受模型、temperature、方案措辞影响太大。
最后靠代码兜底才彻底解决:
_BLOCKER_ELIGIBLE_FAMILIES = frozenset({
"unsafe_sequencing",
"weak_rollback",
"unverified_dependencies",
"feasibility",
})
if severity == Severity.BLOCKER and item.heuristic_family not in _BLOCKER_ELIGIBLE_FAMILIES:
severity = Severity.WARNING评审员哪怕吐出 blocker,只要 heuristic_family 不在白名单里,代码层面直接降级成 warning,根进不了 findings 列表。
改完跑了 92 次 strict 目标,零个 advisory 类 findings 冒充 blocker。剩下的 132 个 blocker 全是实打实的结构缺陷或确定性门控拦下来的。balanced 模式该过的还过,strict 模式该拦的还拦,但拦的理由终于对上了。
这事儿让我重新审视"把判断权交给 LLM"这件事:判断标准如果不落地成可枚举、可校验的规则集,光靠 prompt 里几句形容词根本压不住模型的发散性。frozenset 这层守卫,才是真正的合同。