config.yaml 中的任何字符串设置、用于设置这些配置项的环境变量,以及提供商环境变量:
.env 文件无需加引号。Docker Compose 会对其自身文件中的 ${...} 进行插值,因此在其中请写成 $${file:...};Compose 会将 ${file:...} 传递给 GoModel。
语法
引用的格式为${<scheme>:<reference>}。它可以嵌在更长的值中,一个值也可以包含多个引用:
方案
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 作为额外的方案接入。
解析失败会终止启动
无法解析的引用会使网关终止,错误信息会指明配置项和方案,但绝不会包含值本身: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会在解析其格式之前先解析引用。 - 在控制台管理的实体中,只有控制台管理的凭据中列出的字段接受引用。