为什么规则是
AI 代码审查的秘密武器
结构化规则如何将 AI 代码审查从不可预测的建议转变为确定性、可靠的结果
如果你曾经尝试用 ChatGPT 或 Claude 进行代码审查,你一定遇到过这种情况:同样的代码会根据你提问的方式、之前的对话内容,甚至 AI 当天的"心情"而得到不同的反馈。这种不一致性不仅仅令人沮丧——它是一个根本性问题,使得 AI 代码审查无法在生产环境中可靠使用。
在 diffray,我们通过结构化规则解决了这个问题。让我们深入了解为什么它们是有效 AI 代码审查的关键。
问题:上下文稀释扼杀 AI 性能
当你将整个 PR 加载到 LLM 中,并使用类似"检查这段代码"的提示时,会出现几个问题:
信号淹没在噪音中
AI 试图同时检查安全性、性能、测试、文档、风格——所有内容。结果呢?浅层分析,遗漏关键问题。
"迷失在中间"效应
研究一致表明,长上下文中间的信息会被忽略。你最重要的文件可能正好在 AI 无法有效处理的位置。
结果不一致
同样的检查运行两次——得到不同的结果。这对于团队依赖的工具来说是不可接受的。
误报爆炸
没有焦点,AI 会标记在你的代码库中实际上不是问题的通用模式。研究表明,"上下文灌输"方法会产生 60-80% 的误报率。
解决方案:结构化规则
结构化规则不仅仅是一个提示词——它是一个完整的规范,告诉 AI 具体要寻找什么、在哪里寻找以及如何报告结果。
以下是一个规则的示例:
rules:
- id: sec_sql_injection
agent: security
title: "通过字符串拼接的 SQL 注入"
description: "用户输入拼接到 SQL 查询中允许攻击者执行任意 SQL"
importance: 9
match:
file_glob:
- "src/api/**/*.ts"
- "src/routes/**/*.ts"
- "!**/*.test.ts"
content_regex:
- "query.*\$\{|\+.*query"
checklist:
- "找到所有用户输入用于 SQL 查询的地方"
- "检查是否使用参数化查询或预处理语句"
- "确保没有使用字符串拼接构建查询"
examples:
bad: |
const query = `SELECT * FROM users WHERE id = ${userId}`;
await db.execute(query);
good: |
const query = 'SELECT * FROM users WHERE id = ?';
await db.execute(query, [userId]);这种结构提供了三个关键能力,使 AI 代码审查真正有效。
1. 通过精确定位实现确定性结果
注意到 match 部分了吗?这是模式匹配,定义规则何时触发。
没有模式匹配,审查一个 50 个文件的 PR 意味着要针对每个可能的问题分析所有 50 个文件。有了模式匹配:
没有模式匹配
- 50 个文件 x 所有规则 = 巨大的提示
- 每次检查约 500,000 个 token
- 结果:慢、贵、不聚焦
有模式匹配
- 5 个 API 文件 x API 安全规则
- 每次检查约 50,000 个 token
- 结果:快、省、精准
90%
通过精确模式匹配节省的 token
如果 PR 中有 5 个包含 SQL 查询的 API 文件,只有这 5 个文件会被发送进行 SQL 注入检查。AI 只看到需要评估的内容——不多也不少。
这种精确性消除了困扰早期 AI 代码审查尝试的随机性。相同的代码 + 相同的规则 = 相同的结果。每一次。
2. 多智能体架构:每项任务配备合适的专家
这里变得有趣了。diffray 不使用单一 AI 审查所有内容——它使用 31 个专门的智能体,每个都专注于它最擅长的领域:
安全专家
漏洞、认证、数据泄露
性能专家
N+1 查询、内存泄漏、性能瓶颈
Bug 猎手
空指针、竞态条件、边界情况
React 智能体
Hooks 模式、生命周期、状态管理
TypeScript 智能体
类型安全、泛型、严格模式模式
架构顾问
设计模式、耦合度、可扩展性
每个智能体都有专门的系统提示,包含其领域的专业知识。安全智能体了解 OWASP Top 10。React 智能体理解 Hooks 规则。这种专业化显著提高了检测质量。
但关键点在于:规则定义哪个智能体处理什么。
- id: react_useeffect_cleanup
agent: react # 由 React 专家处理
match:
file_glob: ["**/*.tsx"]
content_regex: ["useEffect"]
checklist:
- "检查 useEffect 是否返回清理函数"
- "确保事件监听器和订阅被清理"这个规则只发送给 React 智能体,只针对 TSX 文件,只在存在 useEffect 时。智能体得到的是专注于单一任务的上下文——而不是 50 个不同任务争夺注意力。
3. 上下文管理:保持 AI 注意力的秘诀
现代 LLM 可以处理 200k+ token。但研究表明,对于复杂推理,实际性能在 25-30k token 左右达到上限。超过这个阈值,你是在为模型无法有效使用的 token 付费。
diffray 的上下文管理系统确保每个智能体只获得它需要的信息:
| 智能体 | 获取 | 排除 |
|---|---|---|
| 安全专家 | 认证流程、API 端点、数据处理 | UI 组件、样式 |
| 性能专家 | 热路径、循环、数据结构 | 文档、配置 |
| React 智能体 | 组件、Hooks、状态管理 | 后端代码、SQL |
每个智能体只获得完成其任务所需的内容。不多不少。结果:注意力集中、更好的结果、更少的误报。
4. 灵活性:项目和团队专属规则
这是规则真正为团队发挥作用的地方。每个代码库都有自己的约定,通用工具并不了解这些:
你的内部库:
- id: use_internal_http_client
agent: consistency
title: "使用内部 HTTP 客户端"
match:
file_glob: ["src/**/*.ts"]
content_regex: ["\\bfetch\\(", "axios\\."]
checklist:
- "找到直接的 fetch() 或 axios 调用"
- "检查代码是否应该使用 @/lib/http-client 中的 httpClient"
examples:
bad: |
const response = await fetch('/api/users');
good: |
import { httpClient } from '@/lib/http-client';
const data = await httpClient.get('/api/users');你的领域特定模式:
- id: money_use_decimal
agent: bugs
title: "金额值使用 Decimal"
match:
content_regex: ["(price|amount|total)\\s*:\\s*(number|float)"]
checklist:
- "找到使用 float/number 类型的金额字段"
- "检查存储是否使用分(整数)或 Decimal 类型"你的合规要求:
- id: pii_logging_check
agent: compliance
title: "永不直接记录 PII"
tags: [compliance-gdpr, compliance-hipaa]
match:
content_regex: ["log.*(email|phone|ssn|password)"]将它们放在 .diffray/rules/ 中,它们就会在下一个 PR 中生效。无需基础设施更改,无需工具更新——只需添加 YAML,你的 AI 审查员就会学习你的标准。
为什么选择 YAML?结构带来智能
你可能会问为什么我们使用结构化的 YAML 而不是简单的提示词。结构提供了自由文本无法实现的能力:
模式匹配和过滤
match 部分在任何内容发送给 AI 之前处理。这在代码中发生,而不是在提示词中——确定性的、快速的、精确的。
语义组织
规则有 id、agent、importance、tags。这支持过滤("只对这个 PR 运行安全规则")、优先级排序("首先显示关键问题")和报告("安全问题与质量问题各有多少?")。
版本控制和审查
规则就是代码。它们存放在你的仓库中,经过 PR 审查,有 git 历史。当有人问"为什么 AI 标记了这个?"时,答案就在每个人都能阅读的 YAML 文件中。
多阶段使用
规则的不同部分在不同阶段使用:match 用于文件过滤(不需要 AI),checklist + examples 用于 AI 审查,id + importance 用于去重和优先级排序。
扁平的提示词无法提供这种职责分离。
结果:真正有效的 AI 代码审查
当你将结构化规则与多智能体架构和智能上下文管理相结合时,你会得到:
确定性结果
相同代码、相同规则、相同结果
聚焦分析
每个智能体专注做好一件事
低误报率
精确匹配消除噪音
团队定制
无需基础设施更改即可添加你的标准
这就是将"AI 代码审查"从演示转变为你的团队真正可以依赖的基础设施的关键。