PicoBot/docs/plans/2026-05-10-incremental-session-recovery-design.md

3.7 KiB
Raw Blame History

启动增量恢复设计

问题

PicoBot 重启后,Session::from_storage() 全量加载 messages 表,恢复的 history 可能直接超出上下文窗口,首次 LLM 调用即触发压缩,浪费 token。

设计

核心思路

last_compressed_message_at 标记最后压缩时刻。恢复时:

  • 加载该标记之后的原始消息
  • 用该 session 的 Timeline 条目替代已压缩部分
  • seq_counter 统一从 SQLite 查 MAX(seq) + 1
messages 表                          memories(timeline)
┌──────────────────────────┐         ┌───────────────────────────┐
│ created_at = T1..T5      │ ← 跳过  │ session = feishu:oc:dialog │
│ (压缩已覆盖用Timeline替代)│       │ created_at 降序             │
├──────────────────────────┤         ├───────────────────────────┤
│ created_at > T6          │ ← 加载  │ 只取最近 3 条               │
└──────────────────────────┘         └───────────────────────────┘

数据变更

sessions 表加列:

last_compressed_message_at INTEGER

SessionMeta / Session 加字段: last_compressed_message_at: Option<i64>

Storage 层新增方法

方法 SQL
get_max_message_seq(session_id) SELECT MAX(seq) FROM messages WHERE session_id = ?
load_messages_after_timestamp(session_id, after_ts) WHERE created_at > ?
load_session_timelines(session_id, limit) WHERE session_id = ? AND category = 'timeline' ORDER BY created_at DESC LIMIT ?

压缩跟踪

compress_if_needed() 返回值改为 CompressionResult { history, created_timelines: bool }compress_once() 中 LLM 摘要路径才置 trueTier 2Tier 1/3 不产生 Timeline。

记录时机handle_message 正常流、溢出重试流、/compact 统一):

if result.created_timelines {
    session.last_compressed_message_at = Some(now());
    session.persist_session_meta().await;
}

Session::from_storage() 恢复逻辑

有压缩标记时:

  1. load_session_timelines(limit=4) → 取 3 条给 LLM第 4 条判"有更多"
  2. 有更多 → 插入提示 user 消息
  3. 逐条插入 Timeline 为 [Previous Context] user 消息
  4. load_messages_after_timestamp(after_ts) → 原始尾消息
  5. repair_tool_call_chains

无压缩标记 → 全量加载(现有行为)。

统一:seq_counter = MAX(seq) + 1

系统提示词

Session.last_compressed_message_at 非空时追加:

## 历史会话
之前的对话摘要已归档。如需回顾历史上下文,使用 `timeline_recall` 工具搜索。

改动清单

# 文件 改动
1 storage/session.rs SessionMetalast_compressed_message_at
2 storage/mod.rs DDL migration + upsert/get_session 加列
3 storage/mod.rs 新增 get_max_message_seq, load_messages_after_timestamp
4 storage/memory.rs 新增 load_session_timelines
5 agent/context_compressor.rs 返回值改为 CompressionResultcreated_timelines
6 session/session.rs Session 加字段,persist_session_meta 加字段
7 session/session.rs from_storage() 重写恢复逻辑
8 session/session.rs handle_message() 压缩后记录标记
9 session/session.rs /compact 命令压缩后记录标记
10 session/session.rs build_system_prompt() 注入 last_compressed_message_at