先看结论与判断条件

  • 应用内默认值必须指向已随候选包验证的安全路由,首次启动、离线、获取失败和配置过期都能独立工作。
  • 远端参数只选择客户端已知的模型和策略,不承载密钥、任意 URL、可执行表达式或未审核模型身份。
  • 条件顺序、版本边界、目标人群和随机百分位必须能在发布前静态展开,避免多个条件意外覆盖。
  • 灰度以稳定但最小化的分桶键分配,同一用户或设备在观察期内保持路由一致,指标按候选身份分别统计。
  • 回滚同时处理远端值、本地激活缓存和不可用模型,离线客户端使用最近已验证配置而不是等待 kill switch。
  • 配置放行记录应绑定应用候选、允许模型清单、模型构建证据、条件快照和验证结果,不能只保存控制台截图。

先把远程配置限制为选择器而不是执行器

远程模型路由的合理职责,是在客户端已经理解并验证的候选集合中选择一个值,而不是从服务器下发任意模型地址、脚本、提示模板或鉴权材料。客户端应把模型标识、运行时要求、允许功能、最低应用版本和回退关系编译成受控目录,远端配置只引用目录中的短标识。收到未知标识、字段类型变化或未声明条件时,解析器直接拒绝整份路由候选,继续使用本地安全默认或上一已验证配置。

这种边界可以缩小错误配置的故障半径。若控制台误填了不存在的模型,新值不会触发任意下载;若攻击者观察到客户端配置,也无法从中获得密钥,因为 Remote Config 本来就不是秘密存储。工程判断是把“可远程改变”和“必须随应用发布”的字段分开:目标百分比、已批准模型选择和非安全文案可以远程调整,信任根、允许模型集合、授权规则和数据边界应由版本化应用或受控服务端策略决定。

模型路由还应与模型更新解耦。路由只在本地候选已经下载、校验并通过运行时准备后才能选择它;配置先到而模型未就绪时,客户端保持旧路由并记录受控状态。反过来,模型下载完成也不自动成为活动路由,仍需目标条件和灰度决策。两个状态机分别维护证据,可以避免“文件存在”与“允许全量使用”被同一个布尔值混淆。

远程路由中可以变化与应固定的边界
对象适合远程配置应由受控代码或服务决定失败默认
模型选择已批准模型短标识允许集合、摘要和运行时要求上一已验证模型
目标范围版本、地区、受控人群和百分位账号授权与合规限制不进入新路由
回退顺序已批准候选间的优先级回退目标是否安全可用应用内安全默认
网络端点已知端点组的短标识域名、证书与鉴权策略拒绝未知端点
密钥与令牌不适合专用秘密管理和短期授权配置中发现即拒绝
可执行逻辑不适合经过发布审查的代码不解析任意表达式

应用内默认值必须覆盖首次启动和离线

Firebase Remote Config for Android 要求客户端设置应用内默认值,再通过 fetch 与 activate 生命周期采用远端参数。对于模型路由,默认值不能是空字符串、最新模型别名或必须联网才能解析的占位符,应指向随当前安装包完成过兼容验证的模型或明确的禁用状态。首次安装没有远端缓存、网络不可用、获取限流或服务异常时,核心流程仍能做出确定决定。

fetch 与 activate 必须分开记录。获取成功只说明客户端拿到一份参数,并不代表值已经通过本地 schema、允许模型、版本、过期和依赖检查;只有所有门禁通过后才生成“已验证配置”快照并原子激活。若使用平台 SDK 的 activate,业务层仍应在读取参数后完成自己的语义校验,而不能把 SDK 接受的字符串等同于模型路由可用。

离线行为需要明确时间边界。上一已验证配置可以缓存并在短期网络中断时继续使用,但配置过期、应用升级或模型被本地清理后要重新判断。工程判断是为配置记录获取时间、验证时间、适用应用版本、所需模型集合和最大离线有效期;过期后退回应用内默认,而不是继续无限期使用旧的实验路由。本文不给出通用时长,具体窗口应由业务风险和真实离线场景验证。

客户端不同配置状态的确定行为
状态可使用的路由必须记录禁止行为
首次启动应用内安全默认应用候选与默认模型身份等待网络导致核心流程无路由
获取成功未验证当前已验证配置远端快照摘要和待验证原因直接读取新模型标识
验证并激活新配置选中的已就绪模型配置版本、条件和模型身份丢失上一可用快照
获取失败未过期的已验证配置错误类别和最后成功时间清空缓存或猜测最新值
配置过期应用内默认或受控降级过期原因与当前环境无限期延长实验配置
所需模型缺失回退链中的可用候选缺失模型和下载状态路由到半成品模型

条件顺序和交集要在发布前展开

Firebase Remote Config conditions 支持按应用版本、平台、国家地区、用户属性和随机百分位等条件选择值,条件顺序会影响最终结果。一个用户可能同时满足多个条件,控制台中靠前条件覆盖后续条件时,原本面向测试版本的模型可能意外成为某个地区的全量值。发布评审不能只读条件名称,应把每个参数的优先顺序、谓词和结果展开成决策表。

版本比较需要使用明确语义。字符串比较容易把不同位数版本放到错误顺序,内部版本号、发布渠道和平台版本也不能混用。客户端收到远端结果后,应再次确认自身应用版本和运行时满足目标模型目录中的边界,即使服务端条件已筛选。条件是选择提示,不是安全断言;账号权限、数据区域和受限功能仍由服务端做最终控制。

目标人群属性要限制来源和生命周期。客户端自报的普通属性适合体验实验,却不适合作为付费授权或高风险数据处理依据。随机百分位需要稳定分桶,避免每次 fetch 都重新抽样导致同一用户在多个模型间跳动;同时应避免用可跨应用追踪的稳定标识。工程判断是采用单应用范围内的随机安装身份或服务端实验身份,并在隐私评审中说明用途和保留边界。

条件发布前需要检查的冲突
冲突类型示例后果静态检查运行时防线
顺序覆盖地区条件覆盖测试版本限制展开所有命中组合和优先级客户端再次验证应用版本
版本语义字符串顺序选错候选统一使用数值构建版本未知格式拒绝配置
人群属性客户端自报值获得受限模型区分实验属性与授权属性服务端执行最终授权
百分位漂移同一主体频繁切换模型固定分桶算法和实验种子缓存已验证分配
平台混用Android 条件选择 iOS 模型模型目录声明平台边界运行时拒绝不兼容候选
条件空集目标用户无法获得任何路由计算覆盖范围和默认分支回到应用内安全默认

灰度发布以候选身份和失败预算为核心

Firebase Remote Config rollouts 可以向部分目标用户开放参数值,并依据监控结果调整或回滚。对模型路由,灰度单位不应只是一个百分比,还要绑定应用版本、模型版本、配置版本、目标条件和分桶种子。指标必须按这组候选身份分开统计,否则旧版本错误、新模型错误和网络问题会混在总量中,团队无法知道扩量依据是否真实。

灰度应从内部可诊断人群开始,再进入小范围真实环境,之后逐级扩大。每一级都预先写明观察窗口、关键业务结果、加载失败、回退次数、资源变化和停止条件。本文不提供固定百分比或性能阈值,因为模型复杂度、设备分布和业务容错不同。项目证据应保存每次扩量前后的配置快照与指标查询,不能只保存最终全量值。

rollout 回滚依赖客户端后续获取和激活,离线或长时间后台的设备不会立即收到 kill switch。因此,高风险路由还需本地失败回退:模型加载失败、固定探针不通过或连续业务错误时,在不等待远端的情况下切回上一已验证模型,并进入坏版本抑制。远端回滚控制未来分配,本地回退保护当前设备,两个机制不能互相替代。

  • 每次灰度绑定配置、模型、应用和分桶身份
  • 候选指标与旧路由指标分开统计
  • 扩量和停止条件在发布前固定
  • 配置快照和指标查询都有时间回执
  • 离线设备具备本地失败回退
  • 坏版本被抑制而不是持续重复激活

回滚要同时处理配置缓存和模型可用性

远端控制台恢复旧值只是回滚开始。客户端可能仍持有已 fetch 未 activate 的新值、已经激活的新配置、本地分桶结果和新模型实例。完整回滚需要定义顺序:停止继续扩量,发布更高版本的回滚配置,客户端验证后原子替换配置快照,新请求选择旧模型,在途请求按原快照完成,并把问题候选加入抑制列表。

上一配置必须仍然可执行。若容量清理已经删除旧模型,远端指向旧标识只会造成第二次失败;若应用升级改变了运行时,旧模型也可能不再兼容。工程判断是路由配置的回退链只能引用本地模型目录中已验证、未过期且适配当前应用的候选。没有可用候选时回到应用内禁用或基础模型默认,而不是递归选择任意远端别名。

Firebase Remote Config use cases 展示按版本或用户群控制功能暴露的应用方式,但用例说明不能证明紧急停用的到达时效。发布演练应覆盖在线、离线、获取失败、激活失败、模型缺失和应用升级等状态,记录每种状态最终选择的路由。只有实际设备结果与决策表一致,团队才能声明该候选的回滚路径通过。

回滚时需要同步核对的状态
状态层可能残留回滚动作完成证据
远端发布错误参数仍面向新用户发布更高配置版本并停止扩量控制面配置快照
fetch 缓存尚未激活的新配置验证版本后拒绝旧错误快照客户端状态记录
活动配置当前仍选择问题模型原子切回已验证快照新请求路由结果
模型实例在途请求持有新模型允许完成或按安全策略终止引用释放与错误记录
本地模型旧模型被清理或不兼容检查回退候选目录摘要、运行时和试加载回执
坏版本抑制下一次 fetch 再次激活记录配置与模型失败身份重试条件和解除依据

用静态校验器拒绝未知模型和断裂回退链

控制台界面便于编辑参数,却不适合证明路由图没有环、所有模型都在允许集合、目标条件有默认分支或百分比处于有效范围。发布前应把远端配置导出成版本化 JSON,由校验器读取同一版本的模型目录和条件 schema,检查模型标识、最低应用版本、目标人群、分桶、有效期和回退链。任何未知字段或无法解释的目标都应失败关闭。

下面示例只读取公开安全的 JSON 文件,验证路由条目的模型是否属于允许集合、百分比是否为整数有效值、受众是否来自已批准类别,并沿 fallback 检查未知节点和循环。它不连接控制台、不包含密钥,也不执行模型下载。实际项目还需验证配置签名、版本、过期时间、条件顺序和候选模型摘要,并把输入文件与客户端发布身份绑定。

校验器输出要进入发布证据,而不是在失败后由操作者手工覆盖。若确实需要新增模型或人群,应先更新受控目录、测试新候选,再修改路由配置;不能通过关闭检查器绕过流程。工程判断是让每次配置变更产生可阅读差异,包括新增模型、目标范围扩大、默认值变化和回退链变化,评审者可以直接判断风险是否扩大。

  • 模型允许集合与客户端候选目录同版本
  • 未知字段和未知人群默认拒绝
  • 所有路由都能到达安全默认
  • 回退链不存在自环或多节点循环
  • 目标范围扩大在差异中清晰可见
  • 校验输入输出与配置发布身份绑定
校验允许模型、目标人群和回退链
from pathlib import Path
import json
import sys

if len(sys.argv) != 2:
    raise SystemExit("usage: validate_routes.py routes.json")

source = Path(sys.argv[1])
if not source.is_file():
    raise SystemExit("route configuration does not exist")

payload = json.loads(source.read_text(encoding="utf-8"))
allowed_models = set(payload.get("allowedModels", []))
approved_audiences = {"internal", "beta", "general"}
routes = payload.get("routes")

if not allowed_models or not isinstance(routes, list) or not routes:
    raise SystemExit("allowedModels and routes must be non-empty")

by_name = {}
failures = []
for route in routes:
    name = route.get("name")
    model = route.get("model")
    percent = route.get("percent")
    audience = route.get("audience")
    if not name or name in by_name:
        failures.append(f"invalid or duplicate route: {name!r}")
        continue
    by_name[name] = route
    if model not in allowed_models:
        failures.append(f"{name}: model is not allowed: {model!r}")
    if not isinstance(percent, int) or not 0 <= percent <= 100:
        failures.append(f"{name}: percent must be an integer from 0 to 100")
    if audience not in approved_audiences:
        failures.append(f"{name}: audience is not approved: {audience!r}")

for name, route in by_name.items():
    seen = {name}
    fallback = route.get("fallback")
    while fallback is not None:
        if fallback not in by_name:
            failures.append(f"{name}: unknown fallback route {fallback!r}")
            break
        if fallback in seen:
            failures.append(f"{name}: fallback cycle reaches {fallback!r}")
            break
        seen.add(fallback)
        fallback = by_name[fallback].get("fallback")

if failures:
    print("route validation failed:")
    for failure in failures:
        print(f"- {failure}")
    raise SystemExit(2)

print(f"validated {len(by_name)} routes and {len(allowed_models)} models")

配置真实性、版本和过期不能只靠传输层

TLS 保护传输通道,却不回答客户端拿到的配置是否仍在授权版本、是否已过期或是否与其他元数据来自同一发布快照。The Update Framework specification 中签名、版本、过期和一致快照的思想适用于高风险路由:客户端或受控服务可以对路由包进行签名,绑定配置版本、允许模型目录摘要和有效期,并拒绝未授权回滚、冻结旧配置与混搭。

这不意味着必须把通用 Remote Config 改造成完整更新框架,而是要按风险选择验证层。普通体验实验可依赖平台配置能力和安全默认,高价值模型、付费路由或数据区域选择则应由服务端授权或额外签名策略控制。Remote Config conditions 只能影响客户端选值,不能替代服务端拒绝越权请求;客户端可观察并修改其本地状态,因此安全边界不能只建立在隐藏参数上。

配置版本还应单调且可追溯。客户端保存最后接受版本和摘要,发现更旧版本时按策略拒绝;过期配置在离线窗口结束后回到应用内默认。紧急回滚通过发布更高版本的安全配置完成,而不是降低版本号。项目没有签名或可信版本服务时,应明确标为未接入,不能把普通 fetch 成功描述成防回滚验证。

不同风险路由需要的信任层
路由类型客户端配置作用额外控制不可依赖
体验实验选择已批准展示模型安全默认与本地兼容检查隐藏参数等于安全
付费模型提示候选模型服务端账号与资源授权客户端人群属性
区域数据处理选择允许端点短标识服务端区域策略和网络边界国家条件单独决定
高价值本地模型选择已验证本地候选签名路由包和模型目录摘要任意远端 URL
紧急停用新请求选择安全默认本地失败回退与服务端拒绝离线客户端立即 fetch
配置回滚采用更高版本安全快照版本、过期与一致性验证降低版本号覆盖历史

发布证据必须连接配置、模型和应用候选

SLSA Provenance v1.1 说明构建证明可以把产物主体与构建者、构建类型、外部参数和依赖材料关联。对模型路由而言,允许模型目录不应只是人工输入的名称;每个模型标识应连接到具体摘要、构建证明引用、运行时要求和设备回归。远端配置选择的是这个不可变身份,而不是会随服务端内容变化的“latest”别名。

每次路由发布建议保存配置 JSON 摘要、条件顺序、平台控制面版本、应用候选摘要、允许模型目录摘要、灰度分桶规则、静态校验结果和回滚演练。监控回执按候选身份分组,明确尚未接入的数据。截图只能辅助人工复核,不能替代可重放配置和实际客户端结果;控制台显示全量不证明全部离线客户端已经激活。

最终结论要写清证据边界,例如指定应用版本、配置快照、模型集合和设备状态下路由符合决策表,不能写成错误配置永远不会生效。准备项目评估时,可通过御盾中央平台提交代表性安装包、模型目录、远端配置快照、条件表、灰度指标和回滚方案,先固定候选身份与验收范围。

  • 配置选择不可变模型身份而非 latest 别名
  • 允许模型目录连接摘要与构建证明
  • 应用、配置和模型候选身份同时入档
  • 条件顺序与分桶规则可以离线重放
  • 离线、过期、缺模型和回滚状态均有设备结果
  • 结论区分控制面发布和客户端实际激活

事实依据与适用边界

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

本文判断事实或工程依据适用限制
Android 客户端应设置应用内默认值,并区分远端参数的 fetch 与 activate 生命周期。Firebase Remote Config for Android 描述默认值、获取和激活远端参数的客户端流程。Remote Config 不是秘密存储或强制安全控制,客户端最终能够观察其采用的参数。
远端参数可按应用版本、平台、地区、用户属性和随机百分位等条件选值。Firebase Remote Config conditions 描述条件类型、参数值选择和条件顺序。条件命中不证明所有客户端已经获取或激活,也不能替代服务端授权。
远程配置可以向部分目标用户逐步开放参数并依据监控调整或回滚。Firebase Remote Config rollouts 描述渐进式 rollout 与结果观察的使用方式。远端回滚不能保证离线客户端立即收到新值,也不能修复已损坏的本地模型。
远程配置可按版本或用户群控制功能暴露,但客户端仍需要预先定义失败行为。Firebase Remote Config use cases 展示远端参数用于版本、人群和功能控制的场景。用例不证明紧急停用时效、模型兼容结果或具体项目效果。
高风险路由配置需要考虑签名、版本、过期和一致快照等元数据验证。The Update Framework specification 定义面向回滚、冻结和元数据混搭风险的更新验证流程。TUF 不直接规定移动模型的业务授权、灰度指标或具体 Remote Config 集成。
允许模型目录可用构建证明连接产物主体、构建者、外部参数和依赖材料。SLSA Provenance v1.1 描述 provenance 与产物主体及构建过程的绑定。provenance 不单独证明模型在特定设备的运行安全、性能或业务正确性。
远端路由应只引用客户端已知模型,并在配置无效时回到上一已验证路由。工程判断:受控允许集合和失败关闭可以限制未知模型或错误条件的故障半径。允许集合、离线期限和回退目标必须由真实应用候选与设备测试确认。
远端回滚与本地失败回退必须同时存在并分别验证。工程判断:远端回滚控制后续配置分配,本地回退保护尚未获取新值或当前模型失败的设备。具体到达时间、错误预算和灰度比例需要项目监控回执,本文不提供通用数值。

工程常见问题

远程配置里的模型标识可以直接写下载 URL 吗?

不建议。配置应引用客户端或受控服务已知的短标识,URL、摘要、运行时要求和授权边界由版本化模型目录管理。未知标识或任意地址应失败关闭。

Remote Config 获取成功后是否可以立即切换模型?

不能。获取只代表收到参数,还要检查 schema、版本、有效期、允许模型、条件、回退链和模型本地可用性,全部通过后再原子激活配置快照。

控制台回滚后离线设备会立即恢复吗?

不会。离线设备无法及时 fetch,因此应用必须内置安全默认、上一已验证配置和模型加载失败回退。远端回滚与本地回退需要分开演练。

随机百分位能否用于付费模型授权?

不能作为最终授权。百分位适合灰度分组,付费权益、租户范围和受限功能仍应由服务端验证。客户端条件只能影响体验选择。

为什么路由回退链需要检测循环?

模型缺失或不兼容时,循环会导致重复解析、反复下载或无确定结果。所有路由应在有限步骤内到达已验证安全默认,未知节点和自环直接拒绝。

申请远程模型路由安全评估需要准备什么?

准备应用候选、允许模型目录、远端配置快照、条件顺序、分桶规则、模型构建证明、监控与回滚方案,再通过御盾中央平台提交申请。

想用自己的 App 验证?

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

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