先看结论与判断条件

  • 本地推理与云端调用是不同数据流,原先允许设备内处理的数据不自动获得网络上传授权。
  • 只有 allowlisted 的本地失败原因可以进入 fallback 评估,输出超差、数据受限或授权缺失不能被包装成普通不可用。
  • 上传清单按字段分类和最小化生成,原始媒体、检索文档、诊断日志与用户问题分别判断,不发送整个本地上下文。
  • 云端令牌要限制 issuer、audience、scope、主体和有效期;发送者约束降低重放风险,但不替代服务端业务授权。
  • 用户选择必须与当前数据类别、云服务目的和会话 generation 绑定,旧同意或另一账号选择不得复用。
  • fallback 前后使用同一输出 schema 与业务终态,云端结果也要经过内容、权限、缓存和页面生命周期校验。

本地与云端是两条独立数据路径

端侧推理通常让输入停留在设备内,云端推理则需要通过网络把字段发送给外部服务。两条路径的接收方、处理位置、保留策略、第三方参与和网络风险不同。产品即使承诺“优先本地”,也不能在本地失败时默认上传,因为用户对本地功能的使用不等于同意云端处理。

架构图要为 localPath 和 cloudPath 分别列出 dataCategories、processors、purpose、retentionClass、authRequirement 和 outputPolicy。fallback 是从一条路径切换到另一条路径的安全决策,不是异常捕获中的备用函数调用。决策通过前,不创建网络请求、不获取云令牌,也不把本地上下文序列化到待发队列。

本地路径也可能使用硬件 delegate 或 CPU 回退,但它们仍在设备内数据域。delegate 不可用时优先尝试经验证的本地 CPU 路径;只有本地能力确实不可满足且业务允许云端时,才进入云 fallback。初始化成功不证明本地结果正确,输出一致性失败应按策略拒绝,而不是自动把敏感输入上传。

本地与云端数据路径的区别
边界项本地推理云端推理fallback 要求
处理位置设备内运行时远端服务重新授权
数据传输通常不上传输入通过网络发送字段最小化清单
身份令牌可能不需要云 token需要受众与 scope重新获取或验证
保留策略本地缓存规则服务端与第三方规则显示目的和期限
失败终态本地降级或不可用网络、授权与服务错误不得静默切换

先判断本地失败是否允许进入 fallback

本地失败原因要使用稳定枚举,如 delegate_unavailable、model_not_supported、resource_pressure、model_integrity_failed、output_validation_failed 和 user_cancelled。只有产品与安全团队批准的 allowlist 可以进入云评估。模型完整性失败、输出验证失败和用户取消通常不应被改写成网络请求,因为它们可能代表候选异常或明确停止。

失败事件绑定 candidateId、modelBundleId、deviceProfile、generation 和 localTerminal。日志文字不参与分支,避免某个 SDK 改文案后错误启用云端。连续失败还要受重试预算和熔断控制,不能在本地、云端之间循环;同一 requestId 最多有一个 active path,旧路径迟到结果按 generation 拒绝。

云端不可达、授权拒绝或用户拒绝上传时,终态回到 cloud_not_authorized、cloud_unavailable 或 local_only_failed。UI 明确告诉用户当前功能没有完成,不伪装成空答案。若业务允许稍后重试,队列只保存授权范围内的最小字段和过期时间,不保存完整本地模型上下文。

本地失败原因的 fallback 决策
localReason是否进入评估下一步禁止行为
delegate_unavailable是先验证 CPU 路径直接上传
model_not_supported按业务策略提示或云评估伪装硬件成功
resource_pressure按当前授权释放资源或云评估无限循环
model_integrity_failed否阻止候选并诊断发送同一模型上下文
output_validation_failed通常否保持失败并核查用云结果掩盖本地错误
user_cancelled否终止请求后台继续上传

上传字段按类别、目的和最小化重新生成

fallback 决策读取 dataInventory,而不是复用本地模型输入对象。用户问题、图片、音频、检索片段、设备诊断、账号标识和模型中间状态分别分类。云端完成任务需要哪些字段,就从 allowlist 构造新的 payload;不需要的 EXIF、路径、日志、缓存键和本地标签全部排除。

高敏字段可能禁止云端处理,或要求当次明确选择。用户选择记录 consentId、accountId、dataCategories、purpose、cloudProviderId、policyVersion、generation 和 expiresAt。换账号、用途、云服务或字段集合后重新确认,不能用“用户曾开启智能功能”覆盖所有未来上传。撤销后新请求立即拒绝,队列中的未发送 payload 失效。

数据最小化还要覆盖上下文历史和 RAG。云模型通常不需要整个聊天数据库,只需要当前请求、保留策略和有限引用;检索片段先核对来源权限是否允许离开设备。若删除关键证据后无法回答,终态是 insufficient_authorized_data,不应为追求答案完整度扩大上传。

云 payload 字段分类门禁
字段类别默认动作允许条件回执
当前用户问题按目的最小化明确云任务需要字段摘要
原始媒体默认拒绝当次选择与必要性类别和大小
RAG 片段默认设备内来源允许云处理citationId
账号标识使用最小主体服务端授权需要subject 类别
设备诊断不随任务上传独立诊断选择diagnosticPolicy
本地日志与路径拒绝无拒绝原因

令牌 audience、scope 与发送者约束分别检查

云请求使用的 access token 必须面向目标资源服务器,audience 与 cloudProviderId 匹配,scope 只包含当前推理动作所需能力,subject 与当前账号一致,并检查 issuer、时间与撤销状态。不能把登录令牌、另一个 API 的 token 或长期通用 token 直接附加到 AI 请求。

OAuth 安全部署还要防止令牌重放、授权码注入、不安全重定向和旧式 grant。移动端只持有完成业务所需的短期凭据,服务端重新执行数据与动作授权,不因为 token 语法有效就接受全部字段。令牌错误与数据政策拒绝分开返回,避免客户端不断刷新 token 绕过政策失败。

DPoP 一类发送者约束可以把 token 与客户端持有的密钥关联,降低被盗令牌在其他发送者处重放的风险。它不证明设备可信,不确认用户同意,也不替代 audience、scope、短有效期与服务端授权。decision receipt 分别记录 senderConstraintRequired、proofPresent 和 proofValidated,不能用一个 attested 布尔值代替全部条件。

云端授权的独立检查项
检查项要回答的问题失败终态不能替代
issuer谁签发 tokentoken_invalid业务授权
audience发给哪个资源服务器wrong_audience用户选择
scope允许什么动作scope_insufficient字段最小化
subject代表哪个账号subject_mismatch当前会话代际
expiry是否仍在时限内token_expired撤销检查
sender proof是否绑定发送者proof_required设备可信与同意

用户可见选择与会话 generation 同步

fallback 提示要发生在上传之前,说明本地处理失败、计划使用云端、发送的数据类别和可选动作。用户选择 local_only、allow_once 或 allow_policy_scope,应用把选择绑定当前 requestId 与 generation。页面销毁、切换账号或新请求开始后,旧选择不能被迟到回调复用。

选择界面不是唯一控制。服务端收到请求后仍核对 consentId、主体、数据类别、purpose 和过期时间,避免被修改客户端绕过。客户端只发送 consent reference,不把 UI 文案当作授权证明。若服务端政策版本更新导致选择无效,返回 consent_refresh_required,由新页面重新呈现。

流式云响应也绑定 generation。用户取消或撤销同意后,客户端停止读取、标记终态并拒绝后续片段写入缓存与 UI;服务端按能力取消或停止后续处理。不能仅隐藏加载动画,后台仍继续发送下一批上下文或把迟到答案写回新会话。

输出、缓存和商店声明都要反映真实路径

云端与本地可能使用不同模型,但面向 App 的 output schema 和 policyVersion 应一致,或通过显式版本适配器转换。云结果同样执行内容类型、引用、工具候选和敏感字段校验;不能因为来自服务端就直接渲染或执行。localResult 和 cloudResult 的缓存键包含 path、modelBundleId、accountId 与 generation。

隐私与 Data safety 声明要覆盖应用和第三方 SDK 实际收集、共享的数据。若产品新增云 fallback,数据清单、用户说明、服务提供方和保留政策需要同步评审。商店声明是透明度要求,不会自动执行技术隔离;payload allowlist、服务端授权、日志脱敏与撤销清理仍要单独实现。

发布证据保存 localReason、fallbackDecision、payloadCategories、consent reference、token 约束、服务端授权、outputValidation 和 finalTerminal。原始 token、证明材料和用户数据不进入普通报告。安全开发记录还要绑定构建、配置、第三方服务和变更审查,使一次云路径启用能够被复核。

fallback 回执的最小证据链
阶段关键字段成功条件失败终态
本地执行reason、candidate、generationallowlisted reasonlocal_blocked
数据决策categories、purpose全部允许且最小化data_not_authorized
用户选择consentId、account、expiry当前请求有效consent_required
令牌检查aud、scope、subject、proof全部匹配token_rejected
云处理provider、schemaVersion服务端授权通过cloud_rejected
输出交付validation、generation当前会话且合格output_blocked

用 fallback 决策门禁检查数据与授权条件

决策文件可以只包含枚举和摘要:localReason、allowedReasons、requestedCategories、allowedCategories、consent、tokenClaims、expectedAudience、requiredScopes、senderProof 和 generation。检查器不发送网络请求、不存真实 token,也不包含用户内容,只验证切换前的确定性条件。

下面的 Python 代码从命令行读取决策。输入缺失时直接非零退出;随后拒绝不允许的本地原因、越界数据类别、同意代际或用途不匹配、audience 错误、scope 缺失和发送者证明未验证。所有条件通过只返回 eligible,实际服务端仍需重复授权。

项目实现还要校验 issuer、subject、时限、撤销与 payload schema,并将服务端结果绑定同一 decisionId。静态门禁通过不能证明 token 安全、设备可信或云端已合规处理,只证明这份脱敏决策记录没有明显缺项。

本地转云 fallback 决策校验器
import json
import sys
from pathlib import Path

def stop(message):
    print(f"cloud fallback rejected: {message}", file=sys.stderr)
    raise SystemExit(2)

def load_decision(path_text):
    path = Path(path_text)
    if not path.is_file():
        print("cloud fallback rejected: decision file is missing", file=sys.stderr)
        raise SystemExit(2)
    try:
        return json.loads(path.read_text(encoding="utf-8"))
    except (OSError, json.JSONDecodeError) as exc:
        stop(f"cannot parse decision: {exc}")

def validate(data):
    reason = data.get("localReason")
    if reason not in set(data.get("allowedReasons", [])):
        stop("local failure reason is not eligible")
    requested = set(data.get("requestedCategories", []))
    allowed = set(data.get("allowedCategories", []))
    if not requested or not requested.issubset(allowed):
        stop("requested data categories are not authorized")
    consent = data.get("consent", {})
    if consent.get("generation") != data.get("generation"):
        stop("consent belongs to another conversation generation")
    if consent.get("purpose") != data.get("purpose"):
        stop("consent purpose does not match the cloud request")
    if not requested.issubset(set(consent.get("dataCategories", []))):
        stop("consent does not cover every requested category")
    claims = data.get("tokenClaims", {})
    if claims.get("audience") != data.get("expectedAudience"):
        stop("token audience does not match the cloud service")
    required_scopes = set(data.get("requiredScopes", []))
    if not required_scopes.issubset(set(claims.get("scopes", []))):
        stop("token scope is insufficient")
    if data.get("senderConstraintRequired") and not data.get("senderProofValidated"):
        stop("sender proof is required but not validated")
    print("cloud fallback decision is eligible for server reauthorization")

if __name__ == "__main__":
    if len(sys.argv) != 2:
        stop("usage: validate_fallback.py decision.json")
    validate(load_decision(sys.argv[1]))

发布门禁同时验证本地失败、云授权和撤销

发布前固定 App、模型、fallbackPolicy、数据清单、云服务和输出 schema。矩阵覆盖本地成功、不支持、资源不足、完整性失败、输出失败、用户取消、无同意、同意过期、wrong audience、scope 缺失、proof 缺失、服务端拒绝、云超时、用户撤销和迟到流式片段。

加固、模型、delegate、云 SDK、OAuth 配置、数据字段、商店声明或服务提供方变化后,重新生成候选身份并重跑关键矩阵。旧同意和 token 测试不能替新配置签字。任何上传前门禁缺失都阻止发布,不用“只在少数设备降级”降低要求。

站内的端侧 delegate 一致性文章可继续检查本地失败是否真实;准备评估商业 App 的端云 AI 数据路径与加固范围时,可通过页面行动按钮进入御盾中央平台提交候选包、数据清单和授权流程。提交只启动评估,数据与权限结论仍以同一候选回执为准。

  • 本地与云端分别建立数据流和输出契约。
  • 只有 allowlisted 本地失败原因进入云评估。
  • payload 从字段 allowlist 重新生成,不复用完整本地上下文。
  • 用户选择绑定账号、用途、类别、服务和 generation。
  • token audience、scope、subject 与发送者约束分别验证。
  • 撤销、取消、迟到响应和服务端拒绝都有明确终态。

事实依据与适用边界

以下内容区分官方事实、本文工程判断和不能外推的范围,避免把设计建议写成未经验证的产品结论。

本文判断事实或工程依据适用限制
delegate 不支持时应保留本地 CPU 路径,而不是直接上传。LiteRT Android Java API 说明检查 delegate 可用性并保留 CPU 执行路径。delegate 或 CPU 初始化成功不证明输出一致或业务可接受。
端侧模型与 LoRA 路径受具体模型和后端条件限制。Google AI Edge LLM Inference for Android 说明基础模型、LoRA 与 GPU 适用条件。该维护期 API 的约束不能外推为所有端侧运行时标准。
云授权部署需要限制令牌重放、授权码注入与不安全流程。RFC 9700 OAuth Security BCP 提供 OAuth 安全部署建议。安全 BCP 不决定具体 AI 服务的数据类别和商业权限。
发送者约束可降低被盗 access token 的重放风险。RFC 9449 OAuth DPoP 定义 token 与客户端密钥的证明机制。DPoP 不证明设备可信,也不替代短期令牌、用户选择和服务端授权。
数据声明要反映应用与第三方 SDK 的实际收集和共享。Declare Android app data use 说明 Data safety 的申报责任。商店声明不是技术隔离、授权或日志脱敏控制。
端云 fallback 变更要保留来源、构建、验证和供应链证据。NIST SP 800-218 SSDF 提供安全开发与变更治理实践。组织级框架不定义具体云服务或证明候选通过。
数据类别、同意、audience、scope 或 proof 任一不满足时不得上传。工程判断:跨越本地到云端数据边界需要全部前置条件同时成立。服务端仍需独立执行主体、用途和数据授权,客户端门禁不是最终授权。
当前不能声称目标 App 的端云降级已经符合授权边界。项目证据尚未接入;需要候选、数据清单、同意、token 与服务端回执。文章提供方法和门禁代码,不替代真实合规与运行验收。

工程常见问题

本地模型不可用时自动调用云端是不是合理降级?

只有在数据类别、用户选择、token 与服务端授权全部通过时才合理。否则应保持本地失败或让用户明确选择,不能静默上传。

用户开启过 AI 功能是否等于同意所有云端上传?

不等于。同意要绑定账号、用途、服务提供方、数据类别、政策版本和有效期,路径或字段变化后重新确认。

有效 access token 能否证明请求有权发送这些数据?

不能。还要核对 issuer、audience、scope、subject、时限和撤销,服务端再对用途与字段执行业务授权。

使用 DPoP 后是否可以省略设备和用户授权检查?

不可以。DPoP 主要约束 token 发送者并降低重放,它不证明设备可信,不代表用户同意,也不决定数据范围。

云 fallback 加入后只更新隐私声明够吗?

不够。声明用于透明度,技术上还要实现 payload allowlist、token 边界、服务端授权、日志脱敏、撤销清理和输出校验。

App 加固后为什么要重测端云降级?

加固可能影响本地模型、网络、token、序列化、缓存和生命周期。候选变化后,旧授权与路径回执不能证明新包行为。

想用自己的 App 验证?

提交候选包、目标系统和关键业务路径,申请御盾 PoC 与兼容性评估。

继续阅读: 移动 AI 应用的运行时安全边界