资讯详情 开源 CLI 代码审查工具:基于 Git Diff 与分层 LLM 的轻量级落地实践
📅 2026/10/19 8:41:28
1. 项目概述一个真正能落地的开源代码审查 CLI 工具“open-code-review”这个名字乍看平平无奇但拆开来看——open不是指“开源”这个老生常谈的标签而是指开放上下文、开放规则、开放反馈路径code review也不是简单地把 PR 描述扔给大模型跑一遍而是要嵌入真实开发流程中解决工程师每天都在面对的三个硬伤第一人工 Code Review 效率低资深同事时间被碎片化吞噬新人改了十遍还是过不了第二静态扫描工具如 SonarQube、ESLint只能查语法和模式对业务逻辑漏洞、边界条件遗漏、API 设计合理性这类“软性缺陷”完全失语第三现有 LLM 辅助工具比如 GitHub Copilot 的 inline suggestion 或某些 IDE 插件缺乏可追溯、可复现、可审计的审查过程一句话“我觉得这里可能有问题”却没法回溯依据、没法比对历史、没法沉淀为团队知识。我从去年开始在两个中型后端团队里推动“open-code-review”的落地实践不是用它替代人而是把它当成一个永不疲倦的初级 Reviewer 高频校验员 历史对照镜。它基于 Git 提交差异diff实时生成结构化审查报告支持自定义规则模板比如“所有对外 HTTP 接口必须有超时配置”、“数据库查询必须带 LIMIT”能自动识别敏感信息泄露风险不只是密钥字面量还包括硬编码 token 构造逻辑、未脱敏日志打印等还能把每次审查结果存档到本地 SQLite 或轻量级服务中形成团队专属的“代码健康趋势图”。它不依赖云端 API核心推理可在本地小模型如 Qwen2.5-0.5B、Phi-3-mini上完成也不绑架你用某家大厂的闭源模型你可以自由切换 OpenRouter 上的任何兼容 OpenAI API 的 LLM甚至接入私有部署的 DeepSeek-Coder 或 CodeLlama。它就是一个命令行里的“代码守门人”输入ocr review --commit abc12343 秒内返回带行号定位、引用规范条目、附带修复建议的 Markdown 报告——不是泛泛而谈的“建议优化”而是“第 87 行json.Unmarshal()缺少错误处理参考 OWASP ASVS 4.1.2 条款建议改为if err ! nil { return err }”。这个词最近在开发者社区高频出现背后是真实痛点的集中爆发Git 已经成为事实标准CLI 是工程师最信任的交互界面LLM 的推理能力已足够支撑轻量级逻辑判断而“code review”这件事本身正从“人盯人”的协作仪式转向“人机协同”的工程实践。它适合三类人一线开发想快速自查提交质量Tech Lead 想统一团队基础规范执行力度以及 DevOps 工程师想把代码健康度纳入 CI 流水线早期卡点。它不承诺取代 Senior Engineer 的深度判断但它能确保 Junior Developer 至少不会把空指针异常、SQL 注入隐患、密钥硬编码这种低级错误带到主干分支。2. 整体设计思路与架构选型逻辑2.1 为什么坚持 CLI 而非 GUI 或 IDE 插件很多人一听到“代码审查LLM”第一反应是做个 VS Code 插件或者 Web 界面。我试过也带团队做过原型最后全部推翻重来。根本原因在于交互粒度与信任链断裂。GUI 和插件天然倾向于“主动推送”——它看到你写了os.Getenv(API_KEY)就弹窗警告但你很可能正处在调试阶段临时用明文 key 测试第三方服务此时弹窗不仅打断心流更让你对工具产生“它不懂我当前上下文”的不信任。而 CLI 是请求驱动的你明确执行ocr review --staged就代表你已完成本地验证准备提交此时才需要一份严肃的审查报告。这个动作本身就是一个质量承诺信号。更重要的是CLI 天然契合 Git 的工作流。Git 的每个原子操作add/commit/push都有清晰的 hook 点pre-commithook 可以无缝集成ocr review --staged失败则阻断提交post-mergehook 可以触发ocr diff HEAD~1..HEAD --formatsummary生成本次合并的健康简报。这些能力在 GUI 层几乎无法稳定实现——IDE 插件无法可靠监听 Git 内部状态Web 界面更无法介入本地 commit 流程。我们团队上线 CLI 集成后pre-commit阶段拦截了 63% 的低级错误密钥泄露、panic 未捕获、日志含 PII而这些错误过去平均要等到 Code Review 阶段才被发现修复成本高出 5 倍以上根据我们内部统计本地修复耗时约 2 分钟CI 失败后修复平均需 17 分钟含等待队列、上下文重建、沟通确认。2.2 为何选择“Diff 为中心”而非“文件/目录扫描”市面上不少 LLM 代码工具喜欢整块读取整个文件甚至整个仓库美其名曰“全局理解”。实测下来这在工程实践中是灾难性的一是速度慢一个 500 行的 Go 文件全量喂给 7B 模型token 开销动辄 3000推理耗时超过 8 秒根本无法放入pre-commit流程二是噪声大模型容易被无关代码比如注释、旧版 TODO、测试桩干扰反而忽略真正的变更点三是可解释性差报告里说“第 120 行有风险”但你根本不确定它是基于当前修改、还是基于旁边一段三年前的遗留代码做出的判断。open-code-review的核心设计哲学是只审查你亲手写的那几行。它调用git diff获取精确的 patch 内容过滤掉无关的上下文比如只保留行和紧邻的-行再将这个精简后的 diff 片段作为 prompt 主体。我们做过对比实验对同一份 PR全文件扫描模式下LLM 给出 12 条建议其中 7 条指向未修改的旧代码误报而 diff 模式下给出 5 条建议全部精准定位到新增/修改行且每条都附带明确的变更理由如“新增的fmt.Sprintf调用未做输入校验可能引发格式字符串漏洞”。这个设计直接决定了工具的可用性底线——它必须让人一眼看懂“为什么是我这行被标红”而不是陷入“它到底在评什么”的困惑。2.3 LLM 推理层为什么放弃“单一大模型”路线热词里反复出现的 “codex cli”、“claude code cli”、“deepseek” 等本质都是绑定特定厂商模型的 CLI 封装。这在 PoC 阶段很香但一旦进入生产环境问题立刻暴露API 调用不稳定尤其国内网络环境下、费用不可控一个中型团队日均审查 200 次按 GPT-4 Turbo 价格算月成本超 3000 元、响应延迟波动大从 200ms 到 5s 不等最关键的是——模型黑盒导致审查逻辑无法审计。你收到一条“建议添加单元测试”但不知道它是基于代码复杂度、还是基于函数长度、还是单纯因为 prompt 里写了“请检查测试覆盖”这种不确定性在金融、医疗等强合规领域是致命的。我们的解法是构建分层推理引擎L0 层规则引擎纯正则 AST 解析用 tree-sitter处理确定性规则如“禁止eval()”、“console.log必须删除”、“密钥变量名匹配.*key.*|.*secret.*”。这部分毫秒级响应零成本100% 可复现。L1 层轻量模型本地运行 0.5B~1.5B 参数的 Code-LLM如 Phi-3-mini、Qwen2.5-Coder专攻“模式识别类”问题如“这个 SQL 查询缺少 WHERE 条件可能引发全表扫描”、“HTTP 客户端未设置 timeout存在连接悬挂风险”。它不生成代码只输出 yes/no 简短依据token 开销控制在 200 以内本地 CPU 推理稳定在 1.2 秒内。L2 层大模型兜底仅当 L0/L1 无法判定时比如涉及复杂业务逻辑的合理性判断才调用远程 LLM可配置 OpenRouter、Together.ai 等多源并强制开启response_format: { type: json_object }确保输出结构化便于后续解析和审计。这个三层架构让open-code-review在我们团队的实际 SLA 达到92% 的审查请求由 L0/L1 完成平均耗时 0.8 秒8% 进入 L2平均耗时 3.4 秒且全部记录原始 prompt 和完整 response供事后审计。它不是一个“LLM 黑箱”而是一个可插拔、可审计、可降级的质量守门人。2.4 安全设计如何从源头杜绝密钥泄露风险热词里高频出现的 “使用 LLM 时如何防止密钥等鉴权信息泄露”直击要害。很多 CLI 工具在获取 diff 时会无差别包含.env文件、配置文件中的敏感字段甚至把git log --grep的历史记录也喂给模型——这等于主动把密钥送进大模型训练语料库。open-code-review的安全机制是四重过滤Git 层预过滤启动时自动读取.gitattributes和.gitignore对*.env,config/*.yaml,secrets/等路径做硬性排除diff 结果中彻底不出现这些文件。Diff 内容净化对提取出的 patch 文本运行基于规则的敏感词扫描非简单关键词匹配而是结合上下文比如password: xxx中的xxx会被标记但password: default不会匹配项自动替换为REDACTED并记录日志。Prompt 构建隔离LLM 的 prompt 模板严格区分“代码上下文”和“审查指令”。代码部分只放净化后的 diff指令部分如“请检查是否有硬编码密钥”单独构造避免模型通过指令反推原始敏感内容。本地模型沙箱当使用本地 LLM 时整个推理过程在内存中完成不写入任何磁盘缓存模型权重文件采用加密存储AES-256密钥由系统 keyring 管理进程退出即销毁。我们曾用真实密钥数据集做过红蓝对抗测试将包含 AWS_ACCESS_KEY_ID、Slack Bot Token、数据库连接串的 50 个恶意 diff 样本输入open-code-review的 L0 规则引擎 100% 拦截并报错“检测到高危密钥模式审查终止”未向任何 LLM 发送请求。这才是真正的“防患于未然”而不是事后靠模型“别记住”这种不可靠的承诺。3. 核心细节解析与实操要点3.1 安装与初始化为什么git是唯一前置依赖open-code-review的安装命令是curl -sSL https://get.ocr.dev | sh它只做三件事下载二进制、校验 SHA256、复制到/usr/local/bin。没有npm install没有pip install没有brew tap。原因很简单Git 是现代开发的事实基础设施而其他工具都是可选的。你的机器上如果没有 Git那根本谈不上做 Code Review——连 diff 都拿不到。强行要求 Python 或 Node.js 环境等于给用户设置第一道门槛而这个门槛和代码审查本身毫无关系。安装后首次运行ocr init它会引导你完成三步配置模型源选择列出本地可用模型自动探测 Ollama、LM Studio 运行的模型和远程 APIOpenRouter、Together.ai 等支持保存多个 profile比如dev-local用 Phi-3-mini、prod-cloud用 Claude-3-Haiku。规则集加载提供开箱即用的规则包OWASP Top 10、Google Java Style Guide、Go Proverbs也支持从 URL 加载团队自定义规则JSON 格式含 rule_id、description、pattern、severity。Git Hook 注册询问是否启用pre-commithook如果同意它会在.git/hooks/pre-commit写入一个 shell 脚本内容仅为ocr review --staged --fail-on-error并确保脚本可执行。这个设计背后的经验是降低首次使用成本就是降低 adoption barrier。我们观察到团队里 73% 的工程师在第一次安装后 2 小时内就完成了init而那些需要先装 Python 再 pip install 再配置环境变量的工具首日使用率不足 12%。CLI 工具的生命力始于“输入命令就能用”的确定性。3.2 Diff 解析引擎如何精准提取“有意义的变更”git diff的原始输出对 LLM 是灾难。它包含大量元信息diff --git a/file.go b/file.go、文件头index xxx..yyy 100644、函数签名 -45,6 47,8 func process(data string) error {还有大量未变化的上下文行- old line/ new line之间的 行。把这些全塞给模型就像让专家医生看一张 X 光片但胶片上还贴着病历单、缴费单和医院 logo。open-code-review的 diff 解析器做了四层精炼语法剥离用正则清除所有diff --git、index、--- a/、 b/等 Git 元信息只保留行和内容行。上下文压缩对每个块只保留行新增和紧邻的-行删除以及最多 2 行 行未变但用于定位。例如 -120,5 122,7 func sendEmail(to string, body string) error { client : smtp.NewClient(...) - return client.Send(...) if err ! nil { return fmt.Errorf(send email failed: %w, err) } return nil解析后变为[DEL] return client.Send(...) [ADD] if err ! nil { [ADD] return fmt.Errorf(send email failed: %w, err) [ADD] }语言感知归一化针对不同语言做 token 级处理。Go 代码会提取函数名sendEmail和参数to, bodyPython 会识别def send_email和selfJS 会剥离async/await修饰符聚焦核心逻辑。这步确保 LLM 看到的不是“一堆符号”而是“一个叫 sendEmail 的函数接收 to 和 body现在增加了错误处理”。敏感内容标记对ADD行中匹配密钥模式的部分如sk-xxx、AKIA...、-----BEGIN RSA PRIVATE KEY-----替换为REDACTED:API_KEY并记录位置后续审查报告中会特别标注“此处存在密钥泄露风险”。这套解析逻辑是我们花了三个月打磨的核心。它让 LLM 的输入从平均 1200 tokens 压缩到 280 tokens推理速度提升 3.2 倍且关键信息零丢失。你可以用ocr diff --raw查看原始 diff用ocr diff --parsed查看精炼后的内容亲眼见证这个“去噪”过程。3.3 规则引擎L0为什么正则不够必须用 Tree-sitter热词里提到的 “git 命令”、“git 教程” 很多但真正深入git diff语义解析的极少。规则引擎看似简单实则暗藏玄机。早期我们只用正则比如/password\s*[:]\s*[]([^])[]/匹配密码赋值。很快发现严重误报user.Password default被标为高危而真正的风险dbPassword : os.Getenv(DB_PASSWORD)却漏掉了——因为正则无法理解os.Getenv是一个动态获取密钥的函数调用。解决方案是集成Tree-sitter。它为 30 语言提供精确的 AST抽象语法树解析让我们能写出语义级规则。例如一条真正有效的密钥检测规则是{ rule_id: SECURE-001, description: 禁止从环境变量直接读取密钥, language: go, ast_pattern: (call_expression (selector_expression (identifier) func_name) (argument_list (string_literal) key_name)), where_clause: func_name os.Getenv key_name ~ /(?i)(key|secret|token|password)/ }这段 JSON 描述的是“在 Go 语言中找到一个函数调用其调用者是os.Getenv且传入的字符串参数名包含 key/secret/token/password忽略大小写”。Tree-sitter 能精准定位到 AST 节点完全规避正则的上下文盲区。我们内置了 47 条基于 Tree-sitter 的规则覆盖安全类硬编码密钥、SQL 注入点fmt.Sprintf(SELECT * FROM %s, table)、XSS 风险innerHTML user_input健壮类panic 未捕获json.Unmarshal后无 err 检查、空指针解引用ptr.Method()无 nil 检查规范类Go 函数名不符合 PascalCase、Python 变量名含下划线但函数名用 camelCase这些规则全部开源在https://github.com/ocr-rules/community团队可以 fork 后修改ocr rules update命令一键同步。它不是黑盒规则而是可读、可验、可改的团队资产。3.4 本地模型推理L1如何让 0.5B 模型读懂 Go 代码“LLM 入门”、“LLM 基础” 这些热词背后是大量开发者对小模型能力的怀疑。确实通用 LLM如 Llama3-8B在代码任务上表现平平但专为代码训练的轻量模型完全不同。我们选择 Phi-3-mini3.8B 参数但量化后仅 2.1GB和 Qwen2.5-Coder1.5B作为主力原因有三训练语料纯净Phi-3-mini 的训练数据 95% 来自 GitHub 公开代码库且经过严格清洗不含自然语言垃圾Qwen2.5-Coder 则在 CodeSearchNet 上做了强化微调对函数签名、类型声明、错误处理模式高度敏感。推理优化到位两者均支持 FlashAttention-2 和 PagedAttention我们在 macOS M2 Ultra 上实测Phi-3-mini-4K-Instruct 量化版GGUF Q4_K_M处理 256 token 输入平均耗时 1.18 秒GPU 显存占用仅 1.2GB。Prompt 工程成熟我们不喂原始 diff而是构造结构化 prompt[TASK] Analyze the following code change and identify security or correctness issues. [LANGUAGE] Go [CONTEXT] Function: sendEmail Parameters: to string, body string [DIFF] [DEL] return client.Send(...) [ADD] if err ! nil { [ADD] return fmt.Errorf(send email failed: %w, err) [ADD] } [INSTRUCTIONS] Output ONLY valid JSON with keys: issues (array), summary (string). No markdown, no explanation.这个 prompt 强制模型聚焦“变更意图”sendEmail 函数增加了错误处理而非泛泛而谈“Go 错误处理最佳实践”。我们收集了 2000 个真实 diff 样本用 GPT-4 生成黄金标准答案然后对 Phi-3-mini 进行 LoRA 微调仅更新 0.3% 参数使其在“是否新增了必要错误处理”这一判断上的准确率从 78% 提升到 94.2%。小模型不是不能用而是要用对场景、喂对数据、调对 prompt。4. 实操过程与核心环节实现4.1 一次完整的pre-commit审查流程假设你正在开发一个用户注册接口刚写完以下代码并执行git add .// handler/user.go func registerUser(w http.ResponseWriter, r *http.Request) { var req struct { Email string json:email Password string json:password } json.NewDecoder(r.Body).Decode(req) // TODO: validate email format // TODO: hash password db.Exec(INSERT INTO users (email, password) VALUES (?, ?), req.Email, req.Password) w.WriteHeader(201) }此时运行git commit -m feat: add user registrationpre-commithook 会触发ocr review --staged。整个流程如下Diff 提取ocr调用git diff --cached获取 staging 区变更识别出handler/user.go新增了registerUser函数。内容净化Tree-sitter 解析 AST发现json.NewDecoder().Decode()无错误检查、db.Exec()无参数校验、TODO注释未清理。敏感词扫描确认无密钥。L0 规则匹配SECURE-003SQL 查询未参数化命中db.Exec(INSERT ... VALUES (?, ?), ...)→ 低危CORRECT-007JSON 解码无错误处理命中json.NewDecoder(...).Decode(...)→ 中危STYLE-012TODO 注释未清理命中// TODO: validate email format→ 提示L1 模型推理将精炼 diff 输入 Phi-3-miniprompt 如前所述模型返回{ issues: [ { line: 12, message: json.Decode() lacks error handling; may panic on invalid JSON, rule: CORRECT-007, severity: medium }, { line: 18, message: SQL query uses string interpolation; vulnerable to SQL injection, rule: SECURE-003, severity: high } ], summary: Critical security risk: raw SQL execution without parameterization. Medium correctness risk: missing JSON decode error check. }报告生成与阻断ocr合并 L0/L1 结果生成 Markdown 报告显示在终端❌ CRITICAL: Line 18 - SQL injection vulnerability db.Exec(INSERT INTO users (email, password) VALUES (?, ?), ...) Rule SECURE-003: Use prepared statements instead of string interpolation ⚠️ MEDIUM: Line 12 - Missing error handling for JSON decode json.NewDecoder(r.Body).Decode(req) Rule CORRECT-007: Always check error from Decode() HINT: Line 8 - TODO comment detected // TODO: validate email format Consider adding validation before DB insertion因存在 CRITICAL 问题pre-commit返回非零退出码commit 被中止。你必须修复后才能提交。这个过程全程离线耗时 1.7 秒M2 Max比一次go build还快。它不是“找茬”而是把资深工程师脑子里的 checklist变成可执行、可审计、可沉淀的自动化守门人。4.2 自定义规则开发如何让团队规范“活”起来热词里反复出现的 “git 配置 gitee 密钥”、“git 教程”说明开发者对 Git 生态极其熟悉但很少有人想到把团队规范也变成 Git 可管理的资产。open-code-review的规则系统设计成 Git-native规则集就是一个 JSON 文件可以像代码一样版本化、Code Review、Merge Request。假设你们团队规定“所有 HTTP Handler 必须记录请求 ID”。传统做法是靠 Code Review 口头提醒效果差。现在你可以写一条规则{ rule_id: TRACE-001, description: HTTP handler must log request ID, language: go, ast_pattern: (function_declaration (function_signature (parameter_list (parameter_declaration (identifier) param))) (block (expression_statement (call_expression (selector_expression (identifier) func_name) (argument_list (identifier) arg)))), where_clause: func_name log.Printf arg reqID, fix_suggestion: Add reqID : uuid.NewString() at function start, and log with log.Printf(\[req:%s] ...\, reqID) }保存为rules/trace-id.json然后执行ocr rules add --file rules/trace-id.json ocr rules list # 确认已加载下次审查时任何新写的 Handler 若未记录 reqID就会被标记。更进一步你可以把这个规则文件提交到团队仓库的/rules目录CI 流水线中加入ocr rules validate步骤确保规则语法正确Code Review 时新规则也要走完整流程——这样团队规范就从“口头约定”变成了“可执行、可验证、可追溯”的工程资产。我们有个客户团队用这套机制在 3 个月内沉淀了 89 条业务专属规则覆盖支付风控、医疗数据脱敏、IoT 设备认证等场景。他们告诉我“以前靠人盯人的规范现在靠git push就自动生效。”4.3 CI/CD 集成如何把审查从“个人习惯”升级为“团队标准”pre-commit是个人防线CI 集成才是团队底线。open-code-review提供原生 CI 支持无需额外插件。以 GitHub Actions 为例在.github/workflows/code-review.yml中name: Code Review on: [pull_request] jobs: review: runs-on: ubuntu-latest steps: - uses: actions/checkoutv4 with: fetch-depth: 0 # 必须获取完整历史用于 diff 计算 - name: Install open-code-review run: curl -sSL https://get.ocr.dev | sh - name: Run code review run: | ocr review \ --diff-base ${{ github.event.pull_request.base.sha }} \ --diff-head ${{ github.event.pull_request.head.sha }} \ --formatjson \ --outputreview-report.json \ --fail-on-critical \ --fail-on-high env: OCR_MODEL: openrouter/anthropic/claude-3-haiku OCR_API_KEY: ${{ secrets.OPENROUTER_API_KEY }} - name: Upload report if: always() uses: actions/upload-artifactv4 with: name: code-review-report path: review-report.json关键点解析--diff-base和--diff-head精确指定 PR 的 base/head commit确保审查范围严格对应本次变更。--formatjson输出结构化结果便于后续解析或存档。--fail-on-critical和--fail-on-high设置 CI 失败阈值CRITICAL 问题必须修复HIGH 问题可设为 warning不阻断。OCR_MODEL和OCR_API_KEY环境变量实现模型源的灵活切换无需修改 workflow 文件。我们实测一个 500 行的 PRCI 审查耗时平均 4.2 秒含模型调用比 SonarQube 扫描快 17 倍。更重要的是它能发现 SonarQube 永远看不到的问题比如“这个新写的风控策略和上周合并的另一条规则逻辑冲突”这种跨 PR 的语义级问题只有 LLM 能捕捉。4.4 审查报告存档与趋势分析如何让“质量”变得可衡量热词里 “git 下载安装教程”、“git 安装步骤详细” 说明大家熟悉 Git 操作但很少思考代码审查本身是不是也可以像代码一样被版本化open-code-review默认将每次审查报告存入本地 SQLite 数据库~/.ocr/reports.db表结构包含report_idUUIDcommit_hash关联 Git 提交authorGit 用户名timestampissues_jsonJSON 字符串含所有问题详情summary文本摘要你可以随时查询# 查看某次提交的详细报告 ocr report show abc1234 # 统计本周各模块问题分布 ocr report stats --since 7 days ago --group-by rule_id # 导出为 CSV 供 BI 工具分析 ocr report export --format csv --since 30 days ago quality-trend.csv我们团队用这个数据做了三件事个人质量画像每月生成工程师的“审查健康分”统计其提交中 CRITICAL 问题率、HIGH 问题修复及时率不用于考核而是帮助新人识别自身薄弱点。模块风险地图按文件路径聚合问题发现payment/目录的 SQL 注入问题占比高达 42%于是针对性组织了一次专项培训。流程优化验证上线新规范如“所有 API 必须返回标准错误格式”后用ocr report stats --rule API-001追踪执行率从首月 31% 提升到第三月 92%。质量不再是模糊的“感觉”而是可量化、可归因、可改进的数据。这就是open-code-review的终极价值它不只告诉你“哪里错了”更帮你回答“为什么错”、“谁在错”、“怎么系统性地不错”。5. 常见问题与排查技巧实录5.1 “模型返回 JSON 格式不稳定”问题的根源与解法热词里提到的 “修复 LLM 返回 JSON 的 Java 库”其实是个伪命题。问题不在客户端解析库而在 LLM 本身。我们遇到过无数次同一个 promptGPT-4 有时返回完美 JSON有时返回Heres the result:\n{\n issues: [...]}有时甚至返回 Markdown 表格。根本原因是LLM 是概率模型不是确定性程序。它没有“必须返回 JSON”的内在约束只是你在 prompt 里“请求”它这么做。我们的解法是三层防御Prompt 层强制要求Output ONLY valid JSON. No markdown, no explanation, no extra text.并在末尾加{issues: []}作为格式锚点。解析层不依赖json.loads()直接解析而是用正则提取{...}内容再尝试json.loads()若失败则用jsonrepair库轻量级 JSON 修复工具自动修正常见错误如末尾逗号、单引号、未转义引号。Fallback 层若修复后仍无效降级到 L0 规则引擎的纯文本报告并记录model_fallback: true日志供后续分析。实测下来这套组合拳将 JSON 解析失败率从 12.7% 降至 0.3%。关键认知是不要指望 LLM 100% 可靠而是设计一个能容忍其不确定性的系统。5.2 “Git Hook 不生效”的 5 个排查路径pre-commithook 失效是最高频问题。我们整理了 97% 的案例按优先级排序排查Hook 文件权限ls -l .git/hooks/pre-commit必须显示-rwxr-xr-x。Mac/Linux 上常见问题是curl下载的脚本默认无执行权限chmod x .git/hooks/pre-commit即可。Hook 路径硬编码有些教程教你在 hook 里写python3 /path/to/ocr.py但ocr二进制路径可能随系统变化。正确做法是ocr review --staged依赖$PATH查找。Git 版本兼容性Git 2.15 才支持core.hooksPath旧版本必须把 hook 放在.git/hooks/下。用git version确认。Shell 环境差异.git/hooks/pre-commit默认用/bin/sh执行但ocr可能依赖bash特性。解决方案在 hook 第一行加#!/bin/bash。Staging 区为空git commit时若没git addstaging 区为空