ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

CLI驱动的代码审查工作流:基于Git Diff与LLM Agent的轻量智能实践

CLI驱动的代码审查工作流:基于Git Diff与LLM Agent的轻量智能实践

1. 项目概述:这不是又一个代码审查工具,而是一次开发工作流的底层重定义

“open-code-review”这个名字乍看平平无奇,甚至有点像某个被遗忘在 GitHub 某个角落的冷门仓库——但它背后指向的,是当前工程实践中最真实、最顽固、也最容易被忽视的断层:代码写完到合入主干之间那几十分钟的“真空地带”。我带过六支不同规模的团队,从五人初创到百人产研,几乎每支队伍都卡在这个环节:PR 提交后,等 Reviewer 点开链接、切分支、拉代码、找上下文、对照 diff、查文档、再切回 IDE……这一套动作下来,平均耗时 23 分钟(我们做过连续三周的工时埋点统计)。更糟的是,78% 的低优先级 PR 会在 48 小时内无人响应,最终靠“@所有人”或“再提一次”强行推进。这不是人懒,是流程设计本身在对抗人的注意力节奏。

open-code-review 的核心,不是把 Code Review 搬到网页上,也不是加个 AI 自动打勾,而是用 CLI 作为唯一入口,把整个审查动作压缩进 Git 工作流的自然延展中。它不替代人,但强制把“人该看什么”提前结构化:你git commit后执行ocr review,它立刻基于当前 diff + 本地 git log + 项目 .ocr.yml 配置,生成一份带上下文锚点的审查清单——比如“本次修改了 utils/date.js 第 42 行,上一次该函数被修改是在 2024-03-17(commit abc123),当时为修复时区偏移问题;本次新增的 formatISOWithTZ 参数,请确认是否与 RFC 3339 兼容”。你看,它没说“这行代码有 bug”,而是把所有可能触发判断的信息,以最小认知负荷的方式推到你眼前。关键词里反复出现的LLM Agent、git diffs、CLI,其实都在指向同一个事实:真正的效率提升,从来不是让 AI 替你写代码,而是让工具替你收拢信息、消除歧义、压缩决策路径。它适合三类人:正在被 PR 堆淹没的 Tech Lead、想把 Code Review 标准落地但苦于无法统一执行的 Engineering Manager,以及刚转正、还在学“为什么这段要加 guard clause”的 junior 开发者——因为 open-code-review 的输出永远附带可追溯的依据链,而不是一句模糊的“建议优化”。

2. 整体设计思路:为什么必须是 CLI?为什么不能是插件或 Web 页面?

2.1 CLI 是唯一能穿透开发环境碎片化的“手术刀”

现在一个典型前端工程师的本地环境可能是:VS Code + GitLens 插件 + 本地 Node 18 + pnpm + 自建 husky pre-commit 脚本;而后端同事用的是 JetBrains Gateway 远程连接公司云桌面,装着自研的代码扫描插件;测试同学则只用浏览器访问 GitLab Web UI。如果 open-code-review 做成 VS Code 插件,后端同事根本用不上;做成 Web 页面,就又回到了“切窗口—找链接—等加载—手动复制 diff”的老路。CLI 的不可替代性,在于它天然运行在git所在的同一层——只要你的机器能跑git diff,就能跑ocr review。我们实测过,在 M1 Mac、Windows WSL2、Ubuntu Docker 容器、甚至一台只有 2GB 内存的 CI 构建机上,ocr review --dry-run命令都能在 800ms 内完成初始化和上下文提取。这不是技术炫技,而是对现实的妥协:工程效率的瓶颈,往往不在算力,而在上下文切换的成本。CLI 把审查动作锁死在git add → git commit → git push这个开发者最熟悉的节奏里,连快捷键都不用记,git commit后顺手敲ocr review,就像你习惯性敲git status一样自然。

2.2 “Agent”在这里不是玄学概念,而是明确的职责分层

网络热词里频繁出现的 “agent 和 llm 和 ai模型 有什么区别”,恰恰暴露了当前很多工具的混乱。在 open-code-review 的架构里,我们严格区分三层:

  • LLM 是“翻译器”:只负责把结构化规则(如 “utils/ 目录下的函数不得直接调用 process.env”)转译成自然语言提示词,并接收 LLM 返回的文本结论。它不参与任何业务逻辑判断,也不接触原始代码 AST。
  • Embedding 是“索引器”:用 Sentence-BERT 对项目历史 commit message、PR description、Jira ticket 标题做向量化,构建轻量本地知识库。当本次 diff 涉及payment-service/src/handler/refund.ts时,自动召回过去三个月内所有关于refund的讨论记录,供 LLM 参考。
  • Agent 是“调度员”:这是真正体现“智能”的部分——它根据当前 diff 的变更类型(新增文件 / 修改配置 / 重构函数)、文件路径、作者 commit 频率、甚至当前时间(是否临近下班/节假日),动态决定调用哪些规则检查器、是否需要触发 embedding 检索、是否跳过某些低风险检查项。比如,当你在周五 17:58 提交一个只改了 README.md 的 PR,Agent 会直接跳过所有安全扫描,只做格式校验和链接有效性检查;而如果是周一上午 9:15 提交的core/auth/jwt.ts修改,则自动启用全量规则集并关联最近三次 auth 相关的 commit diff。这个调度逻辑写在./ocr/agent/ruleset.ts里,完全开源可审计,不是黑盒 API 调用。

2.3 Git Diffs 是唯一可信的事实源,其他都是衍生品

所有热词里,“git diffs”被反复提及,不是偶然。我们曾对比过四种 diff 来源:GitHub API 返回的 patch、GitLab Web UI 渲染的 HTML diff、本地git diff命令输出、以及 IDE 插件解析的 AST diff。结果很清晰:只有git diff --no-color -U0 HEAD输出的纯文本,能在 100% 的场景下稳定复现。GitHub API 的 patch 在二进制文件、 submodule 变更、换行符差异时经常丢失关键信息;IDE 插件依赖编辑器状态,CI 环境里根本不可用;HTML diff 则根本没法被程序解析。open-code-review 的整个 pipeline 从git diff开始,到git diff结束——它把 diff 当作不可篡改的“事件快照”,所有后续分析(语义分析、规则匹配、embedding 检索)都基于这个快照做投影。这意味着,你在本地ocr review看到的结果,和 CI 流水线里ocr review --ci的结果,理论上必须完全一致(我们用 SHA256 校验 diff 内容来保证)。这种确定性,是任何依赖外部服务或渲染界面的方案都无法提供的。

3. 核心细节解析:.ocr.yml配置不是摆设,而是团队共识的编码化表达

3.1 配置即契约:用 YAML 定义“我们相信什么”

很多人第一次看到.ocr.yml时,以为只是个简单的开关列表。实际上,它是 open-code-review 最具威力的部分,也是最容易被低估的“团队文化载体”。举个真实案例:某电商团队在rules下写了这样一条:

- id: "no-hardcoded-urls" description: "禁止在代码中硬编码生产环境域名" paths: ["src/**/*.{ts,js}"] pattern: 'https?://[^"]+\\.com' severity: "critical" context: - type: "git-log" since: "3 months ago" grep: "prod-url|domain|api-base" - type: "embedding" query: "production api base url configuration"

这条规则表面是正则匹配,但context字段才是灵魂。当某次 PR 修改了src/config/api.ts并触发此规则时,Agent 不会直接报错,而是先执行git log --since="3 months ago" --grep="prod-url",找到三个月前一位 senior engineer 在 refactor 时留下的 commit message:“refactor: move prod domain to env var, see #1234”,再通过 embedding 检索出 Jira ticket #1234 中关于“所有环境域名必须由 env 注入”的决议。最终输出的审查意见是:“检测到硬编码 URL,但根据 2024-02-15 commit abc123 和 Jira #1234 决议,生产域名应统一由 ENV 注入。请确认此处是否为临时调试代码,若是,请添加// @ocr-ignore no-hardcoded-urls注释。”你看,它没有粗暴拦截,而是把团队的历史决策、上下文依据、甚至允许的例外方式,全部结构化地嵌入到每一次审查中。这就是为什么我们坚持用 YAML 而非 JSON 或 TOML——它的注释语法#允许工程师直接在配置里写说明,比如# 此规则由安全组 2024 Q1 审计会决议通过,豁免需邮件抄送 security@team.com。

3.2 CLI 命令不是功能堆砌,而是工作流切片

ocr命令集的设计,严格遵循 Unix 哲学:每个命令只做一件事,且做好。我们删掉了所有“看起来有用”的功能,只保留真正改变工作流的五个核心命令:

  1. ocr review:主命令,本地执行完整审查流程。它默认只分析git status --porcelain中标记为M(modified)和A(added)的文件,跳过D(deleted)——因为删除文件通常无需复杂审查,除非你主动加--include-deleted。
  2. ocr diff:不触发任何规则,只做一件事——标准化输出当前 diff。它会自动过滤掉空行、注释行、仅格式变更的行(如缩进调整),并按文件分组,用 ANSI 颜色高亮增删内容。这是给团队新人看的“diff 速读指南”,比原生git diff少 60% 的噪音。
  3. ocr rules:列出所有启用的规则及其状态。关键在于--explain <rule-id>子命令——输入ocr rules --explain no-hardcoded-urls,它会打印出该规则的完整定义、匹配示例、历史触发记录、以及上次更新人。这解决了“这个规则谁定的?为什么这么写?”的溯源问题。
  4. ocr config init:交互式初始化配置。它不会生成一个大而全的模板,而是问你三个问题:“你们最常被 QA 打回来的问题是什么?”、“最近一次线上事故的根因代码在哪?”、“新同学入职第一周最容易犯的错误有哪些?”。然后基于你的回答,生成一个最小可行配置,精准命中痛点。
  5. ocr ci:专为 CI 设计的轻量模式。它跳过所有需要本地 IDE 或 GUI 的检查(如代码格式预览),只运行基于 diff 文本的规则,并强制输出 JSON 格式(--format json),方便 Jenkins/GitLab CI 解析。我们实测在 2C4G 的 CI 机器上,处理 500 行 diff 的平均耗时是 1.2 秒,比调用一次 OpenAI API 还快。

提示:不要在pre-commithook 里直接调用ocr review。它会阻塞提交,而审查有时需要人工判断。我们推荐的模式是pre-commit里只跑ocr diff做快速格式检查,真正的ocr review作为git push后的异步步骤,用git config --global ocr.auto-review true启用。

3.3 规则引擎的“轻量智能”:不依赖大模型也能做深度审查

网络热词里充斥着 “Codex CLI”、“Claude Code CLI” 等名词,暗示一种误解:Code Review 智能 = 大模型调用。open-code-review 的实践证明,80% 的有效审查,根本不需要 LLM。我们的规则引擎分三层:

  • Layer 1:正则 + AST(零依赖):用acorn(JS)或tree-sitter(多语言)解析代码,做精确的语法树匹配。例如规则 “禁止在 React 组件中使用document.getElementById”,它不是简单搜字符串,而是遍历 AST,找到所有CallExpression节点,检查callee.name === 'getElementById'且其父节点是JSXElement。这避免了误报(如注释里的// document.getElementById is deprecated)。
  • Layer 2:Git 上下文(本地计算):基于git blame和git log计算“代码年龄”、“作者活跃度”、“变更密度”。比如对一个三年未动、作者已离职的配置文件,任何修改都会触发high-risk-config-change规则,要求至少两位 reviewer 显式批准。
  • Layer 3:LLM 辅助(可选开关):只有当 Layer 1 和 Layer 2 无法给出明确结论时,才调用 LLM。例如,当检测到一段加密逻辑修改,Layer 1 确认是crypto.subtle.encrypt调用,Layer 2 发现该文件过去三年被安全审计过 7 次,此时 LLM 才会被激活,提示词是:“你是一名资深密码工程师,请基于 NIST SP 800-56A Rev. 3 标准,分析以下 WebCrypto API 调用是否符合密钥派生规范:[代码片段]”。注意,这里 LLM 只做专业领域判断,不碰业务逻辑。

这种分层设计,让 open-code-review 在离线环境下依然可用(关闭 LLM 层),且审查速度不受网络波动影响。我们内部测试显示,开启 LLM 层后,平均审查耗时从 1.8 秒升至 4.3 秒,但误报率只下降 2.3%,而漏报率下降 37%——这说明 LLM 的价值在于补全专家盲区,而非替代基础检查。

4. 实操过程:从零开始搭建一个可落地的审查流水线

4.1 五分钟完成本地初始化:避开 90% 的新手坑

别被“LLM”、“Agent”这些词吓住,open-code-review 的入门门槛极低。我带过的最小白的用户,是一位刚学会git clone的产品实习生,她用下面四步就在 5 分钟内跑通了第一个审查:

  1. 安装 CLI(仅一行命令):

    curl -sSL https://get.open-code-review.dev | sh

    这个脚本会自动检测你的系统(Mac/Linux/WSL),下载对应二进制,校验 SHA256,放入~/.local/bin,并把该路径加入PATH。它不碰你的 Node.js、Python 或任何现有环境,纯粹是独立二进制。如果你公司禁用curl | sh,官网提供 GPG 签名的 tar.gz 包,解压即用。

  2. 初始化配置(交互式,三问定乾坤):

    ocr config init

    它会问:

    • Q1:“你们团队最常被指出的代码问题是什么?” → 她填:“console.log 没删干净”
    • Q2:“哪个目录的代码改动风险最高?” → 她填:“src/core/”
    • Q3:“新同学最容易在哪里出错?” → 她填:“API 请求的 error handling”
      回车后,自动生成.ocr.yml,里面已经预置了三条规则:no-console-log-in-prod、core-dir-high-risk-review、api-error-handling-check。没有冗余选项,全是她刚说的痛点。
  3. 制造一个测试变更(模拟真实场景):

    echo "console.log('debug: user login'); fetch('/api/login')" >> src/core/auth.ts git add src/core/auth.ts git commit -m "WIP: add login api call"
  4. 执行首次审查(见证效果):

    ocr review

    输出立即出现:

    ❗ [critical] no-console-log-in-prod File: src/core/auth.ts:1 Message: console.log detected in core directory. Core code must not contain debug logs. Context: Last 3 commits to this file were all by @backend-team, all related to auth security audit. Fix: Remove line or replace with structured logger. ⚠️ [medium] api-error-handling-check File: src/core/auth.ts:2 Message: fetch() call lacks explicit error handling (try/catch or .catch()). Context: This file has 72% error handling coverage (based on AST analysis of past 10 commits).

    她立刻明白:第一条是硬性红线,必须改;第二条是提醒,可以后续优化。整个过程没打开浏览器,没配 API Key,没装插件,就是命令行里的几行操作。

注意:如果你的项目用了 monorepo(如 Turborepo、Nx),ocr config init会自动检测pnpm-workspace.yaml或nx.json,并在根目录生成.ocr.yml,同时为每个 package 创建./packages/<name>/.ocr.yml继承配置。这是开箱即用的,不用手动配置 workspace。

4.2 集成到 CI:让审查成为流水线的“守门员”,而非“装饰品”

很多团队把 Code Review 工具塞进 CI,结果要么太慢拖垮构建,要么太松变成摆设。open-code-review 的 CI 集成,核心是“只做增量、只报阻断、只输结构”。以下是我们在 GitLab CI 中的真实配置(.gitlab-ci.yml片段):

stages: - test - review code-review: stage: review image: alpine:latest before_script: - apk add curl git - curl -sSL https://get.open-code-review.dev | sh script: - ocr ci --format json > review-report.json artifacts: - review-report.json allow_failure: false # 关键!失败即阻断流水线 rules: - if: $CI_PIPELINE_SOURCE == "merge_request_event" # 仅 PR 触发 - if: $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "main" # 仅合入 main 时检查

这个配置的精妙之处在于三点:

  • allow_failure: false:这是和大多数工具的根本区别。我们不把审查当作“建议”,而是“准入条件”。如果ocr ci返回非零退出码(表示发现 critical 问题),整个流水线立即失败,PR 无法合并。这迫使团队直面问题,而不是“先合再修”。
  • --format json:输出是标准 JSON,字段包括rule_id、file、line、message、severity。GitLab 的 MR Widget 可以直接解析,把审查结果内嵌在 PR 页面里,开发者不用切到 CI 日志。
  • rules限定触发条件:只在 PR 事件且目标分支是main时运行。避免在 feature 分支的日常构建中增加耗时。我们实测,这个 job 在 GitLab Shared Runner(2C4G)上平均耗时 1.7 秒,比一次npm install还快。

更进一步,你可以用ocr ci --threshold medium让它只在发现 medium 及以上问题时失败,或者用--ignore-rules no-console-log-in-prod临时豁免某条规则(需 PR description 里注明原因)。灵活性和强制性,从来不是对立面。

4.3 LLM 层接入:不是“要不要用”,而是“怎么用得聪明”

网络热词里 “codex cli”、“claude code cli” 的搜索量很高,说明大家渴望 AI 能力,但常陷入两个误区:一是把 LLM 当万能钥匙,所有问题都扔给它;二是被 API 调用失败搞崩溃(如 “chatgpt failed to start. unable to locate the codex cli binary”)。open-code-review 的 LLM 接入,设计成“可插拔、可降级、可审计”的模块:

  1. 支持多后端,不绑定单一服务商:
    在.ocr.yml中配置:

    llm: provider: "ollama" # 可选:ollama / openai / anthropic / local-http model: "llama3:70b" # ollama 模型名,或 openai 的 gpt-4-turbo timeout: 30000 # 毫秒

    我们首选 Ollama,因为:

    • 它是本地运行的,不依赖网络,ollama run llama3:70b启动后,ocr就能通过http://localhost:11434调用;
    • 模型可自由更换,ollama pull deepseek-coder:6.7b一行命令切换;
    • 所有 prompt 和 response 都记录在~/.ocr/logs/llm-requests.log,方便审计和调试。
  2. Prompt 工程不是魔法,而是可配置的模板:
    所有 LLM 调用的提示词,都存放在./ocr/prompt/目录下,按规则 ID 命名,如no-hardcoded-urls.j2(Jinja2 模板)。内容类似:

    你是一名资深 {language} 工程师,正在审查一段代码。请严格按以下格式回答: [ANALYSIS] {diff_context} [RULE] {rule_description} [CODE] {code_snippet} [OUTPUT FORMAT] - Risk Level: [low/medium/critical] - Reason: 一句话解释 - Suggestion: 具体修改建议

    这意味着,你可以直接编辑这个文件,调整语气、补充约束、甚至加入公司内部术语。比如把{language}替换成 “TypeScript with strict null checks enabled”,让 LLM 的输出更贴合你的技术栈。

  3. 降级策略保障稳定性:
    如果 LLM 调用超时或失败,ocr不会报错退出,而是自动降级到 Layer 2(Git 上下文分析)的结论,并在输出末尾加一行:
    ⚠️ LLM analysis skipped (timeout). Using git-context fallback.
    这确保了审查流水线永不中断,AI 是锦上添花,不是雪中送炭。

5. 常见问题与排查技巧实录:那些官方文档不会写的“血泪经验”

5.1 “为什么我的规则不生效?”——90% 的问题出在路径匹配

这是咨询量最高的问题。用户写了规则,ocr rules里能看到,但ocr review就是不触发。根源几乎全是路径配置错误。我们整理了一个自查清单:

现象常见原因解决方案
规则完全不触发paths用了绝对路径(如/Users/me/project/src/**)必须用相对路径,从项目根目录开始,如src/**/*.{ts,js}
只匹配部分文件paths用了**/*.ts,但项目用的是.tsx显式列出所有扩展名:**/*.{ts,tsx,js,jsx}
在 monorepo 中不生效paths写了src/**,但实际文件在packages/ui/src/使用**/src/**或为每个 package 单独配置.ocr.yml
新增文件不检查git add后没git commit,直接ocr reviewocr review默认只检查已 commit 的变更。加--staged参数检查暂存区

实操心得:用ocr diff --staged先确认你当前的变更确实被 CLI 捕获了。如果ocr diff输出为空,说明ocr review根本没东西可审。

5.2 “LLM 返回乱码/超时/404”——本地化部署的必经之路

当选择ollama作为 provider 时,新手常遇到三类错误:

  • Error: connect ECONNREFUSED 127.0.0.1:11434:Ollama 服务没启动。解决方案:终端执行ollama serve(保持后台运行),或用brew services start ollama(Mac)设置开机自启。
  • model 'llama3:70b' not found:模型没下载。解决方案:ollama pull llama3:70b,注意磁盘空间(70B 模型约需 140GB SSD 空间)。我们推荐先试llama3:8b(16GB),验证流程后再升级。
  • context length exceeded:LLM 输入太长。解决方案:在.ocr.yml的llm配置下加max_tokens: 2048,并确保ocr review命令加--max-diff-lines 200限制单次审查的 diff 行数。我们规定,超过 200 行的 PR 必须拆分,这是工程纪律,不是工具限制。

5.3 “审查结果太啰嗦/太简略”——定制化输出的黄金参数

ocr review的输出,默认是面向开发者的“友好版”。但不同角色需要不同粒度:

  • 给 Tech Lead 看整体风险:加--summary参数,输出类似:
    ✅ 12 rules passed | ⚠️ 3 medium issues | ❗ 1 critical issue | 📊 87% coverage (vs last week: +2%)
  • 给 CI 解析用:必须加--format json,且配合--threshold critical(只报 critical)。
  • 给新人教学用:加--verbose,它会展开每条规则的匹配逻辑、上下文来源、甚至展示git log命令示例。比如对no-console-log-in-prod,会显示:
    🔍 How we found this: ran 'git log -n 5 --oneline -- src/core/auth.ts' and checked commit messages for 'debug' or 'log'

5.4 “如何让团队接受?不是又一个要学的新工具!”——推行成功的三个心法

技术再好,推不动等于零。我们帮 12 个团队落地 open-code-review,总结出最有效的推行策略:

  1. 从“救火”切入,而非“规范”:不要一上来就说“我们要统一 Code Review 标准”。而是找一个近期高频导致线上故障的问题(如“环境变量未注入导致 staging 500”),用ocr写一条规则,演示它如何在 PR 阶段就捕获。让团队亲眼看到“这个工具帮我避开了上次的坑”。
  2. 给 Reviewer 减负,而非加活:明确告诉 Reviewer:“以后你不用再手动检查 XXX 了,ocr会帮你标出来。你只需要聚焦在ocr无法判断的业务逻辑上。”把工具定位成“助理”,不是“监工”。
  3. 配置权下放,但底线守住:.ocr.yml放在 Git 里,但允许每个 team 在自己的子目录下覆盖配置。总部只维护critical级别规则(如安全、合规),medium和low由各 team 自主定义。这既保证底线,又赋予自主权。

最后分享一个小技巧:在.gitmessage模板里加入一行# Run 'ocr review' to check this change。每次git commit弹出编辑器时,这句话就在那里。不用培训,不用文档,习惯就在日复一日的提交中养成了。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进