Skip to main content
Secret 引用告诉 GoModel 从哪里读取某个值,而不是直接保存该值本身:
引用可用于 config.yaml 中的任何字符串设置、用于设置这些配置项的环境变量,以及提供商环境变量:
在 shell 中请用单引号包裹该值,以免 shell 对其进行展开;.env 文件无需加引号。Docker Compose 会对其自身文件中的 ${...} 进行插值,因此在其中请写成 $${file:...};Compose 会将 ${file:...} 传递给 GoModel。

语法

引用的格式为 ${<scheme>:<reference>}。它可以嵌在更长的值中,一个值也可以包含多个引用:
解析后的值会按原样使用。它可以包含换行符、引号或任何其他字节,因此服务账号 JSON 文件也可以使用,并且解析后的值不会再被扫描以查找其他引用。

方案

file 可直接读取 Docker 和 Kubernetes 的 Secret 挂载,因此无需入口脚本将其复制到环境变量中。该路径必须是常规文件或指向常规文件的符号链接(这些挂载正是如此);FIFO 或设备文件会被拒绝,因为 GoModel 在每次重新加载时都会再次读取该文件。 env 与普通的 ${NAME} 形式有两点不同:它是严格的,并且可以在环境变量中使用,而不仅限于 config.yaml。普通形式的行为不变:${NAME} 和 ${NAME:-default} 会在 config.yaml 中展开,未设置的 ${NAME} 会保持原样,这会导致以它作为密钥的提供商被丢弃。 外部 Secret 管理器(HashiCorp Vault、AWS Secrets Manager、GCP Secret Manager、Azure Key Vault)可以通过 GoModel Pro 作为额外的方案接入。

解析失败会终止启动

无法解析的引用会使网关终止,错误信息会指明配置项和方案,但绝不会包含值本身:
通过环境变量设置的提供商 API 密钥会以该变量名报告,例如 OPENAI_API_KEY_2: secret reference ${file:...}。GoModel 不认识的方案不会在错误中重复显示,因为它是取自值本身的文本;请检查所指明的配置项是否有拼写错误。 重新加载失败时,会保留正在运行的配置。GoModel 绝不会带着未解析的引用启动,也不会将其发送到上游。 每个引用有 30 秒的解析时间。耗时更长的引用(例如位于卡住的网络挂载上的文件)会以 context deadline exceeded 失败,而不会拖住启动、重新加载或控制台保存操作。 只有实际使用的值才会被解析:被环境变量覆盖的 config.yaml 提供商值、GoModel 忽略的提供商环境变量(例如存在多个 openai 提供商且没有一个命名为 openai 时的 OPENAI_MODELS),或因缺少凭据而被跳过的提供商,都不会被查找。

轮换

GoModel 不会轮询 env 或 file 引用。轮换某个引用后,请重新加载:gomodel --reload 或 SIGHUP。 监视 Secret 管理器的扩展(例如 GoModel Pro 的 vault)会在值发生变化时通知 GoModel。随后 GoModel 会重新解析所有引用,并且:
  • 当仅提供商 API 密钥发生变化时,原地替换这些密钥。进行中的请求会使用其开始时的密钥完成。绑定到已移除密钥的会话会转移到另一个密钥;其他大多数会话保持原有密钥。
  • 当 config.yaml 或环境中的任何其他内容发生变化时(DSN、主密钥、代理 URL、服务账号 JSON),像 SIGHUP 一样重新加载配置。重新加载失败时会保留正在运行的配置,并在下一次变化时重试。通过控制台保存的引用永远不会触发配置重新加载;参阅控制台管理的凭据。
  • 当某个引用无法重新解析时,保留所有当前值,并记录一条指明该配置项的警告日志。
日志行会指明发生变化的配置项,但绝不会包含其值:
更改语义缓存嵌入器所用提供商的密钥也会触发重新加载,因为嵌入器保存了自己的一份密钥副本。

控制台管理的凭据

通过控制台或 Admin API 保存的提供商凭据、MCP 服务器请求头和护栏 Secret 字段同样接受引用,语法相同:
  • 引用按输入原样存储;GoModel 在构建提供商、MCP 连接或护栏时解析它。
  • 引用本身不是 Secret,因此对于仅由引用组成的值,控制台和 Admin API 会以不掩码的方式显示;MCP 请求头还可以以认证方案开头(Bearer ${env:TOKEN}),当代理 URL 的密码是引用时,也会显示该代理 URL。字面量 Secret 以及混合了字面文本和引用的值仍会被掩码;将掩码值原样发回会保留已存储的值。
  • 无法解析的引用会在保存时被拒绝,并返回指明字段和方案的 400。
  • 只有主密钥可以添加或更改引用。引用在网关主机上解析,因此它可以读取网关能够读取的任何环境变量或文件,包括主密钥。任何其他凭据(例如具有控制台访问权限的托管密钥)都会收到指明该字段的 403(secret_reference_requires_master_key)。它们仍然可以保存字面量 Secret、发回掩码值,以及重新保存引用未改变的实体。未配置主密钥时,控制台凭据像以前一样保存引用。
  • 出于同样的原因,只有主密钥可以更改持有引用的实体将其发送到的目标:MCP 服务器的 url,提供商的 type、base_url、backend 或 proxy_url,或护栏的类型或服务 URL(例如 Presidio 的 analyzer_url)。其他凭据会收到同样指明该字段的 403,但仍可编辑其他所有字段。
  • 每次解析器调用都会携带一个用于审计的字段路径,例如 provider_credentials.openai.api_keys[0]、mcp_servers.github.headers.Authorization 或 guardrail_definitions.pii.config.api_key。
  • 当被引用的值轮换时,只会重新安装受影响的实体:提供商的密钥会被原地替换,提供商的其他任何变化会重建该提供商,MCP 服务器会重新连接,护栏会被重建。如果引用无法解析,该实体保留其当前值。
在 config.yaml 中声明的护栏规则也以同样方式存储:插件 Secret 字段中的引用按书写内容保存,并在构建护栏时解析,因此数据库中永远不会保存 Secret 本身。 如果已存储的引用在启动时无法解析,相应的提供商凭据或 MCP 服务器会被记录日志并跳过,网关的其余部分照常启动。在重新加载时,正在提供服务的提供商凭据或 MCP 服务器绝不会因此被丢弃,也不会因为某个密钥现在解析为空值而被丢弃:重新加载会失败并指明该实体和字段,正在运行的配置(包括该实体)会继续提供服务。请修复或删除该实体,然后再次重新加载。已经被跳过的实体会再次被跳过,不会阻止重新加载。 护栏作为一个整体加载,并采用失败即拒绝(fail closed)策略:启动失败;重新加载时保留正在运行的配置;定期刷新时保留现有的护栏。 在引用功能出现之前保存的值也以同样方式读取,因此包含 ${scheme:...} 的已存储字面量现在会被视为引用。请使用 $${ 重新保存该值,以使其保持为字面量。 扩展可以注册一个 Secret 写入器。此后,在控制台中输入的字面量会被存储到 Secret 管理器中,只保存其引用;当对应的实体或字段被删除时,写入器的 Secret 也会被删除。如果某次保存仍持有一个其实体已不再存储的写入引用(例如在他人替换该 Secret 之前打开的表单),该保存会被拒绝:请重新加载后再保存。GoModel 核心版本不附带写入器。

字面量 ${

要表示字面量 ${,请写成 $${。pa$${x} 会变成 pa${x}。

限制

  • env 和 file 引用在加载或重新加载配置时解析;参阅轮换。
  • 它们适用于字符串设置。布尔值或数字设置不能是引用;如果 GoModel 解析为数字、布尔值、时长或列表的环境变量(LOGGING_ENABLED、HTTP_TIMEOUT、ENABLED_PASSTHROUGH_PROVIDERS 等)中包含引用,启动会终止。JSON 变量在其字符串值中接受引用。
  • 提供商环境变量是例外:OPENAI_MODELS、OPENAI_MODEL_FILTER_* 和 OPENAI_SESSION_STICKY_KEYS 会在解析其格式之前先解析引用。
  • 在控制台管理的实体中,只有控制台管理的凭据中列出的字段接受引用。
最后修改于 2026年10月24日