运行时与集成

本地 AI 会话超时与清理:空闲 TTL 不等于请求 deadline

分别管理空闲会话到期和单次请求期限,并核实取消确认、会话重建和资源观察。

审核状态: 内容已校验;中文稿供用户审核 · 2026-10-06 · Fact IDs: COVE-LIFECYCLE-01, MEMORY-03, LITERTLM-KOTLIN-CONVERSATION-SNAPSHOT-2026-10

直接回答

会话超时和请求 deadline 解决的是不同问题。空闲会话 TTL 决定一个 conversation owner 在有效活动结束后保留 native session 多久;单次请求 deadline 则限制已经开始的某一次推理等待多久。前者到期可能需要关闭或重建会话状态;后者到期会请求停止当前操作,并要求继续等待终态结果。把两者合成一个定时器,会让用户看到的行为和清理过程难以判断,尤其是新一轮请求刚好在到期边界开始时。 让每个定时器归属于真正拥有对应状态的层。会话协调器可以拥有空闲定时器,因为它能观察已接受的回合、用户关闭动作、应用生命周期变化和 session 身份。推理操作所有者可以设置单次 deadline,因为它知道 native 工作何时开始以及哪个终态回调属于该请求。屏幕只是显示 transcript,不应因此单独拥有会话寿命;UI Flow collector 取消也不能单独证明 native 工作已经停止。如果应用 wrapper 只暴露冷 Flow,在承诺“停止”之前必须先核验实际取消行为。 固定提交的 LiteRT-LM Kotlin Conversation 源码提供 cancelProcess。源码说明当前没有活动推理时该调用是 no-op,Conversation 已关闭时会抛异常。同一源码将 native cancellation status 1 映射为 CancellationException,并备注内部状态回滚仍是待实现请求。这些细节只适用于特定版本,不能证明项目实际解析的 Android 依赖包含该方法、应用层引擎接口暴露了它、取消后 conversation 可复用,或 KV/cache 内存已经释放。 应将取消建模为带确认的状态转换,而不是只让 UI 翻转一个布尔值。记录请求身份、取消原因、native 终态回调或异常,以及清理是否完成。如果 deadline 与正常完成竞态,要将最后事件关联到正确请求并只提交一次。cancelProcess 返回只说明取消调用已返回,不证明 native 推理到达终态。等待对应请求的终态回调或异常,并确认没有操作仍在执行;只有满足后,且会话所有者与解析 API 都允许,协调器才能执行受支持的关闭并重建流程。绝不能强制关闭仍在运行或清理中的 Conversation。用户取消、空闲 TTL 到期和请求 deadline 应保留为不同原因。 Kotlin coroutine timeout 会协作式地取消协程 block,不会自动终止任意 native 或阻塞操作。因此 timeout wrapper 只是策略中的一个信号。应用必须在 runtime API 可用时显式传播取消,持续观察任务完成,并阻止替代请求抢占仍在运行或清理中的 session。如果已解析运行时没有取消方法,应保持“正在停止”,直到对应终态回调到达。只有请求终态已确认、没有 in-flight 工作且会话所有者确认解析 API 支持后,才可执行关闭并重建路径。不能用 close 强行停止活动,也不能因计时器触发就承诺资源立即释放。 为各类终态明确定义可否复用。正常完成后,如果 API 和应用状态允许,同一 conversation 也许可以继续下一轮。取消、deadline 或 native 异常后,先等待对应请求终态并确认没有 in-flight 操作,再由所有者决定是否复用,或在支持时关闭并重建。空闲到期后的重建只能按产品的历史回放策略恢复应用所有的状态,不能假设 native 隐藏状态可序列化。本仓库的 app-facing AiInferenceEngine 接口只暴露 Flow 推理方法,没有 cancel 或 close 方法;具体 InferenceEngine 则有自己的 close 路径。不要暗示当前 ViewModel 可以通过该接口调用 native session API。 内存清理必须与控制流分开测量。conversation 已关闭或取消回调已完成,都不证明所有 native 分配或 KV cache 已归还操作系统。若确实关心资源释放,应在命名明确的构建、制品、运行时和设备上重复固定负载,并在清理及后续任务后观察可用内存诊断。仓库事实支持用 Android Studio Memory Profiler 观察行为,不提供通用 session TTL、内存阈值或保证释放结果。有原始观察记录后再描述方法与结果。 可靠策略应明确哪种活动会重置空闲计时器、活动请求期间是否暂停计时、关闭和应用后台状态如何交互、停止时用户看到什么,以及哪些终态允许复用。使用单调时钟计算经过时间,而非墙上时钟;给 session 加代号,防止旧定时器关闭新会话;所有权结束后取消该 timer。transcript 留存策略应独立于 native session 清理。测试应覆盖计时竞态、活动中到期、用户关闭、request timeout、取消确认、重建和内存观察,但不能把没有依据的默认秒数写进产品建议。

请求 deadline 较短,而空闲会话 TTL 仍在计时

聊天界面启动了一次耗时的本地回答。产品另希望在一段时间没有新用户回合后释放闲置的 native Conversation。请求可能正常完成、被用户取消、超过自己的期限,或在 idle timer 到期时仍未清理完毕。生命周期所有者必须阻止旧 timer 关闭新会话。

决策

用两个独立状态机分别表达会话和请求,为每个定时器绑定 session/request 代号;收到 native 终态后,再决定原 Conversation 是否允许复用。

预期结果

UI 能区分空闲到期、请求取消和 deadline 超时。只有确切解析 API 和版本化测试支持时才复用;否则重建会话,并将清理状态标为已观察或未知。

需要收集的证据

只有将以下证据与同一模型文件和测试运行关联起来,结论才可复核:

  • COVE-LIFECYCLE-01:当前 ModelManager 串行化模型加载并暴露明确生命周期状态。
  • MEMORY-03:应使用精确制品和目标设备的内存诊断记录实际行为,不从生命周期动作推断释放结果。

只有记录了模型身份、构建配置、实际后端、任务样例和失败情况,运行时比较才可复核。

实施流程

  1. 独立命名会话与请求寿命. 分别定义空闲、请求运行、停止中、已完成、已到期、已关闭和重建状态。空闲过期由会话协调器拥有;单次 deadline 由该请求的实际所有者管理。
  2. 核验解析运行时和 wrapper 契约. 记录 Gradle 实际解析的组件,并检查可用 Conversation 方法及应用适配层。不能从上游 commit 推断运行时有 cancel 或 close 方法,也不能假定取消 Flow 收集会传到 native 推理。
  3. 定义终态与复用决定. 将正常完成、用户取消、deadline、native 错误、空闲到期和 close 映射到不同结果。cancelProcess 返回只说明调用已返回;必须收到对应请求的终态回调或异常并确认无操作仍在执行,之后才可考虑复用或由所有者按解析 API 支持的流程关闭并重建。不得强制关闭活动 Conversation。
  4. 让定时竞态具备代号保护. 使用计算经过时间的时钟和 session generation ID。规定哪些已接受活动重置空闲时间、活动推理期间是否暂停到期,并确保旧定时器不会关闭替换后的 Conversation。
  5. 分开记录控制确认和内存证据. 取消原因和终态与内存观察分别记录。如果资源释放是要求,用准确制品、运行时、构建和设备执行可复现负载并观察前后变化,不把 close 或回调完成当成 cache 已释放的证明。
  6. 覆盖生命周期与 timeout 边界. 测试无活动请求时到期、活动中到期、deadline 与正常完成竞态、用户取消、已关闭 session 上的取消、重试、应用后台化和会话重建。确认 transcript 留存独立于 native session 清理。

让每个阶段的状态都可观察。失败信息应指出阶段、模型、运行时和恢复动作,同时避免记录用户私密内容。

验收标准

  • 空闲 session 到期和单次请求 deadline 有独立所有者、重置条件、原因和用户可见状态。
  • 上一个请求未到达匹配终态且仍有 in-flight 工作时,不能复用或关闭/重建 Conversation;是否复用或关闭须由会话所有者按解析版本支持情况决定。
  • 取消确认与内存释放作为不同证据报告,不宣称通用 TTL、native 立即停止或 KV cache 必然释放。

决策对照表

维度选择或证据解读方式
空闲会话 TTL会话所有者观察不到已接受活动后过期 conversation控制会话状态保留多久;不限制正在运行的单次推理时长。
单次请求 deadline限制一个活动任务并在到期时请求取消限制调用方等待时间;native 是否终止仍需运行时配合和终态确认。
内存回收观察在明确清理流程后测量进程和 native 内存只报告某次具名运行观察到的资源变化;TTL 或关闭句柄不保证模型缓存全被归还。

需要避免的失败模式

  • 把协程 deadline 当成 native 推理已停止的证明
  • 取消后未经版本验证就复用 Conversation
  • 将关闭句柄等同于 KV/cache 内存已归还

还要避免静默回退、版本未固定、缺少取消处理,以及把不同配置的结果混在一起下结论。失败运行也应与成功记录一并保存。

最小复现记录

层级记录内容
设备厂商、型号、芯片、内存档位、操作系统版本
软件应用版本和 Git 提交号
模型系列、变体、版本、格式、文件长度、摘要、量化方式
运行时名称、版本、请求后端及实际后端证据
工作负载样例版本、输入摘要、提示词摘要、输出策略
结果完成、失败、取消、回退及保护隐私的诊断信息

发布检查表

  • ☐ 主要搜索问题已回答,且没有未经支持的数字。
  • ☐ 所有模型文件和运行时版本均已固定。
  • ☐ 代表性任务和失败处理策略均有说明。
  • ☐ 生命周期、取消、清理和回退均已测试。
  • ☐ 用户内容与网络边界均有说明。
  • ☐ 结论只适用于被记录的配置。
  • ☐ 新增测试结果时链接到原始方法或证据。

来源与相关证据

中文部署与排错专题见。奇连 AI 端侧专题。

常见问题

Kotlin withTimeout 到期时会停止 native 推理吗?

不会自动停止。协程取消是协作式的;native 或阻塞调用必须观察取消桥接,或自行到达终态回调,应用才能说明工作已经停止。

cancelProcess 返回是否代表 LiteRT-LM 推理已经停止?

不代表。应把方法返回视为取消调用结果,而非终态确认。等待对应请求的回调或异常并确认没有操作仍在执行后,再决定所有者是否可以复用,或关闭并重建 Conversation。

关闭 Conversation 能证明 KV cache 已释放吗?

不能。这是生命周期操作,不是内存测量结果。需要在准确构建、制品、运行时和设备上重复工作负载,再观察内存变化。