使用 Terraform 管理 Onyx 部署级默认 LLM 模型:onyx_llm_provider_default 资源完全指南
【免费下载链接】danswerOpen Source AI Platform - AI Chat with advanced features that works with every LLM项目地址: https://gitcode.com/GitHub_Trending/da/danswer
本篇指南基于开源仓库 terraform-provider-onyx 中的官方文档 llm_provider_default.md 编写,并结合后端 API 与 Provider 源码进行纵深剖析。它适用于所有希望通过 Infrastructure as Code 方式统一管理 Onyx(开源 AI 平台)部署默认文本模型、默认视觉模型与聊天自动命名模型的平台工程师。
为什么需要一个"默认模型"资源
Onyx 是一个开源 AI 平台,其 LLM 供应商(Provider)体系允许管理员注册多个 Provider,每个 Provider 下再配置若干 Model Configuration。整个部署需要指定一个"部署级默认 LLM 模型"——它决定用户发起聊天时默认使用哪个 Provider 的哪个模型。
在 terraform-provider-onyx 中,这个默认值被建模为一个独立资源onyx_llm_provider_default,而不是 Provider 资源上的一个字段。官方文档(terraform-provider-onyx/docs/resources/llm_provider_default.md)给出的定位是:
The deployment-wide default LLM model — a singleton pointer at one provider + model pair (plus optional vision and chat auto-naming defaults).
即:它是一个单例指针,指向"一个 Provider + 一个模型"的组合,并可选附带默认视觉模型(vision)和聊天自动命名模型(chat auto-naming)的配置。
将其独立建模的核心价值在于依赖排序(depends_on ordering):
- 当某个 Provider 需要被删除或缩减(shrunk)时,Terraform 需要先把"默认"指针重定向(repoint)到别的 Provider,再执行删除;
- 由于
onyx_llm_provider_default通过provider_id = onyx_llm_provider.xxx.id引用 Provider 的 id,Terraform 的依赖图会自动保证:先更新/重定向默认指针,再删除持有该默认的 Provider; - 这避免了删除默认 Provider 时后端报错或默认被意外清空的局面(后端 API 对持有 chat 默认的 Provider 删除有保护逻辑,详见下文)。
资源 Schema 详解
onyx_llm_provider_default的 Schema 由 llm_provider_default_resource.go 定义,共 7 个属性,分为三类:
Required(必填)
| 属性 | 类型 | 说明 |
|---|---|---|
provider_id | String | 持有默认模型的onyx_llm_provider资源的 id。 |
model_name | String | 该 Provider 内的模型名称,例如gpt-5-mini。必须命中该 Provider 下可见的model_configurations之一(即必须与onyx_llm_provider中声明的model_configurations里的name对应)。 |
Optional(可选)
| 属性 | 类型 | 说明 |
|---|---|---|
vision_provider_id | String | 默认视觉模型所在的 Provider id。 |
vision_model_name | String | 默认视觉模型名称。 |
chat_naming_provider_id | String | 聊天自动命名专用模型的 Provider id。不设置时,自动命名使用当前会话(session)的模型;删除该对配置会清除服务器端值。 |
chat_naming_model_name | String | 聊天自动命名专用模型名称。 |
配对校验规则:源码中对这四个可选属性都配置了stringvalidator.AlsoRequires验证器,即:
vision_provider_id与vision_model_name必须成对出现(不能只填其中一个);chat_naming_provider_id与chat_naming_model_name必须成对出现。
Read-Only(只读)
| 属性 | 类型 | 说明 |
|---|---|---|
id | String | 恒为"default"。因为该资源是单例,id 固定不变。 |
完整示例配置
官方文档 Example Usage 与示例文件 resource.tf 给出了最小可用配置:
# The deployment-wide default model. Referencing the provider's id also # orders destroys correctly: the default is repointed/released before the # provider holding it is deleted. resource "onyx_llm_provider_default" "this" { provider_id = onyx_llm_provider.openai.id model_name = "gpt-5" vision_provider_id = onyx_llm_provider.openai.id vision_model_name = "gpt-5" }下面是一个更贴近生产实践的组合示例:先创建两个 Provider,再分别把文本默认、视觉默认、聊天命名默认指向不同的模型组合。
# 供应商 A:负责文本对话 resource "onyx_llm_provider" "primary" { name = "openai-primary" provider_type = "openai" api_key = var.openai_api_key model_configurations = [ { name = "gpt-5" }, { name = "gpt-5-mini" }, { name = "gpt-5-nano" }, ] } # 供应商 B:负责视觉与命名 resource "onyx_llm_provider" "vision" { name = "openai-vision" provider_type = "openai" api_key = var.openai_api_key model_configurations = [ { name = "gpt-5" }, { name = "gpt-5-mini" }, ] } resource "onyx_llm_provider_default" "this" { # 部署级文本默认 provider_id = onyx_llm_provider.primary.id model_name = "gpt-5" # 部署级视觉默认 vision_provider_id = onyx_llm_provider.vision.id vision_model_name = "gpt-5" # 聊天自动命名默认 chat_naming_provider_id = onyx_llm_provider.primary.id chat_naming_model_name = "gpt-5-nano" }底层原理:一次 apply 最多三次后端写入
onyx_llm_provider_default的 CRUD 实现在 llm_provider_default_resource.go 中,其核心是apply方法——它"最多做三次写入,把每次成功的结果叠加到 base 之上;失败时返回部分结果以及是否写过任何内容,以便调用方精确持久化服务器端已发生的变更"。
三次写入分别对应三个后端端点(client/llm_provider.go):
| Terraform 字段 | HTTP 方法与路径 | 说明 |
|---|---|---|
provider_id+model_name | POST /admin/llm/default | 设置部署级默认文本模型(SetDefaultLLMModel) |
vision_provider_id+vision_model_name | POST /admin/llm/default-vision | 设置部署级默认视觉模型(SetDefaultVisionModel) |
chat_naming_provider_id+chat_naming_model_name | POST /admin/llm/default-chat-naming | 设置聊天自动命名模型(SetDefaultChatNamingModel) |
| (删除 chat-naming 对) | DELETE /admin/llm/default-chat-naming | 清除聊天自动命名模型(ClearDefaultChatNamingModel) |
在 Go 客户端中,这些调用通过doJSON完成,例如:
// SetDefaultLLMModel sets the global default text model. func (c *Client) SetDefaultLLMModel(ctx context.Context, req DefaultModel) error { return c.doJSON(ctx, http.MethodPost, "/admin/llm/default", req, nil) }而DefaultModel结构体仅包含两个字段:ProviderID int64与ModelName string(llm_provider.go),与文档中"一个 Provider + 一个 Model 的单例指针"定位完全一致。
后端 API 的对应实现
后端 FastAPI 路由定义在 backend/onyx/server/manage/llm/api.py:
POST /admin/llm/default→update_default_provider(provider_id, model_name, ...),权限要求Permission.MANAGE_LLMS;POST /admin/llm/default-vision→update_default_vision_provider(...);POST /admin/llm/default-chat-naming→update_default_chat_naming_provider(...),权限要求Permission.FULL_ADMIN_PANEL_ACCESS;DELETE /admin/llm/default-chat-naming→update_no_default_chat_naming_provider(...),注释明确说明"清除专用命名模型后,自动命名回退到会话的模型"。
这解释了资源文档中的一个关键差异:文本与视觉默认没有 unset API,而聊天命名默认有。
生命周期语义:创建、更新、读取、删除、导入
Create(创建)
Create以空 state 为 base 调用apply,把计划中的三个默认逐一写入。即便部分失败(如 vision 写入失败),也会把已成功的部分写入 state,确保 Terraform state 与服务器端实际状态一致(llm_provider_default_resource.go)。
Update(更新)
Update读取新旧 state,计算clearChatNaming:当计划中chat_naming_provider_id为 null 而旧 state 非 null 时,说明用户从配置中删除了 chat-naming 对,此时会调用DELETE /admin/llm/default-chat-naming清除服务器端值(llm_provider_default_resource.go)。
Read(读取)
Read调用GET /admin/llm/provider?include_image_gen=true(ListLLMProviders)获取服务器端default_text、default_vision、default_chat_naming。值得注意的两个细节(llm_provider_default_resource.go):
- 若服务器端
default_text为空,资源会直接从 state 中移除(RemoveResource); - vision 与 chat-naming 默认只有在被 Terraform 管理(即 state 中非 null)时才会被刷新;未管理时,即使服务器端配置了,state 中也保持 null——避免 Terraform 接管未声明管理的配置。
Delete(删除)
Delete的行为是文档中特别强调、也是最容易踩坑的一点(llm_provider_default_resource.go):
- 文本与视觉默认:Onyx 没有 unset API,因此销毁该资源后,服务器端的默认文本/视觉模型依然保留在原 Provider 上。Provider 只会发出一个 Warning:"Default LLM model left unchanged";
- 聊天命名默认:如果 state 中管理了 chat-naming 对,删除时会调用
DELETE /admin/llm/default-chat-naming将其清除。
换句话说:terraform destroy此资源 ≠ 清空部署默认。如果目标是把默认文本模型切回"无默认",该行为不被 API 支持,属于后端能力边界。
Import(导入)
该资源是单例,导入 id 恒为"default"(import.sh):
#!/bin/sh # Singleton: the import id is always "default". terraform import onyx_llm_provider_default.this defaultImportState会对非"default"的导入 id 直接报错(llm_provider_default_resource.go)。导入后的后续Read会自动从服务器端刷新provider_id与model_name;vision 与 chat-naming 对则保持 null,直到用户在配置中显式声明。
与 onyx_llm_provider 的协同:删除顺序与 force_delete
将默认指针独立成资源的最大收益体现在 Provider 生命周期管理中。后端在删除 Provider 时存在保护逻辑(backend/onyx/server/manage/llm/api.py):
只有 chat 默认会阻止 Provider 删除。删除持有其他流程(文本/视觉)默认的 Provider,会"故意"连带清空该默认——这由测试
test_delete_default_vision_provider_clears_vision_default覆盖。
也就是说:持有文本或视觉默认的 Provider 可以删除,但会连带丢失默认配置;而持有 chat 默认的 Provider 不允许删除,除非传force=true。后端逻辑如下:
model = fetch_default_llm_model(db_session) if model and model.llm_provider_id == provider_id: raise OnyxError( OnyxErrorCode.RESOURCE_IN_USE, "Cannot delete this provider: it holds the deployment's chat " "default model. Repoint that default first, or pass force=true.", )因此,正确做法是让 Terraform 的依赖关系天然保证"先重定向、后删除":onyx_llm_provider_default引用onyx_llm_provider.id,删除 Provider 时 Terraform 会先重算默认指针,再执行 Provider 删除,避免RESOURCE_IN_USE报错。作为兜底,onyx_llm_provider还提供force_delete参数,允许在持有默认的情况下强制删除。
端到端验证:从 AccTest 看资源行为
资源的行为在 llm_provider_default_resource_test.go 的验收测试(AccTest)中被完整验证:
- 创建:创建
onyx_llm_provider(带gpt-5-mini、gpt-5-nano两个 model_configurations 与force_delete = true),再创建onyx_llm_provider_default指向gpt-5-mini,断言id == "default"、provider_id与 Provider 的id一致,并调用testAccCheckServerDefaultModel验证服务器端默认确实被设置; - 更新:将
model_name改为gpt-5-nano,再次断言服务器端默认同步更新; - 导入:以
ImportStateId = "default"执行导入并ImportStateVerify。
这套测试同时覆盖了 Provider 与默认资源的联动,可以作为你在自己基础设施中编写配置时的参考模板。另外,client 层的单元测试(TestSetDefaultLLMModel、TestSetDefaultVisionModel、TestSetDefaultChatNamingModel、TestClearDefaultChatNamingModel)直接验证了四个端点的请求路径与参数构造。
关键要点速查
onyx_llm_provider_default是单例资源,id恒为"default",导入 id 也必须是"default";provider_id+model_name是唯一必填组合,其余均为成对出现的可选属性;- 引用
onyx_llm_provider.xxx.id而非硬编码数字 id,可获得正确的销毁顺序; - 销毁资源不会清空服务器端文本/视觉默认(无 unset API),仅会清除被管理的 chat-naming 默认;
- 后端对"持有 chat 默认的 Provider 删除"有保护(
RESOURCE_IN_USE),需要通过重定向默认或force_delete解决; model_name必须命中 Provider 下可见的model_configurations,否则后端写入会失败。
通过将部署级默认 LLM 纳入 Terraform 管理,你可以把"哪个 Provider、哪个模型作为全局默认"这一关键决策版本化、可审计、可回滚,并与 Provider 资源、权限配置一起构成完整的 LLM 基础设施声明。
【免费下载链接】danswerOpen Source AI Platform - AI Chat with advanced features that works with every LLM项目地址: https://gitcode.com/GitHub_Trending/da/danswer
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考