OpenCode 进阶与排障:API、Client、SDK 与常见问题

Posted on Tue 06 October 2026 in AI 编程 • Sucre Liu

会话之外的三种用法

日常你用 TUI,但 OpenCode 还能被程序使用,按"侵入程度"从低到高有三种:

  1. 命令行一次性运行:opencode run "...",适合脚本和 CI;
  2. HTTP API:服务本身暴露 API,用内置 api 命令或任何 HTTP 客户端调用;
  3. Client / SDK:把 OpenCode 接进你自己的程序。

大多数自动化需求,第 1 种就够了。别一上来就写客户端。

HTTP API:先验证,再集成

服务的 OpenAPI 文档在运行中的服务上:

/openapi.json

内置的 api 命令复用服务发现与认证,所以不用自己拼鉴权:

opencode api get /api/info
opencode api post /api/example --data '{"key":"value"}'
opencode api get /api/example --header 'X-Example:value'

它接受"HTTP 方法 + 路径"或 OpenAPI 的 operation ID;请求体默认 application/json。注意一条:opencode api 在没有可用健康服务时会启动后台服务,所以在脚本里调用要意识到这个副作用。

一个真实用途——手动触发上下文压缩(下一节还会用到):

curl -X POST http://localhost:4096/api/session/ses_example/compact \
  -H 'content-type: application/json' \
  -d '{}'

Client 与 SDK:嵌入的两条路

  • Client:@opencode/client 是生成的 TypeScript 客户端,方法类型与 API 契约同源。默认入口是 Promise 风格资源客户端加流式接口的异步迭代器;@opencode/client/effect 提供 Effect 风格的流与解码类型,其中的 Service API 能发现、启动、停止并认证本地后台服务。
  • SDK:直接把 OpenCode 托管进你的应用,不监听 HTTP。适合"我要在进程内嵌一个代理"的场景。Effect 应用和 Cloudflare Durable Objects 有各自的指南。

选择标准很简单:只是想让它在别处跑任务 → run;要让别的进程通过 HTTP 驱动 → API/Client;要把代理嵌进自己的进程 → SDK。

上下文压缩:省空间,但有代价

长会话接近模型上限时,OpenCode 会用生成的检查点替换较旧的上下文——早期消息仍有存储,但后续请求从最新检查点开始。压缩是有损的,这一点必须先接受。

默认配置大致保留 1.5 万 token 的近期对话:

{
  "compaction": {
    "auto": true,
    "keep": { "tokens": 15000 },
    "buffer": 20000
  }
}

自动压缩在每次模型调用前估算用量,达到这个上限就触发:

estimated >= min(input limit - buffer, context limit - max(output reserve, buffer))

例如输入上限 128k、buffer 20k,输入侧上限就是 108k。两个参数的含义:

  • keep.tokens(默认 15000):本地摘要旁边保留的近期上下文;调大保留更多细节,但留给新工作的空间更少。
  • buffer(默认 20000):低于显式输入上限的安全边距;调大更早开始压缩。

它还能识别 provider 报的上下文溢出:如果没有产生助手输出或其他重试证据,会压缩并重试同一步一次(需要 auto: true);第二次溢出就以错误返回。

provider 也可以选原生压缩:

{
  "providers": {
    "openai": {
      "settings": { "compaction": { "type": "native" } },
      "models": { "gpt-4.1": { "settings": { "compaction": { "type": "summary" } } } }
    }
  }
}

model 设置覆盖 provider 设置。

一个必须知道的极限:如果几乎整个请求都是固定的系统提示和工具 schema,压缩救不了。官方给了个直白的例子——128k 上下文 = 120k 固定指令和工具 + 8k 对话时,没有可压缩的历史。这种情况下要减的是工具和常驻指令,不是对话。

顺带说两个相邻机制:warming 用周期性瞬态请求保持最近活跃的模型会话"热"(默认关闭,注意成本);sharing 字段虽然被接受,但目前尚不支持会话分享。而 instructions 字段也被接受但不加载——项目指令请用 AGENTS.md。

一套可复制的排障流程

OpenCode 是客户端-服务器架构,排障第一步永远是定位在客户端、共享服务,还是某个项目。

# 1. 服务状态
opencode service status
# 2. API 是否健康
opencode api get /api/info
# 3. 卡住/不健康就重启
opencode service restart

浏览器客户端连不上,多半是 CORS。设置允许的 origin(精确到 http/https 和端口,不带路径和末尾斜杠):

opencode service set cors http://192.168.1.10:3001
opencode service get cors
opencode service unset cors

设/取消 CORS 会停止后台服务,下次启动生效;要显式启动用 opencode service start。CORS 不会改变监听地址,也不会绕过服务认证——别把它当安全手段。

看日志。安装版写到:

~/.local/share/opencode/log/opencode.log

每行带 run 和 role,用 role=server 看会话、provider、插件、权限、工具活动:

tail -f ~/.local/share/opencode/log/opencode.log
grep 'role=server' ~/.local/share/opencode/log/opencode.log

抓性能数据(macOS/Linux):先从 /api/info 拿到 pid,再发信号:

kill -SIGPROF <pid>   # 10 秒 CPU 采样 -> cpu-<pid>-<时间戳>.cpuprofile
kill -SIGUSR1 <pid>   # 堆快照 -> heap-<pid>-<时间戳>.heapsnapshot

两份结果都写在日志目录,等日志里出现 "CPU profile written" / "heap snapshot written" 再用 Chrome DevTools 打开。注意:Windows 不支持信号触发,抓堆快照会短暂暂停进程并占用更多内存。

关于服务文件的一条硬规矩:排障时不要删除或编辑服务文件或数据库,用 service 命令管守护进程;要在外部工具里看持久化数据,先备份。相关路径:

~/.local/state/opencode/service.json   # 服务注册
~/.config/opencode/service.json        # 私有服务配置
~/.local/share/opencode/opencode.db    # 数据库(OPENCODE_DB 可覆盖)

报 issue 前,附上最小复现步骤、opencode --version、service status 输出,以及相关日志行(含 run/role)。分享前先脱敏:API key、授权头、提示内容、文件内容、敏感路径。

系列收束

OpenCode 的形态和 Claude Code 很不一样:它更像一个可配置、可编程、可自托管的服务,终端只是它的一种前端。这种设计带来自由,也带来更多需要理解的概念。

如果只能记三条:

  1. 它是服务——排障先看 service status 和日志,别一上来怀疑模型。
  2. 配置分两层——行为进仓库(opencode.json),界面留本机(cli.json)。
  3. 能力靠组合——agent 定角色、skill 定流程、command 定入口、权限画边界、MCP 连外部。

把这三条吃透,剩下的都是细节。