使用 Spring AI Alibaba构建 AI Code Review 应用

很早的时候就想着用AI来做Code Review,最近也看到了一些不错的实现,但是没有一个使用Java来构建的,看的比较费劲,虽然说语言只是一种工具,但是还是想用Java重新写一遍,正好最近Spring AI Alibaba出了正式版,就拿来用了。 简单的效果图 ​​​在这里插入图片描述

1. 架构概览

本应用采用事件驱动架构,其核心工作流程如下:

  1. GitHub Webhook 触发:开发者在 GitHub 仓库中创建或更新一个 Pull Request (PR) 时,会触发一个预先配置好的 Webhook。

  2. 事件接收与处理:后端的 Spring Boot 应用通过 GitHubWebhookController 接收该事件。

  3. 任务分发GithubWebhookServiceImpl 解析 Webhook 负载,提取 PR 相关信息,并异步触发 CodeReviewServiceImpl 执行代码评审任务。

  4. 获取代码变更CodeReviewServiceImpl 调用 GitHubAdapter,通过 GitHub API 获取该 PR 的代码变更详情(diff)。

  5. 调用大模型分析LlmAdapter 负责构建发送给大模型的 Prompt。该 Prompt 包含代码变更、预设的评审规则以及可选的 RAG(检索增强生成)知识。随后,它通过 Spring AI 的 ChatClient 将请求发送给阿里巴巴通义千问模型。

  6. 处理与发布结果:应用接收 LLM 返回的评审建议,将其格式化后,通过 GitHubAdapter 调用 GitHub API,将评审评论发布到对应的 PR 下。

2. 依赖配置 (pom.xml)

<!-- Spring AI 核心与阿里巴巴通义千问集成 -->
        <dependency>
            <groupId>com.alibaba.cloud.ai</groupId>
            <artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
        </dependency>
​
<!-- GitHub API Java 客户端 -->
<dependency>
    <groupId>org.kohsuke</groupId>
    <artifactId>github-api</artifactId>
    <version>1.321</version>
</dependency>
  • spring-ai-alibaba-tongyi-spring-boot-starter:这是 Spring AI 对接阿里巴巴通义千问模型的关键,它提供了自动配置和 ChatClient 实现。

  • github-api:一个便捷的 Java 库,用于与 GitHub REST API 进行交互。

3. 应用配置 (application.yml)

所有外部服务的凭证和行为都在 application.yml 中定义。

server:
  port: 8080
​
spring:
  # Spring AI 配置
  ai:
    dashscope:
      api-key: ${DASHSCOPE_API_KEY}
​
# GitHub App 相关配置
github:
  # App ID
  app-id: ${GITHUB_APP_ID}
  # App 安装后的 Installation ID
  installation-id: ${GITHUB_INSTALLATION_ID}
  # App 生成的私钥(Base64 编码)
  private-key: ${GITHUB_PRIVATE_KEY}
  # Webhook 使用的密钥
  webhook-secret: ${GITHUB_WEBHOOK_SECRET}
  • spring.ai.alibaba.tongyi.*:此路径下的所有配置都用于设置通义千问模型。你需要提供一个有效的 API Key,并可以选择合适的模型。

  • github.*:此处配置了 GitHub App 的认证信息。使用 GitHub App 而非个人访问令牌(PAT)是最佳实践,因为它提供了更细粒度的权限控制。

4. 核心代码实现

4.1. GitHub Webhook 接入

GitHubWebhookController 是应用的入口点。它负责验证和接收来自 GitHub 的 HTTP POST 请求。

// GitHubWebhookController.java
@RestController
@RequestMapping("/api/github")
public class GitHubWebhookController {
    // ...
    @PostMapping("/webhook")
    public ResponseEntity<String> handleWebhook(
            @RequestHeader("X-Hub-Signature-256") String signature,
            @RequestBody String payload) {
        // 1. 验证签名
        // 2. 调用 IGithubWebhookService 处理业务逻辑
        githubWebhookService.processPullRequestEvent(payload);
        return ResponseEntity.ok("Event received");
    }
}

4.2. Code Review 核心服务

CodeReviewServiceImpl 是业务逻辑的核心。它编排了整个代码评审的流程。

// CodeReviewServiceImpl.java
@Service
public class CodeReviewServiceImpl implements ICodeReviewService {
    // ...
    @Override
    public ReviewResultDTO reviewCode(ReviewTaskDTO reviewTask) {
        // 1. 获取代码 diff
        String diff = githubAdapter.getPullRequestDiff(
            reviewTask.getOwner(), reviewTask.getRepo(), reviewTask.getPullRequestNumber());
​
        // 2. 准备 Prompt
        String userMessage = "请评审以下代码变更:\n" + diff;
​
        // 3. 调用 LLM
        String reviewContent = llmAdapter.generateReview(userMessage);
​
        // 4. 解析 LLM 响应并构建 ReviewResultDTO
        // ...
        
        return reviewResult;
    }
}

4.3. 与大模型交互

LlmAdapter 封装了与 Spring AI 和通义千问模型的所有交互细节。

// LlmAdapter.java
@Component
public class LlmAdapter {
​
    private final ChatClient chatClient;
​
    @Autowired
    public LlmAdapter(ChatClient chatClient) {
        this.chatClient = chatClient;
    }
​
    public String generateReview(String codeDiff) {
        // 系统消息,用于设定 AI 的角色和任务
        String systemMessage = "你是一个资深软件工程师,擅长代码评审..."
        // 用户消息,包含具体的代码变更
        String userMessage = "请评审以下代码变更,并以JSON格式返回你的发现...\n\n" + codeDiff;
​
        Prompt prompt = new Prompt(List.of(
            new SystemMessage(systemMessage),
            new UserMessage(userMessage)
        ));
​
        ChatResponse response = chatClient.call(prompt);
        return response.getResult().getOutput().getContent();
    }
}

这里使用了 SystemMessage 来为 AI 设定角色和输出要求,这有助于获得更稳定和结构化的输出。

4.4. 发布评审结果

CodeReviewServiceImpl 获得格式化的评审结果后,会调用 ResultPublishServiceImpl,后者再通过 GitHubAdapter 将评论发布回 GitHub。

// GitHubAdapter.java
public void postReviewComment(String owner, String repo, int prNumber, String commentBody, String commitId, String path, int lineNumber) {
    try {
        GHRepository repository = getGithubClient().getRepository(owner + "/" + repo);
        GHPullRequest pullRequest = repository.getPullRequest(prNumber);
        pullRequest.createReviewComment(commentBody, commitId, path, lineNumber);
    } catch (IOException e) {
        throw new RuntimeException("Failed to post review comment to GitHub", e);
    }
}

5. (暂时简单实现) 结合 RAG 提升评审质量

RAGService 为项目引入了检索增强生成(RAG)的能力。通过将内部的编码规范、最佳实践或常见错误模式文档化并存储在向量数据库(如 Elasticsearch)中,我们可以在生成 Prompt 前,先检索与代码变更最相关的信息。

将这些检索到的信息一并提供给 LLM,可以显著提升评审的准确性和深度,使其更贴合团队的特定规范。

评论: