HIGH、MEDIUM、LOW——没有定义的话,这些就是毫无意义的标签。Claude 对严重程度没有稳定的内部校准。每次运行都根据周围代码上下文对”高严重性”做不同解读。多次运行一致率:41%。跟随机差不多。
加上文字条件(“HIGH:可能丢失数据,安全边界被突破”),一致率升到 72%。在条件旁边再加上代码示例,达到 94%。每一层都有实质贡献。
三层结构
第一层:标签 — HIGH、MEDIUM、LOW(单独没用)
第二层:具体条件
- HIGH:可能丢失数据、安全边界被突破、生产路径崩溃
- MEDIUM:功能不正确但不致命、性能下降
- LOW:风格问题、命名不一致、缺少文档
第三层:代码示例
HIGH 示例:
cursor.execute(f"SELECT * FROM users WHERE id = {user_input}")
→ SQL 注入:查询中未过滤的用户输入
MEDIUM 示例:
for user in users:
orders = db.query(f"SELECT * FROM orders WHERE user_id = {user.id}")
→ N+1 查询:能跑但规模上去就会变慢
LOW 示例:
def calc(x, y): return x + y
→ 缺少 docstring,参数名没有描述性
代码示例把抽象条件锚定到可识别的模式上。“可能丢失数据”仍然有解读空间,一个 SQL 注入代码片段没有。
为什么纯标签不行
一个团队用 200 条代码审查发现测试了严重等级分类:
| 方法 | 多次运行一致率 |
|---|---|
| 仅标签(HIGH/MEDIUM/LOW) | 41% |
| 每个等级加文字条件 | 72% |
| 文字条件 + 代码示例 | 94% |
纯标签接近随机,因为 Claude 每次运行都得自己发明定义。文字条件提供了框架。代码示例填补了剩余差距,消除了”数据丢失”这类抽象词的解读空间。
每个等级都必须定义
常见错误:只定义 HIGH(“数据丢失或安全漏洞”),把 MEDIUM 和 LOW 交给 Claude 自行判断。结果:所有东西都被归为 HIGH,因为那是唯一有具体标准的等级。
MEDIUM 和 LOW 之间的边界与 HIGH 和 MEDIUM 之间的边界同样重要。一个未定义的等级会变成万能收纳箱,从两边吸收发现。
路径相关的严重等级
同一种问题类型在不同代码路径下可以有不同严重等级:
- 生产请求路径上的空指针解引用 → HIGH(崩溃影响用户)
- 仅 debug 日志路径上的空指针解引用 → MEDIUM(外观问题,不影响用户)
“所有空指针解引用都是 HIGH”这种一刀切规则忽略了上下文。标准应该包含路径信息:“生产路径上的 NULL deref → HIGH,debug/测试路径上 → MEDIUM。”
这在单次审查中用条件标准就能处理,不需要按严重等级分多轮跑。
Token 预算优先级
当 prompt 空间有限时,优先给误分类代价最高的类别加代码示例。安全发现被误分为 LOW 可能就没人处理——它们需要示例。风格发现被误分为 MEDIUM 只是小麻烦——纯文字定义可能就够了。
不要为了省 token 就完全跳过示例。加示例带来的 22 个百分点提升(72% → 94%)是整个标准设计中投入产出比最高的一笔。
这些方法修不了未定义的严重等级
数字刻度。 从 HIGH/MEDIUM/LOW 换成 1-10 只是换了个尺度。如果不定义 7 和 4 的区别,你在更宽的尺度上得到同样的不一致。
“保持一致”指令。 这描述的是期望结果,但没提供实现方式。Claude 已经在尽力保持一致了——它缺的是标准。
多轮加多数投票。 用同样没定义的标准跑三次然后取多数票,选出的是出现频率最高的错误答案。歧义不会因为重复而被克服。
连续分数。 用连续分数(4.2 vs 4.5)替代离散等级引入了更多歧义。4.2 和 4.5 的区别比 MEDIUM 和 LOW 还难定义。
按比例降级。 自动把 30% 的 HIGH 发现转为 MEDIUM 完全无视实际严重程度。真正的关键发现被随机降级。
CI/CD 集成
在 CI 流水线中,带代码示例的严重等级定义应该放在 CLAUDE.md 里——版本控制、每次 claude -p 调用时自动加载。把定义嵌在 -p prompt 参数里既脆弱又难维护。CLAUDE.md 确保每次 CI 运行都应用同一套校准过的严重等级标准。
一句话总结: 每个严重等级都要用具体条件加代码示例来定义——纯标签产出 41% 一致率,条件加 31 个百分点,示例再加 22 个百分点,达到 94%。