直接回答
把断电恢复视为持久任务记录、文件系统状态和远端模型表示之间的核对问题,而不是默认续传。设备重启后,应先读取持久化的模型身份与下载阶段,再检查磁盘上的真实临时文件,并在继续追加字节或切换文件之前验证服务器响应。只有当 Range 响应证明它从本地已接受的准确偏移开始,并且仍指向同一模型表示时,才可以续传。如果模型身份、偏移、验证器或关键元数据无法确认,就应隔离这个候选文件或从头安全下载。全过程都要保留已知可用的活动模型,并避免影响与模型无关的用户数据。 断电与普通进程退出并不相同。进程死亡发生时,操作系统仍在运行;突然断电则会让内存中的工作停止,而且可能正好发生在文件写入与下一次持久状态更新之间。任务数据库中的一行记录和磁盘上的临时文件都不能单独代表全部事实。Android 的持久后台任务可以在满足条件时重新安排工作,但持久调度并不会自动把任意文件操作变成事务,也不能证明哪些字节已可靠落盘。应用必须明确自己的检查点次序和恢复政策。 当前项目下载器会写临时路径、追踪进度、使用 HTTP Range 请求续传,并在下载后尝试提升最终文件。这些项目事实适合用来设计恢复测试,但不能证明每一次中断后的写入都已持久保存,也不能证明模型配置总有可信密码学摘要。当前事实卡指出配置中的 SHA-256 字段为空。因此恢复流程不能把长度相同、服务器返回成功、文件名匹配或重命名成功说成摘要完整性验证。如果缺少可信的期望摘要,就要明确说明该信任限制,只描述实际可用的检查,不要暗示比实现更强的来源或完整性证明。 部分文件需要绑定不可变的工件身份。身份至少应区分模型或资源包名称、固定版本或清单版本、已知的预期长度、期望摘要及其来源(若有),以及下载源身份。model.tmp 这样的临时文件名并不能证明它属于某个版本。应用可以持久化“已确认写入到哪里”,但重启后仍要独立读取临时文件实际长度。如果文件比记录短,就按规则退回到更早偏移或从头开始;如果实际文件更长,也不能假定多出的尾部正确,因为断电可能发生在一次不完整写入或状态提交之前。日志中可保留阶段和字节数用于诊断,但不能记录授权头、带令牌网址、提示词或用户内容。 续传前应向服务器请求本地已接受偏移之后的字节,并严格检查响应。部分响应必须恰好从该偏移开始;必须能通过强验证器或等效的固定工件身份证明仍是同一表示;Content-Range 的总长度还要与已知期望长度一致。服务器可能忽略 Range 并返回完整文件;客户端要识别这一情况,不能把完整响应附加到已有部分文件后面。如果版本已经变化、范围不匹配、返回 HTML 错误页或总长度不明,应拒绝本次追加或创建全新的候选文件。RFC 定义了范围请求语义,但具体客户端仍须主动执行这些校验。 应把写入流程设计成可观察的状态机:所有新字节先写入候选文件,而不是活动模型;持久化状态转换只有在对应文件操作达到应用依赖的持久级别后才能提交。慎重使用平台文件 API,并在支持的文件系统上验证真实次序。恢复时,将 worker 状态与文件长度和模型身份对齐,校验远端范围头,只追加可接受内容,再执行配置要求的完整性检查。只有全部检查通过后才提升候选文件。如果提升使用重命名,还要确认候选与目标文件位于所需的同一存储位置;不要假定跨卷移动具备原子性。 不要把所有错误都强行变成自动重试。身份匹配的有效部分文件可以继续;临时文件不存在时可以从零开始;表示已改变时应隔离或删除仅属于模型下载的数据,然后建立新候选;服务器违背范围规则时应停止并给出可诊断错误。如果可信期望摘要存在,应对完整文件执行核验;不存在时就不能声称完成了摘要校验。恢复期间旧模型应继续可用,直到新候选完成规则要求的检查并能被运行时加载。加载失败也应有明确修复或回退路径。
设备在模型传输期间断电
设备重启后,任务记录中的偏移可能与临时文件真实长度不一致,远端服务也可能已提供不同表示。
决策
先核对持久记录、磁盘文件、固定模型身份和 HTTP Range 响应,确认安全后才续传或提升候选文件。
预期结果
可以证明一致的部分内容才续传;有矛盾时隔离或重下,并始终保留原活动模型和用户数据。
需要收集的证据
只有将以下证据与同一模型文件和测试运行关联起来,结论才可复核:
- 事实卡 ANDROID-BG-01、COVE-DOWNLOAD-01 与 COVE-MODEL-02;ModelDownloader 使用临时文件及 HTTP Range,并且当前摘要字段为空。
- Android 持久后台工作、FileDescriptor.sync 与 RFC 9110 Range 请求规范。
收到完整字节流还不够;最终落盘、完整性、运行时加载和恢复路径也必须验证。
实施流程
- 定义检查点. 持久化模型身份、状态结构版本、下载源、已知长度和摘要来源、临时路径、确认偏移、响应验证器与阶段。不要把进程中的句柄或任务记录单独当作落盘证明。
- 重启后核对磁盘. 检查候选文件实际路径、字节长度与当前记录比较。元数据缺失、实际长度矛盾或文件包含尚未提交的额外字节时,应将状态列为不确定而非自动完成。
- 验证远端续传响应. 从已接受偏移发起 Range 请求,核验响应状态、准确起点、总长度、表示验证器和内容类型。服务器忽略范围或模型版本改变时,不得追加到旧字节。
- 仅对候选文件继续. 旧模型保持活动状态,接受的新字节写入独立候选;明确规定写入和检查点顺序,并让低存储、取消和断网都留下可恢复或可重下状态。
- 完成检查再提升. 比较已知完整长度和可信期望摘要,再实际检查运行时加载。摘要缺失时说明信任边界;不能把长度匹配或重命名称为哈希验证。
- 注入断电位置. 覆盖排队前后、文件写入前后、同步与状态提交之间、最后字节后、校验时及提升时的重启,逐一比较预期状态和真实磁盘结果。
让每个阶段的状态都可观察。失败信息应指出阶段、模型、运行时和恢复动作,同时避免记录用户私密内容。
验收标准
- 只有偏移、工件身份与表示元数据均匹配,程序才会向部分文件追加字节。
- 任务记录显示完成或文件名正确均不能单独将模型标为已校验或就绪。
- 身份不明的候选不能替换活动模型;清理行为不会触及用户内容。
- 没有可信期望摘要时,界面和日志都不声称完成密码学哈希验证。
决策对照表
| 维度 | 选择或证据 | 解读方式 |
|---|---|---|
| 继续部分字节 | 本地身份与远端范围响应确证同一表示时。 | 需要逐项验证偏移、总长度和工件身份后才能追加。 |
| 重新下载新候选 | 部分状态缺失、陈旧或互相矛盾时。 | 会增加网络与存储开销,但可保留当前工作模型。 |
| 隔离等待修复 | 文件可能有诊断价值却无法证明可信时。 | 隔离不等于验证,推理运行时不应打开候选文件。 |
需要避免的失败模式
- WorkManager 持久调度不等于应用文件写入具有事务性或断电持久性。
- 文件长度、文件名、成功重命名都不等于可信摘要校验;缺少期望摘要时不得声称已做哈希验证。
还要避免静默回退、版本未固定、缺少取消处理,以及把不同配置的结果混在一起下结论。失败运行也应与成功记录一并保存。
最小复现记录
| 层级 | 记录内容 |
|---|---|
| 设备 | 厂商、型号、芯片、内存档位、操作系统版本 |
| 软件 | 应用版本和 Git 提交号 |
| 模型 | 系列、变体、版本、格式、文件长度、摘要、量化方式 |
| 运行时 | 名称、版本、请求后端及实际后端证据 |
| 工作负载 | 样例版本、输入摘要、提示词摘要、输出策略 |
| 结果 | 完成、失败、取消、回退及保护隐私的诊断信息 |
发布检查表
- ☐ 主要搜索问题已回答,且没有未经支持的数字。
- ☐ 所有模型文件和运行时版本均已固定。
- ☐ 代表性任务和失败处理策略均有说明。
- ☐ 生命周期、取消、清理和回退均已测试。
- ☐ 用户内容与网络边界均有说明。
- ☐ 结论只适用于被记录的配置。
- ☐ 新增测试结果时链接到原始方法或证据。
来源与相关证据
中文部署与排错专题见。奇连 AI 端侧专题。
常见问题
WorkManager 能保证断电后模型文件完整吗?
不能。持久调度不等于应用文件写入原子且持久。重启后必须核对数据库、真实文件和远端表示,并实测检查点的写入顺序。
文件长度一致能证明部分模型字节正确吗?
不能。长度只能发现部分截断,无法证明字节属于正确版本或真实来源。还要核对固定身份和 Range 元数据;有可信摘要时再执行摘要比对。
恢复应直接使用上次保存的偏移吗?
不应直接假定。断电可能让数据库和磁盘不同步;先检查实际长度,再核对服务器范围起点和表示身份。无法协调时应隔离或重新下载。