OpenCode v2 CI 与自动化实战:无交互运行、权限收口与制品闭环

OpenCode v2 CI 与自动化实战:无交互运行、权限收口与制品闭环

这是《OpenCode v2 实战:从零搭建企业级 AI 编程助手》专题第 10 篇。上一篇解决了长会话中的 Compaction、Snapshots 与任务续跑;本篇把 Agent 放进真正的工程流水线:使用 opencode run 无交互执行审查与分析,用独立服务和最小权限缩小影响面,把模型输出、测试结果和差异证据保存为制品,并为超时、失败、重试和人工审批建立明确边界。

把 AI 命令复制进 CI 配置并不难,难的是让这条流水线长期可信。交互式使用时,人可以看到权限弹窗、修正含糊指令、阻止危险操作;无人值守环境没有这些缓冲。一次过宽的授权、一个来自不可信 PR 的提示注入、一条把密钥打印到日志的命令,都会把"自动化提效"变成真实事故。

因此,CI 中的 Agent 不应该被设计成一个拥有仓库全部权限的"自动程序员",而应该被设计成受约束的流水线步骤:输入固定、能力可枚举、输出可归档、失败可解释、写操作可审批。

本文将完成七件事:

  1. 讲清 opencode run 与交互式 TUI 的边界;
  2. 用 --standalone 隔离 CI 会话、配置和工具执行;
  3. 设计适合无人值守环境的 Permissions 与 Policies;
  4. 给出可直接改造的 GitHub Actions 审查流水线;
  5. 把回复、差异、测试和元数据整理成可追溯制品;
  6. 建立超时、失败、重试与幂等策略;
  7. 给出从只读审查到受控修复的分阶段落地方案。

一、先建立正确模型:CI Agent 是一个受控步骤

1. 交互式会话与无交互运行的差异

日常开发时,直接执行 opencode 会打开全屏终端界面。用户能够选择 Agent、继续对话、查看工具调用,并在权限为 ask 时作出决定。

自动化场景应使用:

bash 复制代码
opencode run "Explain this repository"

opencode run 不打开交互界面,而是提交一条消息并把回复打印到终端。它适合脚本、CI Job、定时任务和批处理,但"没有界面"不等于"没有风险":模型仍可能读取文件、调用 Shell、启动子 Agent 或访问已配置的外部工具,实际边界仍由运行账户、配置、权限和组织 Policy 共同决定。

2. 流水线不是聊天窗口

CI 任务应当满足下面的约束:

text 复制代码
固定输入
  → 明确 Agent 与模型
  → 受限工具和目录
  → 有时限的执行
  → 结构化或可归档输出
  → 机器门禁与人工复核

不要让一个 Job 同时"自由理解需求、修改任意文件、执行任意命令、推送分支、发布生产"。职责越多,失败后越难判断是模型、工具、代码、网络还是权限出了问题。

3. 最适合先自动化的任务

优先选择只读、结果可验证、失败不改变外部状态的场景:

场景 输入 输出 推荐风险级别
PR 代码审查 当前差异、仓库规则 审查报告 低
测试失败归因 日志、测试代码 原因与候选修复 低
依赖升级影响分析 Lockfile、变更日志 影响清单 低
文档一致性检查 API、README、示例 不一致项 低
自动生成补丁 明确目录与测试 Patch 制品 中
自动提交或推送 补丁、写入凭证 远程分支 高
部署或生产写入 构建物、环境凭证 外部副作用 极高

第一阶段只让 Agent 输出建议。第二阶段允许它在临时工作区生成补丁,但不推送。只有当审查、测试、审计和回滚都成熟后,才考虑受控写入。

二、opencode run 的关键参数怎样组合

1. 显式选择模型和 Agent

自动化不应依赖某台机器的临时默认值:

bash 复制代码
opencode run \
  --model anthropic/claude-sonnet-5-5 \
  --agent reviewer \
  "Review the current changes for correctness, security, and missing tests."

--model 使用 provider/model 形式;--agent 选择已经配置并评审过的角色。示例模型只用于说明参数,生产环境应锁定团队验证过的模型和 OpenCode 版本。

2. 用文件参数收窄上下文

当任务只涉及少量文件时,可显式附加:

bash 复制代码
opencode run \
  --agent reviewer \
  --file src/server.ts \
  --file src/client.ts \
  "Review these files for concurrency bugs and missing error handling."

显式文件并不自动撤销 Agent 的其他读取能力,因此仍需配置 Permissions。它的价值是让输入意图更清晰,减少模型先扫描整个仓库的成本和噪声。

3. 为脚本输出 NDJSON

需要机器消费事件时,可以使用:

bash 复制代码
opencode run --format json "List the TODO comments" > opencode-events.ndjson

官方将该格式定义为 newline-delimited JSON。NDJSON 适合流式处理和逐行归档,但解析器不应猜测未承诺的字段。升级 OpenCode 后,应先在测试流水线保存一份真实输出,回归内部解析器,再推广新版本。

如果只需要给人阅读的报告,保持默认文本输出更简单:

bash 复制代码
opencode run --agent reviewer "Review the pull request" > opencode-review.md

4. 谨慎理解 --continue 与 --session

继续最近会话:

bash 复制代码
opencode run --continue "Now check the expired-token case"

继续指定会话:

bash 复制代码
opencode run --session ses_4f2a1c "Check edge cases"

这两个能力适合人工驱动的分阶段任务,但普通 CI 更推荐"每次运行输入完整、会话独立"。复用历史会话会引入隐藏状态:上次运行的分支、文件、批准规则和结论可能已经过期。只有当任务确实需要跨 Job 延续时,才保存会话 ID,并把 Commit SHA、配置版本和输入摘要一并记录。

5. --auto 不是安全开关

bash 复制代码
opencode run --auto "Fix the failing test"

--auto 会自动批准没有被明确拒绝的权限请求。它解决的是"无人点击 ask"问题,而不是"自动识别危险动作"。如果默认规则过宽,--auto 会扩大风险。

正确顺序是:

  1. 先用 Permissions 明确允许、询问和拒绝;
  2. 再用 Policies 写不可被项目放宽的硬拒绝;
  3. 让 CI 运行账户本身只有最小系统权限;
  4. 最后才决定特定 Job 是否需要 --auto。

只读审查通常不需要 --auto;受控修复可以在严格 deny 基线上使用,但必须把所有外部副作用排除在外。

三、为什么 CI 应优先使用 --standalone

OpenCode 默认会发现或启动用户级共享后台服务。该服务持有会话、配置、集成、权限和工具执行状态。开发机上共享服务很方便,CI 中却会带来不必要的状态耦合。

bash 复制代码
opencode run --standalone "Review this repository"

--standalone 为当前命令使用私有服务,适合 CI 的原因包括:

  • 不复用开发者本地的会话与保存批准;
  • 不与其他并行 Job 共享运行状态;
  • 环境变量和 Provider Key 只进入本次私有服务;
  • Job 结束后更容易销毁整个执行环境;
  • 故障可以归因到当前 Commit、配置和输入。

可以把一次 CI 运行理解为一次短生命周期沙箱:

text 复制代码
Runner 启动
  → Checkout 固定 Commit
  → 安装锁定版本
  → 注入最小 Secret
  → 启动 standalone 私有服务
  → 执行单一任务
  → 保存报告与证据
  → 销毁 Runner

需要强调:--standalone 隔离的是 OpenCode 服务状态,不是操作系统安全边界。Shell 仍继承 Runner 用户的文件、进程和网络权限。真正的隔离仍要依赖临时 Runner、容器、只读凭证、网络策略和最小化令牌。

四、为无人值守环境设计权限基线

1. ask 在 CI 中通常意味着无法继续

Permissions 的 effect 有 allow、deny 和 ask。交互客户端可以处理 ask,无人值守客户端必须预先决定如何处理请求。不能把所有 ask 粗暴变成 allow,否则审批边界会在最需要它的地方消失。

CI 规则应该尽量确定化:允许什么、拒绝什么都写清楚,未覆盖能力让任务明确失败并输出原因。

2. 只读审查 Agent 示例

jsonc 复制代码
{
  "$schema": "https://opencode.ai/config.json",
  "permissions": [
    { "action": "external_directory", "resource": "*", "effect": "deny" },
    { "action": "read", "resource": "*", "effect": "allow" },
    { "action": "glob", "resource": "*", "effect": "allow" },
    { "action": "grep", "resource": "*", "effect": "allow" },
    { "action": "edit", "resource": "*", "effect": "deny" },
    { "action": "shell", "resource": "*", "effect": "deny" },
    { "action": "shell", "resource": "git status *", "effect": "allow" },
    { "action": "shell", "resource": "git diff *", "effect": "allow" },
    { "action": "shell", "resource": "git log *", "effect": "allow" },
    { "action": "subagent", "resource": "*", "effect": "deny" },
    { "action": "webfetch", "resource": "*", "effect": "deny" },
    { "action": "websearch", "resource": "*", "effect": "deny" }
  ],
  "agents": {
    "ci-reviewer": {
      "description": "Review checked-out code without modifying it",
      "mode": "primary",
      "system": "Review only. Cite file paths and evidence. Never edit files or request credentials.",
      "permissions": [
        { "action": "edit", "resource": "*", "effect": "deny" }
      ]
    }
  }
}

规则按顺序合并,最后一个匹配项生效,因此 Shell 的通配拒绝放在前面,精确的只读 Git 例外放在后面。一次操作如果检查多个资源,其中任何一个为 deny,整个操作都会被拒绝。

3. 默认外部目录必须显式收口

官方文档指出,默认策略没有要求 external_directory 询问,因此 Location 和工作树之外的路径不会自动弹出审批。CI 配置应主动添加:

jsonc 复制代码
{ "action": "external_directory", "resource": "*", "effect": "deny" }

同时要记住:Shell 对命令中目录的推断是尽力而为,不能把路径匹配当成完整沙箱。与其维护一长串"危险命令黑名单",不如为只读 Job 建立极窄的 Shell 白名单。

4. 用 Policies 写不可被仓库放宽的红线

Permissions 属于 Agent 工具规则;Policies 只会进一步收紧,不能授予能力。系统级或组织级配置可以拒绝仓库自行放宽的操作:

jsonc 复制代码
{
  "$schema": "https://opencode.ai/config.json",
  "policies": [
    { "action": "tool.use", "resource": "shell:git push *", "effect": "deny" },
    { "action": "tool.use", "resource": "shell:git tag *", "effect": "deny" },
    { "action": "tool.use", "resource": "shell:gh pr merge *", "effect": "deny" },
    { "action": "tool.use", "resource": "external_directory:*", "effect": "deny" },
    { "action": "integration.use", "resource": "mcp:*", "effect": "deny" }
  ]
}

Policy 在权限规则和已保存批准之后执行;命中 deny 时会直接阻止,不会进入审批。企业环境应把这类红线放在系统配置、受管配置或 Console,而不是只放在仓库内。

5. 三层边界缺一不可

层级 控制对象 典型措施
Runner/容器 文件、进程、网络、系统凭证 临时 Runner、非特权用户、网络出口限制
OpenCode Policy 组织级不可放宽红线 禁止 push、生产工具、外部目录
Agent Permissions 当前角色能做什么 只读 Git、禁编辑、禁子 Agent

只做其中一层都不够。提示词中的"请不要推送"更不能替代强制规则。

五、一个可落地的 GitHub Actions 只读审查流程

下面示例把 OpenCode 作为 PR 的只读审查步骤。它不写仓库、不推送分支,也不使用默认 GITHUB_TOKEN 做外部变更。

yaml 复制代码
name: OpenCode Review

on:
  pull_request:
    types: [opened, synchronize, reopened]

permissions:
  contents: read

concurrency:
  group: opencode-review-${{ github.event.pull_request.number }}
  cancel-in-progress: true

jobs:
  review:
    runs-on: ubuntu-latest
    timeout-minutes: 20

    steps:
      - name: Checkout exact revision
        uses: actions/checkout@v6
        with:
          fetch-depth: 0

      - name: Install pinned OpenCode CLI
        env:
          OPENCODE_VERSION: "2.0.21"
        run: npm install --global "@opencode/cli@${OPENCODE_VERSION}"

      - name: Capture change metadata
        shell: bash
        run: |
          mkdir -p artifacts
          git status --short > artifacts/git-status.txt
          git diff --stat "${{ github.event.pull_request.base.sha }}"...HEAD \
            > artifacts/diff-stat.txt

      - name: Run read-only review
        shell: bash
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
          BASE_SHA: ${{ github.event.pull_request.base.sha }}
          HEAD_SHA: ${{ github.event.pull_request.head.sha }}
        run: |
          set -o pipefail
          opencode run \
            --standalone \
            --agent ci-reviewer \
            --model anthropic/claude-sonnet-5-5 \
            "Review the diff from ${BASE_SHA} to ${HEAD_SHA}. Focus on correctness, security, regressions, and missing tests. Cite file paths and explain evidence. Do not modify files." \
            2>&1 | tee artifacts/opencode-review.md

      - name: Publish job summary
        if: always()
        shell: bash
        run: |
          if [ -f artifacts/opencode-review.md ]; then
            cat artifacts/opencode-review.md >> "$GITHUB_STEP_SUMMARY"
          else
            echo "OpenCode did not produce a review report." >> "$GITHUB_STEP_SUMMARY"
          fi

      - name: Upload evidence
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: opencode-review-${{ github.run_id }}
          path: artifacts/
          retention-days: 14

1. 为什么要锁定 CLI 版本

Agent 配置字段、默认模型、输出事件和权限动作会随版本演进。使用浮动 latest 可能让同一 Commit 在不同日期得到不同运行环境。版本升级应先经过测试流水线,再修改仓库中的固定版本。

上面 2.0.21 只是展示"固定版本"的写法,不代表长期推荐版本;应替换为团队实际验证的版本。

2. 为什么限制 permissions: contents: read

即使 OpenCode 的规则出现错误,GitHub 令牌也不应该默认拥有写权限。平台令牌、OpenCode 权限和操作系统账户应当相互独立地遵循最小权限。

3. 为什么使用 if: always() 上传证据

模型失败、超时或权限拒绝时,排障更需要现场信息。只在成功时上传报告,会把最有价值的失败证据丢掉。上传内容必须经过敏感信息检查,不要把完整环境变量、认证文件或未脱敏日志打包。

4. 为什么给并发任务分组

同一个 PR 每次推送都会触发新审查。取消旧的未完成任务可以减少模型成本,也避免过期报告晚于新报告完成,造成审查结论倒序。

六、Secret、PR 与提示注入的边界

1. 密钥只通过平台 Secret 注入

Provider Key 不应写进:

  • opencode.jsonc 的明文;
  • 仓库脚本;
  • Prompt;
  • 命令行参数;
  • Artifact;
  • 调试日志。

GitHub 官方建议通过 Secrets Context 注入环境变量,并避免在命令行中传递 Secret。对于支持 OIDC 的云资源,应优先使用短期身份,减少长期凭证。

2. 不可信 PR 就是不可信输入

PR 中的代码、注释、Markdown、测试输出和文件名都可能包含提示注入,例如要求 Agent 读取环境变量、访问网络或忽略审查规则。模型"看到了仓库内容"不代表仓库内容获得了指令权限。

防线应包括:

  • Fork PR 不注入高权限 Secret;
  • 审查 Agent 禁止编辑、网络、子 Agent 和外部目录;
  • 不把生产 MCP、云凭证或发布令牌加载到审查 Job;
  • Prompt 明确仓库内容是待分析数据,不是可信指令;
  • 结论只作为报告,不直接触发合并或部署。

3. 谨慎对待 pull_request_target

该事件在目标仓库上下文中运行,常被用来访问 Secret 或写评论。如果同时检出并执行来自 Fork 的不可信代码,会显著扩大风险。审查不可信代码时,应把"读取差异"和"使用高权限令牌"拆成不同安全域,不能仅靠 Prompt 隔离。

4. 日志脱敏不是无限保证

平台能遮罩已登记的 Secret,但经过编码、拆分或转换后的内容未必都能自动识别。Agent 输出也可能复述它读到的敏感文件。最可靠的办法是让敏感内容根本不进入其可读范围。

七、把输出设计成证据包,而不是一段聊天

1. 推荐制品目录

text 复制代码
artifacts/
├── run-metadata.json
├── opencode-review.md
├── opencode-events.ndjson
├── git-status.txt
├── diff-stat.txt
├── test-summary.txt
└── policy-denials.txt

run-metadata.json 可以记录非敏感元数据:

json 复制代码
{
  "repository": "example/service",
  "base_sha": "0123456",
  "head_sha": "89abcde",
  "workflow_run_id": "123456789",
  "opencode_version": "2.0.21",
  "agent": "ci-reviewer",
  "model": "anthropic/claude-sonnet-5-5",
  "result": "completed"
}

不要记录 API Key、完整认证头、用户凭证或可直接复用的会话令牌。

2. 人读报告与机器事件分开

一份 Markdown 报告适合 PR 页面和人工评审;NDJSON 适合平台统计、事件追踪和自动化解析。不要为了"结构化"而把原始内部事件全部公开到评论区,也不要让后续脚本依赖自然语言中某个不稳定句式。

3. Artifact 需要生命周期和完整性

GitHub Actions 可以为 Artifact 设置 retention-days。保留期应按审计和成本要求设定,而不是永久堆积。官方上传动作还会返回 Artifact 的 SHA-256 digest,下载动作会重新计算并验证;关键流程可以把 digest 记录到审计系统。

4. 把验证结果放在模型结论旁边

模型说"测试应该通过"不是证据。制品中应保存真实命令的退出状态和摘要:

text 复制代码
Agent 结论:怀疑缓存失效条件错误
代码位置:src/cache.ts:87
真实验证:npm test -- cache.spec.ts
退出状态:0
测试数量:18 passed
Commit:89abcde

Agent 负责提出假设和解释证据,确定性工具负责证明构建、测试、格式和静态检查是否通过。

八、失败、超时与重试怎样设计

1. 先按失败类型分类

类型 示例 是否自动重试
临时基础设施错误 网络抖动、Provider 5xx 可有限重试
速率限制 429、额度瞬时不足 按退避策略重试
权限拒绝 Shell/目录/Policy deny 不重试,修正规则或任务
输入错误 文件不存在、参数错误 不重试,修复配置
测试失败 代码行为不符合预期 不重复同一动作,进入诊断
已发生外部写入后连接中断 评论、提交、部署状态不明 先查实时状态,禁止盲重放

2. 使用有界指数退避

只对明确可重试、最好是只读且幂等的请求使用重试:

text 复制代码
第 1 次失败 → 等待 5 秒
第 2 次失败 → 等待 15 秒
第 3 次失败 → 等待 45 秒
仍失败 → 保存证据并结束

每次重试都应保留尝试编号和错误类型。不要无限循环,也不要在一次昂贵请求失败后立即并发十次相同请求。

3. Job 和命令都要有时间预算

GitHub Actions 的 timeout-minutes 是外层保险。内部脚本还应限制模型调用、测试和构建各自的时间。这样才能区分"Agent 没有结束""测试卡住"和"整个 Runner 超时"。

4. 外部副作用必须使用幂等键

如果后续流程要写评论或创建工单,使用稳定键避免重复:

text 复制代码
idempotency_key = 仓库 + PR 编号 + Head SHA + 检查类型

重试前先查询该键对应的结果是否已经存在。对于 Git push、发布、付款、数据库写入等不可安全重放的动作,结果不明时必须先读实时状态。

5. 不要让模型自行决定无限重试

重试属于工作流控制逻辑,应由外层脚本或 CI 平台管理。Agent 可以解释失败并建议下一步,但不应通过含糊 Prompt 自行循环调用同一外部系统。

九、从只读审查升级到受控生成补丁

1. 在临时工作区允许编辑

受控修复 Job 可以允许 Agent 编辑指定目录,但仍拒绝 Push、外部目录和生产集成:

jsonc 复制代码
{
  "permissions": [
    { "action": "edit", "resource": "*", "effect": "deny" },
    { "action": "edit", "resource": "src/*", "effect": "allow" },
    { "action": "edit", "resource": "tests/*", "effect": "allow" },
    { "action": "shell", "resource": "*", "effect": "deny" },
    { "action": "shell", "resource": "npm test *", "effect": "allow" },
    { "action": "shell", "resource": "npm run lint *", "effect": "allow" },
    { "action": "shell", "resource": "git diff *", "effect": "allow" }
  ]
}

注意这里的 src/* 使用整值通配匹配;应根据真实目录结构和规范化路径验证规则是否覆盖预期文件。

2. 输出 Patch,不直接推送

bash 复制代码
git diff --binary > artifacts/opencode-fix.patch

随后由独立 Job 完成:

  1. 在干净工作树应用 Patch;
  2. 运行完整测试和安全检查;
  3. 生成变更摘要;
  4. 请求 Code Owner 或维护者批准;
  5. 批准后由受控机器人身份提交。

生成与提交拆开后,即使 Agent 获得编辑权限,也没有远程仓库写权限。

3. 写入流程要跨越明确门禁

text 复制代码
Agent 生成补丁
  → 确定性测试
  → 静态与依赖扫描
  → Patch 制品
  → 人工审批
  → 独立机器人提交

每个箭头都应能回答:输入是什么、由谁批准、证据在哪里、失败后如何恢复。

十、成本控制不是"少用模型"这么简单

1. 只在有信息增量时触发

文档拼写变化不一定需要完整安全审查。可以根据文件路径、标签或变更规模选择是否运行,以及选择不同 Agent 和模型。

2. 先用确定性工具缩小范围

text 复制代码
lint/test/scan 先运行
  → 提取失败摘要
  → 只把相关文件与日志交给 Agent

这比把整个仓库和全部构建日志都塞入 Prompt 更便宜,也更容易复核。

3. 取消过期运行

同一 PR 新 Commit 到来后,旧审查继续运行通常没有价值。使用 Concurrency 取消过期任务,是最直接的成本控制之一。

4. 记录版本、模型与用量

OpenCode 的 stats 命令可以查看模型、成本和 Token 统计;团队还应把 Workflow、Commit、Agent、模型和结果关联起来。没有维度的总账无法回答"哪个自动化检查最贵、是否带来了可验证收益"。

十一、常见反模式

反模式 1:给 Agent 一个仓库写令牌再要求"只审查"

Prompt 不是访问控制。只读任务就不应拥有写令牌。

反模式 2:在 Fork PR 中加载生产 Secret

仓库内容属于不可信输入。高权限 Secret 与不可信代码不应出现在同一执行域。

反模式 3:为了无人值守全局使用 --auto

先收口权限和 Policy,再决定是否自动批准。否则只是把审批消失包装成自动化。

反模式 4:把共享后台服务当作 CI 隔离

共享服务可能携带历史会话、批准和集成。CI 应优先使用 --standalone 和短生命周期 Runner。

反模式 5:只保存最后一段模型回答

没有 Commit、配置版本、测试摘要和权限拒绝信息,报告很难复现。

反模式 6:遇到失败就无条件重跑

权限错误、输入错误和已发生副作用后的未知状态都不应盲目重试。

反模式 7:让 Agent 既生成又发布

补丁生成、确定性验证、审批和远程写入应拆成不同阶段与身份。

十二、分阶段落地路线

阶段 1:建议模式

  • 只读仓库;
  • 禁止网络、编辑和子 Agent;
  • 输出 Markdown 报告;
  • 不作为合并硬门禁;
  • 人工统计误报和有效发现。

阶段 2:证据模式

  • 保存 NDJSON、测试摘要和差异元数据;
  • 固定 CLI、Agent、模型与配置版本;
  • 对权限拒绝、超时和 Provider 错误分类;
  • 为报告建立保留期和脱敏检查。

阶段 3:补丁模式

  • 只允许编辑指定目录;
  • 在临时工作区生成 Patch;
  • 完整测试与扫描;
  • 不直接 Push;
  • 人工审批后由独立身份提交。

阶段 4:受控闭环

  • 只对低风险、可回滚任务自动提交;
  • 使用幂等键和实时状态校验;
  • 组织级 Policy 固化红线;
  • 持续审计权限、成本、命中率和回滚率。

不要跨过前一阶段的证据直接追求"全自动修复"。自动化成熟度来自可重复和可解释,而不是来自省掉了多少确认按钮。

十三、上线检查清单

执行环境

  • 使用临时 Runner、容器或隔离账户;
  • CI 使用 opencode run --standalone;
  • CLI、Action 与关键依赖版本已固定;
  • Job、模型调用和测试都有超时;
  • 同一 PR 的过期运行会被取消。

身份与 Secret

  • Provider Key 来自 CI Secret,不在仓库和参数中;
  • 平台令牌为最小权限;
  • Fork PR 不接触高权限 Secret;
  • 日志与 Artifact 不包含认证材料;
  • 可用 OIDC 的云资源不继续使用长期密钥。

OpenCode 权限

  • external_directory 已显式 ask 或 deny;
  • Shell 使用窄白名单,而不是危险命令黑名单;
  • 编辑、网络、MCP 和子 Agent 按任务关闭;
  • 组织红线写入高优先级 Policies;
  • --auto 只在严格权限基线上使用。

输出与验证

  • 报告包含 Commit、Agent、模型和配置版本;
  • 模型结论旁边有真实测试或扫描证据;
  • 失败时仍上传经过脱敏的诊断制品;
  • Artifact 有保留期,必要时记录 digest;
  • NDJSON 解析器经过目标版本回归。

副作用与恢复

  • 生成补丁与远程提交使用不同 Job 和身份;
  • 写操作前有明确门禁;
  • 重试只覆盖可识别的临时错误;
  • 外部写入有幂等键;
  • 结果不明时先查询实时状态,不盲目重放。

十四、故障排查顺序

1. opencode run 一直不结束

先检查 Job 超时、Provider 响应、工具调用是否卡住,再检查是否遇到无人处理的权限请求。不要直接放宽所有权限。

2. 本地成功,CI 失败

依次核对 CLI 版本、工作目录、配置来源、模型名称、环境变量、文件大小写、系统 Shell 和 Runner 网络。使用 opencode debug config 查看实际合并配置,避免凭印象判断。

3. Agent 读到了工作区外文件

检查 external_directory 规则是否缺失,Runner 账户可见范围是否过大,以及 Shell 是否通过命令间接访问。补上 OpenCode 规则后,也要缩小操作系统文件权限。

4. 报告内容与当前 Commit 不一致

确认 Checkout 的 SHA、Prompt 中的 Base/Head SHA、Artifact 元数据和审查触发时间。不要复用没有绑定 Commit 的旧会话。

5. 流水线频繁被限流

先取消过期任务、收窄触发条件和上下文,再设置有界退避。并发堆积通常比单次请求更容易放大限流。

6. Patch 通过局部测试但完整构建失败

Agent 生成阶段只是一项候选变更。必须在干净工作树重新应用 Patch,并运行完整的确定性门禁,不能把 Agent 自己执行过的局部命令当作最终验收。

十五、总结

OpenCode v2 进入 CI 后,价值不在于"让模型替代一条 Shell 命令",而在于把复杂代码理解、故障归因和候选修复接入已有工程治理。真正可靠的流水线应满足:

text 复制代码
独立服务与短生命周期环境
  → 固定版本、模型和 Agent
  → 最小权限与组织 Policy
  → 明确输入和时间预算
  → 报告、事件、测试与差异制品
  → 有界重试和幂等写入
  → 人工或确定性门禁后再产生副作用

opencode run 提供了无交互入口,--standalone 提供服务级隔离,Permissions 和 Policies 提供工具边界,CI 平台提供身份、超时、并发和制品能力。它们组合起来,才能让 Agent 从"偶尔给出好答案"变成"在工程系统里可重复、可审计、可安全失败的一步"。

下一篇将继续专题第 11 篇:深入 OpenCode v2 的可观测性、成本治理与质量评估,讨论怎样记录模型、Token、工具调用、失败原因与人工采纳结果,并用可量化指标判断 Agent 自动化到底有没有产生净收益。

参考资料

本文依据 2026 年 10 月 24 日可访问的 OpenCode v2 与 GitHub Actions 官方文档整理。OpenCode v2、模型 ID、CLI 参数、权限动作和输出事件仍可能演进;生产环境应以实际安装版本的 opencode run --help、配置 Schema、官方文档和回归验证结果为准。文中的版本号与模型名用于演示固定版本和显式选择的做法,不构成长期版本推荐。

相关推荐
jiangliushi61 小时前
GPT-6.1 Sol 免费用:git status 里中文文件名变成一串数字乱?条命令改好
git·codex·1024程序员节
肖永威1 小时前
AI大模型不是答案机:研发场景下的多模型迭代工作流
人工智能·1024程序员节
INGNIGHT1 小时前
377.组合总和 Ⅳ(背包)
c++·算法·1024程序员节
海盗12341 小时前
微软技术日报 2026-10-24:CA 私钥是 4,Windows 封了中间证书未动父根
人工智能·机器人·aigc·1024程序员节
奶酪博士1 小时前
【1024快乐】用HTML写一个本地版心愿墙页面
html·1024程序员节
“AI国潮设计-小江”1 小时前
AIGC实战:Python+SDXL批量生成英歌舞IP立牌,解锁猪猪蛋糕“反差萌”流量密码(附完整API源码)
开发语言·人工智能·python·prompt·aigc
合尘猫1 小时前
AI客服国标落地一个月:从工程角度看,真正要改的是三处数据结构
数据库·人工智能·架构
wshzd1 小时前
LLM之Agent(117)|DeepSeek-Harness(二十四)Host/Client 分离与 Typert RPC 生成
1024程序员节
kaixin_learn_qt_ing1 小时前
Jenkins
运维·jenkins