跳至正文
OpenCode v2 在 Cloudflare 上怎么用:使用场景与 SDK 入门

OpenCode v2 在 Cloudflare 上怎么用:使用场景与 SDK 入门

官方文档:OpenCode v2 · Cloudflare SDK

AI 参与说明(Agent:Codex):本文依据上述官方入口及相关 SDK、Plugins 和 Cloudflare 文档,讲解使用场景、接入步骤与运行边界。资料核验于 2026-09-09;场景中的业务工具由应用自行实现。

AI 参与及修订记录

AI 参与说明(Agent:Cursor):本文由 Cursor 根据 OpenCode 官方 V2 文档、Cloudflare 官方文档、npm registry 当前包信息与站内既有 Durable Object / Agents SDK / Sandbox 资料辅助调研、撰写和校验。资料核验于 2026-09-09。OpenCode V2 SDK 仍处于 beta,包名、入口与 API 可能变化。运行记录:模型 grok-4.6,提供方 xAI,执行入口 Cursor。reasoning effort 与 CLI 版本未取得运行记录。

本次重写与校验(2026-09-09,Agent:Codex):以官方 Cloudflare SDK 入口重组使用场景和调用步骤。运行记录:模型 gpt-6-astra,reasoning effort ultra,执行入口 Codex Desktop,提供方 openai,CLI 版本 0.153.4(不代表桌面 App 版本)。历史记录仅对应此前阶段。

OpenCode v2 可以作为 SDK 嵌入 Cloudflare 上的应用:用户在网页里提出任务,服务端的 OpenCode 调用模型和工具完成工作,并保存对话上下文。它适合做仓库审查助手、Cloudflare 运维助手,以及接入远程执行环境的在线编码助手。

下面先说明这三类场景,再走一遍安装、初始化、创建 Session 和添加 Plugin 的过程。

英文术语中文名称简要解释
Cloudflare Workers保留原名承接网页请求、运行服务端代码的平台
workerd保留原名Workers 使用的 JavaScript 运行时
Durable Object持久对象有稳定身份、自带持久存储的服务端对象
Embedded host嵌入式宿主在应用内部运行的 OpenCode 实例
Session会话保存用户输入、模型回复和任务上下文的单位
Plugin插件为 OpenCode 配置角色、模型和工具的扩展
Tool工具模型可调用的具体操作,例如读取文档或执行测试
Sandbox SDK沙箱 SDK为命令执行、文件操作等提供隔离环境的 Cloudflare SDK

OpenCode 在 Cloudflare 上能做什么

The workerd SDK embeds OpenCode in a Durable Object and uses its SQLite storage to retain state and durable events across eviction. 官方 Cloudflare SDK 文档

对使用者而言,最直接的变化是:可以在自己的网页或 API 背后运行 OpenCode。前端把任务交给 Worker,Worker 找到对应的 Durable Object,再由其中的 OpenCode 处理。你负责应用入口、模型配置与业务 Tool;SDK 提供 OpenCode 的运行与交互能力。

下面是基于这些能力的应用场景,并非安装 SDK 后自动附送的产品功能。

场景一:仓库审查与迁移方案助手

用户提供一段代码、一次变更或一个仓库地址,要求“检查这个 API 是否适合迁移到 Workers”。OpenCode 可以根据用户提供的材料,结合 Tool 读取的代码和文档,给出问题定位、修改建议与迁移步骤。

最容易开始的方式是直接把小段代码作为任务输入。需要按需浏览完整仓库时,再提供访问 GitHub API 或代码快照的 Tool;仅把仓库 URL 发给 SDK,不等于已经下载仓库或获得读取权限。

这个场景的输出是审查报告。开始时不必具备安装依赖和执行构建的能力,也能检验 OpenCode 是否适合嵌入自己的产品。

场景二:Cloudflare 运维与知识助手

用户问:“这次部署之后为什么报错?”应用提供读取已授权日志、部署信息或 R2 文档的 Tool,OpenCode 根据返回结果继续查询并组织解释。

Cloudflare 的服务通过你的代码接入。例如 R2 binding 交给 Tool 实现,Tool 再把选定文档返回给模型。模型本身不需要持有整个 Cloudflare 账户的凭据。

这类助手的价值在于围绕问题连续取证。若要进一步执行部署或修改配置,需增加对应 Tool,并在实际执行代码里落实权限校验;这不是修改一句 Agent 描述就能完成的能力。

场景三:能够改代码、跑测试的在线助手

用户在网页提交“修复这个失败的测试”,OpenCode 分析任务、决定调用哪些 Tool,再依据执行结果继续修改。

这里需要补上实际工作环境:由 Sandbox SDK、Container 或其他远程服务负责代码文件、命令和测试,Tool 把操作请求和结果接回 OpenCode。@opencode/sdk/workerd 的本地文件系统与进程服务有运行时适配边界,不能直接假定本机 CLI 的全部操作都能在 Worker 内执行。Cloudflare SDK · Sandbox SDK 架构

如果目标只是前两个场景,可以先接读取类 Tool。只有当任务确实需要执行代码时,再增加 Sandbox SDK。

它在应用里怎样运行

flowchart TD
  user["网页:提交任务、查看结果"] --> worker["Worker:接收并路由请求"]
  worker --> object["Durable Object<br/>提供 SQLite 存储"]
  object --> host["OpenCode Embedded host<br/>组织 Session,调用模型"]
  host -->|按需调用| tool["Plugin Tool<br/>读取数据或调用 Sandbox SDK"]

Worker 是对外入口;Durable Object 为 OpenCode 提供存储与实例生命周期;OpenCode 组织 Session 和模型、Tool 的交互。前端展示结果的界面仍由应用实现。

官方这篇文档的接入方式是在 Durable Object 中创建 Embedded host。下文所有代码都围绕这个入口,不需要先启动一个独立的 OpenCode HTTP 服务。SDK Overview

第一步:安装并启动一个最小实例

下面是 TypeScript 的最小健康检查示例。它验证 Worker 能否调用 Durable Object 中的 OpenCode;模型调用放在下一步。

准备一个已有的 Workers TypeScript 项目。如果尚未创建,可按 Durable Objects Getting started 选择 Worker + Durable Objects 模板。

官方当前安装入口是 bun add @opencode/sdk@dev;使用 npm 时对应 npm install @opencode/sdk@dev。V2 SDK is beta; pin the tested package version before relying on its API. SDK 安装说明

本文核验的版本为 0.0.0-dev-19380。在项目根目录安装固定版本:

bash
npm install --save-exact @opencode/sdk@0.0.0-dev-19380

在 wrangler.jsonc 中配置入口、兼容标志,以及使用 SQLite 的 Durable Object:

jsonc
{
  "$schema": "node_modules/wrangler/config-schema.json",
  "name": "opencode-cloudflare-demo",
  "main": "src/index.ts",
  "compatibility_date": "2026-09-09",
  "compatibility_flags": ["nodejs_compat"],
  "durable_objects": {
    "bindings": [
      { "name": "OPENCODE", "class_name": "OpenCodeDO" }
    ]
  },
  "migrations": [
    { "tag": "v1", "new_sqlite_classes": ["OpenCodeDO"] }
  ]
}

这是新示例项目的配置;已有项目应保留原配置和 migration 历史,只合并所需项。nodejs_compat 来自 OpenCode 的 Cloudflare 指南,binding 和 new_sqlite_classes 来自 Durable Objects 配置说明。

src/index.ts:

ts
import { OpenCodeWorkerd } from "@opencode/sdk/workerd"

interface Env {
  OPENCODE: DurableObjectNamespace
}

export class OpenCodeDO {
  private readonly host: Promise<OpenCodeWorkerd.Interface>

  constructor(state: DurableObjectState) {
    this.host = state.blockConcurrencyWhile(() =>
      OpenCodeWorkerd.create({ storage: state.storage }),
    )
  }

  async fetch(request: Request): Promise<Response> {
    const url = new URL(request.url)
    if (request.method !== "GET" || url.pathname !== "/health") {
      return new Response("Not found", { status: 404 })
    }

    const host = await this.host
    const health = await host.health.get()
    return Response.json(health)
  }
}

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    const object = env.OPENCODE.getByName("local-demo")
    return object.fetch(request)
  },
} satisfies ExportedHandler<Env>

这里的固定名称 local-demo 只用于本地验证,让重复请求访问同一个 Durable Object。实际应用应根据已经验证的用户或项目身份选择对象,不能让所有用户共享这个示例对象。

运行并检查:

bash
npx wrangler types
npx wrangler dev

在另一个终端中请求:

bash
curl --fail http://localhost:8787/health

预期得到 HTTP 200 和 OpenCode 的健康检查 JSON。blockConcurrencyWhile() 让请求等待初始化完成;实例存活期间复用同一个 host,不在每次 fetch() 中重新创建。对象被逐出后会重新构造,所以不能依赖 close() 一定执行来保存状态。初始化与生命周期说明

本次固定版本示例已通过 TypeScript 检查、Wrangler 4.129.0 打包和本地 workerd 健康检查,实际返回 HTTP 200、healthy: true;没有进行云端部署。

第二步:接入模型,创建 Session 并提交任务

健康检查通过后,需要配置一个可用模型及其凭据,再执行任务。Cloudflare 上不要照搬本机已登录 CLI 的假设:模型连接需要在这套服务端实例里配置,凭据通过 Worker 的 Secret 提供。OpenCode Plugins:Integrations

以 Anthropic 为例,在已被 Git 忽略的 .dev.vars 中设置 ANTHROPIC_API_KEY,值为自己的有效 API Key;线上通过 Worker Secret 配置同名变量。不要把真实值写进源码或 wrangler.jsonc。Cloudflare Secrets

模型连接可以通过 Plugin 初始化。先安装同版依赖:

bash
npm install --save-exact @opencode/plugin@0.0.0-dev-19380

src/model-plugin.ts:

ts
import { Plugin } from "@opencode/plugin"

export function modelPlugin(apiKey: string) {
  return Plugin.define({
    id: "model-credentials",
    async setup(ctx) {
      const active = await ctx.integration.connection.active("anthropic")
      const credential = active
        ? await ctx.integration.connection.resolve(active)
        : undefined
      if (credential?.type === "key" && credential.key === apiKey) return

      await ctx.integration.connect.key({
        integrationID: "anthropic",
        key: apiKey,
      })
    },
  })
}

在 src/index.ts 顶部导入 modelPlugin,为 Env 增加 ANTHROPIC_API_KEY: string,并将构造函数替换为:

ts
constructor(state: DurableObjectState, env: Env) {
  this.host = state.blockConcurrencyWhile(() =>
    OpenCodeWorkerd.create({
      storage: state.storage,
      config: { model: "anthropic/claude-sonnet-4-6" },
      plugins: [modelPlugin(env.ANTHROPIC_API_KEY)],
    }),
  )
}

导入语句为 import { modelPlugin } from "./model-plugin"。模型 ID 应替换为该账户实际可用的模型;上例展示凭据如何从 env 进入 OpenCode,随后任务中的模型请求会使用这个服务端连接。

Plugin 先检查当前连接,避免 Durable Object 重新构造时重复保存相同凭据。示例将服务端模型连接提供给该实例,不应让浏览器传入或读取 API Key。

接着将 OpenCodeDO.fetch() 替换为以下方法。它保留 /health,并用 POST /review 接收纯文本任务、等待本轮处理,再返回 Session ID 与消息;Worker 的转发入口无需改动:

ts
async fetch(request: Request): Promise<Response> {
  const host = await this.host
  const path = new URL(request.url).pathname
  if (request.method === "GET" && path === "/health") {
    return Response.json(await host.health.get())
  }
  if (request.method !== "POST" || path !== "/review") {
    return new Response("Not found", { status: 404 })
  }

  const text = (await request.text()).trim()
  if (!text) return new Response("Task text is required", { status: 400 })

  const session = await host.sessions.create({ title: "Review a Worker" })
  const admitted = await host.sessions.prompt({ sessionID: session.id, text })
  await host.sessions.wait({ sessionID: session.id })
  const messages = await host.sessions.context({ sessionID: session.id })

  return Response.json({ sessionID: session.id, admitted, messages })
}

在本地开发服务中提交一个不需要仓库的任务:

bash
curl --fail http://localhost:8787/review \
  -H 'Content-Type: text/plain' \
  --data-raw "Review this Worker: export default { fetch() { return new Response('Hello') } }"

模型凭据有效且本轮生成结束后,JSON 的 messages 中可读取模型回复;admitted 是提交记录。这个本地教学接口每次创建新 Session,并在同一请求内等待;给多人使用前,应接入用户认证、Session 归属校验和请求错误处理。

session.id 是后续继续提问和读取上下文的依据,应用应保留它并关联到对应用户。上述任务把待审查代码直接放入文本,因此不需要先准备真实仓库目录。

prompt() returns an admitted inbox item, not the final assistant response. admitted 用来确认输入已接收;wait() 等待 Session 的运行循环空闲,context() 获取当前上下文中的消息(发生 compaction 后不等于全部历史)。wait() 返回不等于任务成功;界面仍需检查消息和 Session 状态,处理权限请求与错误。Session API · Plugins:Sessions

需要边生成边展示时,SDK 还提供 host.events.subscribe(),返回可用 for await 消费的事件流。应用把属于当前用户和 Session 的事件转发给网页;不要把整个实例的事件直接广播给所有访问者。SDK:Stream events

通用 SDK 文档中的 location: { directory: "/workspace" } 是本地工作区示例。给 workerd 传入这个字符串不会创建 Linux 目录,也不会自动检出代码;这里直接使用文本输入来开始。

模型连接、Session 与下文 Plugin 片段已按同版包的实际类型检查;本次没有使用真实 API Key 发起模型生成。

第三步:通过 Plugin 接入自己的能力

Plugin 是把 OpenCode 用到具体业务中的扩展入口。可以修改 Agent 描述、配置模型,或者提供读取文档、查询状态等 Tool。Cloudflare 指南采用随 Worker 打包的 Plugin,并通过 plugins 传入初始化配置。官方 Customize 示例

沿用上一步安装的 @opencode/plugin,添加一个返回代码审查检查项的只读 Tool。示例内容固定,便于先观察 OpenCode 如何调用 Tool;之后再把执行函数接到实际文档源。

src/review-plugin.ts:

ts
import { Plugin } from "@opencode/plugin"

export const reviewPlugin = Plugin.define({
  id: "worker-review",
  async setup(ctx) {
    await ctx.tool.transform((tools) => {
      tools.add({
        name: "review_checklist",
        description: "Read the checklist for reviewing a Cloudflare Worker",
        input: { type: "object", properties: {}, additionalProperties: false },
        execute: async () => ({
          content: "Check HTTP methods, input validation, error responses, and secret handling.",
        }),
      })
    })
  },
})

然后在 src/index.ts 中导入,并在上一步初始化配置里保留模型连接、追加 reviewPlugin:

ts
import { reviewPlugin } from "./review-plugin"

// 放在原有 blockConcurrencyWhile 回调中。
OpenCodeWorkerd.create({
  storage: state.storage,
  config: {
    default_agent: "build",
    model: "anthropic/claude-sonnet-4-6",
  },
  plugins: [modelPlugin(env.ANTHROPIC_API_KEY), reviewPlugin],
})

再次调用 /review,可以把任务写成 Use review_checklist, then review this Worker: ...。OpenCode 能调用这个 Tool,获得检查项后继续审查。若要读取 R2 中实际维护的检查项,就将 binding 通过 Plugin 工厂传入,在 execute() 中读取限定对象并返回文本。Plugins:Tools

官方 Cloudflare 页面还展示了通过 ctx.agent.transform() 修改 Agent 描述的方式。那适合定制角色说明;实际业务能力来自 Tool 的执行代码,访问权限也应在执行代码中落实。

按场景扩展时,可以这样对应:

想让 OpenCode 做的事应用需要提供的 Tool 实现
解释项目中的某个文件读取获授权的 GitHub 文件或代码快照
根据内部文档回答问题查询文档索引,读取选定 R2 对象
分析部署失败原因读取对应项目的部署状态和日志
修改代码并执行测试调用 Sandbox SDK,返回变更、日志和退出码

这些 Tool 名称和业务操作由应用定义。Cloudflare binding 留在服务端代码中;每个 Tool 只暴露完成该任务所需的输入与结果。

使用时最需要记住的边界

  • 模型需要单独接入:SDK 启动和健康检查成功,不代表模型凭据、模型权限或实际生成已经可用。
  • 代码执行需要工作环境:需要 shell、依赖安装或测试时,接 Sandbox SDK 等执行服务;SQLite 保存 OpenCode 状态,不等于代码仓库工作区。
  • 持久化不等于任何任务都会自动继续:官方明确保存 durable events 以支持 eviction recovery;这不直接证明任意 Tool、外部副作用或浏览器断线后的整个任务都能恢复。实际任务应验证中断、重试和恢复行为。
  • Plugin 需要适配 workerd:随 Worker 打包,并检查自身及依赖是否要求本地文件系统、子进程或原生二进制。nodejs_compat 不会把 Worker 变成完整 Linux 主机。

前两类场景可以从“文本任务 → Session → 模型回复”开始,再接一个真实读取类 Tool。在线编码助手则继续补上“Tool → Sandbox SDK → 执行结果”的链路。这样的顺序能逐步验证 OpenCode 在 Cloudflare 上如何完成实际工作。

继续阅读

本文共 3952 字,以 CC 署名-非商业性使用-禁止演绎 4.0 国际 协议进行许可。

评论

博客助手

正在打开博客助手…