直接回答
多轮聊天至少有三类状态:应用所有的持久聊天历史、屏幕所有的瞬时 UI 状态,以及推理引擎所有的 runtime 对话或 session 状态。若把它们当成一个对象,就会出现隐蔽问题:旋转时创建了新对话,重试时同一用户轮次被追加两次,或者新聊天继承了上一条对话的上下文。LiteRT-LM 官方文档描述了围绕模型 runtime 的有状态对话抽象;Android 状态文档则区分界面保留与持久存储。应用必须明确所有权边界,不能把 runtime session 当数据库。 第一轮发送前就定义 conversation ID。应用可持久化对话标识、按顺序排列的用户可见消息、时间信息,以及 active、closed 或 archived 状态。Runtime 状态应按选定模型和提示策略从这些记录重建。不能持久化 native 指针或内部缓存来充当聊天历史。如果 runtime 有不能序列化的隐藏上下文,应说明新建 conversation 的含义,以及需要重新提供哪部分可见历史。重放策略必须针对正在使用的 runtime 版本测试。 把每轮当作事务处理。为 turn 分配标识,先记为 pending,并只追加一次已接受的用户消息。生成结果可能是部分、完整、拒绝或取消。只有到达声明的终态后才提交最终 assistant 消息。若流式生成期间界面重建,新屏幕应观察原 turn ID,不能再发送一次。若进程死亡,就恢复持久消息、标注未完成轮次,并在支持时重建 runtime 状态;还要告诉用户是否需要重试。不能把部分输出默默显示为已完成回答。 取消与重置是不同操作。取消某一轮会停止当前工作,但可能保留对话供下一轮继续;重置则有意清空或替换上下文。新对话要有新 ID 和干净 runtime 状态。若删除可见消息却保留旧 native session,隐藏上下文可能泄漏到后续答案。反过来,若界面销毁时关闭 engine,也可能终止仍由对话协调器负责的工作。要分别定义 engine、conversation 和每个 turn 的生命周期。 测试应让事件顺序一目了然。发送 user A、assistant A、user B,断言第二轮仍属于目标对话,并验证 reset 后上下文隔离。在流式生成中注入取消并旋转屏幕,确认 turn ID 不重复提交。启动两个 conversation ID 并让任务交错调度,证明消息不串联。Fake runtime 可验证应用层所有权和事件顺序;基于真实固定版本库的测试则验证该库支持的行为。Fake 不能证明模型质量。 恢复时只持久化必要数据。较长 transcript 可以放数据库;Bundle 和 saved-state 机制只承载小型 ID、光标或界面位置。历史删除策略与 runtime 清理分开治理。如果产品承诺本地处理,不应为了同步方便就新增远程聊天存储。排查状态泄漏时,也不要记录消息正文;只记录对话/轮次 ID、状态转换、模型修订和已去内容的错误类别。 仓库事实确认 LiteRT-LM runtime 路径及 Cove 显式生命周期管理,但不能证明某个应用已经正确实现多轮对话,也不能保证所有版本都有相同 API 行为。应引用所用精确版本的官方资料,并在项目制品上测试。报告对持久化、重建、重置及取消分别验证了什么;不要声称任意多轮 session 都能跨进程死亡。清楚的状态所有权能追踪失败并避免串聊,即使模型文本本身不确定。 迟到回调是很容易漏测的情况。旧 turn 被取消后,native callback 可能稍后返回;如果只按当前屏幕写入,它会污染新对话。回调必须携带 turn ID 和 conversation ID,协调器仅接受仍然有效的状态转换。完成、取消或关闭后,重复终态通知应幂等处理。用可控调度器测试“取消先发生、旧结果后到”的顺序,确保旧回答不会重新变成 active。 历史记录恢复与 runtime 重新创建也必须分开验证。用户可见历史存在,不代表内部 KV cache 或模型对话对象还存在。若 API 只支持重新提供初始消息,应将其作为新 session 构建步骤并说明;若无法恢复上下文,则明确开始新对话或由用户确认重试。不能根据一个界面显示完整消息就推断模型仍保留同样的上下文状态。 验收记录包含对话 ID、轮次 ID、应用构建、runtime 修订、终态及恢复方式。普通日志不包含真实对话。对于不能跨进程续跑的设计,诚实显示“上次生成未完成,可重新生成”,通常比伪造无缝续接更好。所有结论限定到实际测试的状态策略和库版本。
取消一条流式回答后用户立即打开新对话
第一条本地对话仍有流式回答待完成。用户取消它、打开新对话,之后屏幕在下一轮结束前发生重建。
决策
为新对话创建全新 ID 与 runtime 上下文;第一轮保持取消,禁止迟到回调写入新 transcript。
预期结果
消息仍属于正确对话,取消回答不被假装提交,runtime 清理遵循明确所有权。
需要收集的证据
只有将以下证据与同一模型文件和测试运行关联起来,结论才可复核:
- LITERTLM-01:项目事实卡记录 LiteRT-LM runtime 路径;具体多轮行为要以所用版本官方文档和测试为准。
- COVE-LIFECYCLE-01:当前 Cove 明确管理模型生命周期;不证明应用现有对话可跨进程恢复。
只有记录了模型身份、构建配置、实际后端、任务样例和失败情况,运行时比较才可复核。
实施流程
- 画出三类状态的所有者. 记录应用持久消息与对话 ID、屏幕控件和滚动状态、runtime conversation/session 资源;为每个状态转换指定唯一权威层。
- 定义对话 ID 和轮次事务. 为对话与每一轮分配唯一 ID。用户消息仅提交一次,部分模型输出单独保存,最终回答到达终态后才确认。
- 区分重置、取消、关闭和重试. 将取消一轮与重置整个会话分开。定义 engine 和 session 生命周期,以及重试如何取得新身份而不携带陈旧隐藏上下文。
- 测试顺序、重建与隔离. 重放已知轮次,取消流式生成并旋转屏幕,再交错执行两个对话 ID。断言没有重复提交、迟到回调或跨对话消息。
- 进程丢失后仅从持久状态恢复. 根据支持的历史消息重建 runtime,把未完成轮次标为中断并要求明确重试;不能序列化 native handle 或承诺任务静默继续。
让每个阶段的状态都可观察。失败信息应指出阶段、模型、运行时和恢复动作,同时避免记录用户私密内容。
验收标准
- 每个用户对话和轮次都有稳定 ID,屏幕重建不会重复提交。
- 取消、重置、关闭和重试状态彼此区分,新会话不继承隐藏上下文。
- 交错对话测试证明消息与迟到回调始终绑定正确的 conversation ID。
- 进程恢复只用受支持的持久数据,标注未完成轮次,不保存 native 指针。
决策对照表
| 维度 | 选择或证据 | 解读方式 |
|---|---|---|
| 应用聊天历史 | 持久化带 ID 的用户可见消息顺序 | 用于展示和受控重建,按应用保留政策治理。 |
| Runtime conversation/session | 当作可释放的执行上下文管理 | 可能持有内部状态,不能假设它是可移植持久数据库。 |
| 屏幕状态 | 保存少量 UI 状态并观察活动轮次 | 适合跨界面重建,但不应拥有 native engine。 |
需要避免的失败模式
- 把 runtime conversation 当作永久保存的聊天记录。
- 屏幕重建时再次发送同一轮,或创建新对话却残留上一会话隐藏上下文。
还要避免静默回退、版本未固定、缺少取消处理,以及把不同配置的结果混在一起下结论。失败运行也应与成功记录一并保存。
最小复现记录
| 层级 | 记录内容 |
|---|---|
| 设备 | 厂商、型号、芯片、内存档位、操作系统版本 |
| 软件 | 应用版本和 Git 提交号 |
| 模型 | 系列、变体、版本、格式、文件长度、摘要、量化方式 |
| 运行时 | 名称、版本、请求后端及实际后端证据 |
| 工作负载 | 样例版本、输入摘要、提示词摘要、输出策略 |
| 结果 | 完成、失败、取消、回退及保护隐私的诊断信息 |
发布检查表
- ☐ 主要搜索问题已回答,且没有未经支持的数字。
- ☐ 所有模型文件和运行时版本均已固定。
- ☐ 代表性任务和失败处理策略均有说明。
- ☐ 生命周期、取消、清理和回退均已测试。
- ☐ 用户内容与网络边界均有说明。
- ☐ 结论只适用于被记录的配置。
- ☐ 新增测试结果时链接到原始方法或证据。
来源与相关证据
中文部署与排错专题见。奇连 AI 端侧专题。
常见问题
runtime conversation 就是保存的聊天历史吗?
不是。应用要单独持久化用户可见消息。runtime 上下文是执行资源,可能需要重建或丢弃,并且不能作为聊天数据库导出或长期备份。
取消一条回答时要重置整个对话吗?
默认不必。应分别定义单轮取消和会话重置,并验证下一轮只使用预期上下文,也不会接收已取消轮次的迟到结果或覆盖新消息。
多轮 runtime session 能跨进程死亡吗?
不要假设可以。核对精确库版本能力;否则从持久消息重建,并把未完成生成标为中断,再由用户明确选择重试或开启新对话。