# 消息级溯源 P2 切读方案 > 决策:2026-06-28 — 一次性切读 + 脚本迁移历史数据 ## 现状 - `ai_messages` 表 ✅ 已存在(V21 迁移) - `AiMessageRepo` ✅ CRUD 已实现 - V21 已有一次性数据迁移(从 `ai_conversations.messages` JSON 读 → 写入 `ai_messages`) - **但当前读写路径仍走 `ai_conversations.messages` JSON 列**,`ai_messages` 表未启用 ## 目标 读/写消息完全切换到 `ai_messages` 表,删除 `ai_conversations.messages` JSON 列。 ## 涉及改动 ### 1. 数据迁移(已有 V21,补充幂等脚本) V21 迁移已有从 `ai_conversations.messages` → `ai_messages` 的逻辑。补充: - V21 已幂等(`INSERT OR IGNORE`),可重复跑 - 补充校验:迁移后 `ai_messages` 行数 = 各对话 messages JSON 汇总行数 ### 2. 切读 — 后端代码 | 模块 | 当前 | 改为 | |------|------|------| | `restore_from_messages` | 从 `rec.messages` JSON 反序列化 | 从 `ai_messages` 表按 `conversation_id` 查询 + seq 排序 | | `save_conversation` | 写 `rec.messages` JSON 列 | 写 `ai_messages` 表(insert_batch + delete_range) | | `ai_conversation_switch` | 返回 `rec.messages`(JSON 反序列化) | 返回 `AiMessageRepo.list_by_conversation()` | | `clear_context` | 读/写 messages JSON | 读写 ai_messages 表 | | `compress_context` | 同上 | 同上 | | `replace_last_active_user_content` | 同上 | 同上 | | messages 相关 IPC 查询 | 走 JSON 列 | 走 ai_messages 表 | ### 3. 清理 - `ai_conversations.messages` 列标记废弃(暂不删列,避免大表 ALTER 风险) - 后续 V22 可选删除该列 ### 4. 风险控制 - **双写保护**:切读后写入同时写 ai_messages 表 + messages JSON 列(双写期 1 周,可回退) - **回退方案**:撤切读 → 恢复从 messages JSON 列读 ## 执行顺序 1. 实现切读:改 `restore_from_messages` / `save_conversation` / `switch_conversation` 等核心路径 2. 运行 V21 迁移(幂等,补全遗留数据) 3. 双写期观察(ai_messages 数据一致) 4. 切读完成,标记 messages 列废弃