OpenCode 学习笔记 05:扩展与生产
MCP 扩展、流式输出、CLI 与生产级 Agent 架构
January 22, 2026·17 min read·Yimin
#AI#Agent#OpenCode#TypeScript#MCP#CLI#Production
从玩具到生产,从单机到扩展。AI Agent 不只是能用,还要好用。
本篇目标
| 目标 | 实现 |
|---|---|
| MCP 协议 | 📖 原理介绍 |
| 流式输出 | 📖 原理介绍 |
| CLI 实现 | 📖 原理介绍 |
| AI 概念解析 | ✅ Tool/Skill/MCP/Agent |
| 总结架构 | ✅ 完整回顾 |
一、MCP(Model Context Protocol)
1.1 什么是 MCP?
MCP = AI Agent 的"USB 接口"
┌─────────────────────────────────────────────────────────────┐
│ 传统方式:每个工具都要单独适配 │
│ │
│ Agent ──┬── 文件系统工具 │
│ ├── 数据库工具 │
│ ├── API 工具 │
│ └── 浏览器工具 ← 每个都要写代码适配 │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ MCP 方式:统一协议,即插即用 │
│ │
│ Agent ──── MCP Client ────┬── MCP Server (文件系统) │
│ ├── MCP Server (数据库) │
│ ├── MCP Server (API) │
│ └── MCP Server (浏览器) │
└─────────────────────────────────────────────────────────────┘
1.2 MCP 核心概念
| 概念 | 说明 |
|---|---|
| Server | 提供工具/资源的服务端 |
| Client | 使用工具的客户端(Agent) |
| Tool | 可执行的操作 |
| Resource | 可读取的数据 |
| Prompt | 可复用的提示模板 |
1.3 MCP Server 类型
// OpenCode 配置示例
{
"mcp": {
// 本地 Server:运行本地命令
"filesystem": {
"type": "local",
"command": ["npx", "@modelcontextprotocol/server-filesystem", "/path"]
},
// 远程 Server:连接远程服务
"github": {
"type": "remote",
"url": "https://mcp.github.com",
"oauth": true // 支持 OAuth
}
}
}
1.4 OpenCode 的 MCP 实现
┌────────────────────────────────────────────────────────────┐
│ MCP 模块架构 │
├────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────┐ ┌──────────────────────────────────┐ │
│ │ Config │ ───▶ │ MCP.create() │ │
│ │ (mcp:{})│ │ - StdioClientTransport (local) │ │
│ └──────────┘ │ - StreamableHTTPTransport (remote)│ │
│ │ - SSEClientTransport (fallback) │ │
│ └──────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────┐ │
│ │ MCP Client │ │
│ │ - listTools() │ │
│ │ - callTool() │ │
│ │ - listResources() │ │
│ │ - readResource() │ │
│ └──────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────┐ │
│ │ 转换为 AI SDK Tool │ │
│ │ dynamicTool({ ... }) │ │
│ └──────────────────────────────────┘ │
│ │
└────────────────────────────────────────────────────────────┘
1.5 MCP 认证流程
远程 MCP Server 的 OAuth 流程:
1. Client 尝试连接
└── 返回 401 Unauthorized
2. 发现 OAuth 元数据
└── GET /.well-known/oauth-authorization-server
3. 动态客户端注册(如果需要)
└── POST /register
4. 获取授权 URL
└── 跳转浏览器
5. 用户授权
└── 回调带 code
6. 交换 Token
└── POST /token
7. 重新连接(带 Token)
└── 成功!
1.6 为什么 tiny-agent 不实现 MCP
| 原因 | 说明 |
|---|---|
| 依赖复杂 | 需要 @modelcontextprotocol/sdk |
| 认证复杂 | OAuth 流程、Token 存储 |
| 协议复杂 | JSON-RPC、多种传输方式 |
| MVP 不需要 | 内置工具已够用 |
建议:生产环境直接使用 OpenCode 或其他成熟框架的 MCP 支持。
二、流式输出
2.1 为什么需要流式?
非流式:
用户: 写一篇 1000 字的文章
AI: ...(等待 30 秒)...
AI: [突然输出全部内容]
流式:
用户: 写一篇 1000 字的文章
AI: 好的,
AI: 我来帮你写
AI: 一篇关于...
AI: (实时输出,用户体验好)
2.2 OpenCode 的流式实现
// 使用 AI SDK 的 streamText
const result = await streamText({
model: language,
messages,
tools,
// 流式回调
onChunk(chunk) {
// 实时处理每个 chunk
},
onStepFinish(step) {
// 每个步骤完成时
if (step.text) {
onText(step.text) // 输出文本
}
if (step.toolCalls) {
// 处理工具调用
}
},
})
2.3 流式输出的数据流
┌─────────────────────────────────────────────────────────────┐
│ 流式输出数据流 │
├─────────────────────────────────────────────────────────────┤
│ │
│ LLM API │
│ │ │
│ │ SSE (Server-Sent Events) │
│ │ data: {"type":"content_block_delta","delta":...} │
│ │ │
│ ▼ │
│ AI SDK (streamText) │
│ │ │
│ │ 解析 SSE,生成 chunks │
│ │ │
│ ▼ │
│ onStepFinish / onChunk │
│ │ │
│ │ 回调应用代码 │
│ │ │
│ ▼ │
│ TUI / CLI │
│ │ │
│ │ 渲染到终端 │
│ │ │
│ ▼ │
│ 用户看到实时输出 │
│ │
└─────────────────────────────────────────────────────────────┘
2.4 tiny-agent 的流式实现
// 使用 generateText 的 onStepFinish
const result = await generateText({
model: Provider.getModel(modelId),
messages,
tools,
onStepFinish: (step) => {
if (step.text) {
options.onText?.(step.text) // 回调输出
}
},
})
// 使用方
const response = await AgentLoop.run(userMessage, {
onText: (text) => {
process.stdout.write(text) // 实时写入终端
},
})
三、CLI 实现
3.1 OpenCode CLI 架构
┌────────────────────────────────────────────────────────────┐
│ OpenCode CLI 架构 │
├────────────────────────────────────────────────────────────┤
│ │
│ 命令入口 │
│ ├── opencode (TUI 模式) │
│ ├── opencode run (单次运行) │
│ ├── opencode mcp (MCP 管理) │
│ ├── opencode session (会话管理) │
│ └── opencode debug (调试工具) │
│ │
│ TUI 组件 (Ink + React) │
│ ├── App.tsx (主应用) │
│ ├── Prompt/ (输入组件) │
│ ├── Dialog/ (对话框) │
│ └── Routes/ (路由) │
│ │
│ 交互系统 │
│ ├── Keybindings (快捷键) │
│ ├── Theme (主题) │
│ └── Event (事件) │
│ │
└────────────────────────────────────────────────────────────┘
3.2 TUI vs CLI
| 特性 | TUI (Terminal UI) | CLI (Command Line) |
|---|---|---|
| 交互方式 | 持续交互 | 单次执行 |
| 界面 | 全屏、组件化 | 简单输出 |
| 框架 | Ink (React for CLI) | yargs/commander |
| 适用场景 | 复杂交互 | 自动化脚本 |
3.3 tiny-agent 的 CLI 实现
// 简单的 readline 交互
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
})
const prompt = () => {
rl.question("You: ", async (input) => {
// 处理命令
if (input === "exit") { ... }
if (input === "mode explore") { ... }
// 调用 AI
const response = await AgentLoop.run(input, {
onText: (text) => process.stdout.write(text),
})
prompt() // 继续等待输入
})
}
四、生产级 Agent 架构
4.1 完整架构图
┌─────────────────────────────────────────────────────────────────┐
│ 生产级 AI Agent 架构 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 用户界面层 │ │
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
│ │ │ TUI │ │ CLI │ │ Web │ │ API │ │ │
│ │ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ │ │
│ └───────┴────────────┴────────────┴────────────┴──────────┘ │
│ │ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 核心业务层 │ │
│ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │
│ │ │ Agent │ │ Session │ │ Tool │ │ │
│ │ │ - build │ │ - messages │ │ - read │ │ │
│ │ │ - explore │ │ - compact │ │ - write │ │ │
│ │ │ - plan │ │ - persist │ │ - bash │ │ │
│ │ └──────────────┘ └──────────────┘ │ - grep/glob │ │ │
│ │ │ - skill │ │ │
│ │ └──────────────┘ │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 基础设施层 │ │
│ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │
│ │ │ Provider │ │ Permission │ │ Storage │ │ │
│ │ │ - OpenAI │ │ - allow │ │ - session │ │ │
│ │ │ - Anthropic │ │ - deny │ │ - rules │ │ │
│ │ │ - Proxy │ │ - ask │ │ - snapshot │ │ │
│ │ └──────────────┘ └──────────────┘ └──────────────┘ │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 扩展层 │ │
│ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │
│ │ │ MCP │ │ LSP │ │ Plugin │ │ │
│ │ │ - local │ │ - symbols │ │ - hooks │ │ │
│ │ │ - remote │ │ - diagnose │ │ - transform │ │ │
│ │ │ - oauth │ │ - complete │ │ │ │ │
│ │ └──────────────┘ └──────────────┘ └──────────────┘ │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
4.2 关键设计原则
| 原则 | 说明 | OpenCode 实现 |
|---|---|---|
| 分层 | 职责分离 | UI / Core / Infra / Extension |
| 可扩展 | 支持插件 | MCP / Plugin / Custom Agent |
| 安全 | 权限控制 | Permission 系统 |
| 健壮 | 错误处理 | Retry / Snapshot |
| 高效 | 性能优化 | Stream / Prompt Cache |
4.3 最佳实践
工具设计
✅ 好的工具设计:
- 单一职责(read 只读,write 只写)
- 清晰的参数定义(Zod schema)
- 详细的描述(给 AI 看)
- 安全检查(权限验证)
❌ 避免的设计:
- 工具功能过于复杂
- 参数含义模糊
- 没有错误处理
- 直接执行危险操作
提示词设计
✅ 好的 System Prompt:
- 明确角色定位
- 列出可用工具和用法
- 设定行为规则
- 包含项目上下文
❌ 避免的设计:
- 过于冗长(token 浪费)
- 缺少工具说明
- 没有约束规则
会话管理
✅ 好的会话设计:
- 保存关键历史
- 及时压缩旧消息
- 持久化重要会话
- 支持恢复和回滚
❌ 避免的设计:
- 无限累积消息
- 丢失重要上下文
- 无法恢复状态
五、AI Agent 核心概念解析
5.1 Tool / Skill / MCP / Agent 的区别
┌─────────────────────────────────────────────────────────────────┐
│ AI Agent 核心概念 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Agent(大脑) │ │
│ │ - 决策中枢,负责理解、推理、规划 │ │
│ │ - 调用 Tools/Skills/MCP 完成任务 │ │
│ │ │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │
│ │ │ Tool │ │ Skill │ │ MCP │ │ │
│ │ │ (双手) │ │ (知识) │ │(外部工具) │ │ │
│ │ └──────────┘ └──────────┘ └──────────┘ │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
| 概念 | 类比 | 说明 | 执行方式 |
|---|---|---|---|
| Tool | 双手(吃饭、喝水) | 内置的基本能力,直接执行操作 | 代码执行 |
| Skill | 知识(会开车、换灯泡) | 可载入的指导知识,告诉 AI 怎么做 | AI 解读后调用 Tool |
| MCP | 外部工具(电钻、汽车) | 连接外部系统的标准协议 | 通过协议调用外部服务 |
| Agent | 大脑 | 决策中枢,理解 + 推理 + 执行 | 调用上述所有能力 |
5.2 Skill 的本质
Skill 是"知识",不是"代码"
┌─────────────────────────────────────────────────────────────┐
│ SKILL.md 内容示例 │
├─────────────────────────────────────────────────────────────┤
│ --- │
│ name: git-commit │
│ description: 帮助生成规范的 Git commit 消息 │
│ --- │
│ │
│ # Git Commit 规范 │
│ │
│ ## 格式 │
│ type(scope): subject │
│ │
│ ## 类型 │
│ - feat: 新功能 │
│ - fix: 修复 bug │
│ - docs: 文档更新 │
│ ... │
└─────────────────────────────────────────────────────────────┘
↓ AI 读取 Skill 内容
┌─────────────────────────────────────────────────────────────┐
│ AI 理解知识后,使用 Tool 执行 │
│ 1. 调用 bash 工具: git diff --staged │
│ 2. 分析 diff 内容 │
│ 3. 根据 Skill 规范生成 commit message │
│ 4. 调用 bash 工具: git commit -m "feat: ..." │
└─────────────────────────────────────────────────────────────┘
关键点:Skill 本身不执行代码,AI 读取 Skill 内容后,使用 Tool 来执行操作。
5.3 Multi-Agent vs Subtask
| 概念 | 说明 | 适用场景 |
|---|---|---|
| Multi-Agent | 多个专业化的 Agent 切换 | 不同任务需要不同专家 |
| Subtask | 主 Agent 派遣子 Agent 并行执行 | 大任务分解为多个独立小任务 |
Multi-Agent(专家切换):
┌─────────────────────────────────────────────────────────────┐
│ 用户: 我要修改代码 │
│ └── build Agent(全能模式,可读写) │
│ │
│ 用户: 帮我分析一下这个项目 │
│ └── explore Agent(只读模式,安全) │
│ │
│ 用户: 我想规划一下重构方案 │
│ └── plan Agent(规划模式,不执行) │
└─────────────────────────────────────────────────────────────┘
Subtask(任务分派):
┌─────────────────────────────────────────────────────────────┐
│ 主 Agent: 我需要同时做三件事 │
│ │ │
│ ├── 子任务1: 重构 auth 模块 ──▶ Sub-Agent-1 ──────┐ │
│ ├── 子任务2: 更新测试用例 ──▶ Sub-Agent-2 ────┐ │ │
│ └── 子任务3: 修改文档 ──▶ Sub-Agent-3 ──┐ │ │ │
│ │ │ │ │
│ ◀──────────── 汇总所有结果 ◀────────────────────┴─┴─┘ │
└─────────────────────────────────────────────────────────────┘
5.4 Claude Code vs OpenCode 的 Skill/Hooks
Claude Code 的 Skill + Hooks
Claude Code 的 Skill 支持内置 Hooks,可以在特定事件时自动执行脚本:
# .claude/skills/auto-format/SKILL.md
---
name: auto-format
description: 自动格式化代码
# Skill 内置 Hooks!
hooks:
PostToolUse:
- matcher: "Edit|Write"
command: "${CLAUDE_PLUGIN_ROOT}/scripts/format.sh"
---
当你修改代码后,自动运行格式化。
Claude Code 支持的 Hook 事件:
| 事件 | 触发时机 |
|---|---|
PreToolUse | 工具执行前 |
PostToolUse | 工具执行后 |
UserPromptSubmit | 用户发送消息时 |
SessionStart | 会话开始 |
PermissionRequest | 需要用户授权时 |
OpenCode 的 Hooks 实现
OpenCode 兼容 Claude Code 的 Skills 目录,但 不支持 SKILL.md 中的 hooks。
OpenCode 的 Hooks 通过两种方式实现:
1. 配置文件 hooks(experimental):
// opencode.json
{
"experimental": {
"hook": {
"file_edited": {
"*.ts": [{ "command": ["npm", "run", "format"] }]
},
"session_completed": [{ "command": ["./notify.sh"] }]
}
}
}
2. Plugin hooks(TypeScript):
// 支持的 hooks
"chat.message" // 新消息
"chat.params" // 修改 LLM 参数
"permission.ask" // 权限检查
"command.execute.before" // 命令执行前
"tool.execute.before" // 工具执行前
"tool.execute.after" // 工具执行后
对比总结
| 特性 | Claude Code | OpenCode |
|---|---|---|
| Skills 目录 | .claude/skills/ | .opencode/skill/ + 兼容 .claude/skills/ |
| SKILL.md 内置 Hooks | ✅ 支持 frontmatter | ❌ 不支持 |
| Hooks 配置位置 | SKILL.md | 配置文件 + Plugin |
| Hook 事件 | PreToolUse, PostToolUse... | file_edited, tool.execute.before... |
| 执行方式 | Shell 脚本 | Shell 脚本 / TypeScript |
5.5 概念关系图
┌─────────────────────────────────────────────────────────────────┐
│ AI Agent 概念全景 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────┐ │
│ │ User │ │
│ └────┬────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ Agent (大脑) │ │
│ │ ┌────────────────────────────────────────────────────┐ │ │
│ │ │ Session (会话/记忆) │ │ │
│ │ │ messages + context + rules + skills(知识列表) │ │ │
│ │ └────────────────────────────────────────────────────┘ │ │
│ │ │ │ │
│ │ ┌───────────────┼───────────────┐ │ │
│ │ ▼ ▼ ▼ │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │
│ │ │ Tool │ │ Skill │ │ MCP │ │ │
│ │ │ (内置) │ │ (载入) │ │ (外部) │ │ │
│ │ │ │ │ │ │ │ │ │
│ │ │ read │ │ 知识 │ │ 远程API │ │ │
│ │ │ write │ │ 指导 │ │ 本地服务 │ │ │
│ │ │ bash │ │ 模板 │ │ 数据库 │ │ │
│ │ │ grep │ │ │ │ │ │ │
│ │ └──────────┘ └──────────┘ └──────────┘ │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌──────────────────┼──────────────────┐ │
│ ▼ ▼ ▼ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Permission │ │ Hooks │ │ Sub-Agent │ │
│ │ (权限控制) │ │ (生命周期) │ │ (子任务) │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
六、tiny-agent vs OpenCode 总结
6.1 功能对比
| 功能 | tiny-agent | OpenCode |
|---|---|---|
| 基础 | ||
| Tool 系统 | ✅ 简化 | ✅ 完整 |
| Provider | ✅ 3 个 | ✅ 10+ |
| Agent Loop | ✅ ReAct | ✅ ReAct + 变体 |
| 工具 | ||
| read/write/edit | ✅ | ✅ + 更多 |
| grep/glob | ✅ | ✅ + LSP |
| bash | ✅ 简化 | ✅ + 沙箱 |
| 会话 | ||
| 多轮对话 | ✅ | ✅ |
| 上下文压缩 | ✅ 简单截断 | ✅ AI 摘要 |
| 项目规则 | ✅ | ✅ + URL |
| Skills | ✅ 渐进式 | ✅ 渐进式 |
| 持久化 | ✅ 文件 | ✅ 分层存储 |
| 高级 | ||
| 多 Agent | ✅ 2 种 | ✅ 6+ 种 |
| 权限系统 | ✅ 简化 | ✅ 复杂规则 |
| 重试机制 | ✅ | ✅ |
| Snapshot | ❌ | ✅ Git |
| 子任务 | ❌ | ✅ |
| 扩展 | ||
| MCP | ❌ | ✅ |
| LSP | ❌ | ✅ |
| Plugin | ❌ | ✅ |
| TUI | ❌ readline | ✅ Ink |
6.2 代码量对比
tiny-agent: ~1500 行
OpenCode: ~50000+ 行
tiny-agent 实现了 OpenCode 核心功能的 ~3%,
但覆盖了核心概念的 ~80%。
6.3 学习收获
通过 tiny-agent,我们学习了:
- Tool 系统:定义、参数校验、执行
- Provider 抽象:多模型支持、Proxy 配置
- Agent Loop:ReAct 模式、工具调用
- 会话管理:历史、压缩、持久化
- 规则系统:项目规则、Skills
- 多 Agent:模式切换、权限隔离
- 权限控制:allow/deny/ask
- 重试机制:指数退避
七、下一步
7.1 如果想深入学习
-
阅读 OpenCode 源码
packages/opencode/src/session/prompt.ts- 核心 Agent Looppackages/opencode/src/tool/- 完整工具实现packages/opencode/src/mcp/- MCP 实现
-
实践项目
- 添加更多工具(如网页抓取)
- 实现 Snapshot
- 集成 MCP Server
-
生产部署
- 使用 OpenCode 或 Claude Code
- 配置企业 Proxy
- 自定义 Agent
7.2 相关资源
| 资源 | 链接 |
|---|---|
| OpenCode | github.com/opencode-ai/opencode |
| MCP 协议 | modelcontextprotocol.io |
| AI SDK | sdk.vercel.ai |
| Claude Code | claude.ai/code |
总结
┌─────────────────────────────────────────────────────────────┐
│ AI Agent 学习路线 │
├─────────────────────────────────────────────────────────────┤
│ │
│ Phase 1: 基础架构 │
│ └── Tool + Provider + Agent Loop │
│ │
│ Phase 2: 核心工具 │
│ └── read/write/edit/bash/grep/glob │
│ │
│ Phase 3: 会话与记忆 │
│ └── 多轮对话 + 压缩 + 规则 + Skills │
│ │
│ Phase 4: 高级功能 │
│ └── 多Agent + 权限 + 重试 + Snapshot │
│ │
│ Phase 5: 扩展与生产 │
│ └── MCP + 流式 + CLI + 架构 │
│ │
└─────────────────────────────────────────────────────────────┘
核心心得:
- 从简单开始:tiny-agent 证明了核心功能可以很简洁
- 理解原理:比会用更重要
- 渐进增强:先能用,再好用,最后生产级
- 善用工具:OpenCode 已经很成熟,生产环境直接用
感谢阅读本系列!🎉