开源代码评审范式:基于Git Diff与LLM的CLI驱动质量门禁
1. 项目概述这不是一个“工具”而是一套可嵌入开发流程的开源代码评审范式“open-code-review”这个词乍看像某个具体软件的名字但实际它代表的是一种正在快速演进的工程实践——把大语言模型LLM作为代码评审环节的常态化协作者且整个评审逻辑、提示词工程、上下文构建、结果呈现全部开源、可审计、可定制。我从去年开始在三个不同规模的团队里落地这套方案从最初用现成的 CLI 工具跑通 Git diff 分析到后来自己重写核心调度器、替换 embedding 模型、对接内部知识库再到最近把评审结论自动同步进 Jira 和飞书多维表格整个过程踩过太多坑也验证了几个关键判断第一真正能落地的代码评审 Agent80% 的工作量不在 LLM 调用本身而在如何精准喂给它“该看什么”第二“open”不是指开源许可证而是指评审链路全程透明——谁触发的、用了哪个 prompt 版本、上下文截取范围、模型输出原始 token、人工复核记录全部可追溯第三CLI 不是终端玩具它是连接 IDE、CI 流水线、协作平台的协议层就像当年 curl 之于 HTTP它定义了人机协同的最小交互契约。这个项目最常被误解的点就是把它当成另一个“AI 代码助手”。但它解决的不是“怎么写代码”而是“怎么确认代码写对了”。传统 Code Review 是靠人眼扫描变更、比对规范、质疑设计耗时长、易疲劳、标准难统一而 open-code-review 的目标是让 LLM 先完成 70% 的机械性检查——比如是否违反团队命名约定、是否有未处理的 panic 分支、HTTP handler 是否缺少 rate limit、SQL 查询是否遗漏索引 hint、日志字段是否缺失 trace_id——把这些低阶但高频的问题筛出来再把剩余 30% 需要领域判断、架构权衡、业务语义理解的部分交给人类 reviewer 做深度决策。它不替代人而是把人从“找错”中解放出来专注“判对”。适合两类人一是技术负责人想建立可量化的代码质量基线二是资深工程师想把多年经验沉淀为机器可执行的规则三是中小团队没有专职 QA 或 SRE需要低成本建立基础防护网。如果你还在用 GitHub Copilot 写代码、用 SonarQube 查漏洞、用人工 checklist 过 PR那 open-code-review 就是你下一步该搭的“中间件”。2. 核心设计思路为什么必须从 CLI 入口切入而不是直接集成 IDE 或 Web UI2.1 CLI 是唯一能同时满足“确定性”、“可审计性”和“流水线友好”的入口很多人一上来就想做 VS Code 插件或 Web 界面我试过两次全推翻重来。根本原因在于IDE 插件运行环境不可控——用户装什么版本 Node.js、有没有全局 proxy、本地模型是否加载成功、GPU 显存是否够用这些变量会让评审结果忽好忽坏而代码质量评审最怕的就是“有时准、有时不准”。Web UI 更麻烦它天然引入状态管理、权限隔离、跨域请求、前端渲染延迟等问题当你需要在 CI 中自动触发评审时还得额外写一套 API 代理等于把简单问题复杂化。而 CLI 天生就符合 Unix 哲学“做一件事并做好”。它只接收明确输入git diff 输出、文件路径、配置文件只输出结构化结果JSON/Markdown中间不保存状态、不依赖 GUI、不弹窗、不联网除非你显式指定。我在某电商中台项目里部署时把open-code-reviewCLI 直接塞进 GitLab CI 的before_script阶段只要 PR 提交就会自动拉取 diff、调用本地 Ollama 加载 CodeLlama-7b、生成评审报告、失败时阻断合并。整个过程耗时稳定在 42±5 秒实测 1000 次误差来自磁盘 IO跟网络抖动完全无关。这种确定性是任何图形界面都无法提供的硬性保障。提示不要试图用npx或pip install方式分发 CLI。我们最终采用 Go 编译单二进制文件 SHA256 校验 内部 Nexus 仓库托管的方式。理由很实在Go 二进制无运行时依赖SHA256 防止中间人篡改Nexus 保证所有团队成员下载的是同一版本。曾有团队用npm install -g open-code-review结果因某次 npm registry 临时故障导致 37 个 CI job 全部卡在安装阶段损失 2.3 人日。2.2 “open” 的真实含义评审链路的每个环节都必须可替换、可调试、可回滚“open-code-review”里的 open不是指源码开源虽然它确实是 MIT 协议而是指整个评审管道pipeline的每个环节都暴露为独立模块且接口标准化。我们拆解出五个核心组件Diff 解析器diff-parser负责把git diff原始输出转成结构化变更描述。不用正则硬匹配而是用 libgit2 绑定解析确保能正确识别 rename、copy、binary 文件等边界情况上下文提取器context-extractor根据变更行号向前向后抓取最多 200 行代码同时注入相关 import 语句、类型定义、单元测试片段。这里的关键是“相关性”——不是简单取前后 N 行而是用 CodeBERT 计算语义相似度动态决定提取范围Prompt 编排器prompt-orchestrator把提取的上下文、团队编码规范 Markdown、历史评审案例 JSON按固定模板拼合成 LLM 输入。我们坚持不用 LangChain而是手写模板引擎因为 LangChain 的抽象层会吞掉关键 debug 信息比如某次发现评审漏报 null pointer追查发现是 LangChain 自动 truncation 把关键 if 条件截掉了LLM 调度器llm-router支持同时配置多个后端Ollama 本地模型、OpenAI API、自建 vLLM 服务。调度策略不是轮询而是按“变更类型”路由——比如前端 JSX 变更走 Claude后端 Rust 变更走 CodeLlamaSQL 变更走专门微调的 SQLCoder结果归一化器result-normalizer把不同模型返回的非结构化文本强制映射到统一 schema{file, line, severity: critical|high|medium|low, message, suggestion, rule_id}。这是后续做质量趋势分析的基础。这五个组件全部通过 JSON Schema 定义输入输出彼此之间用 stdin/stdout 管道通信。这意味着你可以单独替换 context-extractor 用更激进的语义提取算法或者把 llm-router 换成支持 MoE 架构的新调度器而无需改动其他模块。去年我们把 prompt-orchestrator 从 Jinja2 切换到 Handlebars只花了 3 小时就完成因为接口契约没变。2.3 为什么必须深度绑定 git diffs而不是文件内容所有成功的 open-code-review 实践都始于对git diff的敬畏。我见过太多团队犯同一个错误直接把修改后的完整文件丢给 LLM。后果很严重——LLM 会陷入“上下文幻觉”比如看到新加入的if err ! nil { return err }却不知道这个 err 是从哪来的上游函数签名是否已改从而给出错误建议。而git diff天然携带了变更的“意图信号” 行是新增逻辑- 行是废弃代码 行标出了精确的变更位置。我们的 diff-parser 会额外解析出这些元信息hunk_header标识变更块在原文件中的起始行号和长度similarity_index用于识别 rename 操作如similarity index 95%避免把重命名误判为删除新增old_mode/new_mode区分文件权限变更这类变更通常无需 LLM 评审index old-hash..new-hash用于关联 Git 对象后续可快速定位 commit message 和 author。实操中我们要求所有评审必须基于git diff --no-color --unified0输出即最小 diff 格式因为它去除了无关空格和颜色控制符减少 LLM token 浪费。一个典型 diff 片段如下diff --git a/internal/service/user.go b/internal/service/user.go index abc123..def456 100644 --- a/internal/service/user.go b/internal/service/user.go -45,0 46,5 func (s *Service) CreateUser(ctx context.Context, req *CreateUserReq) (*CreateUserResp, error) { if req.Name { return nil, errors.New(name cannot be empty) } if len(req.Email) 254 { return nil, errors.New(email too long) }这个 diff 明确告诉 LLM你在第 46 行开始新增了 5 行校验逻辑且只影响CreateUser函数。LLM 不需要知道整个user.go文件长什么样只需要聚焦这 5 行与周边 3 行上下文提取器自动补全的关系。这直接把单次评审 token 消耗从 4000 降到 800 以内响应速度提升 3.2 倍更重要的是误报率下降 68%——因为 LLM 不再被无关代码干扰。3. 核心细节解析从 git diff 到可操作评审结论的七步实操链3.1 第一步标准化 diff 获取与清洗实操耗时2 分钟不要直接用git diff HEAD~1这在 CI 环境中极不稳定。正确做法是使用git diff $CI_MERGE_REQUEST_TARGET_SHA...$CI_COMMIT_SHAGitLab CI或git diff origin/main...HEADGitHub Actions确保对比基准始终是目标分支最新状态。我们封装了一个get-diff.sh脚本#!/bin/bash # get-diff.sh set -e # 支持多种 CI 环境自动探测 if [ -n $GITLAB_CI ]; then BASE_REF$CI_MERGE_REQUEST_TARGET_SHA HEAD_REF$CI_COMMIT_SHA elif [ -n $GITHUB_ACTIONS ]; then BASE_REForigin/$GITHUB_BASE_REF HEAD_REFHEAD else BASE_REForigin/main HEAD_REFHEAD fi # 生成最小化 diff过滤掉 .gitignore 中的文件、vendor 目录、test 文件 git diff --no-color --unified0 $BASE_REF $HEAD_REF \ --diff-filterAM \ --ignore-cr-at-eol \ --no-renames \ | grep -v ^\(diff\|index\|---\|\|\) \ | sed /^$/d \ /tmp/pr-diff.patch关键参数说明--diff-filterAM只保留 Added 和 Modified 文件忽略 Deleted删除文件无法评审、Renamed重命名由 diff-parser 处理--ignore-cr-at-eol防止 Windows/Linux 换行符差异导致 diff 失真--no-renames关闭重命名检测交给后续 parser 处理避免 git 自动 rename 逻辑干扰grep -v和sed组合剥离 diff 头部元信息只保留和-行为后续结构化解析做准备。注意这个脚本必须在 CI job 的before_script阶段运行且/tmp/pr-diff.patch路径需全局可读。曾有团队把 diff 存在$HOME/.cache下结果因 CI runner 重用容器缓存被污染导致评审结果错乱。3.2 第二步Diff 结构化解析实操耗时5 分钟含调试我们不用正则而是用libgit2的 Go bindinggo-git库解析 patch。核心代码逻辑如下func ParseDiff(patchContent string) ([]*DiffHunk, error) { // 用 go-git 的 Patch 解析器而非字符串分割 patch, err : git.ParsePatch(strings.NewReader(patchContent)) if err ! nil { return nil, fmt.Errorf(parse patch failed: %w, err) } var hunks []*DiffHunk for _, file : range patch.Files { // 过滤掉二进制文件、vendor、test 文件 if strings.Contains(file.Path, vendor/) || strings.HasSuffix(file.Path, _test.go) || file.IsBinary() { continue } for _, hunk : range file.Hunks { // 提取变更行号范围 oldStart : hunk.OldStart oldLines : hunk.OldLines newStart : hunk.NewStart newLines : hunk.NewLines // 构建结构化 Hunk hunkObj : DiffHunk{ FilePath: file.Path, OldRange: fmt.Sprintf(%d,%d, oldStart, oldLines), NewRange: fmt.Sprintf(%d,%d, newStart, newLines), Additions: extractLines(hunk.Lines, ), Deletions: extractLines(hunk.Lines, -), } hunks append(hunks, hunkObj) } } return hunks, nil }extractLines函数会遍历hunk.Lines只提取以开头的新增行去掉符号并记录其在新文件中的绝对行号。这个绝对行号至关重要——它是后续 context-extractor 定位上下文的锚点。我们曾用纯正则解析结果在处理多行字符串字面量如sql : SELECT * FROM users\nWHERE id ?时正则把\n当作换行符误切导致行号偏移上下文提取错位。而go-git的 parser 原生支持 Git patch 格式完全规避此问题。3.3 第三步上下文智能提取实操耗时15 分钟含模型微调上下文不是简单地取变更行前后各 10 行。我们采用两阶段提取阶段一静态上下文Static Context基于 AST 分析提取变更行所在函数、结构体、import 块。用gofumptGo或tree-sitter多语言解析源码获取精确作用域。例如当 diff 新增一行return err静态上下文会自动包含所在函数签名func (s *Service) CreateUser(...);函数参数类型定义type CreateUserReq struct { Name string };上游 importerrors和github.com/xxx/pkg/errors。阶段二语义上下文Semantic Context用 CodeBERT 模型计算变更行与文件其他部分的语义相似度动态扩展。具体流程将变更行如if req.Name {和文件所有函数声明分别编码为向量计算余弦相似度取 top-3 最相似的函数将这些函数的完整定义加入上下文。我们微调了一个轻量版 CodeBERT仅 110M 参数在内部代码库上 fine-tune 3 个 epoch使相似度计算准确率从 62% 提升到 89%。微调数据来自历史 PR 评审记录——把被人工标记为“相关”的函数对作为正样本随机采样作为负样本。这个模型打包进 CLI 二进制启动时自动加载无需联网。实操心得语义上下文提取耗时占整个流程 40%但我们发现当变更行数 ≤ 3 时可以跳过语义提取只用静态上下文速度提升 2.7 倍且准确率无损。我们在 CLI 中加了--fast-mode开关CI 默认开启人工触发评审时关闭。3.4 第四步Prompt 工程编排实操耗时30 分钟含 A/B 测试Prompt 不是写一段话扔给 LLM而是一个精密的装配过程。我们的prompt-orchestrator接收三个输入context.json结构化上下文来自步骤 3rules.md团队编码规范如 “error handling 必须用 pkg/errors.Wrap”examples.json历史高质量评审案例格式{input_diff, output_review}。编排逻辑如下你是一名资深 [语言] 工程师正在评审以下代码变更。 请严格遵循以下规则 1. 只评论 diff 中的 行不评论 - 行 2. 每条评论必须包含文件路径、行号、严重等级critical/high/medium/low、具体问题、改进建议 3. 严重等级定义critical可能导致 panic/crashhigh违反核心规范medium可读性/维护性问题low风格建议 4. 不要解释原理只给可操作结论。 团队规范 {{.Rules}} 相关上下文 {{.Context}} 历史优秀案例 {{.Examples}} 待评审 diff {{.Diff}}关键技巧规则注入rules.md不是静态文件而是由 CI 自动从 Confluence 文档生成确保规范永远最新案例蒸馏examples.json每周由 Tech Lead 从 Slack 评审频道手动筛选 5 条最佳评论用脚本自动格式化入库防幻觉指令明确要求“只评论 行”并禁止解释大幅降低 LLM 自说自话概率。我们做过 A/B 测试用相同 diff 输入对比“无规则提示”、“仅规则提示”、“规则案例提示”三种模式。结果显示“规则案例”模式的 critical 问题检出率最高92%且 suggestion 可采纳率达 78%远超其他模式。3.5 第五步LLM 调度与结果归一化实操耗时10 分钟含 fallback 设计llm-router不是简单转发请求。它实现三级 fallback主通道本地 Ollama CodeLlama-7b响应 8s备通道vLLM 集群 DeepSeek-Coder-33B响应 15s用于复杂逻辑兜底通道OpenAI GPT-4-turbo仅当前两通道连续 3 次 timeout 时启用且需人工审批。每次调用都记录请求 ID、时间戳、模型名称、输入 token 数、输出 token 数、耗时原始响应文本未解析归一化后的 JSON 结果。归一化器result-normalizer用正则 有限状态机解析 LLM 输出。例如当 LLM 返回File: internal/service/user.go Line: 47 Severity: high Issue: Missing error wrapping for external service call Suggestion: Use errors.Wrap(err, failed to create user in auth service)归一化器会提取字段填充默认值如rule_id从rules.md中匹配并验证line是否在 diff 新增范围内防止 LLM 胡说。若解析失败则标记为parsing_error进入人工 review 队列。注意必须禁用 LLM 的 temperature0。我们测试发现temperature0 时 LLM 过于死板常漏报temperature0.3 时平衡性最佳。这个参数写死在llm-router配置中不允许 CLI 用户覆盖。3.6 第六步评审结果呈现与集成实操耗时8 分钟含多平台适配CLI 输出默认为 JSON但人类需要可读格式。我们提供--formatmarkdown参数生成 GitHub 风格评论### Critical Issue **File:** internal/service/user.go **Line:** 47 **Rule:** error-handling-must-wrap **Issue:** Direct return of raw error from external service call **Suggestion:** Wrap with errors.Wrap(err, failed to create user in auth service) ### ⚠️ High Severity **File:** internal/service/user.go **Line:** 49 **Rule:** email-validation-length **Issue:** Email length check uses hard-coded 254, should use constant **Suggestion:** Replace 254 with validation.MaxEmailLength更关键的是集成能力GitHub/GitLabCLI 输出 JSON 后用jq提取comments字段调用 API 发布 inline comment飞书通过飞书 Bot webhook将 Markdown 转为富文本卡片自动 相关 reviewerJira解析rule_id匹配 Jira issue 类型如error-handling-must-wrap→BUG自动创建子任务。我们封装了integrate.sh脚本根据$CI_PLATFORM环境变量自动选择集成方式无需人工干预。3.7 第七步效果度量与持续优化实操耗时每周 1 小时不度量就无法优化。我们定义三个核心指标检出率Detection RateLLM 识别出的问题中被人工确认为 true positive 的比例阻断率Block Rate评审标记为critical的 PR被 CI 自动拒绝的比例采纳率Adoption Rate人工 reviewer 在最终评论中引用 LLM 建议的比例。每天凌晨用 Python 脚本从数据库拉取昨日数据生成日报 Markdown自动发到团队 Slack。例如DateDetection RateBlock RateAdoption Rate2024-06-0187.3%12.1%64.5%2024-06-0289.1%13.8%68.2%当 Detection Rate 连续 3 天 85%自动触发prompt-orchestrator的 A/B 测试切换到备用 prompt 模板当 Adoption Rate 50%则推送通知给 Tech Lead检查近期是否新增了未同步的规范。4. 实操过程详解从零部署一个可运行的 open-code-review 环境4.1 环境准备硬件、系统与依赖耗时15 分钟这不是一个“一键安装”工具它对运行环境有明确要求。我们推荐的最小可行配置组件要求理由说明OSLinux x86_64 (Ubuntu 22.04)macOS ARM64 支持不完善Windows 需 WSL2Linux 兼容性最好CPU4 核以上Diff 解析、AST 分析、CodeBERT 推理需多线程RAM≥ 16GBOllama 加载 CodeLlama-7b 需约 8GB预留空间给 OS 和 CI runnerDisk≥ 50GB SSD模型缓存~15GB、Git 仓库克隆、日志存储Docker24.0用于运行 vLLM 集群可选Ollama 也依赖 DockerGit2.35git diff --no-color --unified0在旧版本中行为不一致安装顺序严格如下sudo apt update sudo apt install -y git curl wget build-essentialcurl -fsSL https://get.docker.com | shDockercurl -fsSL https://ollama.com/install.sh | shOllamasudo usermod -aG docker $USER newgrp docker解决 Docker 权限ollama pull codellama:7b下载模型约 4.2GB注意不要用snap install docker它会导致 Ollama 无法访问 Docker socket。我们吃过亏——某次 Ubuntu Server 用 snap 安装 DockerOllama 启动时报connection refused排查 3 小时才发现是 snap 的安全沙箱限制。4.2 CLI 安装与配置耗时10 分钟我们不提供npm install或pip install而是分发预编译二进制# 下载最新版假设版本 0.8.3 wget https://nexus.internal/open-code-review/open-code-review-linux-amd64-0.8.3 chmod x open-code-review-linux-amd64-0.8.3 sudo mv open-code-review-linux-amd64-0.8.3 /usr/local/bin/open-code-review # 校验 SHA256 echo a1b2c3d4e5f6... open-code-review-linux-amd64-0.8.3 | sha256sum -c配置文件~/.config/open-code-review/config.yaml# 全局配置 llm: backend: ollama # 可选 ollama/vllm/openai model: codellama:7b timeout: 30 temperature: 0.3 context: static_lines: 5 # 静态上下文行数 semantic_top_k: 3 # 语义上下文函数数 rules: path: /etc/open-code-review/rules.md # 规范文件路径 integration: github: token: ${GITHUB_TOKEN} # 从环境变量读取 feishu: bot_webhook: ${FEISHU_BOT_WEBHOOK}关键点所有敏感配置token、webhook必须从环境变量读取绝不硬编码。CI 中通过export GITHUB_TOKEN$CI_JOB_TOKEN注入。4.3 规范文件 rules.md 编写耗时1-2 小时首次这不是一份文档而是一个可执行的规则集。每条规则必须包含rule_id、severity、pattern可选、description、suggestion。示例## error-handling-must-wrap **Severity:** critical **Pattern:** return err or return errors.New( **Description:** Raw error returns bypass error context and stack trace. **Suggestion:** Wrap with errors.Wrap(err, context message) or fmt.Errorf(context: %w, err). ## email-validation-length **Severity:** high **Pattern:** len\(req\.Email\) 254 **Description:** Email max length is a business constant, not magic number. **Suggestion:** Define const MaxEmailLength 254 in validation package and use it.pattern字段用于辅助静态分析非必需但强烈建议填写。我们用grep -E在 diff 中快速匹配命中则优先触发该规则的专项检查比通用 LLM 评审更快更准。4.4 CI 集成实战耗时20 分钟GitLab 示例在.gitlab-ci.yml中添加stages: - code-review open-code-review: stage: code-review image: ubuntu:22.04 before_script: - apt-get update apt-get install -y curl git - curl -L https://nexus.internal/open-code-review/open-code-review-linux-amd64-0.8.3 -o /tmp/ocr chmod x /tmp/ocr - export PATH/tmp:$PATH script: - /tmp/ocr --diff-file /tmp/pr-diff.patch --format json --output /tmp/review.json - if [ -s /tmp/review.json ]; then echo Review found issues; exit 1; else echo No issues found; fi allow_failure: true # 防止评审失败阻断 pipeline改为通知 only: - merge_requests关键点allow_failure: true评审是辅助手段不能阻断主流程exit 1当/tmp/review.json非空即有 issue时job 标记为 failed触发后续通知only: merge_requests只在 MR 时运行避免污染 feature branch。通知逻辑放在after_scriptafter_script: - if [ -s /tmp/review.json ]; then /tmp/ocr --integrate feishu --review-json /tmp/review.json; fi4.5 人工触发与调试耗时5 分钟/次日常开发中工程师可在本地快速验证# 1. 生成当前分支 diff git diff origin/main...HEAD --no-color --unified0 pr-diff.patch # 2. 运行评审verbose 模式看详细日志 open-code-review --diff-file pr-diff.patch --verbose # 3. 输出 Markdown 供阅读 open-code-review --diff-file pr-diff.patch --format markdown review.md # 4. 强制指定模型调试用 open-code-review --diff-file pr-diff.patch --llm-model deepseek-coder:33b--verbose会打印每一步耗时、上下文提取内容、原始 LLM 请求/响应是排查问题的第一手资料。我们要求所有新成员入职时必须用--verbose跑通一个简单 diff确保理解整个链路。5. 常见问题与排查技巧实录那些让你加班到凌晨的坑5.1 问题速查表高频故障与一键修复现象可能原因快速诊断命令修复方案open-code-review: command not found二进制未放入 PATH 或权限不足which open-code-reviewls -l $(which open-code-review)sudo chmod x /usr/local/bin/open-code-reviewFailed to parse diff: invalid patch formatdiff 包含 color 控制符或 crlfhead -n 5 pr-diff.patchfile pr-diff.patch重运行get-diff.sh确认--no-color参数生效LLM timeout after 30s模型未加载或显存不足ollama listnvidia-smiollama run codellama:7b预热或换用codellama:3bContext extraction failed: no function found变更行在文件顶部或注释区cat pr-diff.patchgrep -n pr-diff.patch检查 diff 是否真的有 行确认文件语法是否 validReview result emptyLLM 输出格式不符合归一化器预期cat /tmp/review.json | jq .运行open-code-review --verbose查看原始 LLM response5.2 深度排查从 LLM 响应反推 prompt 问题当评审结果明显不合理如把fmt.Println(hello)判为 critical不要急着换模型先看原始响应open-code-review --diff-file pr-diff.patch --verbose 21 | grep -A 20 LLM raw response常见模式及对策模式一LLM 拒绝回答响应I cannot review code as I am an AI assistant.原因prompt 开头缺少角色定义或指令冲突。对策检查rules.md是否有do not review code类表述确保 prompt 模板第一行是你是一名资深 [语言] 工程师...。模式二LLM 胡编乱造响应File: nonexistent.go Line: 999 ...原因上下文提取失败LLM 没收到有效文件路径。对策运行open-code-review --debug-context --diff-file pr-diff.patch检查 context.json 是否为空。模式三LLM 过度谨慎响应对所有 行都标记low无 high/critical。原因severity定义模糊或历史案例全是 low 级别。对策在rules.md中强化 critical 定义向examples.json注入 3 条真实 critical 案例。5.3 性能瓶颈定位当评审慢过人工时平均耗时 60s 就需优化。用time命令分段测量# 测 diff 解析 time open-code-review --diff-file pr-diff.patch --step diff-parser --output /dev/null # 测上下文提取 time open-code-review --diff-file pr-diff.patch --step context-extractor --output /dev/null # 测 LLM 调用 time open-code-review --diff-file pr-diff.patch --step llm-router --output /dev/null典型瓶颈及解法diff-parser 5s通常是go-git解析大 patch100 文件所致。对策在get-diff.sh中加--max-count50限制文件