我让一个LLM扮演"对抗性审查员",结果它把每一个计划都拦了下来。不是因为这些计划不安全,而是因为它觉得"不够全面"。
这是PlannerCritic开源引擎系列文章的第二篇。在这个引擎里,一个LLM负责写计划,另一个LLM负责审查。上一篇讲的是157个目标的实地测试结果,这一篇要讲一个具体的bug——它让我对LLM的判断力有了新的认识。
六字提示词引发的连锁反应
我给审查LLM的系统提示词只有六个词:"You are an adversarial plan reviewer"(你是一名对抗性计划审查员)。当时觉得没问题。
结果跑了16个严格模式的目标,全部升级处理。不是因为计划不安全,而是因为审查员把"完整性"问题当成了阻断理由——"这个计划还可以覆盖边缘情况X"——而不是指出具体的缺陷。
最让人头疼的是:审查员技术上确实在履行职责。我让它对抗,它就在每个计划里都找到了可以反对的点。问题在于,我没有说清楚"哪种对抗"。
两种合同,一个没被发现的错位
严格模式的产品意图是:"没有具体的安全、顺序或回滚违规。"而审查员实际执行的是:"不允许有任何审查意见。"这是两种完全不同的约定,而我直到16个目标都因为错误原因失败后才意识到。
来看看修复前审查员标记为阻断器的两个案例:
- 一个跨账户VPC对等连接计划被拦截,因为审查员说回滚计划"还可以考虑"DNS故障转移场景。这是完整性建议,不是安全缺陷。计划里有回滚,只是没有覆盖每一个假设场景。
- 一个嵌入索引迁移计划被拦截,因为审查员标记了一个关于切换期间潜在延迟的泛泛"风险"。这是风险评论,不是结构性缺陷。
这两个都应该只是警告。引擎本应批准计划并记录已确认的风险,结果却升级给了人工处理。
修复:提示词加代码,双管齐下
提示词改动:把"对抗性计划审查员"改成"计划审查员",并加上明确的严重级别规则:
阻断器只保留给具体的、计划本地的、会让计划无法安全执行的缺陷:不安全排序、回滚薄弱、依赖未验证、可行性问题。风险、缺失步骤归为警告,小观察归为信息。不要把完整性或彻底性担忧升级为阻断器。
代码护栏:用一个frozenset(冻结集合)定义哪些发现类别可以升级为阻断器。即使LLM返回了阻断级别,只要发现类别不在这个集合里,代码就会自动降级为警告。
修复前:每个严格模式目标都失败,因为审查员在阻断建议性意见。修复后:审查员仍然可以提出担忧,但只有真正的安全缺陷才能触发阻断。
教训:LLM判断需要明确边界
这个bug让我意识到,给LLM设定"对抗性"角色时,必须同时定义"对抗什么"。没有边界,它会对抗一切——包括那些本应放行的计划。
一个frozenset就解决了问题。但更根本的教训是:LLM的判断力需要结构化的约束,而不是模糊的角色描述。你告诉它"要严格",它就会严格到把所有东西都拦下来。你得告诉它"严格"具体指什么。
PlannerCritic是开源的,这个修复已经合入代码库。如果你也在构建类似的LLM审查系统,记住:角色提示词要配严重级别规则,规则要配代码强制。三层缺一不可。
热门跟贴