并行上下文管理
将单个对话拆分为 N 个并行上下文,每个上下文独立维护自己的消息历史。非活跃上下文从内存卸载(切换时懒加载),持久化到磁盘。
为什么需要多上下文?
单个对话线性增长——每次工具调用、每次响应都增加 token。上下文会变得嘈杂。多上下文提供:
- 分离:不同任务相互隔离
- 聚焦:每个上下文拥有干净、相关的历史
- 高效:不浪费 token 在无关消息上
- 可恢复:淘汰的上下文被归档到磁盘,不会丢失
上下文管理
创建上下文
/context new 前端设计
/context new 后端API
/context new bug调查
每个上下文拥有独立名称和消息历史。达到上限(max_contexts,默认 5)时自动淘汰最不活跃的上下文。
切换上下文
/context → 打开上下文切换弹框
/context 2 → 切换到上下文 #2
TUI 模式下 /context 无参数打开可视化弹框面板。使用 ↑↓ 导航,Enter 切换,Del 淘汰。按 Esc 关闭。
重命名和删除
/context rename "UI重构" → 重命名当前上下文
/context del 3 → 淘汰上下文 #3
LRU 淘汰
新建上下文且槽位已满时,niuma_code 按三级优先级选择淘汰候选:
- 空上下文 — 消息数为 0 的空壳最先淘汰(价值最低)
- 未命名上下文 — 仅有自动生成摘要、未被用户显式命名的上下文次之
- 最久未使用 — 剩余候选中
last_active_ts最小者被淘汰
当前激活上下文受保护,永远不会被淘汰。
| 状态 | 说明 |
|---|---|
| 激活 | 在内存中,完整历史可用 |
| 非活跃 | 从内存卸载,元数据在清单中,消息在磁盘 |
淘汰是透明的——被淘汰上下文的消息文件({sid}.json)保留在磁盘上,切换回去时可按需恢复。
上下文摘要
切换上下文时,niuma_code 自动从最后一条用户消息(前 20 字)截取作为上下文的显示标签。这是纯内存截断——无 LLM 调用,零延迟。
从 "后端API" 切换到 "前端设计"
→ 摘要已捕获:"修复认证中间件..."
→ 已切换到 前端设计
如果通过 /context new <名称> 或 /context rename <名称> 显式命名了上下文,名称会被固定(pinned),不会被自动摘要覆盖。
/messages 命令
/messages 打开可视化弹框,管理当前上下文的对话历史:
| 操作 | 快捷键 |
|---|---|
| 导航 | ↑↓ |
| 多选 | Space |
| 删除选中 | Delete 或 d |
| 移位 | Alt+↑ / Alt+↓ |
| 合并选中 | m(LLM 分别摘要 user/assistant 两侧) |
| 清空 recall 注入 | c(二次确认) |
| 保存修改 | Ctrl+S |
| 关闭 | Esc |
消息按「对话单元」组织(每个单元从一条 user 消息开始,包含其后所有 assistant 响应直到下一条 user 消息)。编辑操作为预览模式,按 Ctrl+S 后才持久化。
配置
在 settings.json 的 llm 节中配置:
{
"llm": {
"max_contexts": 5,
"resume_latest_context": false
}
}
| 设置 | 默认值 | 说明 |
|---|---|---|
max_contexts |
5 |
活动上下文最大数量,超出后 LRU 淘汰 |
resume_latest_context |
false |
true:重启恢复上次 active 上下文;false:每次进入空上下文(旧对话保留,可 /context 切回) |
持久化
上下文数据存储在 .session/ 目录:
contexts.json— 活跃上下文元数据清单(seq、sid、summary、时间戳){sid}.json— 每个上下文的消息历史
启动时仅加载 active 上下文的消息到内存,其他上下文在切换时懒加载。
工作流示例
/context new API重构
# 进行 API 重构...
/context new 修复bug
# 调查并修复 bug...
/context 1
# 回到 API 重构——上下文完整保留
/context new 编写测试
# 写测试——独立上下文保持整洁
每个上下文维护:
- 独立的消息历史
- 独立的持久化文件(
{sid}.json) - 独立的摘要(自动截取或用户命名)
- 独立的懒加载生命周期