夜雨聆风学习资料网

ARTICLE · 1035336

AI Agent 工程化实战(十):实战——代码审查 Agent 完整项目

AI Agent 工程化实战(十):实战——代码审查 Agent 完整项目

大家好,我是老 J。

上期我们完成了企业客服 Agent,这期来做第二个实战项目:代码审查 Agent

这个项目解决的问题很实际:每次提交代码,人工审查耗时耗力,能不能让 AI 先审一遍?

答案是能。而且我们上期讲的多 Agent 协作、工具系统、可观测性,在这个项目里全部用上。

一、需求分析

1.1 业务场景

一个研发团队,每天有几十个 PR 需要审查。人工审查的问题:

问题
影响
审查时间长
PR 平均等待 4 小时
审查标准不统一
不同人关注点不同
低级问题重复出现
命名不规范、缺少注释
安全漏洞遗漏
SQL 注入、敏感信息

1.2 核心需求

  • • 多维度审查:安全、质量、性能三个维度
  • • 自动化触发:PR 提交时自动审查
  • • 结构化输出:结果按严重程度排序
  • • 可集成:接入 CI/CD 流程

二、架构设计

┌─────────────────────────────────────────────────────────────────┐
│                   代码审查 Agent 架构                            │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│   Git Push ──► CI/CD 触发 ──► 代码审查服务                       │
│                                    │                             │
│                    ┌───────────────┼───────────────┐             │
│                    │               │               │             │
│                    ▼               ▼               ▼             │
│              ┌───────────┐  ┌───────────┐  ┌───────────┐        │
│              │ 安全审查   │  │ 质量审查   │  │ 性能审查   │        │
│              │ Agent     │  │ Agent     │  │ Agent     │        │
│              └─────┬─────┘  └─────┬─────┘  └─────┬─────┘        │
│                    │               │               │             │
│                    └───────────────┼───────────────┘             │
│                                    ▼                             │
│                           ┌─────────────┐                        │
│                           │ 汇总报告     │                        │
│                           │ (Markdown)  │                        │
│                           └─────────────┘                        │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

三、项目结构

code-review-agent/
├── pom.xml
├── src/main/java/com/example/review/
│   ├── CodeReviewApplication.java
│   ├── config/
│   │   └── ReviewAgentConfig.java
│   ├── controller/
│   │   └── ReviewController.java
│   ├── service/
│   │   ├── CodeReviewService.java
│   │   ├── ReviewAggregator.java
│   │   └── GitService.java
│   ├── agent/
│   │   ├── SecurityReviewAgent.java
│   │   ├── QualityReviewAgent.java
│   │   └── PerformanceReviewAgent.java
│   └── model/
│       ├── ReviewRequest.java
│       ├── ReviewResult.java
│       └── ReviewReport.java
└── src/main/resources/
    └── application.yml

四、核心代码实现

4.1 Maven 依赖

<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit</artifactId>
<version>6.7.0.202309050840-r</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>

4.2 三个审查 Agent

@Component
publicclassSecurityReviewAgent {

privatefinal ChatClient chatClient;

publicSecurityReviewAgent(ChatClient.Builder builder) {
this.chatClient = builder
            .defaultSystem("""
                你是安全审查专家,负责检查代码中的安全漏洞。

                重点关注:
                1. SQL 注入(拼接 SQL、未使用参数化查询)
                2. XSS 攻击(未转义的输出)
                3. 敏感信息硬编码(密码、密钥、token)
                4. 权限校验缺失
                5. 不安全的反序列化
                6. 路径遍历
                7. SSRF 攻击

                输出格式(JSON):
                {
                  "risks": [
                    {"level": "高/中/低", "line": 行号, "issue": "问题描述", "suggestion": "修复建议"}
                  ],
                  "summary": "总体评价"
                }
                """
)
            .build();
    }

public String review(String code) {
return chatClient.prompt("审查以下代码:\n```\n" + code + "\n```")
            .call().content();
    }
}
@Component
publicclassQualityReviewAgent {

privatefinal ChatClient chatClient;

publicQualityReviewAgent(ChatClient.Builder builder) {
this.chatClient = builder
            .defaultSystem("""
                你是代码质量审查专家。

                重点关注:
                1. 命名规范(是否清晰、有意义)
                2. 方法长度(超过 50 行需拆分)
                3. 嵌套深度(超过 3 层需重构)
                4. 重复代码
                5. 注释完整性
                6. 异常处理
                7. 魔法数字

                输出格式(JSON):
                {
                  "issues": [
                    {"level": "高/中/低", "line": 行号, "issue": "问题描述", "suggestion": "改进建议"}
                  ],
                  "summary": "总体评价"
                }
                """
)
            .build();
    }

public String review(String code) {
return chatClient.prompt("审查以下代码:\n```\n" + code + "\n```")
            .call().content();
    }
}
@Component
publicclassPerformanceReviewAgent {

privatefinal ChatClient chatClient;

publicPerformanceReviewAgent(ChatClient.Builder builder) {
this.chatClient = builder
            .defaultSystem("""
                你是性能审查专家。

                重点关注:
                1. N+1 查询(循环中查数据库)
                2. 不必要的对象创建
                3. 资源未释放(连接、流)
                4. 算法复杂度
                5. 缓存使用不当
                6. 大循环中的耗时操作

                输出格式(JSON):
                {
                  "issues": [
                    {"level": "高/中/低", "line": 行号, "issue": "问题描述", "suggestion": "优化建议"}
                  ],
                  "summary": "总体评价"
                }
                """
)
            .build();
    }

public String review(String code) {
return chatClient.prompt("审查以下代码:\n```\n" + code + "\n```")
            .call().content();
    }
}

4.3 审查服务(并行执行)

@Service
publicclassCodeReviewService {

privatefinal SecurityReviewAgent securityAgent;
privatefinal QualityReviewAgent qualityAgent;
privatefinal PerformanceReviewAgent performanceAgent;

publicCodeReviewService(SecurityReviewAgent securityAgent,
                             QualityReviewAgent qualityAgent,
                             PerformanceReviewAgent performanceAgent)
 {
this.securityAgent = securityAgent;
this.qualityAgent = qualityAgent;
this.performanceAgent = performanceAgent;
    }

public ReviewReport review(String code) {
// 并行执行三个维度的审查
        CompletableFuture<String> securityFuture =
            CompletableFuture.supplyAsync(() -> securityAgent.review(code));
        CompletableFuture<String> qualityFuture =
            CompletableFuture.supplyAsync(() -> qualityAgent.review(code));
        CompletableFuture<String> performanceFuture =
            CompletableFuture.supplyAsync(() -> performanceAgent.review(code));

// 等待全部完成
        CompletableFuture.allOf(securityFuture, qualityFuture, performanceFuture).join();

// 汇总
ReviewReportreport=newReviewReport();
try {
            report.setSecurityReview(securityFuture.get());
            report.setQualityReview(qualityFuture.get());
            report.setPerformanceReview(performanceFuture.get());
        } catch (Exception e) {
thrownewRuntimeException("审查失败", e);
        }

return report;
    }
}

4.4 报告聚合器

@Service
publicclassReviewAggregator {

public String aggregate(ReviewReport report) {
StringBuildersb=newStringBuilder();
        sb.append("# 代码审查报告\n\n");
        sb.append("生成时间:").append(LocalDateTime.now()).append("\n\n");

        sb.append("## 🔒 安全审查\n\n");
        sb.append(report.getSecurityReview()).append("\n\n");

        sb.append("## 📐 质量审查\n\n");
        sb.append(report.getQualityReview()).append("\n\n");

        sb.append("## ⚡ 性能审查\n\n");
        sb.append(report.getPerformanceReview()).append("\n\n");

        sb.append("---\n");
        sb.append("*本报告由 AI 代码审查 Agent 生成,仅供参考。*\n");

return sb.toString();
    }

public ReviewSummary summarize(ReviewReport report) {
// 统计各维度问题数量
intsecurityIssues= countIssues(report.getSecurityReview());
intqualityIssues= countIssues(report.getQualityReview());
intperformanceIssues= countIssues(report.getPerformanceReview());

return ReviewSummary.builder()
            .totalIssues(securityIssues + qualityIssues + performanceIssues)
            .securityIssues(securityIssues)
            .qualityIssues(qualityIssues)
            .performanceIssues(performanceIssues)
            .build();
    }

privateintcountIssues(String reviewJson) {
// 解析 JSON,统计 issues 数组长度
try {
ObjectMappermapper=newObjectMapper();
JsonNodenode= mapper.readTree(reviewJson);
JsonNodeissues= node.get("issues");
return issues != null ? issues.size() : 0;
        } catch (Exception e) {
return0;
        }
    }
}

4.5 控制器

@RestController
@RequestMapping("/api/review")
publicclassReviewController {

privatefinal CodeReviewService reviewService;
privatefinal ReviewAggregator aggregator;

publicReviewController(CodeReviewService reviewService,
                            ReviewAggregator aggregator)
 {
this.reviewService = reviewService;
this.aggregator = aggregator;
    }

@PostMapping("/code")
public Map<String, Object> reviewCode(@RequestBody ReviewRequest request) {
longstart= System.currentTimeMillis();

ReviewReportreport= reviewService.review(request.getCode());
Stringmarkdown= aggregator.aggregate(report);
ReviewSummarysummary= aggregator.summarize(report);

longduration= System.currentTimeMillis() - start;

return Map.of(
"summary", summary,
"report", markdown,
"duration_ms", duration
        );
    }

@PostMapping("/file")
public Map<String, Object> reviewFile(@RequestBody ReviewRequest request) {
try {
Stringcode= Files.readString(Paths.get(request.getFilePath()));
            request.setCode(code);
return reviewCode(request);
        } catch (Exception e) {
return Map.of("error""读取文件失败: " + e.getMessage());
        }
    }
}

4.6 请求/响应模型

@Data
publicclassReviewRequest {
private String code;
private String filePath;
privateStringlanguage="java";
}

@Data
@Builder
publicclassReviewSummary {
privateint totalIssues;
privateint securityIssues;
privateint qualityIssues;
privateint performanceIssues;
}

@Data
publicclassReviewReport {
private String securityReview;
private String qualityReview;
private String performanceReview;
}

五、集成 CI/CD

5.1 GitHub Actions 配置

name:AICodeReview

on:
pull_request:
branches: [main]

jobs:
review:
runs-on:ubuntu-latest
steps:
-uses:actions/checkout@v4
with:
fetch-depth:0

-name:Getchangedfiles
id:changed
run:|
          git diff --name-only origin/main...HEAD > changed_files.txt
          echo "files=$(cat changed_files.txt | tr '\n' ' ')" >> $GITHUB_OUTPUT

-name:RunAIReview
run:|
          curl -X POST ${{ secrets.REVIEW_SERVICE_URL }}/api/review/code \
            -H "Content-Type: application/json" \
            -d "{\"code\": \"$(cat changed_files.txt)\"}"

5.2 输出到 PR 评论

// 在控制器中添加 GitHub PR 评论
@PostMapping("/pr")
public Map<String, Object> reviewPR(@RequestBody Map<String, String> request) {
StringprUrl= request.get("prUrl");
Stringcode= request.get("code");

ReviewReportreport= reviewService.review(code);
Stringmarkdown= aggregator.aggregate(report);

// 通过 GitHub API 提交评论
// ... 具体实现参考 GitHub API 文档

return Map.of("status""reviewed""report", markdown);
}

六、测试验证

6.1 测试脚本

#!/bin/bash
BASE_URL="http://localhost:8080"

echo"1️⃣ 审查代码"
curl -s -X POST $BASE_URL/api/review/code \
  -H "Content-Type: application/json" \
  -d '{
    "code": "public void transfer(String from, String to, int amount) {\n    String sql = \"UPDATE account SET balance = balance - \" + amount + \" WHERE id = \" + from;\n    jdbcTemplate.execute(sql);\n}"
  }'
 | jq '.summary'

6.2 预期输出

{
"summary":{
"totalIssues":5,
"securityIssues":3,
"qualityIssues":1,
"performanceIssues":1
},
"report":"# 代码审查报告\n\n## 🔒 安全审查\n\n风险:SQL 注入...",
"duration_ms":3500
}

七、系列总结

十期 AI Agent 工程化实战到此全部完结:

期数
主题
核心内容
为什么 Agent 不再是"调参"
2026 趋势 + 系列规划
Agent 核心组件
Harness 架构 + ReAct 循环
第一个 Java Agent
Spring AI + Tool Calling
记忆系统
短期 + 长期 + 向量数据库
工具系统
多工具协同 + MCP 协议
多 Agent 协作
主从架构 + 任务分解
可观测性
追踪 + 评估 + 调试
生产级架构
高可用 + 异步 + 缓存 + 成本
企业客服 Agent
完整项目实战
代码审查 Agent
完整项目实战

我是老 J,Agent 工程化系列十期完结,下个系列见。

相关学习资料