OpenCode 架构设计与核心技术深度解析
项目简介
OpenCode 是一款强大的开源终端 AI 编程助手,使用 Go 语言构建。该项目由 SST 团队开发,后于 2025 年 9 月归档,核心开发者加入 Charmbracelet 团队,项目以 Crush 的名称继续发展。
“OpenCode is a powerful AI coding agent. Built for the terminal.” — GitHub
项目数据 (归档时):
| 指标 | 数值 |
|---|---|
| GitHub Stars | 70,000+ |
| Contributors | 500+ |
| Commits | 7,000+ |
| 月活用户 | 650,000+ |
整体架构
OpenCode 采用 六层分层架构 设计,实现了清晰的关注点分离:
flowchart TB
subgraph "Entry Points"
CLI["CLI (Cobra Command)"]
end
subgraph "Application Core"
APP["App Orchestrator"]
CONFIG["Config Service"]
end
subgraph "User Interface"
TUI["Bubble Tea TUI"]
PAGES["Pages (Chat/Logs)"]
DIALOGS["Dialogs (Permission/Session)"]
end
subgraph "AI Processing"
AGENT["Agent Service"]
PROVIDER["LLM Providers"]
PROMPT["Prompt Builder"]
end
subgraph "Tool Execution"
TOOLS["Tool Registry"]
PERM["Permission Service"]
BUILTIN["Built-in Tools"]
MCP_TOOLS["MCP Tools"]
end
subgraph "Data & Integration"
DB["SQLite Database"]
LSP["LSP Clients"]
MCP_SRV["MCP Servers"]
end
CLI --> APP
APP --> CONFIG
APP --> TUI
TUI --> PAGES
TUI --> DIALOGS
APP --> AGENT
AGENT --> PROVIDER
AGENT --> PROMPT
AGENT --> TOOLS
TOOLS --> PERM
TOOLS --> BUILTIN
TOOLS --> MCP_TOOLS
APP --> DB
APP --> LSP
MCP_TOOLS --> MCP_SRV
核心设计原则
- Client/Server 分离: TUI 前端与 HTTP 后端分离,支持远程操作
- 事件驱动: 基于 Pub/Sub 模式的松耦合通信
- 依赖注入: App Orchestrator 聚合所有服务
- 类型安全: SQLC 生成类型安全的数据库操作代码
目录结构
opencode/├── cmd/ # CLI 入口点 (Cobra)│ └── root.go # 主命令定义与订阅初始化├── internal/ # 核心应用逻辑│ ├── app/ # App Orchestrator│ │ └── app.go # 服务聚合与初始化│ ├── config/ # 配置加载与验证│ ├── tui/ # Bubble Tea UI│ │ ├── pages/ # Chat, Logs 页面│ │ └── dialogs/ # Permission, Session 对话框│ ├── llm/ # AI 处理层│ │ ├── agent/ # Agent 编排│ │ ├── provider/ # LLM Provider 抽象│ │ ├── prompt/ # System Prompt 构建│ │ └── tools/ # 工具接口与实现│ ├── session/ # Session 生命周期管理│ ├── message/ # 消息持久化│ ├── history/ # 文件变更追踪│ ├── permission/ # 权限请求处理│ ├── lsp/ # Language Server 客户端│ ├── db/ # SQLC 生成的查询│ └── pubsub/ # 事件发布系统├── scripts/ # 工具脚本├── main.go # 应用入口├── go.mod / go.sum # Go 依赖└── sqlc.yaml # SQL 代码生成配置Bubble Tea TUI 框架
OpenCode 的终端界面基于 Bubble Tea 构建,这是一个实现 Elm Architecture 的 Go TUI 框架。
Elm Architecture 核心循环
flowchart LR
M[Model] -->|View| V[View]
V -->|User Input| MSG[Message]
MSG -->|Update| M
三大核心函数:
| 函数 | 职责 | OpenCode 实现 |
|---|---|---|
Init() | 返回初始命令 | 初始化 Session、加载配置 |
Update() | 处理消息更新状态 | 路由键盘/系统事件到组件 |
View() | 渲染 UI | 组合 Pages + Dialogs |
组件层级
appModel (Root)├── Pages│ ├── ChatPage (主聊天界面)│ │ ├── Editor (输入组件)│ │ │ ├── Attachment Support (文件/符号附件)│ │ │ ├── History Navigation (Ctrl+P/N)│ │ │ └── Bash Mode (! 前缀)│ │ └── Messages (消息渲染)│ │ └── PartCache (渲染缓存优化)│ └── LogsPage (日志页面)└── Dialogs ├── PermissionDialog (权限确认) ├── SessionDialog (会话切换) ├── CommandDialog (命令面板) └── ModelDialog (模型选择)事件处理流程
sequenceDiagram
participant User
participant TUI
participant PubSub
participant Agent
participant Tools
User->>TUI: 输入 Prompt
TUI->>Agent: 发送消息
Agent->>Tools: 调用工具
Tools-->>PubSub: 发布 ToolResult 事件
PubSub-->>TUI: 转发为 Bubble Tea Msg
TUI->>TUI: Update() 更新状态
TUI->>User: View() 渲染 UI
键盘快捷键
全局控制:
| 快捷键 | 功能 |
|---|---|
Ctrl+C | 退出 |
Ctrl+? | 帮助 |
Ctrl+K | 命令面板 |
Ctrl+O | 模型选择 |
Ctrl+N | 新建 Session |
Ctrl+A | 切换 Session |
Tab | 切换 Agent (Build/Plan) |
编辑器模式:
| 快捷键 | 功能 |
|---|---|
Ctrl+S / Enter | 发送消息 |
Ctrl+E | 外部编辑器 |
Esc | 退出编辑 |
j/k/h/l | Vim 风格导航 |
Event-Driven Pub/Sub 系统
OpenCode 使用泛型 Pub/Sub 模式 (pubsub.Event[T]) 实现组件间的松耦合通信。
事件类型
| 事件 | 发布者 | 订阅者 | 用途 |
|---|---|---|---|
AgentEvent | Agent Service | TUI | AI 响应流、工具调用 |
PermissionRequest | Permission Service | TUI Dialog | 请求用户授权 |
SessionEvent | Session Service | TUI | Session 创建/切换 |
MessageEvent | Message Service | TUI | 消息持久化通知 |
LogMessage | 各组件 | Logs Page | 调试日志 |
订阅初始化
// cmd/root.go - setupSubscriptions()func setupSubscriptions() { // 为每种事件类型创建 goroutine go func() { for event := range pubsub.Subscribe[AgentEvent]() { // 转发为 Bubble Tea 消息 program.Send(AgentEventMsg{Event: event}) } }() // ... 其他事件类型}设计优势
- 解耦: 发布者无需知道订阅者
- 可扩展: 新增功能只需订阅相关事件
- 异步: 不阻塞主 UI 线程
- 可测试: 事件可被 Mock
Agent 服务与 LLM 集成
Agent 循环机制
Agent 服务通过 AI SDK 的 streamText 函数实现持续的 LLM 交互循环:
flowchart TD
START[接收 Prompt] --> BUILD[构建 System Prompt]
BUILD --> STREAM[调用 streamText]
STREAM --> PROCESS{处理响应流}
PROCESS -->|text-delta| RENDER[渲染文本]
PROCESS -->|tool-call| EXEC[执行工具]
EXEC --> PERM{需要权限?}
PERM -->|Yes| ASK[请求用户授权]
ASK --> APPROVED{批准?}
APPROVED -->|Yes| RUN[执行工具]
APPROVED -->|No| ABORT[中止]
PERM -->|No| RUN
RUN --> RESULT[工具结果]
RESULT --> STREAM
PROCESS -->|finish-step| CHECK{达到停止条件?}
CHECK -->|No| STREAM
CHECK -->|Yes| END[完成]
RENDER --> PROCESS
System Prompt 构建
Prompt 采用分层组装:
1. Provider-specific System Prompt (针对不同 LLM 优化)2. User System Prompt (可选自定义)3. Agent-specific Prompt (Build/Plan 不同)4. Environment Context (工作目录、日期、平台)5. Custom Config Prompts (AGENTS.md, CLAUDE.md)支持的 LLM Providers
OpenCode 通过 AI SDK 实现 Provider 抽象,支持 75+ 模型:
| Provider | 主要模型 | 认证方式 |
|---|---|---|
| Anthropic | Claude 4 Sonnet/Opus, Claude 3.5/3.7 | ANTHROPIC_API_KEY |
| OpenAI | GPT-4.1, GPT-4.5, GPT-4o, O1/O3 | OPENAI_API_KEY |
| Gemini 2.5, Gemini 2.0 Flash | GEMINI_API_KEY | |
| GitHub Copilot | 多模型访问 | GITHUB_TOKEN |
| AWS Bedrock | Claude 3.7 Sonnet | AWS Credentials |
| Groq | Llama, DeepSeek R1 | GROQ_API_KEY |
| Azure OpenAI | Enterprise 部署 | Azure Credentials |
| VertexAI | Gemini (GCP) | GCP Credentials |
| Local | Ollama, LM Studio | LOCAL_ENDPOINT |
Agent 类型
Primary Agents (直接交互):
| Agent | 用途 | 工具权限 |
|---|---|---|
| Build | 默认开发 Agent | 全部允许 |
| Plan | 规划与分析 | edit/bash 需确认 |
Subagents (专业助手):
| Agent | 用途 | 调用方式 |
|---|---|---|
| General | 复杂多步任务 | 自动/@general |
| Explore | 快速代码探索 | 自动/@explore |
切换方式: Tab 键切换 Primary Agent, @ 提及调用 Subagent
工具系统
工具注册架构
flowchart LR
subgraph "Tool Registry"
RESOLVE["resolveTools()"]
end
subgraph "Tool Sources"
BUILTIN["Built-in Tools"]
MCP["MCP Tools"]
PLUGIN["Plugin Tools"]
end
BUILTIN --> RESOLVE
MCP --> RESOLVE
PLUGIN --> RESOLVE
RESOLVE --> AGENT["Agent Service"]
Built-in 工具清单
文件操作:
| 工具 | 功能 | 权限控制 |
|---|---|---|
read | 读取文件内容 (支持行范围) | allow |
write | 创建/覆盖文件 | edit |
edit | 精确字符串替换修改 | edit |
patch | 应用 patch 文件 | edit |
搜索发现:
| 工具 | 功能 | 示例 |
|---|---|---|
grep | 正则搜索文件内容 | grep "TODO" --include="*.go" |
glob | 模式匹配查找文件 | **/*.ts, src/**/*.tsx |
list | 列出目录内容 | 支持 glob 过滤 |
执行集成:
| 工具 | 功能 | 特殊处理 |
|---|---|---|
bash | 执行 Shell 命令 | Tree-sitter 安全解析 |
lsp | LSP 服务器交互 | 定义、引用、诊断 |
skill | 加载 SKILL.md 文件 | 扩展能力 |
用户交互:
| 工具 | 功能 |
|---|---|
question | 向用户提问 (支持选项) |
webfetch | 获取网页内容 |
todowrite / todoread | 任务列表管理 |
工具执行流程
sequenceDiagram
participant Agent
participant ToolRegistry
participant Permission
participant Tool
participant FileSystem
Agent->>ToolRegistry: 调用工具
ToolRegistry->>Permission: ask()
Permission->>Permission: 检查缓存
alt 未缓存
Permission->>User: 显示确认对话框
User->>Permission: 批准/拒绝
Permission->>Permission: 更新缓存 (支持通配符)
end
Permission->>Tool: execute()
Tool->>FileSystem: 执行操作
FileSystem-->>Tool: 结果
Tool-->>Agent: 返回结果
Agent->>Agent: 继续 LLM 循环
权限系统
权限状态:
| 状态 | 说明 |
|---|---|
allow | 无需确认直接执行 |
ask | 需要用户确认 |
deny | 禁止执行 |
通配符支持:
{ "permission": { "bash": { "git *": "allow", "rm *": "ask", "sudo *": "deny" } }}级联批准: 批准一个权限会自动批准所有匹配的待处理请求。
LSP 集成
OpenCode 集成 Language Server Protocol 提供代码智能功能。
支持的功能
| 功能 | 状态 | 用途 |
|---|---|---|
| Diagnostics | 已暴露给 AI | 错误检查、Lint 信息 |
| Definitions | 已实现 | 跳转定义 |
| References | 已实现 | 查找引用 |
| Completions | 已实现 | 代码补全 |
| Hover | 已实现 | 悬停信息 |
“While the LSP client implementation supports the full LSP protocol, currently only diagnostics are exposed to the AI assistant.” — DeepWiki
配置示例
{ "lsp": { "go": { "command": "gopls", "args": ["serve"] }, "typescript": { "command": "typescript-language-server", "args": ["--stdio"] }, "python": { "command": "pylsp" } }}LSP 反馈循环
flowchart LR
EDIT[AI 编辑文件] --> NOTIFY[通知 LSP Server]
NOTIFY --> DIAG[获取诊断信息]
DIAG --> FEED[反馈给 LLM]
FEED --> FIX[AI 修复问题]
FIX --> EDIT
这使得 AI 能够获得类似 IDE 的实时反馈,提高代码质量。
MCP (Model Context Protocol) 集成
MCP 是一个标准化协议,允许 AI 助手与外部工具和服务交互。
传输类型
| 类型 | 连接方式 | 适用场景 |
|---|---|---|
| Stdio | 子进程标准输入/输出 | 本地工具 |
| SSE | HTTP Server-Sent Events | 远程服务 (支持 OAuth 2.0) |
配置示例
{ "mcpServers": { "sentry": { "type": "stdio", "command": "npx", "args": ["-y", "@sentry/mcp-server"] }, "context7": { "type": "sse", "url": "https://mcp.context7.ai/sse" }, "custom-tool": { "type": "stdio", "command": "/path/to/my-mcp-server", "env": { "API_KEY": "${MY_API_KEY}" } } }}动态工具注册
sequenceDiagram
participant OpenCode
participant MCPServer
participant ToolRegistry
OpenCode->>MCPServer: 连接
MCPServer->>OpenCode: 返回可用工具列表
OpenCode->>ToolRegistry: dynamicTool() 注册
Note over ToolRegistry: MCP 工具与内置工具统一可用
OpenCode->>MCPServer: 调用工具
MCPServer->>MCPServer: 执行
MCPServer->>OpenCode: 返回结果
官方 MCP Server 集成
| Server | 功能 |
|---|---|
| Sentry | 查询项目 Issues 和错误数据 |
| Context7 | 搜索文档 |
| Grep (Vercel) | 搜索 GitHub 代码片段 |
Session 管理与持久化
Session 生命周期
stateDiagram-v2
[*] --> Created: opencode 启动
Created --> Active: 用户开始对话
Active --> Active: 消息交互
Active --> Compacting: Token 接近 95%
Compacting --> NewSession: 自动总结
NewSession --> Active
Active --> Saved: 用户退出
Saved --> Active: 恢复 Session
Active --> [*]: 用户删除
数据持久化 (SQLite + SQLC)
核心表结构:
| 表 | 字段 | 用途 |
|---|---|---|
sessions | id, created_at, updated_at | Session 元数据 |
messages | id, session_id, role, content, parts | 消息历史 |
files | id, session_id, path, changes | 文件变更追踪 |
SQLC 类型安全:
version: "2"sql: - engine: "sqlite" queries: "internal/db/queries.sql" schema: "internal/db/schema.sql" gen: go: package: "db" out: "internal/db"Auto-Compact 机制
当对话 Token 接近模型上下文窗口的 95% 时,系统自动触发压缩:
- 调用
AgentSummarizer生成对话摘要 - 创建新 Session 并附加摘要
- 保持对话连续性
flowchart LR
CHECK[检查 Token 使用率] --> TRIGGER{>= 95%?}
TRIGGER -->|No| CONTINUE[继续对话]
TRIGGER -->|Yes| SUMMARIZE[生成摘要]
SUMMARIZE --> CREATE[创建新 Session]
CREATE --> ATTACH[附加摘要]
ATTACH --> CONTINUE
配置系统
配置文件优先级
1. 命令行参数 (最高)2. ./.opencode.json (项目级)3. $XDG_CONFIG_HOME/opencode/.opencode.json4. $HOME/.opencode.json (最低)完整配置结构
{ "data": { "directory": ".opencode" }, "providers": { "anthropic": { "apiKey": "${ANTHROPIC_API_KEY}" }, "openai": { "apiKey": "${OPENAI_API_KEY}", "baseURL": "https://api.openai.com/v1" }, "local": { "baseURL": "http://localhost:11434/v1" } }, "agents": { "coder": { "model": "claude-3.7-sonnet", "maxTokens": 5000, "temperature": 0.7, "maxSteps": 50 }, "plan": { "model": "claude-3.7-sonnet", "permission": { "bash": "ask", "edit": "ask" } } }, "lsp": { "go": { "command": "gopls" }, "typescript": { "command": "typescript-language-server", "args": ["--stdio"] } }, "mcpServers": { "example": { "type": "stdio", "command": "path/to/mcp-server" } }, "shell": { "path": "/bin/bash", "args": ["-l"] }, "autoCompact": true, "debug": false}与同类工具对比
| 特性 | OpenCode/Crush | Claude Code | Aider | Cursor |
|---|---|---|---|---|
| 界面 | TUI (Terminal) | TUI | CLI | IDE (VS Code Fork) |
| 开源 | Yes (MIT) | No | Yes | No |
| 语言 | Go + Bubble Tea | TypeScript | Python | TypeScript |
| 上下文方式 | LSP + Session + Files | Context Protocol | Git + Repo Map | IDE Context |
| MCP 支持 | Yes | Yes | No | No |
| 本地模型 | Yes (Ollama) | No | Yes | Limited |
| 多 Provider | 75+ | Anthropic Only | Multiple | Limited |
| 价格 | Free | $20/month (Pro) | Free | $20/month |
“The ‘terminal-based AI coding agents’ trend is hot, and everyone is experimenting to see which tool will stick.” — Hacker News
设计亮点总结
架构优势
- Client/Server 分离: TUI 与后端解耦,支持远程操作 (如手机 App)
- Event-Driven Pub/Sub: 组件松耦合,易于扩展
- 类型安全数据层: SQLC 生成的代码消除 SQL 注入风险
- 可插拔 Provider: 统一接口支持 75+ LLM
技术选型理由
| 技术 | 选型理由 |
|---|---|
| Go | 编译为单二进制、跨平台、性能优秀 |
| Bubble Tea | Elm Architecture 保证 UI 可预测性 |
| SQLite | 零配置、嵌入式、足够性能 |
| SQLC | 编译时 SQL 验证、类型安全 |
| AI SDK | Provider 抽象、流式支持 |
扩展性设计
flowchart TB
subgraph "Core (不变)"
AGENT["Agent Loop"]
TUI["Bubble Tea TUI"]
PUBSUB["Pub/Sub System"]
end
subgraph "可扩展 (Plugin)"
TOOLS["Custom Tools"]
MCP_EXT["MCP Servers"]
PROVIDER["New Providers"]
end
TOOLS --> AGENT
MCP_EXT --> AGENT
PROVIDER --> AGENT
参考资料
官方资源
深度分析
- How Coding Agents Actually Work: Inside OpenCode - 详细的代码级分析
- DeepWiki: OpenCode Architecture - 架构图解
- Model Context Protocol - MCP 官方规范
社区讨论
相关项目
- AI SDK (Vercel) - LLM Provider 抽象层
- SQLC - Go SQL 代码生成
- mcp-language-server - LSP 客户端实现参考