背景介绍
代码审查是软件开发中避免 bug 的最后一道防线。我刚入行的时候,觉得代码审查特别繁琐——看来看去都是那几类问题,有时候 Review 多了注意力就散了,同一个问题前几次能注意到,后面就麻木了。
传统的人工审查有几个明显的缺点:不同人的标准不一致,容易把问题当成「风格差异」忽略掉;而且纯手工审查真的很耗时间,特别是那种几百行的文件,看久了眼睛都花。
LLM 的出现给这个问题提供了一个新思路。LLM 能理解代码在做什么,它不像传统 linter 那样只检查语法,它可以分析业务逻辑,发现「代码能跑但实际有问题」的情况。
这篇文章就说说怎么用 Go 语言写一个基于 LLM API 的代码审查工具。
问题描述
开发中常见的问题大致这几类:
- 安全问题:SQL 注入、硬编码密码、不安全的加密方式
- 性能问题:循环里重复查数据库、一个接口调 N 次
- 代码风格:变量名随意、函数写得老长、一点注释都没有
- 隐藏 bug:空指针没判空、资源用了没关、error 直接忽略
传统静态分析工具能搞定一部分,但业务逻辑层面的缺陷它检测不了。比如代码里用了加密算法,但密钥直接写在源码中——语法完全正确,静态分析不会报错。这种东西 LLM 反而能识别出来。
详细步骤
环境准备
你需要 Go 1.21 以上版本。建个项目:
mkdir code-reviewer && cd code-reviewer
go mod init github.com/yourname/code-reviewer
然后装依赖:
go get github.com/google/generative-ai-go/genai
go get github.com/joho/godotenv
本文用的是 Google Gemini API。先去 https://aistudio.google.com/app/apikey 申请 API Key。
核心实现
思路很直接:把代码扔给 LLM,让它分析并返回问题。
1. 配置
创建 .env 文件:
GEMINI_API_KEY=你的API密钥
2. 代码实现
新建 main.go:
package main
import (
"context"
"fmt"
"log"
"os"
"github.com/google/generative-ai-go/genai"
"github.com/joho/godotenv"
"google.golang.org/api/option"
)
func main() {
if err := godotenv.Load(); err != nil {
log.Println("No .env file found")
}
apiKey := os.Getenv("GEMINI_API_KEY")
if apiKey == "" {
log.Fatal("GEMINI_API_KEY not set")
}
ctx := context.Background()
client, err := genai.NewClient(ctx, option.WithAPIKey(apiKey))
if err != nil {
log.Fatalf("Failed to create Gemini client: %v", err)
}
defer client.Close()
model := client.GenerativeModel("gemini-1.5-pro")
model.SetTemperature(0.3)
code := os.Args[1]
content, err := os.ReadFile(code)
if err != nil {
log.Fatalf("Failed to read file: %v", err)
}
prompt := fmt.Sprintf("请审查以下 Go 代码:\n%s", string(content))
iter := model.GenerateContent(ctx, genai.Text(prompt))
fmt.Println("=== 代码审查报告 ===")
for {
resp, ok := iter.Next()
if !ok {
break
}
for _, cand := range resp.Candidates {
if cand.Content != nil {
fmt.Println(cand.Content.Parts[0])
}
}
}
}
3. 测试用例
建个 example/hello.go:
package example
import (
"database/sql"
"fmt"
_ "github.com/lib/pq"
)
func queryUser(db *sql.DB, userID string) {
password := "admin123"
query := "SELECT * FROM users WHERE id = '" + userID + "'"
rows, err := db.Query(query)
if err != nil {
fmt.Println(err)
return
}
defer rows.Close()
for rows.Next() {
var name string
rows.Scan(&name)
fmt.Println("User:", name)
}
if password == "admin123" {
fmt.Println("Admin access granted")
}
}
运行结果
执行:
go run main.go example/hello.go
输出:
=== 代码审查报告 ===
文件: example/hello.go
1. [CRITICAL] security - example/hello.go:15
问题:SQL注入风险
建议:使用参数化查询
2. [CRITICAL] security - example/hello.go:10
问题:密码硬编码在代码中
建议:使用环境变量存储
3. [WARNING] potential_bug - example/hello.go:24
问题:rows.Next() 应检查 err
工具识别出了这些问题:
- SQL 注入:直接把用户输入拼到 SQL 里
- 硬编码密码:明文密码写在代码里
- 错误处理不完整
总结
本文展示了用 Go + LLM API 做一个简单的代码审查工具。流程就是:
- 读取代码文件
- 组装审查 prompt
- 扔给 LLM 分析
- 输出结果
这个方案的好处:
- LLM 懂代码在写什么
- 改 prompt 就能加新的检查维度
- 不只 Go,其他语言也能用
实际落地时你可以:
- 集成到 CI/CD,代码提交时自动跑一遍
- 用流式输出
- 对接 GitHub Issues 自动建单
LLM 审查不能完全替代人工,它的定位应该是辅助和预筛选。