Skip to content

第四章 Opencode 工具链与会话模型

← 返回目录 | 上一章:Opencode Agent 系统 | 下一章:OmO 插件架构 →


4.1 内置工具注册表

Opencode 的工具系统采用注册表模式(tool/registry.ts),每个工具是一个包含 namedescriptionparameters(Zod schema)、execute 函数的对象。Agent 通过工具白名单控制可用工具。

Opencode 内置 19 个工具,覆盖文件操作(read/write/edit/apply_patch)、搜索(grep/glob)、Shell 执行(bash)、Web 访问(webfetch/websearch/codesearch)、任务管理(todowrite/question)、Agent 协作(task/skill)、代码智能(lsp)、控制流(batch/plan_exit/invalid)等领域。部分工具受条件开关控制(如 LSP、WebSearch 需要启用对应实验特性)。

完整工具清单、参数说明、使用场景和 OmO 扩展对比:详见 工具系统完整解析

4.2 MCP 协议支持

MCP (Model Context Protocol) 是 Anthropic 提出的标准化协议,用于 LLM 与外部工具/数据源的通信。Opencode 实现了完整的 MCP 客户端:

支持的传输方式

  • stdio:通过子进程的标准输入/输出通信(本地工具)
  • StreamableHTTP:基于 HTTP 的流式传输(远程服务)
  • SSE (Server-Sent Events):基于 HTTP SSE 的传输(旧版远程协议)

OAuth 2.0 支持:对于需要身份验证的远程 MCP 服务器,Opencode 实现了完整的 OAuth 2.1 + PKCE 流程,包括:

  • 自动发现授权服务器元数据
  • 动态客户端注册
  • 本地回调服务器接收授权码
  • Token 缓存与刷新

关键设计:Opencode 本身不内置任何 MCP 服务器。所有 MCP 工具都是用户通过配置文件添加的。这与 OmO 形成鲜明对比——OmO 内置了 3 个 MCP 服务器。

4.3 LSP 服务器管理

Opencode 内置了对 22+ 种编程语言的 LSP (Language Server Protocol) 支持,这是其代码理解能力的核心:

支持的语言服务器(部分):

语言LSP 服务器自动下载
TypeScript/JavaScripttypescript-language-server
Gogopls
Rustrust-analyzer
Pythonbasedpyright
Javajdtls
C/C++clangd
C#OmniSharp
Rubysolargraph
PHPintelephense
Kotlinkotlin-language-server
Zigzls
Lualua-language-server

LSP 提供的能力(通过 LspTool 暴露给 Agent):

  • textDocument/definition — 跳转到定义
  • textDocument/references — 查找所有引用
  • textDocument/documentSymbol — 文件符号大纲
  • workspace/symbol — 全项目符号搜索
  • textDocument/publishDiagnostics — 错误/警告诊断
  • textDocument/rename — 安全重命名
  • textDocument/prepareRename — 重命名预检查

自动下载机制:当用户打开包含特定语言文件的项目时,Opencode 会自动检测并下载对应的 LSP 服务器二进制文件(通常下载到 ~/.opencode/lsp/ 目录),实现开箱即用。

4.4 Skill 系统

Skill 是一种轻量级的能力扩展机制——本质上是一个 SKILL.md 文件,包含结构化的指令和上下文信息:

markdown
---
name: my-skill
description: 做某件事的专家指南
tools: [BashTool, ReadTool]     # 可选:需要的工具
mcp:                             # 可选:嵌入式 MCP 服务器
  my-server:
    command: npx
    args: ["-y", "my-mcp-server"]
---

# 指令内容

当用户要求做 X 时,按以下步骤操作:
1. 首先检查 ...
2. 然后执行 ...

发现路径(按优先级):

  1. ~/.claude/ — 全局 Claude 风格配置目录
  2. ~/.agents/skills/ — 全局 Agent Skill 目录
  3. .opencode/skills/ — 项目级 Skill 目录
  4. 配置文件中指定的自定义路径/URL

加载流程:Agent 调用 SkillTool → 读取 SKILL.md → 解析 frontmatter → 将指令内容注入到当前对话的系统提示中 → 如有嵌入式 MCP,启动对应服务器并注册工具。


4.5 SQLite 持久化模型

Opencode 使用 SQLite 作为本地数据库(基于 better-sqlite3),存储所有会话数据。数据模型设计简洁但完备:

Session (会话)
 ├── id: string (ULID)
 ├── title: string
 ├── created_at / updated_at

 ├── Message (消息) ×N
 │    ├── id: string (ULID)
 │    ├── session_id: FK
 │    ├── role: "user" | "assistant"
 │    ├── created_at
 │    │
 │    └── Part (消息片段) ×M
 │         ├── type: "text" | "reasoning" | "tool" | "file" |
 │         │         "step-start" | "step-finish" | "patch" |
 │         │         "compaction" | "subtask"
 │         ├── content: JSON (类型特定的数据)
 │         └── tool_invocation_id: string (工具调用关联)

 └── Todo (待办) ×K
      ├── id: string
      ├── content: string
      ├── status: "pending" | "in_progress" | "completed" | "cancelled"
      └── priority: "high" | "medium" | "low"

Part 类型详解

Part 类型内容说明
text文本内容Agent 的文字回复
reasoning推理过程模型的思考过程(如 Claude 的 thinking)
tool工具调用+结果包含工具名、输入参数、执行状态、输出结果
file文件路径用户上传的文件
step-start/finish步骤标记标记一轮 LLM 调用的开始和结束
patch代码补丁结构化的代码变更记录
compaction压缩摘要上下文压缩后的摘要内容
subtask子任务引用Task 工具创建的子会话引用

4.6 上下文窗口管理

AI 模型有固定的上下文窗口大小(通常 128K-200K tokens)。当对话过长时,Opencode 需要在不丢失关键信息的前提下压缩对话。

压缩策略session/compaction.ts):

  1. 工具输出裁剪:优先删除旧工具调用的详细输出

    • 保护最近 40K tokens 内的工具输出不被裁剪
    • 单个工具输出超过 20K tokens 的优先裁剪
    • 裁剪后替换为 [output truncated — old tool output removed to save context]
  2. 摘要压缩:如果裁剪不够,使用专门的 compaction Agent 生成对话摘要

    • 摘要 Agent 收到完整对话历史
    • 生成关键信息的浓缩总结
    • 原始消息被替换为 compaction Part
  3. 自动触发:当 token 使用率接近上下文窗口上限时自动触发

4.7 消息处理流水线

从用户输入到最终响应,消息经过以下处理流水线:

用户输入

┌─ 消息持久化到 SQLite
├─ 组装消息序列:System Prompt + 历史消息 + 新消息
├─ 插件 Hook: chat.message(可修改消息)
├─ 插件 Hook: chat.params(可修改请求参数)
├─ 上下文窗口检查(是否需要压缩)
├─ 插件 Hook: experimental.chat.messages.transform(可变换整个消息序列)

调用 LLM API(流式)

┌─ 解析流式响应(文本 chunk / 工具调用 / 推理内容)
├─ 实时推送到 UI
├─ 持久化每个 Part
├─ 如有工具调用:
│   ├─ 插件 Hook: tool.execute.before
│   ├─ 权限检查(敏感操作需用户确认)
│   ├─ 执行工具
│   ├─ 插件 Hook: tool.execute.after
│   ├─ 将结果追加到消息序列
│   └─ 再次调用 LLM(循环)
├─ 插件 Hook: event(事件流通知)

最终响应 → 持久化 → 推送到 UI

关键观察:这个流水线中有 6 个插件 Hook 注入点。OmO 正是通过这些注入点实现了其全部增强功能——从后台任务通知到上下文工程,全部无需修改 Opencode 核心代码。


← 返回目录 | 上一章:Opencode Agent 系统 | 下一章:OmO 插件架构 →