36 lines
2.8 KiB
Markdown
36 lines
2.8 KiB
Markdown
---
|
||
name: conversation_model_persistence
|
||
description: 当加载/恢复对话时发现模型未恢复、新建对话后旧对话模型被覆盖、或修改 /api/model、_apply_workspace_personalization_preferences 时,应该索引本记忆
|
||
---
|
||
|
||
---
|
||
name: conversation_model_persistence
|
||
description: 当加载/恢复对话时发现模型未恢复、新建对话后旧对话模型被覆盖、或修改 /api/model、_apply_workspace_personalization_preferences 时,应该索引本记忆
|
||
---
|
||
|
||
# 对话模型持久化约定(对话级隔离架构版)
|
||
|
||
## 核心规则
|
||
|
||
- 每个对话的 `model_key` 保存在对话文件的 `metadata.model_key`。
|
||
- **对话级 terminal(`_bound_conversation_id` 非空)的模型由绑定加载权威恢复**(`WebTerminal._ensure_conversation` 用 `restore_model=True`),其它任何逻辑不得覆盖它。
|
||
- **工作区级 terminal(未绑定)刻意 `restore_model=False`** 自动加载最近对话:避免 /new 页面显示旧对话模型。
|
||
|
||
## 四条关键防线(2026-07-20 修复,commit 1289c31d)
|
||
|
||
1. **`core/web_terminal.py::_ensure_conversation`**:绑定路径 `load_conversation(bound_id, restore_model=True)`。工作区自动加载路径保持 `restore_model=False`。
|
||
2. **`server/chat/settings.py::/api/model`**:仅当请求显式携带 `conversation_id` 且与 terminal `current_conversation_id` 一致时才 `save_conversation`;无 cid(/new 页面)不持久化——工作区级 terminal 的 current 可能是陈旧对话,盲存会把模型写错对话或用陈旧 history 覆盖新消息。
|
||
3. **前端 `static/src/app/methods/ui/model.ts::handleModelSelect`**:POST /api/model 必须带 `conversation_id: this.currentConversationId`。
|
||
4. **`server/context.py::_apply_workspace_personalization_preferences`**:对 `_bound_conversation_id` 非空的 terminal 跳过 session 模型恢复与 default_model 应用——否则 session 里的全局模型会把对话级 terminal 恢复好的模型再盖掉(重启后回变默认的直接元凶)。
|
||
|
||
## 会话级语义
|
||
|
||
- `session["model_key"]` 是全局"用户最后选择的模型":用于工作区级 terminal 恢复与 /new 继承,**不代表任何具体对话的模型**。
|
||
- 任务创建时前端随任务传 `model_key`(`send.ts`),`server/tasks/models.py` 在任务起点 `terminal.set_model(rec.model_key)`——前端是任务模型的权威来源。
|
||
- `set_model()` 可能因图片/视频不兼容或模型被禁用抛异常,加载场景应捕获降级。
|
||
- 管理员强制禁用模型的切换(context.py 406/549 行附近)对对话级 terminal 仍然生效,属正当覆盖。
|
||
|
||
## 验证脚本
|
||
|
||
- `_experiments/verify_model_fix.py`:p1 全周期(带cid切换→落盘、不带cid不污染)、p2 重启后保持;另需验证 `GET /api/status?conversation_id=X` 返回对话保存模型。
|