多模型 Provider 路由
多模型 Provider 路由
学习目标
理解 Khoj 如何通过模型槽位系统和 PriceTier 门控实现多 LLM 提供商的统一管理与路由。
前置知识
本章涉及多模型适配架构的通用原理,建议先阅读:
下文假设你已理解上述概念,直接聚焦 Khoj 的模型槽位系统和 PriceTier 门控实现。
项目实践
三大 Provider 统一抽象
Khoj 的 src/khoj/processor/conversation/ 目录下有三个 provider 子目录:
conversation/├── openai/│ ├── gpt.py # OpenAI 聊天接口│ └── utils.py # 补全、重试、超时处理├── anthropic/│ ├── anthropic_chat.py # Anthropic 聊天接口│ └── utils.py└── google/ ├── gemini_chat.py # Google Gemini 接口 └── utils.py每个 provider 实现一个 converse() 函数,接受统一的 ChatML 格式消息,返回流式响应。agenerate_chat_response() 根据 chat_model.model_type 枚举(OPENAI / ANTHROPIC / GOOGLE)切换到对应的 provider。
模型槽位系统
Khoj 的 ServerChatSettings 定义了 6 个模型槽位:
| 槽位 | 用途 | 典型模型 |
|---|---|---|
chat_default | 默认对话模型 | Gemini 2.5 Flash |
chat_advanced | 高级对话模型 | Claude Sonnet 4 |
think_free_fast | 免费用户推理(快速) | Haiku 4.5 |
think_free_deep | 免费用户推理(深度) | Claude 3.7 Sonnet |
think_paid_fast | 付费用户推理(快速) | Haiku 4.5 |
think_paid_deep | 付费用户推理(深度) | Opus 4 |
这种设计的核心思路是:不同用户群体使用不同模型,同一用户在不同场景下自动切换模型。免费用户的 deepthought 使用免费额度内的模型,付费用户可以使用更强大的模型。
PriceTier 门控
ChatModel: - price_tier: FREE | STANDARD - subscribed_max_prompt_size: 订阅用户的最大 prompt 大小每个 ChatModel 关联一个 PriceTier。用户能否使用该模型取决于其订阅状态:
- 免费用户:只能使用
FREE层级的模型 - 付费用户(STANDARD 订阅):可以使用所有模型,且享受更大的上下文窗口
ChatModel 通过 AiModelApi 关联 API 密钥,实现了模型配置与凭据的分离:管理员统一管理 API 密钥,用户只需选择模型,无需关心密钥配置。
OpenAI 结构化输出自适应
OpenAI provider 实现了三级结构化输出支持检测:
StructuredOutputSupport: - TOOL: 通过 tool_use 实现结构化输出 - SCHEMA: 原生 JSON schema 支持 - OBJECT: response_format object 模式在初始化时自动检测当前模型支持的结构化输出等级,选择最合适的 API 调用方式。这意味着同一个 Khoj 部署可以无缝适配不同版本的 OpenAI 模型(如旧版仅支持 response_format,新版支持 tool_use)。
支持模型一览
| 提供商 | 支持模型 |
|---|---|
| OpenAI | gpt-4o, gpt-4o-mini, gpt-4.1 系列, o1/o1-mini, o3/o3-mini/o3-pro, o4-mini, gpt-5 系列 |
| gemini-3-pro, gemini-2.5 flash/pro, gemini-2.0, gemini-1.5 | |
| Anthropic | Claude 3.5/3.7 Sonnet, 3.5 Haiku, Haiku 4.5, Sonnet 4, Opus 4 |
问题与规避
| 问题 | 影响 | 规避策略 |
|---|---|---|
| 模型 API 不可用 | 用户无法对话 | 多个槽位配置不同的模型作为备选;provider utils.py 中实现 backoff 重试 |
| Vision 模型需要额外配置 | 图片理解不可用 | vision_enabled 字段标记支持视觉的模型,自动获取 vision 模型配置 |
| 不同模型的 prompt 大小限制不同 | 长对话可能超出限制 | model_to_prompt_size 映射表管理每个模型的最大上下文 |
| Reasoning 模型需要特殊提示 | deepthought 模式输出质量下降 | 为 reasoning 模型使用独立的 system prompt 和参数(如 max_completion_tokens) |
设计取舍
为什么是 6 个固定槽位而不是动态的模型列表?
固定槽位简化了路由逻辑——系统只需要判断”当前用户 + 当前场景 → 哪个槽位”,而不需要复杂的优先级匹配。缺点是灵活性受限:如果需要新增场景(如”夜间模式使用便宜模型”),就需要增加新槽位。
为什么不使用模型路由/故障转移层?
Khoj 的模型选择是管理员预先配置的,而非运行时动态路由。原因是 Khoj 的目标用户是个人/小企业,模型选择是管理决策而非技术决策——管理员决定用哪些模型、分配给什么层级的用户。这与企业级 SRE 场景中的自动故障转移不同。