AI+CICD: 使用本地大模型进行代码审核
需求来源
疫情后对产品研发工作的最大影响,是随着经济下行,公司在不停地裁员,导致研发团队人力资源严重不足。 事情多得做不完,过去还在定期组织的质量控制手段–code review,现在也忙得没有时间组织了。
早就听说*-coder系列开源大模型在编码方便挺强悍,于是决定尝试使用本地大模型加入到CICD流程中,在团队提交代码的时候,由AI进行code review工作。
计划
我们的源代码管理环境使用gitea,只要配置workflow工作流就可以了。在工作流中把diff信息交给本地编程大模型进行评估,并把结果输出,根据结果决定后续行为。
所以,我们需要:
- 一个workflow配置文件
- 一个程序负责提取diff并调用到模型并反馈结果
- 一个本地大模型服务
我们倒序进行实现。
本地编程大模型服务
参考《LLM:使用Ollama访问本地大模型》,我们使用Ollama搭建本地编程大模型服务。
curl -fsSL https://ollama.com/install.sh | sh
ollama serve
编程大模型这里选择口碑极好的qwen3-coder:30b
ollama pull qwen3-coder:30b
代码检测程序
使用Python调用ollama非常容易,但是考虑到gitea的runner是一个docker环境,在同一的镜像中,运行Python和相关的库需要从网络拉取依赖包会导致一些麻烦。所以这里使用go静态编译,直接生成一个bin文件放在本地文件服务器上,runner直接拉取一个bin就可以工作,不需要任何依赖环境,流程更简洁速度也更快。
定义本地ollama地址和模型
var (
ollamaURL = getEnv("OLLAMA_ENDPOINT", "http://ai.internal:11434")
model = "qwen3-coder:30b"
)
获取diff信息:
func getGitDiff() (string, error) {
cmd := exec.Command("git", "diff", "HEAD^", "HEAD")
output, err := cmd.Output()
if err != nil {
return "", fmt.Errorf("获取 git diff 失败: %w", err)
}
return string(output), nil
}
最后传递这样一个提示词
你是一个代码质量审查专家。请分析以下 Git Diff 代码变更,并严格按 JSON 格式返回结果。
JSON 格式要求:
{{
"score": (0-100的整数,代表代码质量和安全性),
"summary": "简短的总结",
"risks": ["风险点1", "风险点2"],
"suggestions": ["改进建议1"]
}}
代码变更内容:
{diff_text}
静态编译后,放置在本地文件服务器上
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o ai-codereview ai-codereview.go
rsync -vhP ai-codereview user@fileserver:/gitea/action/
在工作流中加入AI代码审查
现在万事俱备,只欠东风。先找一个不那么重要的项目进行实验,比如testcase项目,
首先在gitea的设置的action中,添加变量 OLLAMA_ENDPOINT=http://ai.internal:11434
然后创建工作流
# 创建工作流
mkdir -p .gitea/workflows
touch ai-codereview.yaml
在jobs中添加流程:
- name: AI Code Review
env:
OLLAMA_ENDPOINT: ${{ secrets.OLLAMA_ENDPOINT }}
run: |
curl -sSL http://10.0.1.1/gitea/action/ai-codereview -o /tmp/ai-codereview
chmod +x /tmp/ai-codereview
/tmp/ai-codereview 2>&1 | tee ai_report.log
提交代码,这个项目就已经具有AI智能代码审核功能了。
本次提交的AI评审报告:
---AI评审报告---
得分:75
总结:代码变更引入了新的AI审核机制,通过调用ollama模型进行代码质里分析。整体结构清晰,但存在安全和可维护性风险。
风险:使用硬编码的默认 ollama 地址可能导致配置错误或安全漏洞,从外部 URL 下载可执行文件(/tmp/ai-codereview)存在执行未验证代码的风险,未对AI返回结果做充分校验,可能影响审核逻辑的准确性
[结果] ✅ 代码质量合格。
验证
创建TUI的helloword代码,提交
--- AI 评审报告 ---
得分: 65
总结: 代码功能变更但存在安全隐患和可读性问题
风险: 使用了非ASCII字符和特殊符号,可能导致终端显示异常或编码问题, 代码可读性差,难以维护和理解原始功能意图
[结果] ✅ 代码质量合格。
给项目增加个README
--- AI 评审报告 ---
得分: 100
总结: 本次变更主要涉及工作流名称的修改和README文件的更新,均为非核心代码变更,无安全风险。
风险:
[结果] ✅ 代码质量合格。

下面编写一个存在CVE漏洞的代码并提交,得到:
--- AI 评审报告 ---
得分: 35
总结: 代码存在严重安全漏洞,包括路径遍历攻击和不安全的文件操作
风险: 路径遍历攻击漏洞:直接使用用户输入的文件名拼接路径,可访问任意文件, 使用已废弃的ioutil.ReadFile函数:应使用os.ReadFile替代, 缺少输入验证和过滤:未对用户输入进行任何安全检查
[结果] ❌ 代码质量未达标,拒绝合并!
实际效果达到预期
高危代码阻断工作流
上述实验中使用的方法是通过Push 触发的 Action,代码是进入仓库后才执行的审核,无法实现高危代码拦截。 可以通过gitea的Pull Request工作流(简称PR)来实现合并代码前拦截,思路如下。
- 禁止直接 push 到 main 分支
- 强制通过 PR 合并代码
- PR 触发 AI 审核,审核通过才合并到main
在gitea的设置/分支中,做如下设置:
- main分支禁止直接 push
开发流程稍作调整,本地在分支上开发,提交后创建PR,并由AI进行审核,审核通过后才可以合并到main
改进后的流程如下:
开发者 → feature分支 → 创建PR到main → 触发AI审核 → 通过才能合并
↓
失败则阻止合并
这样就可以防止高危代码进入main分支了。
结论
一些toB的AI商业产品也在做类似的事情,其实自己做一个实现也并不复杂。
实验证明,本地离线大模型确实可以识别风险代码,并对代码问题提出有价值的改进建议,使用4090显卡的话,30b大模型可以秒级完成代码审核(测试代码改动幅度小于一屏的条件下),完全值得你把它放到CICD流程中来。