凌晨3点,你让AI Agent写了一个React组件。它能跑,但里面藏着:
这些问题在运行时不会报错,但会在生产环境埋雷。Agent Code Quality检测的目标就是在代码进入代码库之前,自动识别这些问题。
// AI经常写出的问题代码
// ❌ 错误:内联函数导致不必要的重渲染
<Button onClick={() => handleClick(id)} />
// ✅ 正确:使用useCallback缓存
const handleButtonClick = useCallback(() => handleClick(id), [id]);
<Button onClick={handleButtonClick} />
// ❌ 错误:useEffect依赖不完整
useEffect(() => {
fetchData(userId);
}, []); // 缺少userId依赖
// ✅ 正确:声明所有依赖
useEffect(() => {
fetchData(userId);
}, [userId]);
// ❌ 错误:直接setState前一个状态
setCount(count + 1);
// ✅ 正确:使用函数式更新
setCount(prev => prev + 1);
// ❌ AI喜欢在循环里做昂贵操作
for (const item of items) {
const result = expensiveCalculation(item);
results.push(result);
}
// ✅ 应该批量处理
const results = items.map(item => expensiveCalculation(item));
// ❌ AI经常忘记memo
const ExpensiveComponent = ({ data }) => {
return {heavyTransform(data)};
};
// ✅ 使用React.memo避免不必要渲染
const ExpensiveComponent = React.memo(({ data }) => {
return {heavyTransform(data)};
});
// ❌ 直接使用用户输入
const query = `SELECT * FROM users WHERE id = ${userId}`;
// ✅ 参数化查询
const query = 'SELECT * FROM users WHERE id = ?';
db.query(query, [userId]);
// ❌ 不安全的HTML渲染
<div dangerouslySetInnerHTML={{ __html: userInput }} />
// ✅ 先进行转义
import DOMPurify from 'dompurify';
<div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(userInput) }} />
来自millionco的react-doctor是专门检测AI生成React代码质量的工具:
# 安装React Doctor
npm install -g @millionco/react-doctor
# 检测单个文件
react-doctor check src/components/MyComponent.jsx
# 检测整个项目
react-doctor scan ./src
# 与CI集成
react-doctor ci --threshold 80
# 在SKILL.md中定义代码质量检查
triggers:
- file_created: "*.jsx"
- file_modified: "*.tsx"
actions:
- name: code_quality_check
type: shell
command: |
npm run lint
npm run type-check
react-doctor check ${file_path}
- name: report_issues
type: notify
channel: feishu
template: |
🔍 代码质量检测完成
文件: ${file_path}
问题数: ${issues_count}
详情: ${report_url}
{
"rules": {
"react-hooks-exhaustive-deps": "error",
"react-no-array-index-key": "warn",
"react-no-inline-functions": "warn",
"no-dangerously-set-innerhtml": "error",
"no-sql-injection": "error",
"no-eval": "error",
"performance-no-large-bundle": "warn"
},
"thresholds": {
"error": 0, // 超过0个error则阻止合并
"warn": 10, // 超过10个warn则发出警告
"score": 80 // 代码质量评分低于80则阻止合并
}
}
// 检测AI常见的「过度封装」问题
const noOverAbstraction = {
meta: {
type: 'suggestion',
docs: {
description: '避免过度抽象,AI经常创建不必要的包装函数'
}
},
create(context) {
return {
FunctionDeclaration(node) {
if (node.body.body.length === 1 &&
node.body.body[0].type === 'ReturnStatement') {
// 函数只有一行return,可能是过度封装
context.report({
node,
message: '考虑直接使用该函数而不是创建包装器'
});
}
}
};
}
};
# GitHub Actions工作流
name: AI Code Quality Check
on:
pull_request:
types: [opened, synchronize]
jobs:
quality-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
- name: Install Dependencies
run: npm ci
- name: Run Linter
run: npm run lint
- name: Run Type Check
run: npm run type-check
- name: Run React Doctor
run: npx react-doctor scan ./src
- name: Quality Gate
run: |
if [ $(cat quality-report.json | jq '.score') -lt 80 ]; then
echo "代码质量评分低于80,请修复后再合并"
exit 1
fi
AI生成代码 → 自动质量检测 → 人类审查 → 修改 → 合并
│ │ │
└── 初稿 ──────┴── 发现问题 ──┴── 最终把关