
1. 项目概述这不是一个“工具”而是一套可落地的开源代码评审工作流“open-code-review”这个词乍看像某个新发布的 CLI 工具名但实际它代表的是一种正在快速演进的工程实践范式——把传统依赖人工、高成本、低频次的代码评审Code Review通过开源可审计的流程设计、轻量级 CLI 驱动、Git Diff 原生集成以及 LLM Agent 的智能辅助能力重构为开发者日常开发中“默认开启、按需触发、结果可追溯”的常态化环节。我从去年开始在三个不同规模的团队里推动类似实践不是用某款闭源 SaaS 服务也不是直接套用 GitHub Copilot 或 Cursor 的内置功能而是从零搭建一套完全透明、可定制、不绑定任何云厂商的本地化评审链路。核心就三件事Diff 能被精准提取、Agent 能被稳定调用、结论能被结构化沉淀。它不替代人做决策但能把人从“逐行比对变更、查文档确认规范、翻历史找类似 case”这些重复劳动里解放出来把注意力真正聚焦在“这个逻辑是否引入竞态”“这个 API 兼容性是否被破坏”这类高价值判断上。适合中大型技术团队的基建同学、重视代码质量的 Tech Lead、以及正在构建内部 Developer ExperienceDevX平台的工程师——尤其当你发现团队 PR 平均评审时长超过 48 小时、新人提交的 PR 经常被反复打回、或者 Code Style 检查靠人工肉眼盯导致标准不一的时候这套思路比买一个“AI 代码审查 SaaS”更可控、更可持续。它和你搜到的那些热词——比如 “codex cli”、“trae cli”、“claude code cli”——本质区别在于出发点不同后者大多是某个大模型厂商或 IDE 厂商推出的“客户端封装”目标是让你更快地调用他们的模型 API而 open-code-review 是一个工程方法论 最小可行工具链的组合体它的 CLI 不是黑盒二进制而是用 Python 或 Rust 写的、几十行核心逻辑、所有 prompt 和解析规则都明文可见的脚本。你可以把它理解成“给 Git Diff 配一个会写代码的实习生”这个实习生不替你写代码但会在你git commit后自动跑一遍告诉你“第 37 行新增的 try-catch 没有 log 错误上下文建议补上”“这个函数签名和上个月合并的 utils/v2.py 第 12 行冲突可能影响下游调用”。它不依赖飞书、不绑定 Gemini、不强制你开 ChatGPT 订阅——只要你有一台能跑 Python 的机器、一个可用的开源 LLM比如 Qwen2.5-7B-Instruct 或 DeepSeek-Coder-V2-6.7B就能跑起来。DeepSeek 属于代码垂类大模型Code LLM和通用 LLM如 GPT-4、Claude的区别在于它在训练时用了海量 GitHub 开源代码对函数签名、AST 结构、测试覆盖率等工程信号更敏感而 Agent 是指它被赋予了“目标导向的执行能力”——不是被动回答问题而是能主动读取 diff、调用 lint 工具、生成 review comment、甚至根据配置自动提 issue。Embedding 则是另一层能力用于把你的私有代码库向量化让 Agent 在评审时能参考内部最佳实践而不是只靠通用知识。这些概念不是割裂的open-code-review 正是把它们串成一条流水线Git Diff → Embedding 检索相似变更 → LLM Agent 分析风险 → CLI 输出结构化报告 → 人工确认后归档。2. 整体架构设计与选型逻辑为什么不用现成的“AI Code Review”工具2.1 核心矛盾SaaS 工具的便利性 vs. 工程可控性的不可调和我最早试过三类方案第一类是 GitHub Marketplace 里的 AI Review 插件比如 CodeRabbit、Sourcery它们部署快点几下就接入但问题也很直接——你永远不知道它看了你多少行代码、用了什么 prompt、是否把敏感字段比如数据库密码硬编码上传到了第三方服务器。去年我们有个金融客户因为合规审计卡在这一关最终全部下线。第二类是 IDE 厂商提供的 CLI比如你提到的 codex cli、zcode cli它们确实深度集成在 VS Code 或 JetBrains 里体验流畅但本质上是厂商的“API 代理层”所有请求都走他们的中转服务一旦他们调整计费策略或限制调用频次比如最近 Codex CLI 对免费用户加了 rate limit你的自动化流程就断了。第三类是开源模型本地部署比如直接用 Ollama 跑 Llama3-8B但你会发现没有 Git Diff 解析器没有评审规则引擎没有结果归档模块——它只是一个“会说话的终端”离真实工程场景差着至少五个中间件。open-code-review 的设计起点就是绕开这三类陷阱。它不追求“开箱即用”而是提供一个可拆解、可替换、可审计的最小骨架。整个流程只有四个核心组件Diff 提取器diff-extractor不是简单git diff而是能识别出“哪些是业务逻辑变更、哪些是测试文件、哪些是 lockfile”并过滤掉格式化改动比如 Prettier 自动加的空格评审调度器review-router根据变更类型feature / bugfix / refactor和文件路径/src/api/ vs. /tests/动态选择不同的 prompt 模板和 LLM 实例比如 API 层用更强的 DeepSeek-Coder测试文件用更轻量的 Phi-3Agent 执行器agent-runner这才是真正的“智能体”它不是单次调用 LLM而是能执行多步操作先调用pylint --errors-only获取语法错误再把错误信息和 diff 一起喂给 LLM最后生成带行号引用的 comment结果归档器review-archiver把每次评审的原始 diff、LLM 输入输出、人工确认记录存到本地 SQLite 或团队已有的 Confluence/Notion 数据库形成可回溯的质量基线。这个架构看起来比 SaaS 多写几百行代码但它带来的收益是确定的当审计要求你证明“评审过程未泄露代码”时你只需打开diff-extractor.py指着第 42 行if file_path.endswith(.env) or SECRET in line: continue说“这里明确跳过了所有含 SECRET 的行”当业务方要求“对支付模块的变更必须额外检查幂等性实现”时你只需在review-router的配置里加一条规则而不是等 SaaS 厂商排期。2.2 CLI 定位不是命令行界面而是工程胶水很多人看到 “CLI” 就默认它是“终端里敲几个字启动服务”的工具但在 open-code-review 里CLI 是连接 Git、编辑器、CI/CD 和本地模型的协议适配器。它的核心价值不是“多酷炫”而是“多稳”。我对比过十几种 CLI 框架Click、Typer、Clap、Cobra最终选了 Typer原因很实在它生成的--help文档天然支持 Markdown可以直接粘贴进团队 Wiki参数校验逻辑和业务逻辑能写在同一函数里避免“参数解析层”和“执行层”之间传参出错我们曾因 Click 的nargs2解析 bug 导致 diff 被截断引发一次线上事故对 Windows 用户友好——很多开源模型 CLI比如 ollama run在 PowerShell 下路径处理有问题Typer 的Path类型能自动处理跨平台路径。一个典型的 open-code-review CLI 命令长这样oc-review --diff HEAD~1 --model deepseek-coder:6.7b --ruleset payment-module --output json拆解来看--diff HEAD~1不是简单执行git diff HEAD~1而是调用 diff-extractor它会排除node_modules/、.gitignore里声明的路径合并同一文件的多次修改避免同一个函数被改了三次却生成三条重复 comment把二进制文件图片、PDF标记为 “skipped”不送入 LLM--model deepseek-coder:6.7b指向本地 Ollama 实例如果该模型未运行CLI 会自动拉起并等待就绪而不是报错退出--ruleset payment-module加载一个 YAML 文件里面定义了“支付模块专属规则”比如必须检查transaction_id是否被日志记录、retry_count是否有上限、callback_url是否经过白名单校验--output json是关键——它让结果变成结构化数据方便后续接入 Jenkins Pipeline 或飞书机器人而不是一堆人类可读的文本。这种设计让 CLI 成为了“可编程的评审开关”。你可以把它嵌入 pre-commit hook在git commit时自动运行也可以放在 CI 的test阶段之后作为质量门禁甚至能配合 VS Code 的 task.json按 CtrlShiftP 触发“当前文件评审”。它的存在意义是让 AI 评审能力像git status一样成为开发者肌肉记忆的一部分而不是一个需要单独打开网页、登录账号、等待加载的“功能”。2.3 LLM Agent 与通用 LLM 的本质差异目标驱动 vs. 问答驱动这是最容易被混淆的概念。网上很多教程把 “用 LLM 写 review comment” 等同于 “实现了 Agent”其实差得很远。举个真实例子我们有个 PR 修改了订单状态机新增了一个PENDING_PAYMENT状态。一个通用 LLM比如直接调用 OpenAI API可能会回复“检测到新增状态枚举值建议补充对应的状态流转图。”这没错但没用——它没告诉你“状态流转图该画在哪”“现有代码里哪几个函数会受此影响”“数据库迁移脚本是否同步更新”。而一个真正的 LLM Agent 会这样做规划Planning识别出这是状态机变更需要检查三处order_state.py枚举定义、state_machine.go流转逻辑、migrations/202405_add_payment_state.sqlDB 变更工具调用Tool Calling运行grep -n PENDING_PAYMENT src/order_state.py定位到第 15 行执行git show HEAD~1:src/state_machine.go | grep -A5 -B5 TRANSITION获取旧版流转逻辑查询本地 SQLite 数据库确认migrations/目录下是否有对应 SQL 文件推理与生成Reasoning Generation综合三处信息生成 comment“order_state.py第 15 行新增PENDING_PAYMENT但state_machine.go第 89 行的VALID_TRANSITIONS映射未包含此状态当前仅支持CREATED → CONFIRMED会导致状态机拒绝该流转。请同步更新state_machine.go并补充 migration 文件migrations/202405_add_payment_state.sql。”这个过程里LLM 不是“回答问题”而是“执行任务”。它需要能解析自身输出的 tool call 指令比如{ tool: grep, args: [-n, PENDING_PAYMENT, src/order_state.py] }能处理工具返回的原始结果grep 的输出是纯文本需提取行号能在多次迭代中保持上下文第一次发现缺失 migration第二次要确认文件名是否符合团队规范。我们用的是 LangChain 的OpenAIToolsAgent框架但做了关键改造把所有 tool call 的 schema 硬编码为 Git/Shell 命令而不是依赖 OpenAI 的 function calling——这样既保证兼容性又避免被厂商锁定。Agent 的 prompt 里明确写了“你是一个资深后端工程师正在做 Code Review。你只能使用以下工具grep、git show、sqlite3、pylint。每次输出必须以{tool: ..., args: [...]}开头或以{review_comment: {...}}结束。禁止自由发挥。” 这种“强约束”看似死板实测下来比宽松 prompt 稳定 3.2 倍我们统计了 1000 次评审宽松 prompt 有 217 次生成无效 tool call强约束仅 68 次。3. 核心模块实现详解从 Git Diff 到结构化 Review Comment3.1 Diff 提取器超越git diff的语义感知能力git diff命令输出的是“字符级差异”但代码评审需要的是“语义级差异”。比如这段 diff- def calculate_total(self, items): - return sum(item.price for item in items) def calculate_total(self, items, tax_rate0.0): subtotal sum(item.price for item in items) return subtotal * (1 tax_rate)字符 diff 显示删了 1 行、增了 3 行但语义上这是一次向后兼容的函数签名增强新增可选参数而非破坏性变更。如果直接把原始 diff 喂给 LLM它可能误判为“函数逻辑被重写”忽略最关键的tax_rate默认值设计。open-code-review 的 diff-extractor 就是为解决这个问题而生。它的核心算法分三步第一步AST 辅助解析。对 Python/JS/Go 等主流语言我们用tree-sitter构建 AST对比新旧版本的函数节点。以上例为例AST 会识别出函数名calculate_total未变参数列表从(self, items)变为(self, items, tax_rate0.0)其中tax_rate是新增的带默认值参数函数体被重构但核心计算逻辑sum(item.price for item in items)仍存在只是被赋值给subtotal变量。第二步变更类型分类。基于 AST 差异我们定义了 7 类语义变更类型判定条件评审侧重点SIGNATURE_CHANGE函数/方法参数增删、默认值变更、返回类型变化兼容性、调用方影响、文档更新LOGIC_REFINE函数体重构但输入输出不变如变量重命名、循环展开性能影响、可读性提升STATE_MACHINE_ADD枚举新增值、状态流转图新增边状态一致性、异常分支覆盖CONFIG_ADD新增配置项如settings.py里加ENABLE_FEATURE_X True配置生效范围、默认值安全性DEPRECATION标记deprecated或TODO: remove in v2.0替代方案、移除时间表TEST_COVERAGE新增/修改测试文件且覆盖新代码路径测试完整性、边界 caseINFRA_CHANGE修改 Dockerfile、K8s YAML、Terraform资源申请合理性、安全策略第三步上下文注入。diff-extractor 不只输出差异代码还会附加关键上下文被修改文件的前 5 行通常是 import 语句帮助 LLM 理解依赖该函数在调用栈中的位置通过git grep -n calculate_total -- src/获取近 3 次对该文件的 commit messagegit log -3 --oneline -- src/order_state.py判断是否属于连续迭代。实操中我们用 Python 的subprocess调用tree-sitterCLI但做了重要优化缓存 AST 解析结果。因为同一个文件在一次 PR 中可能被多次 diff比如 reviewer 要求 rebase 后重新评审重复解析 AST 会拖慢 40% 速度。我们用文件路径 commit hash 作为 key存到内存 LRU cache命中率稳定在 89%。这部分代码不到 200 行但让评审延迟从平均 8.3 秒降到 3.1 秒测试环境MacBook Pro M2, 16GB RAM。3.2 Review Router让不同代码区域享受定制化评审“一刀切”的评审规则必然失效。支付模块的变更和 CI 脚本的变更风险维度完全不同。review-router 的作用就是把 diff-extractor 输出的语义变更路由到最匹配的评审策略。它的配置是一个 YAML 文件rulesets.yamldefault: model: qwen2.5:7b prompt_template: generic-review.j2 max_tokens: 2048 rules: - name: payment-module match_paths: - ^src/payment/.* - ^src/core/transaction.* match_types: - SIGNATURE_CHANGE - STATE_MACHINE_ADD model: deepseek-coder:6.7b prompt_template: payment-review.j2 tools: - grep - sqlite3 max_tokens: 4096 - name: infra-change match_paths: - ^Dockerfile$ - ^k8s/.*\\.yaml$ model: phi3:3.8b prompt_template: infra-review.j2 tools: - grep max_tokens: 1024Router 的匹配逻辑是先按match_paths正则匹配文件路径再按match_types匹配语义变更类型如果多条规则匹配取max_tokens最大的那条优先保障复杂逻辑的评审深度如果都不匹配回落到default。关键细节在于prompt_template的设计。以payment-review.j2为例它不是简单描述“请评审代码”而是包含角色设定“你是一名有 10 年支付系统经验的 SRE熟悉 PCI DSS 合规要求”输入约束“你将收到1) Git Diff 片段2) 该文件近 3 次 commit message3) 当前函数在调用链中的位置格式order_service → payment_gateway → transaction_processor”输出格式“严格按 JSON 输出{ severity: critical|high|medium|low, line_number: 42, message: ..., suggestion: ... }。禁止任何额外文本。”这种结构化输出让后续的 agent-runner 能直接解析无需正则提取。我们测试过相比自由文本 promptJSON 强约束让 LLM 输出格式错误率从 34% 降到 7%且suggestion字段的可执行性即开发者能直接 copy-paste 使用提升 2.8 倍。3.3 Agent Runner多步工具调用的稳定执行引擎LLM Agent 的最大挑战不是“能不能调用工具”而是“调用失败后怎么恢复”。比如grep命令找不到文件或sqlite3查询超时通用框架往往直接报错中断。agent-runner 的设计哲学是“把失败当作正常流程的一部分”。它的执行循环伪代码如下for step in range(MAX_STEPS): # Step 1: LLM 生成 tool call 或 final answer response llm.invoke(prompt_with_history) if response starts with {tool: ...}: # Step 2: 解析 tool call执行命令 tool_name, args parse_tool_call(response) try: result execute_tool(tool_name, args) # Step 3: 把结果追加到 history进入下一轮 history.append(fTool {tool_name} returned: {result}) except ToolExecutionError as e: # Step 4: 失败时生成“降级提示”喂给 LLM history.append(fTool {tool_name} failed: {e}. Try alternative approach.) # 例如grep 失败时提示“请直接分析 diff 中的上下文” else: # Step 5: LLM 生成最终 review comment结束循环 return parse_final_output(response)实操中最常遇到的失败场景是git show HEAD~1:...报错 “fatal: bad revision”。原因通常是PR 的 base 分支不是main而是release/2.3导致HEAD~1指向错误。我们的解决方案是在 agent-runner 启动时先执行git merge-base HEAD origin/main获取正确的 base commit再用它替换HEAD~1。这个逻辑被封装成get_base_commit()工具所有其他 tool call 都依赖它形成“失败-降级-重试”的韧性链路。另一个关键优化是tool result 截断。LLM 的 context window 有限而grep -r PENDING_PAYMENT .可能返回上千行。agent-runner 会对文本类结果grep、cat只保留前 50 行 后 10 行对结构化结果sqlite3 的 JSON 输出只取前 20 条记录在截断处插入提示“[TRUNCATED: 127 lines omitted. Full result available viaoc-review --debug]”。这既保证 LLM 能看到关键信息又避免 context overflow。我们在 100 次压力测试中验证截断策略让 token 使用量降低 63%而关键信息保留率达 99.2%通过人工抽样比对。3.4 Review Archiver让每一次评审都成为团队知识资产评审结果如果只停留在 CLI 输出里它的价值就折损 80%。review-archiver 的使命是把瞬时的 AI 判断固化为可检索、可复用、可度量的团队资产。它支持两种存储模式本地 SQLite适合个人或小团队schema 如下CREATE TABLE reviews ( id INTEGER PRIMARY KEY, pr_number TEXT, commit_hash TEXT, file_path TEXT, line_number INTEGER, severity TEXT CHECK(severity IN (critical,high,medium,low)), message TEXT, suggestion TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, confirmed_by TEXT, -- 人工确认者空表示未确认 confirmed_at TIMESTAMP );Confluence REST API适合中大型团队自动创建页面标题为 “PR#1234 Review Summary”内容包含Diff 摘要变更文件列表、总行数AI 生成的 top 3 high/critical issues人工确认记录谁、何时、确认了哪些、驳回了哪些关联 Jira ticket如果 PR message 里有JIRA-123。Archiver 的核心价值在于反哺规则迭代。我们每月跑一次 SQLSELECT file_path, COUNT(*) as issue_count, AVG(CASE WHEN severitycritical THEN 1 ELSE 0 END) as critical_ratio FROM reviews WHERE created_at date(now, -30 days) GROUP BY file_path ORDER BY issue_count DESC LIMIT 5;结果会暴露“高频出问题的模块”。比如上月src/payment/gateway.py出现了 17 次critical问题我们就知道要么这个模块的评审规则太松要么开发者培训不到位。于是我们把gateway.py加入payment-moduleruleset并在 prompt 里增加一条“特别检查process_payment函数的幂等性实现必须包含idempotency_key参数校验和 DB 唯一索引”。这种“评审 → 归档 → 分析 → 优化规则”的闭环让 open-code-review 不是静态工具而是持续进化的质量引擎。它不承诺“100% 发现所有 bug”但能确保“同样的错误第二次出现时AI 一定会提醒”。4. 实操部署与避坑指南从零到每天自动运行4.1 环境准备三步完成基础部署Step 1安装核心依赖# 推荐用 conda 创建独立环境避免 Python 版本冲突 conda create -n oc-review python3.10 conda activate oc-review # 安装 open-code-review 主包假设已发布到 PyPI pip install open-code-review # 安装本地 LLM 运行时Ollama # macOS: brew install ollama ollama pull qwen2.5:7b deepseek-coder:6.7b # Linux: curl -fsSL https://ollama.com/install.sh | sh ollama pull ... # Windows: 下载 ollama-windows-amd64.exe添加到 PATH提示不要用pip install ollama那是 Python SDK不是运行时。Ollama 必须作为系统服务运行否则oc-review无法连接。Step 2初始化配置# 生成默认配置 oc-review init # 编辑 ~/.oc-review/config.yaml # 关键配置项 models: default: qwen2.5:7b payment: deepseek-coder:6.7b tools: enabled: [grep, sqlite3, pylint] storage: type: sqlite # 或 confluence confluence_url: https://your-team.atlassian.net/wiki confluence_token: your-api-token注意confluence_token必须是 Personal Access Token且权限包含read:confluence-content.all和write:confluence-content.all。用邮箱密码会失败。Step 3验证基础功能# 测试 diff-extractor echo test test.py git add test.py git commit -m test oc-review --diff HEAD~1 --dry-run # 测试 LLM 连通性 oc-review --model qwen2.5:7b --test-prompt Hello, are you ready? # 测试完整流程模拟一个简单变更 git checkout -b feature/test-review echo def hello(): return world hello.py git add hello.py git commit -m add hello func oc-review --diff HEAD~1 --output markdown如果最后一步输出类似## [CRITICAL] hello.py:1 - Function lacks type hints说明环境已就绪。4.2 集成到开发工作流让评审成为本能Pre-commit Hook推荐给个人在.git/hooks/pre-commit里添加#!/bin/sh # 跳过 CI 构建时的 hook if [ -n $CI ]; then exit 0 fi # 只对 Python 文件运行 CHANGED_PY$(git diff --cached --name-only | grep \.py$) if [ -n $CHANGED_PY ]; then echo Running open-code-review on changed Python files... # 限制只检查新增/修改的函数避免全量扫描 oc-review --diff HEAD --files $CHANGED_PY --ruleset default --output json 2/dev/null | \ jq -r .[] | select(.severitycritical or .severityhigh) | \(.file_path):\(.line_number) \(.message) | \ sed s/^/PRE-COMMIT ERROR: / # 如果有 critical/high 问题阻止 commit if [ $? -eq 0 ]; then echo Critical/High issues found. Fix them before committing. exit 1 fi fi实操心得不要在 pre-commit 里做 full review只检查critical/high且超时 5 秒自动跳过。否则开发者会因“评审慢”而禁用 hook。我们实测只检查高危问题平均增加 commit 时间 1.2 秒开发者接受度达 92%。CI/CD 集成推荐给团队在.gitlab-ci.yml或.github/workflows/review.yml中review-code: stage: test image: python:3.10 before_script: - pip install open-code-review ollama # 安装 CLI 和 SDK - ollama pull qwen2.5:7b # 拉取模型CI runner 通常无 GPU用小模型 script: - oc-review --diff $CI_COMMIT_BEFORE_SHA --model qwen2.5:7b --output json review-report.json after_script: - | if [ -s review-report.json ]; then # 提取 critical 问题数 CRITICAL_COUNT$(jq [.[] | select(.severitycritical)] | length review-report.json) if [ $CRITICAL_COUNT ! 0 ]; then echo Found $CRITICAL_COUNT critical issues! # 发送到飞书机器人示例 curl -X POST https://open.feishu.cn/open-apis/bot/v2/hook/xxx \ -H Content-Type: application/json \ -d {\msg_type\:\text\,\content\:{\text\:\PR #$CI_PIPELINE_ID has $CRITICAL_COUNT critical issues. Report: $(cat review-report.json | base64)\}} exit 1 fi fi注意CI 环境里不要用deepseek-coder:6.7b它需要 GPU。我们用qwen2.5:7b作为 CI 默认模型它在 CPU 上推理速度是deepseek-coder的 3.1 倍且对常见 Python 问题识别准确率只低 4.2%基于 500 个样本测试。VS Code 集成提升体验在 VS Code 的settings.json中{ task.problemMatchers: [$oc-review], tasks: { version: 2.0.0, tasks: [ { label: Review Current File, type: shell, command: oc-review --file ${file} --model qwen2.5:7b --output markdown, group: build, presentation: { echo: true, reveal: always, focus: false, panel: shared, showReuseMessage: true, clear: true } } ] } }然后按CtrlShiftP→ “Tasks: Run Task” → “Review Current File”就能在终端看到结构化评审结果。我们还开发了一个简易插件把oc-review的 JSON 输出渲染成 VS Code 的 Problems 面板点击 error 能直接跳转到对应行——这部分代码已开源在 GitHub。4.3 常见问题与独家排查技巧问题现象根本原因解决方案oc-review报错Connection refusedOllama 服务未启动或端口被占用执行ollama serve手动启动检查~/.ollama/config.json的host是否为127.0.0.1:11434macOS 上可能被Little Snitch阻止需放行评审结果全是{review_comment: {message: I cannot provide a review...}}LLM context overflowprompt diff 超过模型限制在config.yaml中设置max_tokens: 1024或启用--truncate-diff参数自动截断长 diffgrep工具调用返回空但文件明明存在oc-review运行在虚拟环境而grep在系统 PATH但某些 shell如 zsh的PATH未继承在config.yaml中显式指定tools.grep.path: /usr/bin/grep或改用shutil.which(grep)动态查找Confluence 存储失败报401 UnauthorizedPersonal Access Token 权限不足或已过期重新生成 token勾选read:confluence-content.all和write:confluence-content.all检查confluence_url是否带/wiki后缀正确应为https://xxx.atlassian.net不加/wiki同一 PR 多次评审结果不一致LLM 的 temperature 设置过高默认 0.7导致随机性大在config.yaml中全局设置temperature: 0.1对critical问题强制temperature: 0.0独家避坑技巧Prompt 版本管理不要把 prompt 写死在代码里。我们用jinja2模板存放在~/.oc-review/prompts/每次oc-review启动时加载。这样更新规则只需改 YAML 和模板无需发版。模型降级策略在config.yaml中配置fallback_models: - qwen2.5:7b - phi3:3.8b - tinyllama当deepseek-coder:6.7b响应超时30s自动切换到下一个模型。实测让 99.8% 的评审请求能在 15 秒内完成。