OpenCode Session 管理:持久化、分支与 Undo
OpenCode Session 管理:持久化、分支与 Undo
用 AI 编程助手最怕什么?不是它写错代码,而是聊了半小时的上下文,手一滑——没了。很多 CLI 工具关掉终端就什么都没了,那种痛,经历过的人都懂。
OpenCode 从设计之初就把 Session 持久化当成核心能力来做。每次对话都自动存入本地 SQLite 数据库,关机、断电、换终端,回来接着聊。不仅如此,它还支持 Session 分支、Undo/Redo、上下文自动压缩、对话分享——一套完整的 Session 生命周期管理。
这篇文章是我深入 OpenCode 文档和源码后的总结,把 Session 管理的方方面面都梳理清楚。
本文提纲
- SQLite 持久化:Session 存在哪里
- Session 创建与恢复
- Session 分支:安全探索的底气
- Undo 与 Redo:后悔药的正确吃法
- 上下文压缩:对话太长怎么办
- Session 共享:团队协作的桥梁
- Session 导出与导入
- Session 时间线与事件回放
- 实战技巧与配置建议
SQLite 持久化:Session 存在哪里
OpenCode 把所有 Session 数据存在本地 SQLite 数据库中。数据库文件位于项目目录下的 .opencode/state.db(路径可通过 OPENCODE_CONFIG_DIR 环境变量自定义)。
选择 SQLite 是个很务实的设计决策:
- 零配置:不需要额外安装数据库服务,OpenCode 启动就能用
- 单文件:整个数据库就是一个文件,备份、迁移、删除都很方便
- 事务支持:Session 的写入、更新、Undo 操作都在事务里,不怕数据损坏
- 性能够用:Session 数据量不大,SQLite 绰绰有余,读写都快
OpenCode 使用 Drizzle ORM 来操作 SQLite。Drizzle 是一个轻量级的 TypeScript ORM,类型安全、无运行时开销,和 OpenCode 的技术栈非常契合。Drizzle 的 schema 定义清晰,迁移也很方便,适合这种本地嵌入式场景。
数据表主要包含这几类:
- Session 表:存储 Session 元数据(ID、标题、创建时间、父 Session 等)
- Message 表:存储每条消息(用户消息、AI 回复)
- Part 表:存储消息的各个部分(文本、工具调用、工具结果等)
- Event 表:记录 Session 生命周期内的各种事件
这种分层设计让 OpenCode 能精确地追踪每一轮对话的完整上下文,也为 Undo、分支、压缩等高级功能打下了基础。
Session 创建与恢复
每次在 TUI 里按 ctrl+x n 或输入 /new,OpenCode 就创建一个新的 Session。每个 Session 有唯一 ID、标题(可以自动生成,也可以手动指定)、创建时间和完整的消息历史。
启动 OpenCode 时,有几种方式控制 Session 行为:
# 默认:继续上一次的 Session
opencode --continue
# 恢复指定 Session
opencode --session abc123
# 启动新 Session(默认行为)
opencode在 TUI 里,用 ctrl+x l 或 /sessions 命令可以打开 Session 列表,浏览所有历史对话,选中一个就能直接跳过去继续聊。/sessions 也支持别名 /resume 和 /continue,记哪个都行。
用 CLI 脚本化操作也很方便:
# 列出所有 Session
opencode session list
# 以 JSON 格式输出,方便程序处理
opencode session list --format json
# 只看最近 5 个
opencode session list -n 5OpenCode 还会通过 small_model(默认用便宜的 Haiku 模型)自动为每个 Session 生成标题,这样在 Session 列表里一眼就能找到你想要的对话。
Session 分支:安全探索的底气
这个功能我觉得是 OpenCode Session 管理里最精巧的设计。
想象一个场景:你正在和 AI 讨论一个复杂功能的实现,聊到一半想试一个不同的方案,但不想丢失当前的对话进度。传统做法是手动复制对话内容,或者开个新窗口重新描述上下文。
OpenCode 的 Session 分支(Fork)完美解决了这个问题。
# 继续上一次对话,但以分支方式——原 Session 不受影响
opencode --continue --fork
# 从指定 Session 分支
opencode --session abc123 --forkFork 出来的新 Session 会保留原 Session 的完整消息历史作为起点,但从那一刻起,两条路就分道扬镳了。你可以在分支里大胆尝试各种方案,搞砸了也不影响主线的对话。
在 SDK 层面,Session 有 parentID 字段来追踪分支关系,通过 session.children() API 可以列出某个 Session 的所有子分支。这构成了一棵 Session 树,非常适合管理复杂的探索式开发流程。
实际使用中,我经常这样做:
- 主 Session 保持稳定的方案讨论
- 遇到不确定的地方,Fork 一个分支去试
- 试通了,把结果贴回主 Session
- 试不通,直接删掉分支,回到主线
这种工作流让 AI 辅助编程变得更可控,不用担心"聊歪了"。
Undo 与 Redo:后悔药的正确吃法
AI 写的代码不满意怎么办?OpenCode 的 /undo 命令不仅能撤回消息,还能回滚文件变更。
# 撤回最后一轮对话(包括 AI 对文件做的修改)
/undo
# 撤回后反悔了,重做
/redoUndo 的实现依赖两套机制协同工作:
消息层面:SQLite 数据库里记录了完整的消息链。/undo 会移除最近一条用户消息及其后所有 AI 回复。/redo 则把它们恢复回来。
文件层面:OpenCode 使用内部的 Git 快照系统追踪 Agent 对文件做的每一次修改。/undo 时,文件变更也会一并还原;/redo 时重新应用。这个快照系统默认开启,可以在配置里关掉:
{
"snapshot": false
}但说实话,我不建议关掉。没有 Snapshot,Undo 就只能撤回消息不能回滚代码,功能大打折扣。
几个实用技巧:
/undo可以连续执行多次,一步步往回退- Undo 之后你可以修改 Prompt 重新提问,不用从头来
- 快捷键
ctrl+x u(Undo)和ctrl+x r(Redo)比输入命令快得多
有个前提条件值得注意:项目必须是 Git 仓库。OpenCode 的文件回滚依赖 Git,如果你的项目还没 git init,Undo 只能撤回消息,不能恢复文件。
上下文压缩:对话太长怎么办
LLM 的 Context Window 是有限的。一个 Session 聊久了,历史消息越来越长,最终会撑爆窗口。很多工具到这一步就直接报错或者截断,用户体验很差。
OpenCode 用 Compaction(上下文压缩)优雅地解决了这个问题。
当 Context Window 快满的时候,OpenCode 会自动触发压缩:
- 用 LLM 对当前 Session 的历史消息生成一份摘要
- 用摘要替代原始的冗长对话
- 保留最近几轮完整对话作为即时上下文
- 继续正常对话,用户几乎感知不到
这个行为可以通过配置精细控制:
{
"compaction": {
"auto": true,
"prune": true,
"reserved": 10000
}
}- auto:是否自动压缩,默认
true。设为false后只在手动执行/compact(快捷键ctrl+x c)时才压缩 - prune:压缩时是否移除旧的工具输出(Tool Result),默认
true。工具调用结果往往很长但参考价值递减,清掉能省大量 token - reserved:预留的 token 缓冲区大小,默认 10000。确保压缩过程本身不会导致上下文溢出
手动压缩也很有用。当你觉得对话变得冗长、AI 开始"忘记"前面的内容时,主动 /compact 一下往往能改善回复质量。
压缩对用户基本透明——你不会丢失任何重要信息,只是旧的对话被智能摘要替代了。如果你需要回顾原始对话,Session 时间线功能依然保留着完整的事件记录。
Session 共享:团队协作的桥梁
OpenCode 支持把 Session 生成公开链接分享给其他人。这在团队协作中非常有用——让同事看看你遇到的问题,或者向社区展示 AI 辅助编程的效果。
三种分享模式:
Manual(默认):需要主动执行 /share 命令才会分享。分享后生成类似 opncd.ai/s/<share-id> 的链接,自动复制到剪贴板。
{
"share": "manual"
}Auto:每次新对话自动分享,适合经常需要同步进度的场景。
{
"share": "auto"
}Disabled:完全禁用分享功能。对安全要求高的项目,可以在项目配置里设置并提交到 Git,确保团队成员都不能意外分享。
{
"share": "disabled"
}不再需要分享时,用 /unshare 移除链接和远程数据。也可以通过环境变量 OPENCODE_AUTO_SHARE 控制自动分享行为。
分享出去的对话包含完整的消息历史、所有 AI 回复和 Session 元数据,所以分享前最好检查一下是否包含敏感信息。企业版还支持 SSO 认证限制和自托管分享服务。
Session 导出与导入
OpenCode 提供了完整的 Session 导出导入功能,让你能备份、迁移和分享对话数据。
导出:
# 交互式选择要导出的 Session
opencode export
# 导出指定 Session
opencode export abc123导出的是 JSON 格式,包含完整的消息、工具调用、元数据等信息。在 TUI 里也可以用 /export(快捷键 ctrl+x x)导出当前对话为 Markdown 并在编辑器中打开。
导入:
# 从本地文件导入
opencode import session.json
# 从分享链接导入
opencode import https://opncd.ai/s/abc123从分享链接导入这个功能特别实用。同事给你发了一个 OpenCode 的分享链接,你可以直接导入到本地继续讨论,而不是从头开始描述上下文。
SDK 也提供了对应的 API:
// 列出所有 Session
const sessions = await client.session.list()
// 获取某个 Session 的详情
const session = await client.session.get({ path: { id: "abc123" } })
// 删除 Session
await client.session.delete({ path: { id: "abc123" } })Session 时间线与事件回放
OpenCode 的 Session 不是一条简单的消息列表,而是一条完整的时间线。每个 Session 记录了从创建到当前状态的所有事件——消息发送、工具调用、文件变更、压缩操作、分支创建等。
通过 SDK 可以深度访问这些数据:
// 获取 Session 的所有消息
const messages = await client.session.messages({ path: { id: "abc123" } })
// 每条消息包含 info(元数据)和 parts(内容部分)
messages.forEach(msg => {
console.log(msg.info.role, msg.parts)
})
// 获取某个 Session 的所有子分支
const children = await client.session.children({ path: { id: "abc123" } })事件订阅则提供了实时监听能力:
const events = await client.event.subscribe()
for await (const event of events.stream) {
console.log("Event:", event.type, event.properties)
}这意味着你可以构建自己的 OpenCode 监控面板、日志分析工具或自动化工作流。事件流包含了所有 Session 的状态变更,非常适合用来做:
- 实时监控:追踪多个并行 Session 的执行状态
- 审计日志:记录 AI 做了什么操作,方便事后回溯
- 自动化触发:某个 Session 完成后自动触发下一个流程
Session 的 revert 和 unrevert API 也很有意思——对应 /undo 和 /redo 的底层能力,你可以通过编程方式回滚和恢复 Session 状态:
// 回滚到某条消息之前
await client.session.revert({ path: { id: "abc123" }, body: { messageID: "msg456" } })
// 恢复回滚的内容
await client.session.unrevert({ path: { id: "abc123" } })实战技巧与配置建议
用了一段时间后,我总结了几个让 Session 管理更好用的配置技巧。
合理配置 Compaction。如果你的项目比较大、工具调用多,建议把 reserved 调大一些:
{
"compaction": {
"auto": true,
"prune": true,
"reserved": 20000
}
}为不同项目设置不同的分享策略。内部项目可以 auto 分享方便协作,外部项目用 manual 或 disabled 保护隐私。在项目根目录的 opencode.json 里设置,提交到 Git 后团队成员自动继承。
利用 Session 标题快速定位。opencode run 支持 --title 参数给 Session 起名字:
opencode run --title "refactor-auth" "重构认证模块"这比自动生成的标题直观多了,在 Session 列表里一眼就能找到。
善用 CLI 的非交互模式。opencode run 可以在脚本里调用,配合 --continue 和 --fork 实现自动化工作流:
# 在已有 Session 上继续工作
opencode run --continue --format json "继续上次的重构"
# 从某个 Session 分支探索新方案
opencode run --session abc123 --fork "试试不同的数据库设计"配合 SDK 做深度集成。如果你想在 OpenCode 之上构建自己的工具,SDK 提供了完整的 Session CRUD、消息发送、事件订阅等能力。比如你可以写一个 Slack Bot,把团队消息转发到 OpenCode Session 里,AI 的回复再发回 Slack。
OpenCode 的 Session 管理从持久化存储到分支探索,从上下文压缩到团队分享,形成了一套完整的对话生命周期管理方案。它解决了 AI 编程助手最大的痛点之一——对话状态的丢失和管理,让你能真正把 AI 当成一个持续协作的编程伙伴,而不是一次性的问答工具。
作者: itech001 来源: 公众号:AI人工智能时代 主页: https://www.theaiera.cn(每日分享最前沿的AI新闻和技术)
本文首发于 AI人工智能时代,转载请注明出处。