对话压缩与会话恢复
对话压缩与会话恢复
学习目标
本章要解决的核心问题:当 AI 编程对话越来越长,超出模型上下文窗口时,如何压缩历史对话?会话如何在关闭后恢复?
你将学到:
- Continue 的对话压缩(compactConversation)机制
- 基于 SQLite 的本地会话持久化
- Control Plane 远程会话同步
- CLI 的
--resume和cn ls会话恢复
前置知识
本章涉及上下文压缩和记忆系统的通用原理,建议先阅读:
项目实践
对话压缩
当对话超出模型的上下文窗口时,Continue 使用 compactConversation 进行摘要压缩:
// 伪代码摘要async function compactConversation({ sessionId, index, historyManager, currentModel }) { // 1. 加载会话历史 const session = historyManager.load(sessionId);
// 2. 确定需要压缩的部分(最早的消息) const messagesToCompact = session.history.slice(0, index);
// 3. 使用 LLM 生成摘要 const summary = await currentModel.generateSummary({ messages: messagesToCompact, systemPrompt: "请总结这段编程对话的关键信息和上下文。" });
// 4. 用摘要替换原始消息 session.compactSummary = summary; session.compactIndex = index; historyManager.save(session);}压缩策略:
- 保留最近的对话消息(不压缩)
- 将早期对话压缩为摘要
- 摘要包含关键的代码片段、文件路径、决策记录
- 使用当前对话中配置的 chat 模型执行压缩
本地会话存储
Continue 使用 SQLite 存储本地会话历史:
用户开始新对话 ↓historyManager.create(session) ↓每条消息追加到 SQLite ↓用户关闭 IDE → 会话自动保存 ↓用户重新打开 → 从 SQLite 加载会话管理 API:
historyManager.list()— 列出所有会话(按时间排序)historyManager.load(id)— 加载特定会话的完整历史historyManager.save(session)— 保存或更新会话historyManager.delete(id)— 删除会话historyManager.clearAll()— 清除所有本地会话
远程会话同步
Continue 支持通过 Control Plane 同步会话到远程服务器:
// 本地 + 远程会话合并on("history/list", async (msg) => { const localSessions = historyManager.list(msg.data);
// 检查是否启用远程会话 const shouldFetchRemote = await configHandler.controlPlaneClient .shouldEnableRemoteSessions();
// 获取远程会话 const remoteSessions = shouldFetchRemote ? await configHandler.controlPlaneClient.listRemoteSessions() : [];
// 合并 + 按时间排序 return [...localSessions, ...remoteSessions] .sort((a, b) => new Date(b.dateCreated) - new Date(a.dateCreated)) .slice(0, limit);});远程会话的加载:
on("history/loadRemote", async (msg) => { return configHandler.controlPlaneClient.loadRemoteSession(msg.data.remoteId);});CLI 会话恢复
CLI 提供了独特的会话恢复体验:
# 恢复当前终端的最后一次会话cn --resume
# 列出所有历史会话并选择cn ls
# JSON 格式输出(适合脚本)cn ls --jsonCLI 的会话管理:
- 每个终端会话有唯一的 session ID
- 会话历史保存在本地 SQLite 中
cn ls显示一个 TUI 选择器,按屏幕高度限制条目数--resume自动恢复最后一次的对话上下文
问题与规避
陷阱 1:压缩后的信息丢失
现象:对话压缩后,LLM 无法回答关于早期对话细节的问题。
原因:摘要压缩本质上是有损的——只保留关键信息。
规避:
- 压缩 prompt 指示保留代码片段、文件路径、决策等关键信息
- 用户可以手动回顾压缩前的完整历史(如果有保存的话)
- 重要的结论应该让用户确认并记录到规则文件中
陷阱 2:SQLite 数据库锁竞争
现象:多个进程同时写入会话历史时出现 SQLITE_BUSY 错误。
规避:索引系统明确处理这种情况——在 CodebaseIndexer 中对 SQLITE_BUSY 错误不做清除索引处理(区别于其他 SQLite 错误)。会话写入也采用类似的策略。
陷阱 3:远程会话同步延迟
现象:在 VS Code 中开始对话,切换到 CLI 时看不到最新的历史记录。
原因:远程会话同步是异步的,可能需要几秒才能传播。
规避:本地会话总是立即可用。远程会话作为补充,不保证实时一致。
设计取舍
对话压缩 vs 截断
| 方案 | 优势 | 代价 |
|---|---|---|
| 截断 | 简单,零成本 | 丢失历史信息 |
| 压缩(摘要) | 保留关键信息 | 需要额外的 LLM 调用,有损压缩 |
| 滑动窗口 | 保留最近 N 条消息 | 早期信息完全丢失 |
Continue 选择压缩(摘要),因为编程对话的早期部分通常包含重要的上下文信息(项目结构、架构决策、已发现的文件路径),这些信息在后续对话中仍然相关。截断会丢失这些关键上下文。
本地优先 + 远程可选
Continue 的会话存储策略是本地优先:
- 所有会话首先在本地 SQLite 中存储
- 远程同步是可选的(需要 Control Plane 登录)
- 即使远程服务不可用,本地会话仍然可用
这与一些云端优先的方案(如 Cursor 的云端历史)不同,Continue 保证了即使没有网络连接,会话历史也不丢失。