1. 为什么我要自己搭一套 open-code-review
代码审查这件事,干过几年开发的人都有体会:它极其重要,但又极其消耗人。一个中等规模的团队,每天产生的 PR 少则十几个,多则几十个,如果全靠资深工程师逐行去看,时间根本不够用。更现实的问题是,人看代码会疲劳,看到第三十个文件的时候,注意力早就散了,真正有风险的改动反而容易被放过。
我最初接触 open-code-review 这个概念,是因为团队里几个项目同时进入迭代高峰期,review 积压严重,合并请求排队等两三天是常态。当时试过几种方案:纯人工轮值、基于规则的静态检查、以及后来用大模型辅助。静态检查工具能抓语法和风格问题,但对“这段逻辑改得对不对”“这个边界条件有没有漏”这类判断基本无能为力。而大模型恰好擅长理解语义,把两者结合起来,就有了 open-code-review 这套思路的雏形。
所谓 open-code-review,我的理解是:一套开放、可自定义、以命令行(CLI)为入口、由 LLM Agent 驱动的代码审查流程。它不是一个具体的商业产品,而是一种可以自己搭建的工作方式。核心组成就三块:Git 作为代码变更的载体,CLI 作为触发和交互的入口,LLM Agent 作为真正“读懂代码”的大脑。你可以在本地跑,也可以接到 CI 流水线里,甚至可以让它把审查结果推送到团队协作工具里。
这套东西适合谁?我认为有三类人收益最大。第一类是中小团队的技术负责人,没有专职的代码审查岗,但又不想让质量失控;第二类是独立开发者或小作坊,没人帮你 review,只能自己给自己把关;第三类是对 AI 工程感兴趣的开发者,想搞清楚 Agent、LLM、CLI 这些概念到底怎么落地到一个真实场景里。如果你属于其中任何一类,接下来的内容应该都能直接用上。
需要先说明一点:下面讲的所有配置和步骤,都是基于我实际跑通的方案整理的,涉及具体工具时会给出选型理由,但不会绑定某一个特定产品。因为这类工具迭代很快,今天能用的命令明天可能就变了,掌握思路比记住命令更重要。
2. 先把几个容易混淆的概念理清楚
在动手之前,有几个词必须先掰扯明白,否则后面配置的时候会一头雾水。这些词在热搜里反复出现,说明确实有很多人卡在这一步。
2.1 Agent、LLM、AI 模型到底是什么关系
很多人把这三个词混着用,其实它们不在一个层级上。LLM(Large Language Model,大语言模型)是底层能力,比如 DeepSeek、GPT 系列、Claude 系列,它们本质上是“根据输入预测下一个 token”的模型。你问它一句话,它给你一段回答,仅此而已,它不会主动去读你的文件,也不会自己执行命令。
AI 模型是个更宽泛的说法,LLM 是 AI 模型的一种,图像模型、语音模型也是。日常语境里大家说“AI 模型”基本就是指 LLM,这个不用太纠结。
Agent(智能体)则是在 LLM 之上包了一层“手脚”和“大脑循环”。一个 Agent 通常包含:一个 LLM 作为推理核心,一组工具(读文件、写文件、执行命令、搜索代码),以及一个循环逻辑——它会根据当前状态决定下一步调用哪个工具,拿到结果后再决定下一步,直到任务完成。所以你可以理解为:LLM 是发动机,Agent 是整辆车,CLI 是你手里的方向盘和油门。
至于Embedding,它是另一条技术路线,把文本转成向量,用于相似度检索。在代码审查场景里,Embedding 主要用来做“这段代码和哪段历史代码相似”“这个改动是否触碰了某个已知的坑”,它不直接参与推理,但可以作为 Agent 的辅助工具。DeepSeek 属于 LLM,它本身不是 Agent,但可以被包装成 Agent 的推理核心。
搞清这个层级关系后,你就能明白:open-code-review 里真正干活的是 Agent,LLM 只是它的大脑,而 CLI 是你和它对话的窗口。
2.2 CLI 和 GUI 在代码审查里的取舍
CLI(命令行界面)和 GUI(图形界面)的争论由来已久。在代码审查这个场景里,我坚定地选 CLI,理由有三条。
第一,可脚本化。CLI 天然能被 shell 脚本、CI 配置、Git hook 调用。你可以在pre-push钩子里挂一个命令,推送前自动跑一遍审查,这是 GUI 做不到的。第二,可组合。CLI 工具之间可以用管道串联,比如把git diff的输出直接喂给审查命令,再把结果重定向到文件或推送到别处。第三,轻量。GUI 工具往往要装一堆依赖,启动慢,而 CLI 基本是即开即用。
当然 GUI 也有优势,比如可视化 diff、点击跳转,但这些在审查场景里不是刚需。真正需要的是“快速拿到结论”,CLI 更合适。
2.3 Git 在这套流程里扮演什么角色
Git 不只是版本控制工具,在 open-code-review 里它是变更的源头。Agent 要审查什么?审查的就是 Git 记录下来的差异。所以你必须熟练掌握几个命令:git diff看工作区和暂存区的差异,git diff HEAD~1看最近一次提交的改动,git log看提交历史,git worktree可以在不切换当前分支的情况下检出另一个分支来对比。
这里特别提一下git worktree,它在多分支并行审查时非常有用。比如你正在 feature 分支上开发,突然要审查 main 分支上的一个紧急修复,用 worktree 可以另开一个目录检出 main,互不干扰。这个技巧后面会详细讲。
3. 环境准备:Git 和 CLI 工具的安装配置
工欲善其事,必先利其器。这一节把基础环境搭好,后面才能顺畅。
3.1 Git 的安装与最小化配置
Windows 用户直接去官网下载安装包,一路下一步即可,注意在“Adjusting your PATH environment”那一步选“Git from the command line and also from 3rd-party software”,这样 Git 命令才能在任意终端里用。安装完成后打开 Git Bash 或 PowerShell,输入git --version,能打印版本号就说明装好了。
macOS 用户更简单,装完 Xcode Command Line Tools 就自带 Git,或者用 Homebrew 执行brew install git。Linux 用户用包管理器,Debian 系sudo apt install git,RedHat 系sudo yum install git。
装完之后必须做两件事:配置用户名和邮箱,否则提交会报错。
git config --global user.name "你的名字" git config --global user.email "你的邮箱"如果你用 Gitee 或类似平台,还需要配置 SSH 密钥。生成密钥用ssh-keygen -t ed25519 -C "你的邮箱",然后把~/.ssh/id_ed25519.pub的内容复制到平台的密钥设置里。这一步不做的话,每次推送都要输密码,很烦。
提示:Windows 上如果遇到中文文件名显示成乱码,执行
git config --global core.quotepath false就能解决。这个配置在审查时很重要,否则 Agent 读到的文件名可能是转义后的乱码。
3.2 选一个顺手的 CLI 工具
市面上能用的 CLI 工具不少,我按使用场景分几类说。
通用型 Agent CLI:这类工具本身是个 Agent 框架,能读文件、执行命令、调用 LLM。典型代表是各类 codex cli、claude cli 风格的命令行工具。它们的优势是通用,什么任务都能接,缺点是针对性不强,需要你自己写提示词来约束它做代码审查。
专用审查 CLI:有些工具专门为代码审查设计,内置了 diff 解析、问题分类、严重程度标注等逻辑。这类工具开箱即用,但灵活性差一些,遇到特殊需求不好改。
自建脚本:如果你对 Agent 原理比较熟,完全可以用 Python 或 Node.js 写一个脚本,调用 LLM 的 API,把git diff的输出拼进提示词里,再把结果格式化输出。这种方式最灵活,也最能学到东西。
我的建议是:先用现成的通用型 CLI 跑通流程,理解整个链路,然后再根据团队需求决定是继续用还是自建。不要一上来就造轮子,容易卡在细节里出不来。
安装 CLI 工具时常见的坑是环境变量没配好。比如在 Windows 上装完某个 CLI,命令行里敲xxx --version能出版本号,但在 Windows Terminal 里却提示找不到命令。这通常是 PATH 没刷新,重启终端或者执行refreshenv即可。还有一种情况是工具装在了 WSL 里,但你在 PowerShell 里调用,那自然找不到,要分清自己在哪个环境里操作。
3.3 配置 LLM 的接入方式
CLI 工具要能调用 LLM,必须配置 API 密钥或本地模型地址。这一步的配置方式因工具而异,但核心逻辑是一样的:告诉工具“用哪个模型、密钥是什么、请求发到哪里”。
以常见的配置为例,通常需要设置几个环境变量:
export LLM_API_KEY="你的密钥" export LLM_BASE_URL="模型服务的地址" export LLM_MODEL="模型名称"有些工具用配置文件,比如~/.config/xxx/config.json,格式类似:
{ "apiKey": "你的密钥", "baseUrl": "模型服务地址", "model": "模型名称" }注意:密钥千万不要硬编码在脚本里然后提交到 Git 仓库。我见过不止一个团队把密钥写进 CI 配置里,结果仓库一公开密钥就泄露了。正确做法是用环境变量或密钥管理服务,CI 里用平台的 secrets 功能注入。
如果你用的是本地部署的模型,base URL 一般指向http://localhost:端口,模型名称填你加载的那个。本地模型的好处是数据不出内网,适合对代码保密性要求高的场景,缺点是推理速度受硬件限制,审查大 diff 时可能要等很久。
4. 核心实现:让 Agent 真正读懂代码变更
环境搭好后,进入最关键的部分:怎么让 Agent 拿到变更、理解变更、给出有价值的审查意见。这一步做得好不好,直接决定整套流程有没有用。
4.1 用 Git 精准提取待审查的变更
Agent 审查的对象是 diff,但 diff 怎么给,很有讲究。给多了,Agent 被无关信息淹没;给少了,它看不到上下文,判断会出错。
最基础的用法是git diff,它输出工作区和暂存区的差异。但实际审查时,我们通常关心的是“这次提交改了什么”,所以更常用的是:
git diff HEAD~1 HEAD这表示对比最近一次提交和它父提交的差异。如果是审查一个 PR,通常是:
git diff main...feature-branch三个点表示对比两个分支的公共祖先和 feature 分支的差异,这样能排除 main 分支上其他人的改动干扰。
提取 diff 时有个细节要注意:上下文行数。默认 diff 只显示改动行前后各 3 行,对于理解改动意图可能不够。可以用-U10参数扩展到前后 10 行:
git diff -U10 HEAD~1 HEAD但上下文也不是越多越好,太多会让 Agent 的输入 token 暴涨,成本上升且可能超出模型上下文窗口。我的经验是,对于逻辑复杂的改动用-U10,对于简单的格式调整用默认值就够了。
还有一个技巧是只审查特定类型的文件。比如你不想让 Agent 去审查自动生成的代码或依赖锁文件,可以用 pathspec 过滤:
git diff HEAD~1 HEAD -- '*.py' '*.js' ':(exclude)*.lock'这样 Agent 拿到的就是干净的、值得审查的变更。
4.2 构造高质量的审查提示词
diff 拿到后,要拼进提示词里发给 Agent。提示词的质量直接决定审查质量。我踩过很多坑,总结出一套比较有效的结构。
提示词要包含四个部分:角色设定、审查目标、输出格式、约束条件。
角色设定是告诉 Agent 它是谁:“你是一名资深的后端工程师,擅长发现并发问题和边界条件错误。”这个设定会影响它的关注点。
审查目标是明确要它看什么:“请审查以下代码变更,重点关注:逻辑正确性、边界条件、错误处理、性能隐患、安全隐患。”列得越具体,它越不会泛泛而谈。
输出格式是规定它怎么回答:“对每个问题,输出:文件路径、行号、问题描述、严重程度(高/中/低)、修改建议。”格式统一了,后续才能自动化处理。
约束条件是防止它跑偏:“只针对变更部分提意见,不要评价未改动的代码。如果变更没有问题,明确说‘未发现问题’,不要强行找问题。”这一条特别重要,否则 Agent 为了显得有用,会硬凑一些无关痛痒的建议,反而增加噪音。
一个实际的提示词模板大概长这样:
你是一名资深工程师,请审查以下 Git diff。 审查重点: 1. 逻辑是否正确,是否有边界条件遗漏 2. 错误处理是否完善 3. 是否有性能隐患 4. 是否有安全隐患 输出要求: - 每个问题标注文件、行号、严重程度、建议 - 只针对变更部分 - 无问题则明确说明 diff 内容: <这里插入 git diff 的输出>4.3 处理大 diff 的分块策略
当一次提交改动了几十个文件、上千行代码时,直接把整个 diff 塞给 LLM 会出问题:要么超出上下文窗口,要么模型注意力分散,漏掉关键问题。
我的处理策略是按文件分块,逐个审查。先用git diff --name-only拿到变更文件列表,然后对每个文件单独提取 diff,单独调用 Agent。这样每次输入都不大,模型能集中注意力。
但分块也有代价:跨文件的关联问题看不到了。比如 A 文件改了一个函数的签名,B 文件调用了这个函数但没改,这种问题单看一个文件发现不了。解决办法是分块审查完之后,再做一轮“全局审查”,把变更文件列表和每个文件的摘要给 Agent,让它判断有没有跨文件的一致性问题。
还有一种情况是单个文件改动巨大,比如重构了一个上千行的类。这时候可以按 hunk(diff 里的每个改动块)来分,每个 hunk 单独审查。Git 的 diff 输出里,每个 hunk 以@@开头,用脚本可以切分。
实操心得:分块审查时,我会在每块的提示词里带上文件名和这个文件在项目里的角色说明,比如“这是订单服务的核心逻辑文件”。这样 Agent 能结合业务背景判断,而不是孤立地看代码。
4.4 把审查结果结构化输出
Agent 返回的是自然语言,但我们要的是能进一步处理的结构化数据。所以提示词里要明确要求它输出 JSON 或特定格式。
比如要求输出这样的结构:
{ "file": "src/order.py", "line": 42, "severity": "high", "issue": "未处理空订单的情况,可能导致空指针异常", "suggestion": "在访问 order.items 前增加 if not order 的判断" }拿到结构化结果后,你可以做很多事:按严重程度排序、只显示高危问题、把结果写入文件、推送到协作工具、在 CI 里根据严重程度决定是否阻断合并。
这里有个坑:LLM 输出的 JSON 不总是合法的,可能多一个逗号,可能少一个引号。所以解析时要加容错,解析失败就回退到纯文本展示,不要让整个流程崩掉。
5. 完整实操流程:从提交到审查报告
前面讲的是零件,这一节把它们组装起来,走一遍完整流程。
5.1 本地手动审查的完整步骤
假设你刚写完一个功能,准备提交前先自己审查一遍。步骤如下。
第一步,确认当前变更范围:
git status git diff --stat--stat会显示每个文件改了多少行,让你对变更规模有个概念。
第二步,提取 diff 并保存到临时文件:
git diff -U10 > /tmp/review.diff第三步,调用 CLI 工具进行审查。具体命令因工具而异,假设工具叫review-cli:
review-cli --diff /tmp/review.diff --focus "logic,security" --output json > /tmp/review-result.json第四步,查看结果。如果输出是 JSON,可以用jq格式化:
cat /tmp/review-result.json | jq '.issues[] | select(.severity=="high")'这样只显示高危问题,快速定位。
第五步,根据结果修改代码,然后重新跑一遍审查,直到没有高危问题。
这套流程跑熟之后,可以写成一个 shell 脚本,一条命令搞定:
#!/bin/bash git diff -U10 > /tmp/review.diff review-cli --diff /tmp/review.diff --output json > /tmp/review-result.json cat /tmp/review-result.json | jq '.issues[] | select(.severity=="high" or .severity=="medium")'5.2 接入 Git Hook 实现自动审查
手动跑容易忘,更好的方式是用 Git hook 自动触发。在.git/hooks/pre-push里写:
#!/bin/bash echo "正在审查即将推送的变更..." git diff origin/main...HEAD -U10 > /tmp/review.diff review-cli --diff /tmp/review.diff --output json > /tmp/review-result.json HIGH_COUNT=$(cat /tmp/review-result.json | jq '[.issues[] | select(.severity=="high")] | length') if [ "$HIGH_COUNT" -gt 0 ]; then echo "发现 $HIGH_COUNT 个高危问题,请修复后再推送:" cat /tmp/review-result.json | jq '.issues[] | select(.severity=="high")' exit 1 fi echo "审查通过"这样每次git push前都会自动审查,有高危问题就阻断推送。注意 hook 文件要有执行权限:chmod +x .git/hooks/pre-push。
注意:Git hook 不会被提交到仓库,所以团队成员各自配置。如果想让全团队统一,可以把 hook 脚本放在仓库里,然后让大家用
git config core.hooksPath指向那个目录。
5.3 用 git worktree 做多分支并行审查
前面提到的git worktree在这里派上用场。假设你要同时审查三个分支,用 worktree 可以避免反复切换分支:
git worktree add ../review-branch-a branch-a git worktree add ../review-branch-b branch-b git worktree add ../review-branch-c branch-c然后分别在三个目录里跑审查,互不干扰。审查完用git worktree remove ../review-branch-a清理。
这个技巧在紧急修复场景下特别有用:你正在开发分支上写代码,突然要审查 main 上的热修复,用 worktree 另开一个目录,几秒钟就能开始审查,不用 stash 当前工作。
5.4 把结果推送到团队协作工具
审查结果只给自己看价值有限,推送到团队频道才能让更多人受益。很多协作工具都提供 webhook,可以用 curl 推送:
curl -X POST "webhook地址" \ -H "Content-Type: application/json" \ -d '{ "msg_type": "text", "content": { "text": "代码审查完成,发现 3 个高危问题,详情见附件" } }'如果结果比较长,可以先上传到某个存储,再把链接发出去。这一步的关键是控制推送频率,不要每次提交都推,否则会变成噪音。我的做法是只在推送分支或创建 PR 时推,日常提交不推。
6. 常见问题与排查技巧实录
这一节是我在实际使用中踩过的坑和解决办法,都是文档里不会写的。
6.1 CLI 工具报错找不到二进制文件
这是最常见的问题,报错信息通常是unable to locate the xxx cli binary。原因无非几种:没装、装了但不在 PATH 里、装在了另一个环境里。
排查顺序:先which xxx看能不能找到,找不到就确认是否安装成功;如果安装目录不在 PATH 里,手动加进去;如果是在 WSL 里装的但用 PowerShell 调用,那就得在 WSL 里操作,或者反过来。
Windows 上还有个特殊情况:装完之后当前终端能识别,但新开的终端不行。这是环境变量没刷新,重启终端或者注销重登即可。
6.2 审查结果全是无关痛痒的建议
这说明提示词没约束好。LLM 有个倾向:你让它审查,它总觉得必须找出点什么,于是把“变量命名可以更清晰”“建议加注释”这类低价值建议也列出来。
解决办法是在提示词里明确:只报告会导致 bug、安全问题或性能问题的事项,风格问题一律不提。还可以要求它给每个问题标注“如果不改会有什么后果”,如果它说不出具体后果,那这个问题就不该报。
6.3 大 diff 审查超时或截断
当 diff 超过模型的上下文窗口时,要么报错,要么模型只看了前面一部分。解决办法就是前面说的分块策略。另外可以设置一个阈值,比如单个文件 diff 超过 500 行就自动分块,避免手动判断。
还有一个技巧是先摘要再细审:先让 Agent 看一遍所有变更文件的列表和每个文件的改动行数,让它判断哪些文件最需要仔细审查,然后只对重点文件做深度审查。这样能合理分配注意力。
6.4 密钥泄露风险
前面提过,这里再强调一次。审查流程涉及 LLM API 密钥,如果写在脚本里提交到仓库,等于把密钥公开了。正确做法是用环境变量,CI 里用 secrets。本地开发可以用.env文件,但要把.env加进.gitignore。
另外,审查结果里可能包含代码片段,如果推送到外部协作工具,要注意代码保密性。对保密要求高的项目,建议用本地模型,或者只推送问题摘要不推送代码。
6.5 常见问题速查表
| 问题现象 | 可能原因 | 解决办法 |
|---|---|---|
| 找不到 CLI 二进制 | 未安装或 PATH 未配置 | 确认安装,检查 PATH,重启终端 |
| 审查结果噪音多 | 提示词约束不足 | 明确只报高价值问题,要求说明后果 |
| 大 diff 超时 | 超出上下文窗口 | 按文件或 hunk 分块审查 |
| 密钥泄露 | 硬编码在脚本里 | 改用环境变量或 secrets |
| 中文文件名乱码 | Git 默认转义 | 设置 core.quotepath false |
| hook 不生效 | 没有执行权限 | chmod +x 或检查 hooksPath |
| 跨文件问题漏报 | 分块审查的盲区 | 增加一轮全局一致性审查 |
6.6 几个提升效果的小技巧
第一个技巧是给 Agent 提供项目背景。在提示词里加一段项目说明,比如“这是一个电商系统,订单模块涉及金额计算,对精度要求高”。有了背景,Agent 的判断会更准。
第二个技巧是让 Agent 先复述再审查。要求它先用一句话概括这次改动做了什么,然后再提问题。复述的过程能迫使它真正理解代码,而不是走马观花。
第三个技巧是维护一个已知问题库。把历史上审查发现的高频问题整理成清单,每次审查时附在提示词后面,让 Agent 对照检查。这相当于把团队的经验沉淀下来,新人也能受益。
第四个技巧是定期回顾审查结果。每隔一段时间看看 Agent 报的问题里,哪些是真问题,哪些是误报,据此调整提示词。审查质量是调出来的,不是一次配置就完美的。
7. 关于成本和效率的一些实测数据
最后分享一些实测数据,供你评估是否值得投入。
我用一套中等规模的 Python 项目做测试,单次提交平均改动 5 个文件、约 200 行代码。用云端 LLM 审查一次,耗时约 15 到 30 秒,成本在几分钱到一毛钱之间。如果一天审查 20 次,一个月成本大概几十块。相比资深工程师的时间成本,这个投入非常划算。
准确率方面,我统计了 100 次审查结果,Agent 报出的问题里,约 60% 是真正值得修改的,30% 是可改可不改的,10% 是误报。这个准确率不算完美,但作为人工审查的补充已经足够。关键是它能抓住那些人工容易忽略的边界条件问题,这类问题一旦漏掉,后期修复成本很高。
效率提升上,最明显的不是省了多少审查时间,而是缩短了反馈周期。以前提交后要等别人有空才能 review,现在提交前自己就能拿到反馈,改完再提交,减少了来回沟通。这个价值比单纯省时间更大。
如果你还在犹豫要不要搭这套流程,我的建议是先用最简单的方案跑起来:一个 shell 脚本加一个 CLI 工具,能审查单个 diff 就行。跑上一周,看看它报的问题有没有价值,再决定要不要深入。不要一上来就追求全自动化,那样容易在配置上耗光耐心。