先看结论与判断条件
- 应用内默认值必须指向已随候选包验证的安全路由,首次启动、离线、获取失败和配置过期都能独立工作。
- 远端参数只选择客户端已知的模型和策略,不承载密钥、任意 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,因此应用必须内置安全默认、上一已验证配置和模型加载失败回退。远端回滚与本地回退需要分开演练。
随机百分位能否用于付费模型授权?
不能作为最终授权。百分位适合灰度分组,付费权益、租户范围和受限功能仍应由服务端验证。客户端条件只能影响体验选择。
为什么路由回退链需要检测循环?
模型缺失或不兼容时,循环会导致重复解析、反复下载或无确定结果。所有路由应在有限步骤内到达已验证安全默认,未知节点和自环直接拒绝。
申请远程模型路由安全评估需要准备什么?
准备应用候选、允许模型目录、远端配置快照、条件顺序、分桶规则、模型构建证明、监控与回滚方案,再通过御盾中央平台提交申请。