运行时 · 状态机 · 流程
运行时深度解析
从用户输入到代码修改落地,opencode 经历了 Plan → Build 双 Agent 编排、LLM API 调用、工具并行执行、System Prompt 动态构建等关键流程。本文用状态机图与流程图完整还原每个环节。
⚙️ 双 Agent 执行流程
一次完整的用户请求经历以下阶段。Plan Agent 先行分析,产出结构化方案后,Build Agent 按方案逐步执行,每步均可调用工具并将结果反馈给 LLM。
1
用户输入 (USER_INPUT)
TUI 接收用户消息,或通过 -p 标志传入 prompt。消息追加至当前 session 的消息列表,触发 Agent 编排流程。
2
Plan Agent — 分析阶段
Plan Agent 以只读工具集(read_file、grep、search_files、list_directory)扫描代码库,理解任务意图、识别影响范围、生成结构化实施步骤。输出包含:要修改的文件列表、每步操作说明、潜在风险点。
3
Build Agent — 执行阶段
Build Agent 接收 Plan Agent 输出,获得全工具访问权限(含写入、Shell 执行),按计划逐步执行。每步执行后验证结果(如运行类型检查、lint),根据反馈动态调整后续步骤。
4
LLM API 调用 (LLM_CALL)
当前 session 消息历史(含 system prompt、用户消息、工具结果)被序列化发送至选定的 LLM Provider。支持流式返回(SSE),TUI 实时渲染增量 token。
5
工具调用并行执行 (TOOL_CALLS)
LLM 响应中包含 tool_use 块时,opencode 提取所有工具调用并并行执行(Promise.all),最大化吞吐量。各工具结果以 tool_result 消息追加至上下文,触发下一轮 LLM 调用。
read_file
grep
list_directory
search_files
6
循环直至 DONE
LLM 调用 → 工具执行 → 结果追加 → 再次 LLM 调用,此循环持续直至 LLM 不再产生 tool_use,发出完成信号(stop_reason: end_turn)。
7
Session 持久化 (PERSIST)
完整对话历史(含工具调用、结果、最终响应)序列化写入磁盘。若开启 --share,同步推送至 opencode.ai console。
🔄 Agent 循环状态机
以下状态机图展示 Build Agent 单轮执行循环的完整状态转移。分支条件决定是否继续工具调用循环或终止。
USER_INPUT
用户消息 / -p prompt 注入
▼
PLAN_AGENT_RUN
只读工具 · 分析意图 · 输出方案
▼
BUILD_AGENT_RUN
接收 Plan 输出 · 全工具访问
▼
LLM_CALL
Provider API · 流式返回 · Token 渲染
▼
stop_reason == "tool_use" ?
YES
NO
TOOL_EXECUTE
并行执行所有工具
▼
TOOL_RESULTS → LLM
结果追加 · 重新调用
↺ 回到 LLM_CALL
RESPONSE
最终回复渲染至 TUI
▼
PERSIST_SESSION
写入磁盘 · 可选共享
📝 System Prompt 构建管道
每个 session 启动时,opencode 按固定顺序组装 system prompt。各层内容追加叠加,最终通过可选的 JS transform 钩子做全局变换。
① 基础指令 (Base Instructions)
内置 opencode 行为规范 · 工具使用格式 · 安全约束
+
② AGENTS.md (项目级,如存在)
项目根目录的 AGENTS.md 全文追加 · 技术约定 · 禁止操作
+
③ 匹配技能 (Auto-matched Skills)
语义匹配得分最高的 N 个 SKILL.md 内容 · 项目 > 全局 > 插件
↓ (可选)
④ experimental.chat.system.transform
JS eval · 入参: system (string), extraContext · 返回值替换最终 prompt
↓
⑤ 最终 System Prompt → LLM
发送至 Provider API · 每轮对话保持不变直至 /compact 或 session 重启
Transform 钩子示例
// ~/.config/opencode/opencode.json
{
"experimental": {
"chat": {
"system": {
"transform": "return system + '\\n\\n## 额外约束\\n今天是 ' + new Date().toLocaleDateString('zh-CN') + ',请用中文回复。'"
}
}
}
}
// 更复杂的用法(多行字符串)
{
"transform": "const extra = process.env.TEAM_CONTEXT || ''; return system + extra"
}
transform 中的 JS 表达式在 opencode 进程中直接 eval 执行,拥有访问 process.env 的能力,请勿放入不可信内容。该特性标记为 experimental,API 可能变更。
🧩 Skill 注入流程
opencode 在每次 session 启动时执行一次技能扫描与注入。整个流程分为四个阶段,确保最相关的技能内容被自动纳入 system prompt。
扫描技能库
按优先级遍历
项目 → 全局 → 插件
项目 → 全局 → 插件
→
解析 Frontmatter
提取 name
& description
& description
→
语义匹配
与项目上下文
计算相关性分
计算相关性分
→
注入 Prompt
TopK 技能内容
追加至 system
追加至 system
语义匹配依据的项目上下文
| 上下文信号 | 示例 | 影响技能 |
|---|---|---|
| 文件扩展名分布 | .tsx, .css 文件占多数 | 前端/React 相关技能分数提升 |
| package.json 依赖 | react, tailwindcss | UI 框架技能相关性更高 |
| 配置文件存在 | prisma/schema.prisma | 数据库/ORM 技能优先注入 |
| AGENTS.md 关键词 | "FastAPI", "TypeScript" | 对应技术栈技能分数加权 |
| 当前任务 prompt | "Fix the login form UI" | 前端/认证相关技能优先 |
🗜️ Context 压缩机制 (/compact)
当对话历史过长,接近 LLM context 窗口上限时,/compact 命令将历史消息压缩为摘要,释放空间以继续长任务。
压缩前
~24 条消息
~80K tokens
→
/compact
/compact
压缩后
1 摘要 + 最新消息
~8K tokens
压缩行为细节
- ✓ 摘要由 LLM 本身生成,保留关键决策、已做修改、待完成任务等核心信息
- ✓ 摘要以单条 assistant 消息替换原始消息列表,保持 API 消息格式合法
- ✓ 压缩前的完整历史仍持久化在磁盘,可通过 session 恢复查看
- ⚡ 也可配置为自动压缩(auto-compact),在 token 数达到阈值时自动触发,无需手动 /compact
🔗 Session 共享架构
opencode --share 将当前 session 实时发布至 opencode.ai,团队成员无需安装 opencode 即可通过浏览器查看完整操作过程。
共享 session 默认公开可访问(知链接即可看),请避免在包含敏感信息(API Key、密码、内部代码)的 session 中启用共享。autoshare: false 为默认安全设置。
🤖 非交互模式与 CI/CD 集成
使用 -p 标志时,opencode 进入非交互模式:执行完成后以退出码 0(成功)或非 0(失败)退出,适合在 CI 流水线中调用。
# GitHub Actions 示例
- name: AI Code Review
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
run: |
opencode -p "Review the diff in this PR for security issues and code quality.
Output a structured report with severity levels."
# 退出码处理
opencode -p "Run tests and fix any failures" || echo "opencode task failed"
# 组合使用:指定模型 + 非交互 + 禁用自动压缩
opencode --model anthropic/claude-opus-4 \
--no-auto-compact \
-p "Refactor src/api/ to use the repository pattern"
🔧 工具执行细节
| 工具 | Plan Agent | Build Agent | 执行方式 |
|---|---|---|---|
| read_file | ✓ | ✓ | Bun.file().text() |
| write_file | ✗ | ✓ | Bun.write() |
| execute_command | ✗ | ✓ | Bun.spawn() / $`` |
| grep | ✓ | ✓ | ripgrep 子进程 |
| search_files | ✓ | ✓ | glob 文件系统遍历 |
| web_fetch | ✗ | ✓ | fetch() API |
| git_* | ✗ | ✓ | git CLI 子进程 |
| lsp_* | ✗ | ✓ | LSP stdio 协议 |
📡 流式响应处理
opencode 全程使用流式 API(SSE / streaming),实现 token 级别的实时渲染。TUI 使用 React 状态更新驱动增量显示,用户无需等待完整响应。
// 简化的流式处理伪代码
async function streamLLM(messages, onToken) {
const stream = await provider.chat.stream({ messages })
for await (const chunk of stream) {
if (chunk.type === 'text_delta') {
onToken(chunk.text) // TUI React 状态更新
}
if (chunk.type === 'tool_use') {
toolCalls.push(chunk)
}
if (chunk.stop_reason === 'end_turn') break
}
// 并行执行所有收集到的工具调用
if (toolCalls.length > 0) {
const results = await Promise.all(toolCalls.map(executeT))
return streamLLM([...messages, ...results], onToken) // 递归
}
}
opencode · Anomaly / SST · github.com/sst/opencode
深度文档 · 2026-05-22