资讯动态

基于LLM Agent与Git的本地CLI代码审查工具实战

发布时间:2026/9/20 13:13:42 来源:尧图企业网站定制
1. 为什么我要自己动手做一个 open-code-review 工具代码审查这件事做过团队协作的人都有体会。理想状态下每次提交都应该有人认真看一遍指出潜在问题、风格偏差、逻辑漏洞。但现实往往是提交量一大审查就变成了走过场点个Approve了事。尤其是当团队里只有一两个熟悉全局的人时审查队列能排到第二天。我最初的想法很简单能不能让机器先过一遍把那些明显的问题筛出来人只需要看机器标记出来的部分市面上确实有一些商业化的代码审查服务但要么按人头收费要么需要把代码推到第三方平台对于内部项目来说不太现实。于是我开始琢磨自己搭一套。open-code-review这个项目就是在这个背景下诞生的。它的核心思路是利用LLM Agent的能力结合Git的 diff 信息通过一个CLI工具在本地完成代码审查。你不需要把代码上传到任何地方所有分析都在本地进行Agent 读取 diff、理解上下文、给出审查意见最后输出一份结构化的报告。这套东西适合谁用我认为有三类人比较合适一是小团队里负责代码质量的那个人想在不增加太多负担的前提下提升审查覆盖率二是个人开发者想在自己提交前先让 Agent 帮忙看一眼三是对 LLM Agent 和 CLI 工具感兴趣、想了解怎么把这两者结合起来的技术爱好者。需要说明的是这个项目不是一个全自动替代人类审查的方案。它的定位是辅助把机械性的检查交给机器把需要判断力的部分留给人。这个边界很重要后面我会详细讲。2. 核心概念拆解Agent、LLM、CLI 到底怎么区分在动手之前有必要把几个容易混淆的概念理清楚。我在搜索热词里看到很多人问agent 和 llm 和 ai 模型有什么区别这个问题确实值得先说清楚因为后面整个工具的设计都建立在这些概念之上。2.1 LLM 是引擎Agent 是司机LLMLarge Language Model大语言模型本质上是一个输入文本、输出文本的函数。你给它一段 prompt它给你一段回复。它本身没有记忆、没有工具、没有行动能力。DeepSeek、GPT 系列、Claude 系列这些都属于 LLM。你可以把 LLM 理解成一台发动机——动力很强但光有发动机跑不起来。Agent则是在 LLM 之上加了一层决策循环。它不仅能调用 LLM还能决定下一步该做什么是去读一个文件还是执行一条命令还是直接给出答案。Agent 有工具调用能力、有状态管理、有循环控制。用开车的比喻LLM 是发动机Agent 是司机——司机知道什么时候踩油门、什么时候转弯、什么时候停车。那Embedding又是什么Embedding 是把文本转换成向量的技术主要用于语义搜索和相似度计算。它和 LLM 不是一回事但在 RAG检索增强生成场景里经常配合使用。代码审查这个场景里Embedding 主要用来做代码片段的相似度匹配比如找出历史上类似的修改。2.2 CLI 为什么比 GUI 更适合这个场景CLICommand Line Interface就是命令行工具。很多人觉得 CLI 不如 GUI 直观但在代码审查这个场景里CLI 有几个天然优势可组合CLI 工具可以管道串联git diff | open-code-review这种用法在 GUI 里很难实现可脚本化可以写进 CI/CD 流程也可以做成 Git hook轻量不需要启动一个完整的桌面应用资源占用小跨平台Windows、macOS、Linux 都能跑只要装了 Git我选择 CLI 还有一个很实际的原因代码审查的输入本身就是文本diff输出也是文本审查意见CLI 是最自然的交互方式。GUI 反而会增加不必要的复杂度。2.3 Git 在整个链路里的角色Git在这里不只是版本控制工具它还是变更信息的提供者。git diff命令能精确地告诉你哪些文件改了、改了哪几行、是新增还是删除。这些信息是代码审查的起点。我见过有人想用全量代码分析来做审查就是把整个仓库的代码都丢给 LLM 看一遍。这个思路有两个问题一是 token 消耗巨大二是 LLM 在大量无关代码里容易迷失重点。正确的做法是只分析 diff让 Agent 聚焦在这次改了什么上。这里有个细节值得注意git diff的输出格式对 LLM 并不友好。它包含了很多元信息如diff --git、index、---、这些行直接丢给 LLM 会浪费 token。所以我在工具里加了一层预处理把 diff 解析成结构化的 JSON只保留文件路径、变更类型、具体变更行这些关键信息。3. 环境准备Git 安装与配置的完整流程在开始写代码之前得先把基础环境搭好。这一节我会把 Git 的安装和配置讲透因为后面所有操作都依赖它。3.1 Git 安装Windows、macOS、Linux 三平台Windows 平台的安装方式有几种。最直接的是去 Git 官网下载安装包一路 Next 就行。安装过程中有几个选项需要注意默认编辑器建议选 VS Code 或 Notepad不要用 Vim除非你真的很熟PATH 环境选Git from the command line and also from 3rd-party software这样在 CMD 和 PowerShell 里都能用换行符处理选Checkout Windows-style, commit Unix-style line endings避免跨平台协作时的换行符问题终端模拟器选Use Windows default console window就行MinTTY 有时候会有编码问题如果你习惯用包管理器也可以用winget install Git.Git或者choco install git。我实测下来 winget 最省事一条命令搞定。macOS 平台最简单装个 Xcode Command Line Tools 就自带 Git 了xcode-select --install或者用 Homebrewbrew install gitLinux 平台用包管理器# Debian/Ubuntu sudo apt install git # CentOS/RHEL sudo yum install git # Arch sudo pacman -S git安装完成后验证一下git --version能输出版本号就说明装好了。3.2 Git 基础配置别跳过这一步很多人装完 Git 就直接用结果提交记录里全是默认的用户名和邮箱后期想改都麻烦。装完第一件事就是配置身份git config --global user.name 你的名字 git config --global user.email 你的邮箱如果你用 Gitee 或 GitHub邮箱最好和平台账号一致这样提交记录能正确关联到你的账号。还有几个配置我建议一起做了# 设置默认分支名为 main git config --global init.defaultBranch main # 开启颜色显示 git config --global color.ui auto # 设置默认编辑器 git config --global core.editor code --wait # 处理中文文件名显示问题 git config --global core.quotepath false最后一条core.quotepath false特别重要。默认情况下 Git 会把中文文件名转义成八进制git status里看到一堆\344\275\240这种乱码。关掉之后就能正常显示中文了。3.3 SSH 密钥配置一次配置长期省事如果你要推送到远程仓库SSH 密钥比每次输密码方便得多。生成密钥ssh-keygen -t ed25519 -C 你的邮箱一路回车就行。然后把公钥~/.ssh/id_ed25519.pub的内容复制到 Gitee 或 GitHub 的 SSH 设置里。验证是否配置成功ssh -T gitgitee.com看到欢迎信息就说明通了。注意私钥文件id_ed25519千万不要泄露也不要提交到仓库里。公钥.pub结尾才是给别人看的。4. open-code-review 的架构设计与核心模块环境准备好之后进入正题。这一节我会把整个工具的架构拆开讲包括每个模块的职责、为什么这么设计、以及实现时的关键细节。4.1 整体数据流从 diff 到审查报告整个工具的数据流可以分成五个阶段变更采集调用git diff获取变更内容diff 解析把原始 diff 解析成结构化数据上下文构建根据变更文件路径读取相关文件的完整内容作为上下文Agent 审查把结构化 diff 和上下文一起交给 LLM Agent让它逐文件审查报告生成把 Agent 的输出整理成可读的报告这个流程看起来简单但每个阶段都有坑。比如第二阶段git diff的输出格式在不同 Git 版本、不同配置下会有差异解析逻辑得写得足够健壮。再比如第三阶段读取多少上下文合适读太多会爆 token读太少 Agent 又看不懂。我的做法是对于每个变更文件读取变更行前后各 50 行的内容作为上下文。这个数字是实测出来的——50 行足够让 Agent 理解函数级别的逻辑又不会让 token 消耗失控。如果是配置文件或文档就读取整个文件因为这类文件通常不大。4.2 diff 解析模块把非结构化文本变成结构化数据git diff的原始输出长这样diff --git a/src/main.py b/src/main.py index 1234567..abcdefg 100644 --- a/src/main.py b/src/main.py -10,6 10,8 def process_data(data): result [] for item in data: if item is None: continue result.append(item.transform()) return result这里面真正有用的信息是文件路径src/main.py、变更位置第 10 行开始、变更内容新增了两行。其他都是元信息。我写了一个解析器把 diff 转成这样的结构{ file: src/main.py, changes: [ { type: addition, line_number: 12, content: if item is None: }, { type: addition, line_number: 13, content: continue } ] }这样 Agent 拿到的就是干净的数据不用自己去解析 diff 格式。解析的时候有几个边界情况要处理二进制文件git diff对二进制文件只会输出Binary files differ这种直接跳过重命名文件diff 里会有rename from和rename to需要特殊处理模式变更文件权限变更如100644变100755也要识别出来大文件超过一定行数的 diff 要截断避免 token 爆炸4.3 Agent 设计为什么不用单次 LLM 调用一开始我图省事直接把整个 diff 丢给 LLM让它一次性给出所有审查意见。结果发现两个问题第一注意力分散。当 diff 涉及十几个文件时LLM 对后面文件的审查质量明显下降经常漏掉问题。第二无法追问。有些问题需要看更多上下文才能判断比如这个函数在别处是怎么调用的单次调用没法让 LLM 主动去查。所以我改成了 Agent 模式。Agent 的工作流程是这样的接收一个文件的 diff 和上下文分析变更判断是否有问题如果有疑问可以调用工具去读取更多文件给出该文件的审查意见处理下一个文件这个循环由 Agent 自己控制它决定什么时候需要更多信息、什么时候可以下结论。实测下来审查质量比单次调用高出一大截。Agent 可用的工具我设计了三个read_file(path)读取指定文件的完整内容search_code(keyword)在仓库里搜索包含关键词的代码get_file_history(path)获取文件的提交历史这三个工具覆盖了大部分需要更多上下文的场景。4.4 审查规则让 Agent 知道该看什么LLM 虽然聪明但如果你不给它明确的审查标准它给出的意见会很泛比如建议添加注释变量命名可以更清晰这种正确的废话。我在 prompt 里内置了一套审查规则分成几个维度维度检查内容严重级别正确性逻辑错误、边界条件、空值处理高安全性注入风险、敏感信息泄露、权限校验高性能循环嵌套、重复计算、不必要的 IO中可维护性函数过长、重复代码、魔法数字中风格命名规范、注释完整性、格式一致性低Agent 在审查时会按照这个框架逐项检查输出时也会标注严重级别。这样人看起来就有优先级先看高严重级别的问题。这套规则不是死的你可以根据自己的项目特点调整。比如前端项目可能更关注 XSS 风险后端项目可能更关注 SQL 注入。我把规则做成了配置文件改起来很方便。5. 实操从零跑通一次完整的代码审查理论讲完了这一节我带你走一遍完整流程。假设你已经有一个 Git 仓库里面有一些未提交的变更。5.1 安装与初始化首先克隆项目假设你已经有了代码git clone 你的仓库地址 cd open-code-review安装依赖。我用的是 Python依赖管理用 pippip install -r requirements.txt主要依赖就三个openai调用 LLM、pygit2Git 操作、rich终端输出美化。然后配置 API 密钥。我建议用环境变量不要硬编码在代码里export OPEN_CODE_REVIEW_API_KEY你的密钥 export OPEN_CODE_REVIEW_MODELdeepseek-chat如果你用的是其他 LLM 服务改一下base_url就行。工具本身不绑定特定厂商只要接口兼容 OpenAI 格式就能用。5.2 第一次运行审查未提交的变更最简单的用法是直接在当前仓库运行open-code-review review默认情况下它会审查工作区和暂存区的所有变更。输出大概长这样正在分析变更... 发现 3 个文件变更共 47 行修改 [1/3] src/main.py 高: 第 23 行item 可能为 None建议添加空值检查 中: 第 45 行循环内重复调用 len()建议提取到循环外 [2/3] src/utils.py 低: 第 12 行函数名 processData 建议改为 process_data 以符合 PEP8 [3/3] README.md 无问题 审查完成共发现 3 个问题这个输出是给人看的。如果你需要机器可读的格式加--format jsonopen-code-review review --format json report.json5.3 审查指定提交范围更多时候你想审查的是某几次提交而不是工作区的变更。比如审查最近 3 次提交open-code-review review --range HEAD~3..HEAD或者审查两个分支之间的差异open-code-review review --range main..feature-branch这个功能在 code review 场景里特别实用。当同事提了一个 PR你可以先在本地跑一遍看看 Agent 有没有发现什么问题然后再人工审查。5.4 集成到 Git Hook提交前自动审查如果你想让每次提交前都自动跑一遍审查可以配置 Git hook。在.git/hooks/pre-commit里写入#!/bin/bash open-code-review review --staged --fail-on high--staged表示只审查暂存区的变更--fail-on high表示如果发现高严重级别的问题就阻止提交。这样配置之后每次git commit都会先跑一遍审查。如果有高严重级别的问题提交会被阻止你需要先修复。注意Git hook 默认不会同步到远程仓库每个开发者需要自己配置。如果你想让整个团队都用可以把 hook 脚本放在仓库里然后写个安装脚本。5.5 踩坑记录我遇到过的几个问题问题一diff 太大导致超时。有一次审查一个重构提交涉及 50 多个文件Agent 跑了十几分钟还没结束。后来我加了一个限制单次审查最多处理 20 个文件超过的部分分批处理。同时加了超时机制单个文件超过 60 秒就跳过。问题二LLM 返回格式不稳定。有时候 Agent 会返回一段自由文本而不是我期望的 JSON 格式。解决办法是在 prompt 里明确要求以 JSON 格式输出并且在解析时做容错处理——如果 JSON 解析失败就用正则从文本里提取关键信息。问题三中文注释乱码。这个前面提过是core.quotepath的问题。在工具里我加了一步处理读取 diff 后先做一次编码转换确保中文正常显示。问题四API 调用失败重试。网络抖动或者服务限流都会导致 API 调用失败。我加了指数退避重试最多重试 3 次。如果还是失败就跳过当前文件在报告里标注审查失败。6. 进阶玩法让审查更贴合你的项目基础功能跑通之后可以做一些定制化让工具更贴合自己的项目特点。6.1 自定义审查规则前面提到审查规则是配置化的。配置文件长这样rules: - name: 禁止硬编码密钥 pattern: (api_key|password|secret)\\s*\\s*[\][^\][\] severity: high message: 检测到硬编码的敏感信息建议使用环境变量 - name: 函数长度限制 type: function_length max_lines: 50 severity: medium message: 函数超过 50 行建议拆分 - name: TODO 注释检查 pattern: TODO|FIXME severity: low message: 存在待办事项建议在合并前处理这些规则会在 Agent 审查之前先跑一遍命中的问题直接标记出来。Agent 再在此基础上做更深层的语义分析。这样既保证了确定性问题的检出率又发挥了 LLM 的语义理解能力。6.2 项目上下文注入每个项目都有自己的潜规则比如所有数据库操作必须走 ORMAPI 返回必须用统一的响应格式。这些规则很难用正则表达但可以写进 prompt 里。我在项目根目录放了一个.open-code-review.md文件里面写项目的约定# 项目审查约定 - 所有数据库操作必须使用 SQLAlchemy ORM禁止裸写 SQL - API 响应必须使用 Response.success() 或 Response.error() 包装 - 日志使用 logger 对象禁止直接 print - 所有公开函数必须有 docstring工具启动时会自动读取这个文件把内容注入到 Agent 的 system prompt 里。这样 Agent 就知道该项目的特殊约定审查意见会更贴合实际。6.3 审查结果的历史追踪单次审查的价值有限但如果把每次审查的结果都存下来就能做趋势分析。我在工具里加了一个--save选项把审查结果存到.open-code-review/history/目录下。存下来的数据可以用来回答这些问题最近一个月高严重级别问题是在增加还是减少哪类问题最常出现哪个文件的审查问题最多这些数据对团队改进代码质量很有参考价值。我甚至写了个简单的脚本把历史数据生成趋势图放在团队的周报里。6.4 与 CI/CD 集成如果你用 GitHub Actions 或 Gitee Go可以把审查集成到 CI 流程里。以 GitHub Actions 为例name: Code Review on: [pull_request] jobs: review: runs-on: ubuntu-latest steps: - uses: actions/checkoutv3 with: fetch-depth: 0 - name: Setup Python uses: actions/setup-pythonv4 with: python-version: 3.10 - name: Install open-code-review run: pip install -r requirements.txt - name: Run review env: OPEN_CODE_REVIEW_API_KEY: ${{ secrets.API_KEY }} run: open-code-review review --range origin/main..HEAD --format json report.json - name: Upload report uses: actions/upload-artifactv3 with: name: review-report path: report.json这样每次 PR 都会自动跑一遍审查报告作为 artifact 保存。审查者可以先看 Agent 的报告再看代码效率会高很多。7. 关于 LLM 选型与成本控制的一些经验最后聊几个实际使用中绕不开的问题。7.1 不同 LLM 在代码审查场景的表现我测试过几个主流模型在代码审查任务上的表现。整体来说代码能力强的模型在审查任务上也更强但差距没有想象中那么大。对于常规的代码审查找空值、找边界条件、找风格问题中等规模的模型就够用了。只有在涉及复杂业务逻辑判断时大模型才有明显优势。成本方面如果按每次审查 10 个文件、每个文件 2000 token 计算一次审查大概消耗 2 万 token。用中等价位的模型一次审查成本在几毛钱左右。对于个人开发者来说完全可以接受对于团队来说更是九牛一毛。7.2 怎么控制 token 消耗几个实用的技巧只传 diff不传全量代码这是最基本的前面已经强调过上下文按需加载不要一次性把所有相关文件都读进来让 Agent 自己决定需要读什么缓存重复内容如果多个文件有相同的上下文比如都 import 了同一个模块可以缓存起来避免重复传输限制单文件大小超过 500 行的 diff 直接截断只审查前 500 行我实测下来做好这几点token 消耗能降低 60% 以上。7.3 审查结果的准确率问题必须承认LLM 的审查结果不是 100% 准确的。会有误报把没问题的地方标成问题也会有漏报真正的问题没发现。我的经验是把 Agent 当成一个初级审查者。它提出的问题值得看一眼但不要盲从。特别是高严重级别的问题一定要人工确认。低严重级别的问题可以批量处理比如风格问题可以配置自动修复。另外Agent 的审查质量会随着 prompt 的优化而提升。我建议你花点时间调 prompt把项目里常见的问题类型、团队关注的审查点都写进去。这个投入是值得的一次调好长期受益。7.4 一个容易被忽略的细节审查意见的可操作性Agent 给出的审查意见最好能直接指导修改。比如第 23 行 item 可能为 None就比存在空值风险更有用。我在 prompt 里明确要求 Agent 输出时包含文件路径、行号、问题描述、修改建议。这样审查者可以直接定位到代码按建议修改。如果 Agent 能给出具体的代码修改建议比如建议改为if item is None: continue那就更好了。我在最新版本里加了这个功能Agent 会尝试给出修改后的代码片段。实测下来对于简单问题Agent 的建议直接可用对于复杂问题建议可能不完整但至少提供了思路。这套工具我用了大半年迭代了十几个版本现在已经成为我日常开发流程的一部分。它不能替代人工审查但确实能把审查效率提升一个档次。如果你也在为代码审查的事情头疼不妨试试这个思路。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价