跳到主要内容

opencode — 架构与原理

30 秒导读: opencode 是一个跑在终端里的开源 AI 编码 agent。你打一句"帮我修这个 bug",它会自己读文件、改代码、跑命令,边干边问你要不要批准危险操作。它的真正本体是一个 Effect-TS 写的服务端(会话循环 + 工具 + 权限),终端 UI 只是众多客户端之一。

1. 这是什么(零基础也能懂)

  • 一句话定义: opencode 是一个开源的、命令行里的 AI 编码助手——把大模型接上你的真实代码库,让它能读文件、改文件、跑 shell、查网页,自动把一个编码任务做到底。

  • 解决什么问题 / 给谁用: 假设你在终端里想让 AI 帮你改一个大项目的代码。你不想把文件一个个复制粘贴进聊天框,也不想 AI 在你不知情时 rm -rf。opencode 给你:① 一个能直接操作你工作区的 agent;② 每个危险动作前的批准闸门;③ provider 无关(Anthropic / OpenAI / Google / 本地都行)。给的人:命令行重度用户、想要可审计/可自托管编码 agent 的工程师。

  • 它能做什么(功能):

    • 多轮自主循环:读 → 改 → 跑 → 看结果 → 再改,直到任务收敛。
    • 内置工具:read / edit / write / grep / glob / shell / webfetch / task(派生子 agent)等。
    • 细粒度权限:对每个工具、每个文件路径、每条 bash 命令单独决定 allow/ask/deny。
    • 客户端多样:终端 TUI、桌面 app、HTTP/SDK,共享同一个服务端。
    • 长会话不爆:上下文快溢出时自动总结历史(compaction)。
  • 用起来什么样: 一段最小的命令行交互——

# 安装后,在你的项目目录里
$ opencode
> 帮我把 src/auth.ts 里的回调改成 async/await

# opencode 会:读 auth.ts → 提出 edit → (若权限是 ask)弹出批准 → 写盘 → 可能跑测试
# 你也可以一次性跑(非交互):
$ opencode run "列出所有 TODO 注释并归类"
  • 一句话直觉/类比: 把它想成"一个住在你终端里、有手有脚的结对程序员":模型是大脑(决定做什么),工具是手脚(真正动文件/跑命令),权限系统是"动手前先举手问一声"的礼貌,而服务端是把这一切编排起来的神经中枢。

2. 顶层全景(它大概怎么转)

2.1 client / server 拆分

opencode 最重要的架构决定:它不是一个单体 CLI,而是一个服务端 + 一群客户端。所有真正干活的逻辑(会话、工具、权限)都在 packages/opencode/src 的服务端;TUI、桌面、SDK 都通过 HTTP API 连上来。

┌─────────── 客户端们 ───────────┐
终端 TUI ──┐ │
桌面 App ──┼──► HTTP / WebSocket ──► opencode 服务端
SDK / 脚本 ┘ (packages/server) (packages/opencode/src)

┌──────────────────────┼───────────────────────┐
▼ ▼ ▼
会话循环 工具系统 权限闸门
(session/) (tool/) (permission/)
│ │ │
▼ ▼ ▼
LLM provider 文件/Shell/网页 ask/allow/deny
(AI SDK / 原生) (真实副作用)

怎么读这张图:左边是"谁在用它",中间是 HTTP 边界,右边是服务端三大支柱。客户端从不直接碰文件,一切经服务端。

2.2 核心部件一句话职责

部件干什么在哪个文件
CLI 入口解析子命令(run/serve/tui…),启动对应流程packages/opencode/src/index.ts
会话循环反复"喂模型 → 处理工具 → 再喂"直到收敛packages/opencode/src/session/prompt.ts(runLoop)
流处理器把 LLM 的事件流(文本/推理/工具)落成会话 partpackages/opencode/src/session/processor.ts
LLM 适配调 provider、把 AI SDK 流归一成 LLMEventpackages/opencode/src/session/llm.ts
工具注册表收集内置 + 插件 + 自定义工具,按模型/agent 过滤packages/opencode/src/tool/registry.ts
工具定义统一的 Tool.define:schema 校验 + 截断 + 执行packages/opencode/src/tool/tool.ts
容错编辑edit 工具的 9 级降级匹配packages/opencode/src/tool/edit.ts
权限服务工具执行前的 allow/ask/deny 裁决packages/opencode/src/permission/index.ts
压缩服务上下文溢出时总结/裁剪历史packages/opencode/src/session/compaction.ts

2.3 主线走一遍(高层,不进代码)

一次"帮我改个文件"从头到尾:

  1. 入口:opencode run "..."index.ts 派到 RunCommand,创建一个会话并写入 user 消息。
  2. 进循环:SessionPrompt.runLoop 开始 while(true),每一轮叫一个"step"。
  3. 组装上下文:取出历史消息、当前 agent 的系统提示、可用工具集,交给 processor.process
  4. 流式调模型:LLM.stream 调 provider,吐回一串事件(文本增量、工具调用、推理…)。
  5. 处理工具:processor 遇到 tool-call 就触发该工具执行;执行前 permission.ask 闸门可能拦下来问你。
  6. 回灌结果:工具结果作为新消息塞回历史,循环回到第 3 步,让模型看见结果继续。
  7. 收敛:当模型这一步既没工具调用、finish 又不是 tool-calls 时,循环 break,返回最后一条 assistant 消息。

3. 阅读地图(建议顺序)

这是个大项目(client/server + Effect-TS + 多子系统),拆成 5 章由浅入深:

  1. 01-agent-loop.md — 先搞懂"循环怎么转"。这是项目名所指的价值核心:runLoop + processor。读完你能讲清一次工具调用从请求到生效的全过程。
  2. 02-tool-system.md — 工具是 agent 的手脚。看 Tool.define 的统一外壳、注册表怎么收集/过滤工具、插件工具怎么桥接。
  3. 03-fuzzy-edit.md — 招牌技术:模型给的 oldString 几乎从不和磁盘一字不差,edit 用 9 级降级匹配兜住。最值得带走的精华。
  4. 04-permission.md — 安全闸门。通配规则裁决、bash 命令拆成"人类可懂前缀"、doom-loop 防呆。
  5. 05-context-compaction.md — 长会话怎么不爆 token:溢出检测 → 自动总结 → 历史裁剪。

4. 它的几个"不一样"(读前先有数)

  • Effect-TS 满地跑。 几乎每个服务都是 Layer.effect(Service, Effect.gen(...)),函数是 Effect.fn("Name")(function*(){...})yield* 在这里类似 await,但带依赖注入和可中断性。第一次看会懵,认准"yield* = 取一个能力/拿一个结果"就行。

  • provider 无关靠 AI SDK。 默认走 Vercel 的 ai 包(streamText),opencode 把它的 fullStream 归一成自己的 LLMEvent(见 session/llm/ai-sdk.ts),还有一条实验性的"原生 runtime"旁路。

  • 数据真相在 SQLite。 会话、消息、part 都落 drizzle ORM 管的 SQLite 表(SessionTable/PartTable),不是纯内存。

5. 代码地图(导航索引)

主题文件路径符号名
CLI 入口与子命令注册packages/opencode/src/index.tscli, RunCommand, ServeCommand
会话主循环packages/opencode/src/session/prompt.tsrunLoop, loop
LLM 事件处理packages/opencode/src/session/processor.tsService, handleEvent, process
provider 调用packages/opencode/src/session/llm.tsstream, run
工具统一定义packages/opencode/src/tool/tool.tsdefine, wrap, InvalidArgumentsError
工具注册表packages/opencode/src/tool/registry.tsService, tools, fromPlugin
容错编辑packages/opencode/src/tool/edit.tsreplace, BlockAnchorReplacer
权限裁决packages/opencode/src/permission/index.tsevaluate, ask, reply
上下文压缩packages/opencode/src/session/compaction.tsbuildPrompt, PRUNE_PROTECT