ARTICLE · INTELLIGENCE

战地情报 · 详情页

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

开源可插拔代码审查CLI工具:Git+LLM+规则引擎的分层实践

开源可插拔代码审查CLI工具:Git+LLM+规则引擎的分层实践

1. 项目概述:一个真正能落地的开源代码审查 CLI 工具到底长什么样?

“open-code-review”这名字乍看像一句口号,但拆开来看——open不是泛泛而谈的“开源精神”,而是指开放可插拔的模型接入能力、开放可定制的规则引擎、开放可审计的审查过程;code review也不是 IDE 里点几下“Run Inspection”的静态扫描,而是在 Git 提交上下文里,用 LLM 理解真实业务逻辑、识别语义级风险、生成可追溯的修复建议。我过去三年在三个不同规模的团队里推动过代码审查自动化,踩过所有坑:从用 SonarQube 报一堆“高危但无意义”的空指针警告,到接入某商业 LLM 审查服务后发现它连if (user != null && user.getName() != null)都看不懂业务含义,再到自己搭 pipeline 被 prompt 工程拖垮迭代节奏……最终沉淀出的结论很朴素:真正的 open-code-review,必须把“人”的判断权留在链路最前端和最末端,中间环节只做精准提效,而不是越俎代庖。

这个工具的核心价值,不是替代资深工程师,而是让 junior 开发者提交 PR 前就能看到“这段 SQL 为什么在高并发下会锁表”,让 team lead 在合并前快速确认“这个新引入的 SDK 是否存在已知 CVE”,让 QA 同事不用翻几十页文档就能理解“这次改动对支付链路的幂等性影响”。它不依赖特定云厂商、不绑定某个大模型 API、不强制你改写全部开发流程——你只需要在git commit后多敲一行ocr review --staged,它就自动提取变更文件、构造带函数签名与注释的上下文、调用本地或远程 LLM、结构化输出 JSON 格式报告,并支持一键导出为 GitHub/GitLab 评论。关键词open-code-review、CLI、LLM、code review、Git全部落在实操链条上:CLI 是入口形态,Git 是触发场景,LLM 是推理引擎,code review 是交付目标,open 是架构底色。如果你正在被低效的 CR 流程拖慢交付节奏,或者想给团队引入 AI 辅助但又怕失控,这个项目就是为你写的——它不承诺“全自动”,但保证“每一步都可控、可调试、可替换”。

2. 整体设计思路:为什么放弃“端到端黑盒”而选择“分层可插拔”架构?

2.1 拒绝“LLM 万能论”:从三个真实失败案例反推架构原则

先说一个血泪教训:去年帮一家金融客户部署某 SaaS 化代码审查平台,他们要求“开箱即用”,我们直接用了厂商默认配置。结果上线第一周就出事——LLM 把一段处理身份证号脱敏的正则表达式(/^\d{17}[\dXx]$/)判定为“存在硬编码风险”,理由是“数字字面量过多”。更离谱的是,它建议改成Pattern.compile("^\d{17}[\\dXx]$"),反而引入了未转义的反斜杠漏洞。问题根源在哪?不是模型不够强,而是输入上下文缺失关键信息:没有传入该正则所在的类名(IdCardMasker)、没有附带单元测试用例(验证了 18 位校验码逻辑)、没有提供项目级安全规范文档(明确允许身份证正则硬编码)。这让我彻底放弃“喂代码进黑盒→吐报告”的幻想。

第二个案例更典型:团队用codex cli接入飞书机器人,设定“每次 PR 提交自动触发审查”。结果某次提交了 300 行 CSS 变更,LLM 直接超时返回空响应,飞书机器人发了一条“审查完成✅”,实际什么都没干。排查发现codex cli的默认 timeout 是 30s,而大模型处理长文本时 token 计算耗时波动极大,尤其当 prompt 里塞了大量 import 语句和类型定义时。这暴露了CLI 层缺乏弹性熔断机制——不能因为单个文件处理失败就中断整个 PR 审查流。

第三个痛点来自合规:某政务系统要求所有代码审查数据不得出内网。我们尝试用 Ollama 本地跑llama3:70b,但发现模型对 Java Spring Boot 的@Transactional传播行为理解严重偏差,把REQUIRES_NEW错判为“事务嵌套风险”。根本原因在于——通用大模型缺乏领域知识微调,而微调成本又远超团队承受能力。

基于这些教训,“open-code-review”的架构设计坚持三条铁律:

  1. 上下文必须显式构造,而非隐式猜测:不依赖 LLM 自己去“猜”代码意图,而是由 CLI 主动提取 AST 节点、关联 Git Blame 历史、注入 Javadoc 和单元测试片段,形成结构化 context blob;
  2. LLM 调用必须可降级、可超时、可重试:当远程 API 失败时,自动 fallback 到本地小模型(如phi-3:3.8b),并记录降级日志供审计;
  3. 规则引擎必须独立于模型:把“是否使用了不安全的反序列化库”这类确定性检查,交给基于 CVE 数据库的规则匹配器,LLM 只负责解释“为什么这个反序列化调用在当前上下文中特别危险”。

提示:很多团队一上来就想“用最强模型”,结果陷入 prompt 调优泥潭。我的经验是——先用phi-3跑通全链路,再逐步替换为更强模型。因为 90% 的 CR 问题本质是上下文组织问题,不是模型能力问题。

2.2 四层解耦架构:每个模块都能独立替换

整个工具按职责划分为四个物理隔离层,通过标准接口通信:

层级名称职责可替换性示例
L1Git Context Builder解析git diff输出,提取变更文件、行号范围、关联 commit message;调用tree-sitter生成 AST,提取函数签名、参数类型、注释文本支持替换为git-delta增强 diff 渲染,或集成syntect实现语法高亮
L2Context Orchestrator组装 L1 输出 + 项目元数据(如pom.xml中的依赖版本、.editorconfig缩进规则),生成标准化 JSON context 对象;内置缓存机制避免重复解析相同文件可接入企业知识库 API,动态注入内部 SDK 文档片段
L3LLM Adapter封装不同 LLM 调用方式:OpenAI 兼容 API、Ollama REST、本地 GGUF 加载;统一处理 token 计数、streaming 响应、JSON Schema 强制输出替换为llama-cpp-python直接加载.gguf文件,绕过 HTTP 开销
L4Review Renderer解析 L3 返回的 JSON 结构(含 severity、file、line、message、suggestion 字段),渲染为终端 ANSI 彩色输出 / GitHub Markdown 评论 / JUnit XML 报告导出为 SonarQube Generic Issue Format,无缝接入现有 CI 系统

这种设计带来两个关键收益:一是故障隔离——当 L3 层 LLM 调用失败,L4 仍能输出 L1/L2 的静态分析结果(如“检测到未使用的 import”);二是渐进升级——团队可以先用 L3 的ollama run phi-3跑通流程,半年后再把 L3 替换为openai.ChatCompletion.create(model="gpt-4o"),其他层完全无感。

2.3 为什么坚持 CLI 形态?不是 GUI 或 IDE 插件

有人问:“为什么不做 VS Code 插件?”答案很实在:CLI 是唯一能穿透所有开发环境的通用接口。我们团队有三类开发者:前端用 VS Code、后端用 IntelliJ、运维用 Vim —— 如果只做 IDE 插件,就得维护三套代码,且无法在 CI 流水线中复用。而 CLI 只需一个二进制文件,curl -L https://github.com/xxx/ocr/releases/download/v1.2.0/ocr-linux-amd64 -o /usr/local/bin/ocr,然后chmod +x /usr/local/bin/ocr,立刻生效。

更重要的是,CLI 天然契合 Git 工作流。我们把ocr注册为 Git 的pre-commithook:

# .git/hooks/pre-commit #!/bin/sh # 在 git commit 前自动运行审查 if ! ocr review --staged --fail-on-critical; then echo "❌ open-code-review 发现严重问题,请修复后重试" exit 1 fi

这样 junior 开发者在本地提交时就收到即时反馈,而不是等 CI 运行 15 分钟后才在 GitHub 上看到红叉。实测数据显示,采用 pre-commit hook 后,PR 中被拒的“明显低级错误”(如空指针、SQL 注入漏洞)下降 67%。GUI 和 IDE 插件永远做不到这种深度工作流集成——它们只是“锦上添花”,而 CLI 是“雪中送炭”。

3. 核心细节解析:从 Git Diff 到结构化审查报告的完整链路

3.1 Git Context Builder:如何把原始 diff 变成 LLM 能懂的“业务语言”

LLM 理解代码的最大障碍,不是语法,而是缺少执行上下文。一段user.getName()调用,在 UserService 里可能是安全的,在 PaymentService 里却可能因上游未校验导致 NPE。open-code-review的 Context Builder 正是解决这个问题的关键模块。

它的工作流程分三步:

第一步:精准定位变更范围
不简单用git diff --name-only,而是解析git diff -U0的 unified diff 格式,提取每个文件的变更块(hunk)。例如:

diff --git a/src/main/java/com/example/UserService.java b/src/main/java/com/example/UserService.java index abc123..def456 100644 --- a/src/main/java/com/example/UserService.java +++ b/src/main/java/com/example/UserService.java @@ -45,0 +46,3 @@ public class UserService { + public User getUserById(Long id) { + return userRepository.findById(id).orElse(null); + }

Context Builder 会记录:文件路径src/main/java/com/example/UserService.java,新增行号46-48,变更类型ADD。这比单纯知道“修改了 UserService.java”精确 100 倍。

第二步:AST 驱动的语义提取
用tree-sitter-java解析变更行所在函数的完整 AST:

{ "type": "method_declaration", "name": "getUserById", "parameters": [{"type": "long", "name": "id"}], "return_type": "User", "body": { "type": "return_statement", "expression": { "type": "method_invocation", "object": "userRepository", "method": "findById", "arguments": ["id"] } } }

同时提取该方法的 Javadoc(如果有):

/** * 根据用户ID查询用户信息 * @param id 用户唯一标识,非空 * @return 用户对象,不存在时返回 null */

第三步:注入项目级元数据
自动读取项目根目录下的配置文件:

  • pom.xml→ 提取spring-boot-starter-web版本(用于判断是否支持@Valid注解)
  • .editorconfig→ 获取indent_style = space,避免 LLM 误判缩进风格问题
  • SECURITY.md→ 加载自定义规则:“禁止在 controller 层直接返回 entity,必须封装为 DTO”

最终组装的 context JSON 示例(精简版):

{ "file": "src/main/java/com/example/UserService.java", "hunk_start_line": 46, "hunk_end_line": 48, "ast": { /* 上述 AST 结构 */ }, "javadoc": "根据用户ID查询用户信息...", "project_metadata": { "framework": "spring-boot-3.2.0", "security_policy": ["禁止controller返回entity"] } }

注意:Context Builder 默认跳过test/、resources/目录下的文件,但可通过--include-test参数开启。实测发现,80% 的误报来自测试代码被当作生产逻辑分析——比如 Mockito 的when().thenReturn()被 LLM 误判为“硬编码返回值”。

3.2 Context Orchestrator:如何让 LLM “专注思考”而非“费力阅读”

LLM 的 token 限制是硬伤。一个 2000 行的 Java 文件,光源码就超 10k tokens,根本塞不进gpt-4o的 128k 上下文。Orchestrator 的核心任务,就是用最少的 tokens 传递最多的信息。

它采用“三层压缩策略”:

Layer 1:语法级压缩

  • 移除所有空白符和注释(保留 Javadoc,因其含业务语义)
  • 将private final UserService userService;压缩为UserService userService;
  • 用占位符替换长字符串:"SELECT * FROM users WHERE id = ?"→"SQL_QUERY_PLACEHOLDER"

Layer 2:语义级聚焦
只保留与变更行直接相关的代码片段:

  • 向上追溯 3 层调用栈(通过tree-sitter分析getUserById被哪些 controller 调用)
  • 向下提取被调用的userRepository.findById方法签名(含其 interface 定义)
  • 关联该文件的单元测试中@Test方法名(如shouldReturnNullWhenIdNotFound)

Layer 3:向量化摘要
对压缩后的文本,用轻量级 embedding 模型(如all-MiniLM-L6-v2)生成 384 维向量,存入本地 SQLite。下次遇到相似变更(如另一个findById调用),直接召回历史审查结论,避免重复 LLM 调用。

最终发送给 LLM 的 prompt 结构如下(以gpt-4o为例):

你是一名资深 Java 架构师,正在审查以下代码变更。请严格按 JSON Schema 输出,不要任何额外文字。 [CONTEXT] - 文件: UserService.java - 变更: 新增 getUserById 方法(行46-48) - 关键 AST: method_declaration(name="getUserById", parameters=[long id], return_type=User) - Javadoc: "根据用户ID查询用户信息,id非空,不存在时返回null" - 项目框架: spring-boot-3.2.0 - 安全策略: 禁止controller返回entity [CODE SNIPPET] public User getUserById(Long id) { return userRepository.findById(id).orElse(null); } [INSTRUCTIONS] 1. 判断是否存在空指针风险(考虑 findById 返回 Optional) 2. 检查是否符合安全策略(controller 层调用此方法是否违规) 3. 给出具体改进建议(含代码示例) 4. 严重等级:critical / high / medium / low [OUTPUT SCHEMA] { "severity": "medium", "message": "findById.orElse(null) 可能导致调用方 NPE,建议改为 orElseThrow() 或封装为 Optional<User>", "suggestion": "return userRepository.findById(id).orElseThrow(() -> new UserNotFoundException(id));", "references": ["https://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/repository/CrudRepository.html#findById(ID)"] }

实测表明,这种结构化 prompt 使gpt-4o的 JSON 输出成功率从 62% 提升至 98.3%,且平均 token 消耗降低 41%。

3.3 LLM Adapter:如何让不同模型“说同一种语言”

Adapter 层的核心挑战,是抹平各家 LLM API 的差异,同时保留各自优势。我们不追求“一套 prompt 走天下”,而是为每个模型定制最佳实践。

OpenAI 兼容 API(GPT-4o、Claude-3)

  • 启用response_format: { "type": "json_object" }强制 JSON 输出
  • 设置temperature: 0.1降低随机性(CR 场景不需要创意)
  • max_tokens动态计算:基于 context token 数 × 1.5,避免截断

Ollama(phi-3、llama3)

  • 使用--format json参数启动模型(需模型本身支持)
  • 关键技巧:在 system prompt 末尾添加"Output ONLY valid JSON. No explanations.",实测比单纯设 temperature 更有效
  • 启用num_ctx: 16384避免长上下文截断

本地 GGUF(Qwen2、DeepSeek-Coder)

  • 通过llama-cpp-python直接加载.gguf文件,绕过 HTTP 开销
  • 关键参数:n_threads=8(充分利用 CPU 核心),n_gpu_layers=35(若 GPU 显存 ≥ 12GB)

Adapter 还内置智能降级策略:

  1. 首先尝试调用OLLAMA_HOST=http://localhost:11434 ocr review
  2. 若超时(>15s)或返回非 JSON,则自动切换到OPENAI_API_KEY=sk-xxx ocr review --model gpt-3.5-turbo
  3. 若 OpenAI 也失败,最后 fallback 到本地qwen2-0.5b.Q4_K_M.gguf(500ms 内必响应)

所有调用均记录详细日志:

2024-06-15 14:22:31 INFO [LLMAdapter] Using model: phi-3:3.8b, context_tokens: 2187, response_time: 8.3s 2024-06-15 14:22:32 WARN [LLMAdapter] Fallback triggered: phi-3 timeout >10s, switching to gpt-3.5-turbo

实操心得:别迷信“最强模型”。我们对比过gpt-4o和phi-3对同一段 Spring Boot 代码的审查——gpt-4o在 CVE 识别上略优(+3%),但phi-3对@Transactional传播行为的理解准确率反而高 12%。原因?phi-3在训练时接触了更多开源 Java 项目。选模型要“看菜下饭”,不是“越大越好”。

4. 实操过程详解:从零安装到生产级 CI 集成

4.1 三步极速安装:适配 Windows/macOS/Linux

安装过程刻意设计为“无依赖、无编译、无网络阻塞”,所有二进制文件预编译好:

macOS(Intel/Apple Silicon)

# 下载并安装(自动识别芯片架构) curl -L https://github.com/open-code-review/ocr/releases/download/v1.3.0/ocr-darwin-arm64 -o /usr/local/bin/ocr chmod +x /usr/local/bin/ocr # 验证安装 ocr --version # 输出:open-code-review v1.3.0 (commit abc123)

Windows(PowerShell)

# 下载到 C:\tools\ Invoke-WebRequest -Uri "https://github.com/open-code-review/ocr/releases/download/v1.3.0/ocr-windows-amd64.exe" -OutFile "C:\tools\ocr.exe" # 添加到 PATH $env:Path += ";C:\tools" [Environment]::SetEnvironmentVariable("Path", $env:Path, [EnvironmentVariableTarget]::Machine) # 验证 ocr --version

Linux(通用 x86_64)

wget https://github.com/open-code-review/ocr/releases/download/v1.3.0/ocr-linux-amd64 -O /usr/local/bin/ocr chmod +x /usr/local/bin/ocr

注意:所有二进制文件均通过upx压缩,ocr-linux-amd64仅 8.2MB。实测在 10Mbps 带宽下 5 秒内下载完成,比git clone整个仓库快 20 倍。

4.2 首次运行:用--dry-run理解审查逻辑

切忌直接ocr review!先用--dry-run查看 Context Builder 如何解析你的代码:

# 进入任意 Git 仓库,模拟一次变更 git checkout -b feature/user-service echo "public class Dummy {}" >> src/main/java/com/example/Dummy.java git add src/main/java/com/example/Dummy.java # 查看将要发送给 LLM 的上下文 ocr review --staged --dry-run

输出示例:

{ "context": { "file": "src/main/java/com/example/Dummy.java", "hunk_start_line": 1, "hunk_end_line": 1, "ast": {"type": "class_declaration", "name": "Dummy"}, "project_metadata": {"framework": "unknown", "security_policy": []} }, "llm_request": { "model": "phi-3:3.8b", "prompt_tokens": 187, "max_tokens": 512 } }

这个命令不会调用 LLM,只展示 Context Builder 的输出。你可以检查:

  • hunk_start_line是否准确(避免误判整个文件)
  • project_metadata.framework是否识别出 Spring Boot(若未识别,检查pom.xml是否在根目录)
  • security_policy是否加载了自定义规则文件

4.3 模型配置:本地 Ollama vs 远程 OpenAI 的实测对比

open-code-review默认使用本地 Ollama,但需先启动服务:

# macOS/Linux 启动 Ollama brew install ollama # macOS # 或 curl -fsSL https://ollama.com/install.sh | sh # Linux # 拉取推荐模型(国内镜像加速) OLLAMA_BASE_URL=https://mirrors.ustc.edu.cn/ollama/ ollama pull phi-3:3.8b OLLAMA_BASE_URL=https://mirrors.ustc.edu.cn/ollama/ ollama pull llama3:8b # 验证模型可用 ollama list # NAME ID SIZE MODIFIED # phi-3:3.8b 1a2b3c... 2.1GB 2 hours ago

配置文件~/.ocr/config.yaml示例:

llm: provider: ollama # 可选:openai, ollama, local_gguf model: phi-3:3.8b timeout: 15 max_retries: 2 # 自定义规则(覆盖默认规则) rules: - id: "avoid-null-return" pattern: "orElse\\(null\\)" severity: "medium" message: "orElse(null) 可能导致调用方 NPE" suggestion: "使用 orElseThrow() 或返回 Optional" # 项目级覆盖 projects: "/path/to/your/project": llm: model: "gpt-4o" api_key: "sk-xxx" rules: - id: "custom-payment-rule" pattern: "PaymentService.*process.*" severity: "critical"

实测性能对比(审查 1 个 50 行 Java 方法):

模型平均响应时间JSON 成功率内存占用适合场景
phi-3:3.8b(Ollama)8.2s96.7%2.1GB本地开发、CI 测试环境
gpt-3.5-turbo(OpenAI)2.1s98.3%<100MB生产环境、高并发审查
qwen2-0.5b(GGUF)0.4s89.1%1.2GB离线环境、边缘设备

提示:首次运行ocr review时,Ollama 会自动下载模型。如果遇到failed to pull model,请检查OLLAMA_BASE_URL是否指向可用镜像(清华、中科大镜像在国内稳定)。

4.4 生产级 CI 集成:GitHub Actions 完整配置

将ocr集成到 CI 是价值最大化的关键。以下是经过 12 个团队验证的 GitHub Actions 配置:

# .github/workflows/code-review.yml name: Open Code Review on: pull_request: types: [opened, synchronize, reopened] jobs: review: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: fetch-depth: 0 # 必须获取完整历史,用于 git blame # 安装 ocr(预编译二进制,无需编译) - name: Install open-code-review run: | curl -L https://github.com/open-code-review/ocr/releases/download/v1.3.0/ocr-linux-amd64 -o /tmp/ocr chmod +x /tmp/ocr sudo mv /tmp/ocr /usr/local/bin/ocr # 安装 Ollama(可选,若用远程模型可跳过) - name: Install Ollama run: | curl -fsSL https://ollama.com/install.sh | sh # 拉取模型(仅首次运行需要,后续缓存) - name: Pull phi-3 model if: always() run: ollama pull phi-3:3.8b || true # 执行审查 - name: Run open-code-review id: ocr run: | # 设置超时防止卡死 timeout 120s ocr review \ --pr-number ${{ github.event.number }} \ --fail-on-high \ --output-format github-pr-comment \ --report-file /tmp/ocr-report.json || true # 发布审查结果到 PR 评论 - name: Post review comments if: always() uses: actions/github-script@v6 with: script: | const report = require('/tmp/ocr-report.json'); if (report.results && report.results.length > 0) { const comment = `## 🧠 open-code-review 报告\n\n${report.results.map(r => `- [${r.severity.toUpperCase()}] ${r.file}:${r.line} ${r.message}` ).join('\n')}`; github.rest.issues.createComment({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, body: comment }); }

关键设计点说明:

  • fetch-depth: 0:确保git blame能获取历史作者信息,用于判断“谁写的这段有风险的代码”
  • timeout 120s:硬性超时,避免 Ollama 模型加载失败导致整个 CI 卡住
  • || true:即使审查失败(如模型崩溃),也不中断 CI,保证构建流程不被阻塞
  • --fail-on-high:仅当出现 high/critical 级别问题时,才让 CI step 失败(可配置为--fail-on-critical)

实测效果:在 500 行变更的 PR 上,该 workflow 平均耗时 42s,其中ocr review占 31s(主要耗时在模型推理),比传统 SonarQube 扫描快 3.2 倍。

4.5 高级技巧:用--template自定义审查维度

默认审查聚焦“安全、性能、可维护性”,但业务团队常需定制维度。ocr支持 Jinja2 模板驱动的审查:

# 创建自定义模板 cat > payment-template.j2 << 'EOF' { "review_points": [ {% for file in files %} {% if "Payment" in file.name %} { "file": "{{ file.name }}", "line": {{ file.hunk_start_line }}, "severity": "critical", "message": "支付相关代码必须通过 PCI-DSS 合规检查", "suggestion": "请提交至安全团队进行专项审计" } {% endif %} {% endfor %} ] } EOF # 运行模板审查 ocr review --staged --template payment-template.j2 --output-format json

更强大的是结合jq进行动态规则:

# 检查所有 SQL 字符串是否包含参数化占位符 ocr review --staged --template '{ "sql_injection_check": [ {% for line in git_diff_lines %} {% if "String sql =" in line and "?" not in line %} { "file": "{{ file }}", "line": {{ loop.index }}, "severity": "critical", "message": "SQL 字符串未使用参数化查询,存在注入风险" } {% endif %} {% endfor %} ] }' | jq '.sql_injection_check[]'

实操心得:模板不是万能的,但它是连接“LLM 智能”和“业务规则”的桥梁。我们有个电商团队,用模板强制所有OrderService方法必须包含@Transactional注解,漏写直接 CI 拒绝合并——这比靠人工 Code Review 可靠 100 倍。

5. 常见问题与排查技巧实录:那些文档里不会写的坑

5.1 “Unable to locate the codex cli binary” 类错误的根因分析

这个错误看似是路径问题,实则暴露了更深层的架构认知偏差。open-code-review与codex cli的根本区别在于:

维度codex cliopen-code-review
定位方式依赖PATH中的codex二进制自包含二进制,无外部依赖
模型加载必须提前codex install模型模型由 Ollama 管理,ocr只调用 API
配置存储~/.codex/config.json~/.ocr/config.yaml

所以当你看到unable to locate the codex cli binary,第一反应不应该是“加 PATH”,而是“你在混用两个工具”。正确做法:

  1. 彻底卸载codex:npm uninstall -g codex-cli或pip uninstall codex-cli
  2. 删除残留配置:rm -rf ~/.codex
  3. 重新安装ocr:按 4.1 节步骤操作

注意:某些教程教你在package.json里写"scripts": {"review": "codex review"},这会导致npm run review时优先找node_modules/.bin/codex,而非全局ocr。解决方案是显式指定路径:"review": "/usr/local/bin/ocr review"

5.2 LLM 返回不稳定?先检查这三个隐藏开关

Dify 的 SQL 查询内容太多导致 LLM 返回不稳定,本质是上下文膨胀失控。open-code-review提供三个关键开关:

开关 1:--max-context-lines(默认 200)
限制发送给 LLM 的代码行数。实测超过 300 行时,gpt-4o的 JSON 解析失败率飙升至 35%。建议:

  • Java/Python 项目:设为150
  • 前端项目(JSX 复杂):设为100
  • 配置文件(YAML/JSON):设为50

开关 2:--skip-large-files(默认 >500KB)
自动跳过超大文件(如生成的 protobuf 文件)。避免 LLM 被无关内容干扰。

开关 3:--cache-dir(默认~/.ocr/cache)
启用 SQLite 缓存,对相同变更哈希(SHA256 of context)直接返回历史结果。实测在持续集成中,缓存命中率达 63%,平均提速 2.8 倍。

排查命令:

# 查看实际发送的上下文大小 ocr review --staged --dry-run | jq '.context | length' # 查看缓存命中情况 ls -lh ~/.ocr/cache/*.db

5.3 Git 配置陷阱:为什么git -c diff.mnemonicprefix=false会影响审查?

这个 Git 配置关闭了“记忆前缀”(如origin/main→o/main),看似只是显示优化,实则破坏了ocr的分支识别逻辑。ocr在 PR 模式下需要知道 base branch 名称来:

  • 获取 base branch 的pom.xml版本(对比当前变更)
  • 执行git merge-base计算共同祖先(确定最小审查范围)

当mnemonicprefix=false时,git rev-parse --abbrev-ref origin/HEAD返回origin/HEAD而非main,导致ocr无法识别 base branch。

修复方案:

# 永久修复(推荐) git config --global diff.mnemonicprefix true # 或临时修复(CI 中) git -c diff.mnemonicprefix=true ocr review --pr-number 123

提示:git -c core.quotepath=false也是常见陷阱——它禁用路径转义,导致含空格的文件名

RELATED READING

延伸阅读

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