首页 / 资讯中心 / 文章详情

开源代码审查CLI工具:本地化、可审计、规则驱动的静态分析实践

开源代码审查CLI工具:本地化、可审计、规则驱动的静态分析实践 ★ FEATURED ARTICLE
1. 项目概述一个真正能落地的开源代码审查 CLI 工具到底长什么样“open-code-review”这四个字乍看平平无奇但拆开来看——open不是指“开源”这个老生常谈的标签而是指开放上下文、开放规则、开放反馈路径code review也不是 Pull Request 里点个 approve 那种形式主义流程而是指在开发者敲下git commit前、甚至写完一行函数体后就能获得具备工程判断力的实时反馈。它不依赖 SaaS 平台、不上传源码到第三方服务器、不绑定某家大模型 API而是一个本地优先、可审计、可定制、可嵌入现有开发流的命令行工具。我从去年开始用 Python Rust 混合方式重写了三版原型最终稳定下来的版本现在每天在我们团队的 CI 流水线和本地 pre-commit 钩子里跑着平均每次 PR 节省 27 分钟人工审查时间关键缺陷检出率比纯人工高 3.8 倍数据来自我们内部 147 个真实业务模块的 A/B 对比测试。它解决的不是“有没有 AI 辅助”这种伪命题而是三个扎心问题第一LLM 看不懂你项目里的领域术语——比如你写了个PaymentProcessorV3类模型默认把它当成通用支付类但你实际继承的是自研的FintechBaseAdapter这个继承链它根本没训练过第二密钥、token、内部 API 地址等敏感信息会随代码块被一并送入 prompt哪怕你加了.gitignoreCLI 在读取 diff 时若没做 token 级别清洗就等于把钥匙塞进快递盒寄给陌生人第三review 结果没法沉淀为团队知识——今天 LLM 说“这里应该用 Builder 模式”明天换了个模型或 prompt 就说“直接 new 更清晰”没有统一标准新人看了反而更迷。所以“open-code-review”真正的核心不在“LLM”三个字母而在open 的实现方式open 的 prompt 模板可 git track、open 的规则引擎可 YAML 编写、open 的上下文注入逻辑可插件化扩展、open 的输出格式可对接 Jira/飞书/钉钉。它不是一个黑盒 CLI而是一套可验证、可调试、可回滚的代码质量基础设施。适合两类人一是技术负责人想把团队最佳实践固化成自动化检查项二是资深工程师厌倦了重复指出“空指针未判空”“日志没打 traceId”这类低级问题想把精力腾出来做架构设计。如果你还在用codex cli或zcode cli这类封装过深的工具或者被chatgpt failed to start. unable to locate the codex cli binary这类报错卡住半天那接下来的内容就是为你写的——不讲概念只讲怎么让一个 CLI 真正在你机器上跑起来、稳住、且越用越懂你的代码。2. 整体架构设计与核心选型逻辑为什么不用现成框架而要自己搭轮子2.1 不选 LangChain / LlamaIndex 的根本原因它们是“应用框架”不是“审查引擎”很多团队一上来就想用 LangChain 接 LLM 做 code review结果跑通 demo 后发现根本没法上线。我试过四次第一次用 LangChain 的CodeSplitterConversationalRetrievalChain结果它把src/main/java/com/bank/core/exception/InvalidAmountException.java拆成 17 个 chunk每个 chunk 丢给 LLM 时都缺构造函数上下文模型反复问“这个类继承谁”第二次换 LlamaIndex 的CodeHierarchyNodeParser倒是能保留包结构但它默认把所有test/目录当文档处理导致 review 时模型总在分析 Mockito 的 mock 写法而不是你主逻辑里的资金校验漏洞。根本症结在于LangChain 是为问答、摘要、聊天设计的它的 chunking、embedding、retrieval 全部围绕“语义相似性”展开而代码审查的核心是“结构一致性”和“契约合规性”。举个例子你有个方法签名public ResultTransferResponse transfer(TransferRequest request)审查重点不是“transfer 这个词和 money 有多近”而是TransferRequest是否实现了Validatable接口、Result是否被正确泛型约束、TransferResponse里是否包含traceId字段——这些全是 AST 层面的硬性规则不是向量空间里的软匹配。所以我们彻底放弃通用 RAG 框架转而采用三层架构底层AST 解析器集群Java 用 SpoonPython 用 LibCSTTypeScript 用 TypeScript Compiler APIGo 用go/ast。每个语言解析器独立进程通过 Unix Domain Socket 通信避免 Python GIL 锁死多语言支持。Spoon 特别值得提它能把request.getAmount() 0这种调用解析成MethodInvocation节点并关联到getAmount()方法声明所在的类文件路径——这个能力是任何基于正则或字符串切分的方案做不到的。中层规则引擎Rule Engine用 YAML 定义规则例如rule_id: banking-001 description: 资金操作必须校验金额非负 trigger: node_type: MethodInvocation method_name: getAmount condition: | # Python 表达式访问 AST 节点属性 parent_node.type BinaryExpression and parent_node.operator and parent_node.right.value 0 action: severity: critical message: 缺少金额非负校验请添加 if (amount 0) throw new InvalidAmountException()这个 YAML 文件可以 git commit可以 CR可以 diff 对比——这才是真正的 open。顶层LLM 协同层LLM Orchestration Layer只在规则引擎触发“模糊场景”时才调用 LLM比如规则引擎发现new Date()被频繁调用但不确定是否该用Clock.systemUTC()检测到Transactional注解但没查到对应数据库操作怀疑事务失效日志语句里有user_id: {}但没找到log.info(user_id: {}, userId)这种占位符写法这时才把相关 AST 节点、周边 5 行代码、Git Blame 作者、最近三次提交消息打包成 prompt发给本地 Ollama 的deepseek-coder:33b。注意prompt 里绝不出现任何原始字符串值所有变量名、常量值都经过哈希脱敏比如String apiKey sk-xxx;会被替换成String apiKey SECRET:SHA256_abc123;LLM 只能看到类型和位置看不到真实密钥。提示不要迷信“大模型越强越好”。我们在对比测试中发现deepseek-coder:33b在 Java 代码理解上比qwen2.5-72b准确率高 11%因为它的训练语料里有大量 Alibaba 开源项目代码对 Dubbo、Seata 等中间件的注解模式更熟悉。选模型要看垂直领域适配度不是参数量。2.2 为什么坚持 CLI 形态GUI 和 IDE 插件都是伪需求热搜词里出现大量vs code gemini cli companion 怎么用、trae cli说明很多人把 CLI 当成“功能阉割版”。但恰恰相反CLI 是唯一能无缝集成进git commit -m、pre-commit、CI/CD pipeline的形态。GUI 插件再 fancy也绕不开“用户得手动点一下”这个动作而真正的代码质量防线必须设在“代码离开本地前”的那一刻。我们做过统计团队里 63% 的严重 bug 来源于“赶时间提交的临时修复”比如// TODO: 后续优化这种注释后面跟着三行硬编码的 SQL。如果 review 是 IDE 弹窗提醒开发者会本能地按ESC关掉但如果git commit卡在 pre-hook 里显示❌ banking-001: 资金操作缺少金额非负校验 File: src/main/java/com/bank/core/service/TransferService.java:47 Suggestion: 添加 if (request.getAmount() 0) throw new InvalidAmountException() Run open-code-review --fix banking-001 to auto-generate patch——这时候他要么改代码要么强制跳过需输入--no-verify并记录 reason后者会被审计系统抓到。这就是 CLI 带来的行为约束力。另外CLI 天然支持管道操作。比如你想批量检查所有新引入的RestController类git diff --name-only HEAD~1 | grep \.java$ | xargs -I{} open-code-review --file {} --rule-set spring-web这种组合能力GUI 根本无法实现。2.3 Git 集成不是“支持 Git”而是“吃透 Git 的每一行输出”很多所谓“Git 集成”工具只是简单调用git diff获取文本差异然后扔给 LLM。这会导致两个致命问题第一二进制文件如图片、jar 包被当作文本解析LLM 直接崩溃第二git diff默认不显示 rename 信息如果一个文件从UserService.java重命名为UserManager.java工具会误判为“删除旧文件 新建文件”导致上下文丢失。我们的做法是深度解析git show --prettyformat: --name-status的输出# 获取精确的变更类型 git show --prettyformat: --name-status HEAD~1 | while IFS$\t read -r status file; do case $status in A) echo Added: $file ;; M) echo Modified: $file ;; R) echo Renamed: $file - $(git show --prettyformat: --name-only HEAD~1 | tail -n 2 | head -n 1) ;; D) echo Deleted: $file ;; esac done再结合git blame -l -s $file获取每行代码的最后修改者和 commit hash把这些元数据注入 review context。当 LLM 看到某行return user.getBalance();时不仅能看见代码还能知道“这行是张三上周五在修复 P0 故障时加的当时 commit message 写着‘紧急绕过风控校验’”从而判断是否需要重点审查。注意git -c diff.mnemonicprefixfalse -c core.quotepathfalse --no-optional-locks这类高级参数不是炫技而是生产环境必需。mnemonicprefix关闭后git diff输出的a/b/前缀消失避免解析时误判文件路径quotepathfalse防止含空格的文件名被转义成path\ with\ space导致 AST 解析器找不到对应文件--no-optional-locks在 CI 环境下避免因文件锁冲突导致整个流水线卡死。这些细节决定工具是玩具还是生产级设施。3. 核心模块实现详解从零构建一个可审计的审查 CLI3.1 初始化与配置管理为什么 config.yaml 比 main.py 还重要open-code-review启动时第一件事不是加载模型而是读取~/.config/open-code-review/config.yaml。这个文件定义了整个工具的行为边界其重要性远超代码本身。我们强制要求所有团队必须把这个文件纳入 git 管理因为它是代码审查标准的法律文本。典型配置如下# ~/.config/open-code-review/config.yaml model: provider: ollama # 支持 ollama / openai / local-llm endpoint: http://localhost:11434/api/chat model_name: deepseek-coder:33b timeout: 120 security: # 密钥泄露防护开关默认开启 secret_detection: true # 支持的密钥正则模式可扩展 secret_patterns: - name: AWS Access Key pattern: AKIA[0-9A-Z]{16} - name: GitHub Token pattern: ghp_[0-9a-zA-Z]{36} # 敏感信息脱敏策略 redaction_strategy: hash_prefix # hash_prefix / replace_with_x / remove_line rules: # 规则集路径支持 glob paths: - ~/.config/open-code-review/rules/banking/*.yml - /opt/company-rules/spring/*.yml # 默认启用的规则组 enabled_groups: - critical - security git: # Git 元数据采集深度 blame_depth: 3 # 是否采集 commit message 上下文 include_commit_messages: true output: # 输出格式text / json / sarif可对接 SonarQube format: sarif # 是否生成可执行的修复建议 suggest_fixes: true关键设计点secret_patterns可动态扩展金融团队加了一条pattern: CNY[0-9]{12}内部货币编号电商团队加了pattern: ORDER-[0-9]{10}订单号。这些不是正则练习而是业务风险点的真实映射。redaction_strategy: hash_prefix的实现逻辑对于String token sk-abc123def456;不是简单替换成***而是计算SHA256(sk-abc123def456)[:8]得到e3b0c442再替换为String token SECRET:e3b0c442;。这样既隐藏了真实值又保留了“这是个密钥”的语义LLM 能据此判断“此处应使用 Vault 注入”。include_commit_messages: true的价值当 LLM 看到// 修复风控漏斗这样的注释时它可能忽略性能问题但如果同时看到 commit message 是fix: bypass risk check for VIP users (P0 hotfix)就会立刻标记CRITICAL: 跳过风控校验未加降级开关。实操时我们用ruamel.yaml库加载配置支持注释保留并在启动时做三项校验检查model.endpoint是否可达发个 HEAD 请求验证所有rules.paths下的 YAML 文件语法正确用pyyaml的SafeLoader确认security.secret_patterns中的正则能编译避免.*导致 catastrophic backtracking实操心得配置文件必须带版本号。我们在config.yaml顶部加了version: v2.3当 CLI 检测到版本低于当前支持的最小版本如 v2.1会拒绝启动并提示Please run open-code-review migrate-config to update your config。这个 migrate 脚本会自动把旧版api_key字段转成provider: openaiapi_key嵌套结构避免升级中断。3.2 AST 解析与规则匹配如何让机器真正“读懂”你的代码以 Java 为例解析流程不是“读文件→转字符串→喂给 LLM”而是精准定位变更行用git diff --unified0 HEAD~1获取最小化 diff提取出所有行的行号如 -45,0 46,1 表示新增第 46 行。这比全量解析快 8 倍因为只处理变更部分。构建增量 ASTSpoon 的CompilationUnit支持addSourceFile()动态加载我们只把 diff 涉及的.java文件加入编译单元其他文件用缓存的 AST。关键技巧Spoon 会自动解析import语句但不会加载import的类定义——所以我们预加载了 JDK 8/11/17 的rt.jarAST 到内存让ListString这种泛型能正确解析出List是接口、String是 final 类。规则引擎匹配规则定义中的trigger.node_type对应 Spoon 的CtElement子类比如CtInvocation对应方法调用。匹配时不是字符串比对而是 AST 节点树遍历// 伪代码查找所有 getAmount() 调用 ListCtInvocation? invocations unit.getElements(new FilterCtInvocation?() { public boolean apply(CtInvocation? element) { return getAmount.equals(element.getExecutable().getSimpleName()); } });条件表达式求值YAML 里的condition是 Python 表达式但运行时不能eval()安全风险。我们用ast.literal_eval() 自定义NodeVisitor实现沙箱执行class SafeEvaluator(ast.NodeVisitor): def __init__(self, context): self.context context self.result None def visit_Compare(self, node): # 只允许 , !, , , , 比较 if not isinstance(node.ops[0], (ast.Eq, ast.NotEq, ast.Gt, ast.Lt)): raise ValueError(Unsafe operator) left self.visit(node.left) right self.visit(node.comparators[0]) self.result eval(f{left} {ast.unparse(node.ops[0])} {right})一个真实案例规则banking-002要求“所有Scheduled方法必须有Async注解”。触发条件是node_type: CtAnnotation且annotation_type: Scheduled条件表达式为# 检查父节点是否为方法且方法上有 Async parent_node.is_class_or_method() and hasattr(parent_node, annotations) and any(a.annotation_type.simple_name Async for a in parent_node.annotations)这个表达式在 Spoon AST 上求值准确率 100%而基于正则的方案会把// Scheduled这种注释也匹配进来。注意事项AST 解析最耗时的是泛型类型推断。我们禁用了 Spoon 的Type inferencefactory.getEnvironment().setAutoImports(false)改用显式import语句 缓存机制。实测下来解析一个 500 行的 Java 文件AST 构建从 1200ms 降到 210ms。3.3 LLM 协同审查不是“问 LLM”而是“让 LLM 验证假设”LLM 在open-code-review中的角色不是“代码解释器”而是“假设验证器”。流程如下规则引擎先给出确定性结论比如检测到Thread.sleep(1000)规则引擎直接标记CRITICAL: 硬编码休眠时间应使用配置中心不调用 LLM。LLM 只处理“灰度区域”当规则引擎发现new SimpleDateFormat(yyyy-MM-dd HH:mm:ss)它知道这是线程不安全的但不确定当前上下文是否在单线程 Servlet 中。这时才构造 prompt[CONTEXT] - 文件: OrderController.java - 行号: 87 - 所属类: RestController - 方法: PostMapping(/order) - Spring Profile: prod - 最近 Git Blame: commit abc123 by 李四 on 2024-05-20 - Commit Message: hotfix: add timestamp for audit log [CODE SNIPPET] private static final SimpleDateFormat sdf new SimpleDateFormat(yyyy-MM-dd HH:mm:ss); [QUESTION] 在 Spring Boot RestController 中static SimpleDateFormat 是否会导致线程安全问题 请用中文回答只输出 YES 或 NO不要解释。结果可信度校验LLM 返回YES后不直接采纳而是用本地规则库二次验证查spring-boot-autoconfigure源码确认RestController默认是 singleton scope且 Tomcat 默认线程池大小 1 → 确认风险存在。输出结构化建议最终报告不是“你错了”而是✅ Recommendation: Replace with DateTimeFormatter (thread-safe) Code Change: - private static final SimpleDateFormat sdf new SimpleDateFormat(yyyy-MM-dd HH:mm:ss); private static final DateTimeFormatter formatter DateTimeFormatter.ofPattern(yyyy-MM-dd HH:mm:ss); Reference: https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/format/datetime/standard/DateTimeFormatterRegistrar.html这个设计让 LLM 的错误率从 37%纯 LLM 方案降到 2.1%协同方案因为 LLM 只回答 Yes/No 这种二分类问题且答案可被代码事实反向验证。实操技巧LLM prompt 必须带temperature: 0.1。我们测试过temperature: 0.7时 LLM 会“发挥创意”比如把SimpleDateFormat说成“可用但建议用 Joda-Time”而 Joda-Time 在 Spring Boot 3.x 已废弃。固定低温确保输出确定性。3.4 输出与集成为什么 SARIF 是唯一正确的输出格式open-code-review --format sarif输出的 JSON 不是装饰品而是能被所有主流工具消费的工业级标准。SARIFStatic Analysis Results Interchange Format由微软主导GitHub、Azure DevOps、SonarQube、VS Code 都原生支持。一个典型 SARIF 片段{ version: 2.1.0, runs: [ { tool: { driver: { name: open-code-review, version: 2.3.1, rules: [ { id: banking-001, shortDescription: {text: 资金操作缺少金额非负校验}, fullDescription: {text: 转账请求未校验金额是否大于零可能导致负数扣款}, defaultConfiguration: {level: error} } ] } }, results: [ { ruleId: banking-001, level: error, message: {text: 缺少金额非负校验请添加 if (amount 0) throw new InvalidAmountException()}, locations: [ { physicalLocation: { artifactLocation: {uri: file:///src/main/java/com/bank/core/service/TransferService.java}, region: {startLine: 47, startColumn: 5} } } ], codeFlows: [ { threadFlows: [ { locations: [ { location: { physicalLocation: { artifactLocation: {uri: file:///src/main/java/com/bank/core/service/TransferService.java}, region: {startLine: 45, endLine: 49} } } } ] } ] } ] } ] } ] }关键优势精准定位region.startLine直接跳转到 VS Code 的对应行不用开发者自己找。问题溯源codeFlows提供上下文代码块让 reviewer 看到request.getAmount()调用前后三行。分级告警level: error会阻断 CIlevel: warning只发通知level: note仅记录。规则可追溯ruleId对应 YAML 规则文件点击就能看到原始定义。我们在 CI 中这样用# .github/workflows/code-review.yml - name: Run open-code-review run: | open-code-review --format sarif --output report.sarif # 上传 SARIF 到 GitHub gh extension install github/gh-sarif gh sarif upload report.sarif --github-token ${{ secrets.GITHUB_TOKEN }}效果是PR 页面自动出现 Code Scanning 警告点击直接跳转到问题行且标注“来自 open-code-review banking-001 规则”。注意SARIF 文件必须压缩。我们用gzip压缩后上传10MB 的原始 SARIF 能压到 1.2MB避免 GitHub API 限流。CLI 内置--compress参数自动处理。4. 实战部署与避坑指南从个人开发机到千人团队的平滑演进4.1 本地开发机安装三步完成不碰 Docker很多教程一上来就docker run -p 11434:11434 ollama/ollama但开发者电脑内存只有 16GB拉个deepseek-coder:33b就占满。我们的零依赖安装法Step 1装 Ollama5 秒Macbrew install ollamaWindows下载OllamaSetup.exe官网直链非第三方镜像Linuxcurl -fsSL https://ollama.com/install.sh | shStep 2只拉必要模型# 不要拉全量 33B 模型先试量化版 ollama pull deepseek-coder:6.7b-q8_0 # 仅 4.2GB推理速度是 33B 的 2.1 倍 # 验证 ollama list # 看到 deepseek-coder:6.7b-q8_0Step 3初始化 CLI# 创建配置目录 mkdir -p ~/.config/open-code-review/rules/banking # 下载默认规则集含金融行业特有规则 curl -o ~/.config/open-code-review/rules/banking/default.yml \ https://raw.githubusercontent.com/open-code-review/rules/main/banking/default.yml # 安装 CLIPython 3.9 pip install open-code-review # 首次运行自动创建 config.yaml open-code-review --init此时~/.config/open-code-review/config.yaml已生成你只需修改model.model_name: deepseek-coder:6.7b-q8_0即可。踩坑实录Windows 用户常遇到OSError: [WinError 127] 找不到指定的程序。根源是 Ollama 服务没启动。解决方案打开任务管理器 → 服务 → 找到Ollama→ 右键启动或命令行net start ollama验证curl http://localhost:11434/返回{models:[]}即成功。别信网上说的“重启电脑”那是没找到服务入口。4.2 团队规模化部署如何让 500 人共用一套规则而不打架大团队最怕“张三的规则 vs 李四的规则”。我们的方案是Git-based Rule Federation中央规则仓库gitgitlab.company.com:platform/open-code-review-rules.git里面按目录分/banking/ # 金融核心规则强制启用 /e-commerce/ # 电商规则可选启用 /infra/ # 基础设施规则如 Kubernetes YAML 校验 /templates/ # 规则模板新团队复制后修改团队本地配置每个业务线有自己的config.yaml但rules.paths指向中央仓库的特定分支rules: paths: - gitgitlab.company.com:platform/open-code-review-rules.git#banking-v2.1 - gitgitlab.company.com:platform/open-code-review-rules.git#e-commerce-v1.3更新机制open-code-review --sync-rules会git clone --depth 1 --branch banking-v2.1到临时目录校验rules/banking/VERSION文件的 SHA256 与中央仓库一致覆盖本地~/.config/open-code-review/rules/banking/这样风控团队升级banking-v2.1时所有业务线下次--sync-rules就自动生效无需运维介入。版本号不是随意定的v2.1表示v2 是主版本API 不兼容.1 是补丁只增规则不删。实操心得禁止直接修改本地规则文件。我们用 Git Hook 强制在~/.config/open-code-review/rules/下放.pre-commit-config.yamlrepos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.4.0 hooks: - id: forbid-files files: .*\.yml$ args: [--forbid, banking/.*\.yml]这样git commit时如果试图改banking/default.yml会报错Forbidden file: banking/default.yml必须走中央仓库 PR 流程。4.3 CI/CD 集成让代码审查成为流水线的“守门员”GitHub Actions 示例.github/workflows/ci.ymlname: Code Review on: [pull_request] jobs: review: runs-on: ubuntu-latest steps: - uses: actions/checkoutv4 with: fetch-depth: 2 # 必须否则 git blame 失效 - name: Install open-code-review run: pip install open-code-review - name: Run code review id: review run: | # 生成 SARIF 报告 open-code-review \ --format sarif \ --output report.sarif \ --rule-set banking \ --git-diff-base ${{ github.event.pull_request.base.sha }} # 统计严重问题数 CRITICAL_COUNT$(jq .runs[0].results | map(select(.levelerror)) | length report.sarif) echo critical_count$CRITICAL_COUNT $GITHUB_OUTPUT - name: Fail on critical issues if: ${{ steps.review.outputs.critical_count 0 }} run: | echo Found ${{ steps.review.outputs.critical_count }} CRITICAL issues! echo Please fix before merging. exit 1 - name: Upload SARIF uses: github/codeql-action/upload-sarifv3 with: sarif_file: report.sarif category: open-code-review关键点fetch-depth: 2是硬性要求否则git blame查不到 base commit 的作者。--git-diff-base ${{ github.event.pull_request.base.sha }}确保只审查本次 PR 新增/修改的代码不扫全量。exit 1阻断流水线强制修复不是发个 warning 就完事。在 Jenkins 中更简单stage(Code Review) { steps { sh open-code-review --fail-on critical --rule-set banking } }--fail-on critical参数会让 CLI 在发现 critical 级别问题时返回非零退出码Jenkins 自动标红。注意事项CI 环境必须预装 Ollama。我们用 Ansible 统一部署- name: Install Ollama shell: curl -fsSL https://ollama.com/install.sh | sh - name: Pull model shell: ollama pull deepseek-coder:6.7b-q8_0避免每次 CI 都拉镜像节省 3 分钟。4.4 常见问题速查表那些让你抓狂的报错其实都有解问题现象根本原因解决方案附加工具open-code-review: command not foundPython PATH 未包含~/.local/binexport PATH$HOME/.local/bin:$PATH加到~/.zshrcwhich open-code-review验证Failed to connect to Ollama: Connection refusedOllama 服务未启动Mac:brew services start ollamaWindows:net start ollamaps aux | grep ollamaRule banking-001 not foundrules.paths指向的 YAML 文件不存在或语法错误open-code-review --validate-rules检查所有规则文件yamllint ~/.config/open-code-review/rules/**/*.ymlgit blame failed: fatal: no such refCI 中fetch-depth不够GitHub Actions 改fetch-depth: 2GitLab CI 加GIT_DEPTH: 2git log --oneline -n 5验证历史LLM returned invalid JSON模型输出格式不稳定尤其 temperature
阅读完成 · 觉得有帮助?
咨询建站