本文将分享如何从零开始构建一个基于 DeepSeek AI 的智能代码审查系统,实现自动化、专业化的代码质量把控。
📌 前言
在软件开发过程中,代码审查(Code Review)是保证代码质量的重要环节。然而,人工代码审查往往面临以下挑战:
- ⏰ 耗时耗力:审查一个大型 PR 可能需要几十分钟甚至几小时
- 📊 质量不稳定:审查质量受审查者经验、状态、时间等因素影响
- 🔄 响应滞后:需要等待团队成员有空进行审查
- 📈 难以量化:缺乏统一的评分标准和质量指标
那么,能否让 AI 来辅助甚至自动完成代码审查工作呢?答案是肯定的!
本文将介绍我开发的 AI Code Review 系统,它能够:
- ✅ 自动分析代码提交的差异
- ✅ 从多个维度评估代码质量
- ✅ 生成详细的审查报告和改进建议
- ✅ 给出量化的质量评分(0-100 分)
🎯 为什么选择这个技术栈?
在开始实现之前,让我们先看看技术选型的考量。
后端:Node.js + Express
选择 Node.js 的原因:
- 高效的 I/O 处理:代码审查系统需要频繁调用外部 API(DeepSeek、Gitee),Node.js 的异步非阻塞特性非常适合
- 生态丰富:npm 生态提供了大量成熟的库,如
express、mongoose、axios等 - 开发效率高:JavaScript 语法简洁,开发和调试都很方便
- 易于部署:支持 PM2、Docker 等多种部署方式
Express 框架则提供了:
- 简洁的路由系统
- 丰富的中间件生态
- 灵活的扩展能力
数据库:MongoDB
选择 MongoDB 而非传统关系型数据库:
- 灵活的文档结构:审查报告内容不固定,使用文档数据库更灵活
- 快速开发:使用 Mongoose 可以快速定义模型和进行 CRUD 操作
- JSON 友好:与 Node.js 配合天然,数据格式统一
- 易于扩展:支持水平扩展,适合未来增长
AI 模型:DeepSeek
选择 DeepSeek 的原因:
- 代码理解能力强:DeepSeek 在代码分析任务上表现出色
- 中文支持好:对中文技术文档和注释的理解很准确
- API 稳定:提供标准的 OpenAI 兼容接口,易于集成
- 性价比高:相比 GPT-4,DeepSeek 的定价更加友好
🏗️ 系统架构设计
整个系统的架构如下:
┌─────────────────┐
│ Gitee Repo │
│ (代码仓库) │
└────────┬────────┘
│ Push Event
│ Webhook
↓
┌─────────────────────────────────────────────┐
│ AI Code Review System │
│ ┌────────────┐ ┌──────────────────────┐ │
│ │ Express │ │ Review Router │ │
│ │ Server │→ │ (处理审查请求) │ │
│ └────────────┘ └──────────┬───────────┘ │
│ ↓ │
│ ┌──────────────────────┐ │
│ │ AI Service │ │
│ │ (调用 DeepSeek) │ │
│ └──────────┬───────────┘ │
│ ↓ │
│ ┌──────────────────────┐ │
│ │ MongoDB │ │
│ │ (存储审查结果) │ │
│ └──────────────────────┘ │
└─────────────────────────────────────────────┘
│
↓
┌─────────────────┐
│ Web UI │
│ (查看报告) │
└─────────────────┘
核心流程
- 代码提交触发:开发者提交代码到 Gitee,触发 Webhook
- 接收并解析:Express 服务器接收 Webhook,解析出代码差异
- AI 分析:调用 DeepSeek API,传入代码 diff 进行分析
- 生成报告:AI 返回结构化的审查报告(Markdown 格式)
- 存储结果:将审查结果保存到 MongoDB
- 展示报告:通过 Web 界面查看审查结果
💻 核心功能实现
1. AI 审查服务
这是整个系统的核心,让我们看看关键代码:
// src/services/ai.service.js
import OpenAI from "openai";
const systemPrompt = `你是专业的资深代码审查工程师。给定一次提交的 diff,
请进行结构化审查:
- 评估风险、复杂度、测试覆盖面、可读性、安全性
- 指出潜在 bug、风格/架构问题,并给出改进建议
- 最终给出0-100分的评分与简要总结
输出 Markdown 报告,包含:总体结论、亮点、问题清单(带严重级别与建议)、建议测试用例。`;
export async function analyzeDiffWithAI({
projectName,
commitId,
author,
diffText,
}) {
const client = new OpenAI({
apiKey: process.env.DEEPSEEK_API_KEY,
baseURL: process.env.DEEPSEEK_BASE_URL || "https://api.deepseek.com",
});
const userPrompt = `项目: ${projectName}\n提交: ${commitId}\n作者: ${author}\n--- DIFF START ---\n${diffText}\n--- DIFF END ---`;
const response = await client.chat.completions.create({
model: process.env.DEEPSEEK_MODEL || "deepseek-chat",
messages: [
{ role: "system", content: systemPrompt },
{ role: "user", content: userPrompt },
],
temperature: 0.2, // 降低随机性,保持审查的一致性
});
const mdReport = response.choices?.[0]?.message?.content;
// 从报告中提取分数
const match = mdReport.match(/(?:得分|评分)[::]\s*(\d{1,3})/);
const score = match ? Number(match[1]) : 60;
return { mdReport, score, modelUsed: response.model };
}
设计要点:
- 精心设计的 Prompt:明确告诉 AI 需要审查哪些方面,输出什么格式
- 低温度参数:
temperature: 0.2保证审查的稳定性和一致性 - 结构化输出:要求 AI 输出 Markdown 格式,便于展示
- 错误处理:包含完整的错误处理和降级方案
2. 数据模型设计
// src/models/ReviewResult.js
import mongoose from "mongoose";
const reviewResultSchema = new mongoose.Schema(
{
projectName: { type: String, required: true, index: true },
commitId: { type: String, required: true },
author: { type: String, default: "unknown" },
repoUrl: String,
diffText: String,
mdReport: { type: String, default: "" },
score: { type: Number, default: 60, min: 0, max: 100 },
modelUsed: String,
status: {
type: String,
enum: ["pending", "completed", "failed"],
default: "pending",
},
},
{
timestamps: true, // 自动添加 createdAt 和 updatedAt
},
);
// 创建复合索引,优化查询性能
reviewResultSchema.index({ projectName: 1, createdAt: -1 });
export const ReviewResult = mongoose.model("ReviewResult", reviewResultSchema);
设计亮点:
- 使用索引优化查询性能
- 使用枚举类型约束状态字段
- 自动时间戳记录创建和更新时间
- 分数范围验证(0-100)
3. Gitee Webhook 集成
// src/webhook/review.router.js
router.post("/webhook/gitee", async (req, res) => {
try {
const event = req.body;
// 验证 Webhook 签名(可选但推荐)
const secret = process.env.GITEE_WEBHOOK_SECRET;
if (secret) {
const signature = req.headers["x-gitee-token"];
if (signature !== secret) {
return res.status(403).json({ error: "Invalid signature" });
}
}
// 只处理 Push 事件
if (event.hook_name !== "push_hooks") {
return res.json({ message: "Event ignored" });
}
// 获取最新的 commit
const lastCommit = event.commits?.[event.commits.length - 1];
if (!lastCommit) {
return res.json({ message: "No commits found" });
}
// 获取代码差异
const diffText = await fetchDiffFromGitee(
event.repository.full_name,
lastCommit.id,
);
// 创建审查任务
const review = await ReviewResult.create({
projectName: event.repository.name,
commitId: lastCommit.id,
author: lastCommit.author.name,
repoUrl: event.repository.html_url,
diffText,
status: "pending",
});
// 异步执行 AI 审查
performReview(review._id, {
projectName: event.repository.name,
commitId: lastCommit.id,
author: lastCommit.author.name,
diffText,
});
res.json({
success: true,
reviewId: review._id,
message: "Review started",
});
} catch (error) {
console.error("Webhook error:", error);
res.status(500).json({ error: error.message });
}
});
关键技术点:
- 签名验证:防止恶意请求
- 异步处理:立即返回响应,避免超时
- 错误处理:完善的异常捕获和日志记录
4. Web 界面展示
前端使用原生 JavaScript + Markdown 渲染库,实现了一个简洁美观的界面:
<!-- public/index.html 核心部分 -->
<div class="review-card">
<div class="review-header">
<h2 class="project-name">{{ projectName }}</h2>
<div class="score-badge" data-score="{{ score }}">
<span class="score-value">{{ score }}</span>
<span class="score-label">/100</span>
</div>
</div>
<div class="review-meta">
<span>📝 Commit: {{ commitId }}</span>
<span>👤 Author: {{ author }}</span>
<span>📅 Date: {{ createdAt }}</span>
</div>
<div class="review-report markdown-body">
<!-- AI 生成的 Markdown 报告 -->
</div>
</div>
使用 marked.js 将 Markdown 转为 HTML,使用 highlight.js 高亮代码块。
🎨 用户体验优化
1. 评分可视化
根据分数显示不同颜色:
.score-badge[data-score] {
/* 90-100: 绿色(优秀) */
/* 70-89: 蓝色(良好) */
/* 50-69: 橙色(一般) */
/* 0-49: 红色(较差) */
}
通过颜色直观反映代码质量。
2. 实时加载状态
async function loadReview(reviewId) {
showLoading();
try {
const response = await fetch(`/api/results/${reviewId}`);
const data = await response.json();
if (data.data.status === "pending") {
// 如果还在处理中,3秒后重试
setTimeout(() => loadReview(reviewId), 3000);
} else {
renderReview(data.data);
}
} finally {
hideLoading();
}
}
轮询检查审查状态,提供流畅的用户体验。
3. 响应式设计
@media (max-width: 768px) {
.review-card {
padding: 1rem;
}
.review-header {
flex-direction: column;
}
.score-badge {
margin-top: 1rem;
}
}
完美支持移动端访问。
🚀 部署与运维
PM2 进程管理
使用 PM2 实现生产环境的稳定运行:
// ecosystem.config.js
module.exports = {
apps: [
{
name: "ai-code-review",
script: "src/server.js",
instances: 2, // 集群模式,2个实例
exec_mode: "cluster",
env: {
NODE_ENV: "production",
PORT: 3000,
},
error_file: "./logs/error.log",
out_file: "./logs/out.log",
log_date_format: "YYYY-MM-DD HH:mm:ss",
max_memory_restart: "500M", // 内存超过 500M 自动重启
autorestart: true,
watch: false,
},
],
};
优势:
- 自动重启:进程崩溃后自动恢复
- 集群模式:充分利用多核 CPU
- 日志管理:统一的日志收集
- 资源限制:防止内存泄漏
Docker 容器化
FROM node:18-alpine
WORKDIR /app
# 安装依赖
COPY package*.json ./
RUN npm ci --only=production
# 复制源码
COPY . .
EXPOSE 3000
CMD ["node", "src/server.js"]
配合 Docker Compose:
version: "3.8"
services:
app:
build: .
ports:
- "3000:3000"
environment:
- MONGO_URI=mongodb://mongo:27017/ai_code_review
depends_on:
- mongo
mongo:
image: mongo:latest
volumes:
- mongo-data:/data/db
volumes:
mongo-data:
一键启动整个系统:docker-compose up -d
Nginx 反向代理
server {
listen 80;
server_name your-domain.com;
location / {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
# 设置超时时间(AI 审查可能需要较长时间)
proxy_connect_timeout 300;
proxy_send_timeout 300;
proxy_read_timeout 300;
}
}
📊 实际使用效果
让我们看看实际的审查报告示例:
审查案例 1:添加参数验证
代码变更:
function calculate(a, b) {
- return a + b;
+ if (typeof a !== 'number' || typeof b !== 'number') {
+ throw new Error('参数必须是数字');
+ }
+ return a + b;
}
AI 评分:85/100
审查要点:
- ✅ 亮点:添加了类型检查,提高了代码健壮性
- ⚠️ 建议:
- 考虑处理
NaN和Infinity等特殊情况 - 建议添加单元测试
- 可以考虑使用 TypeScript 进行类型检查
- 考虑处理
审查案例 2:SQL 注入风险
代码变更:
async function getUser(username) {
- const query = `SELECT * FROM users WHERE name = '${username}'`;
+ const query = 'SELECT * FROM users WHERE name = ?';
+ return db.query(query, [username]);
}
AI 评分:95/100
审查要点:
- ✅ 亮点:修复了 SQL 注入漏洞,使用参数化查询
- ✅ 安全性:大幅提升,从严重风险降为安全
- 💡 其他建议:考虑添加输入验证和日志记录
💡 经验总结
成功经验
-
Prompt 工程很重要
- 花时间优化 system prompt,明确告诉 AI 要做什么
- 要求结构化输出,便于后续处理
- 提供具体的评分标准和范例
-
异步处理是关键
- AI 审查需要时间,不能阻塞主流程
- 使用状态机模式管理审查状态
- 提供进度反馈,提升用户体验
-
数据持久化很必要
- 保存所有审查历史,便于追溯
- 可以分析审查数据,优化 AI prompt
- 支持多项目管理和对比分析
遇到的挑战
-
大文件 Diff 处理
- 问题:巨大的 diff 可能超过 AI 的 token 限制
- 解决:对大 diff 进行分段处理,或只审查关键文件
-
审查质量的一致性
- 问题:AI 审查结果可能不够稳定
- 解决:降低 temperature,优化 prompt,收集反馈持续改进
-
成本控制
- 问题:频繁调用 AI API 会产生费用
- 解决:
- 只审查重要分支的提交
- 设置文件大小限制
- 使用缓存避免重复审查
🔮 未来展望
这个项目还有很多可以改进的地方:
短期计划
-
支持更多代码托管平台
- GitHub、GitLab 集成
- 支持私有部署的 GitLab
-
增强 AI 能力
- 支持多模型切换(GPT-4、Claude 等)
- 实现 AI 审查的人工反馈循环
-
优化报告展示
- 添加代码高亮对比视图
- 支持导出 PDF 报告
长期愿景
-
智能学习
- 基于历史审查数据训练定制模型
- 学习团队的代码风格和偏好
-
集成开发环境
- 提供 VS Code 插件
- 支持本地实时审查
-
团队协作
- 多人审查协作
- 审查意见讨论区
- 代码质量趋势分析
🎓 总结
通过这个项目,我深刻体会到:
-
AI 不是要取代人类审查者,而是作为一个得力助手,处理常规性、重复性的审查工作,让人类审查者可以专注于更复杂的架构和业务逻辑问题。
-
技术选型要务实,不必追求最新最热的技术栈,选择成熟稳定、适合场景的技术才是最重要的。
-
用户体验至关重要,即使是内部工具,也要注重交互设计和使用体验,这样才能真正提高开发效率。
-
持续迭代改进,第一版不需要完美,先上线使用,在实际使用中发现问题并改进。
📚 参考资源
- 项目地址:GitHub Repository
- DeepSeek API:platform.deepseek.com/
- Express 文档:expressjs.com/
- MongoDB 文档:docs.mongodb.com/
- PM2 文档:pm2.keymetrics.io/
如果你对这个项目感兴趣,欢迎:
- ⭐ 给项目点个 Star
- 🐛 提交 Issue 反馈问题
- 🔧 提交 Pull Request 参与开发
- 💬 在评论区分享你的想法
让我们一起用 AI 的力量提升代码质量! 🚀