新增 Provider
对应源码
| 扩展环节 | 源码 |
|---|---|
| 配置字段和 Provider 名称 | nanobot/config/schema.py、nanobot/providers/registry.py |
| Provider 构造分派 | nanobot/providers/factory.py::_make_provider_core、make_provider |
| 通用响应、Tool Call、stream/retry 契约 | nanobot/providers/base.py::LLMProvider、LLMResponse、ToolCallRequest |
| 设置页同步 | nanobot/webui/settings_api.py、webui/src/lib/provider-brand.ts |
| 现有 Provider 测试模式 | tests/providers/ |
学习目标
读完后,你应当能够:
- 先判断是否只需配置已有
customProvider; - 为 OpenAI-compatible 服务完成最小注册;
- 判断何时必须写新的 Provider backend;
- 设计消息、Tool Call、stream、reasoning、usage 和错误归一化测试。
前置知识
- 理解 Provider 解析与 Fallback;
- 知道 OpenAI-compatible 只表示 API 形状相似,不保证所有字段和流事件相同;
- 能阅读异步 HTTP/SDK 调用。
1. 先选最小层级
flowchart TD A["要接入一个模型服务"] --> B{"已有 Provider 可配置?"} B -->|"是"| C["只写 config/preset"] B -->|"否"| D{"OpenAI-compatible?"} D -->|"基本兼容"| E["ProviderSpec + ProvidersConfig"] D -->|"协议/认证/响应不同"| F["新 backend + factory 分支"]
DeepSeek 已存在于当前 registry,不需要新增 Provider。
2. 仅配置 custom
如果服务允许自定义 apiBase、API key 和 model,并能被 OpenAICompatProvider 正确处理,先尝试 provider: custom。
这一层不修改源码,适合本地 vLLM、企业网关或还未正式进入 registry 的 endpoint。只有需要自动识别、状态展示、默认 base 或特定请求适配时,才新增 ProviderSpec。
3. OpenAI-compatible Provider 的最小改动
官方开发文档给出的当前最小路径是两处:
nanobot/providers/registry.py
ProviderSpec(
name="myprovider",
keywords=("myprovider", "mymodel"),
env_key="MYPROVIDER_API_KEY",
display_name="My Provider",
default_api_base="https://api.myprovider.example/v1",
)nanobot/config/schema.py
在 ProvidersConfig 增加:
myprovider: ProviderConfig = Field(default_factory=ProviderConfig)registry 随后为环境变量、auto detection、status 和部分 WebUI credential surface 提供统一元数据。
4. ProviderSpec 不是展示表
它会影响真实请求。常用字段包括:
backenddefault_api_baseis_gatewayis_localis_directis_oauthdetect_by_key_prefixdetect_by_base_keywordstrip_model_prefixsupports_max_completion_tokensmodel_overridesthinking_stylegateway_reasoning_stylereasoning_as_contentreasoning_effort_remap- reasoning history 处理字段。
PROVIDERS 的顺序也影响匹配优先级。源码注释明确要求 gateway 优先。新增关键词不能过宽,否则可能把其他模型误判为此 Provider。
5. 何时需要新 backend
以下情况通常超出 ProviderSpec:
- 完全不同的认证协议;
- 非 OpenAI 消息或 Tool schema;
- 独特的 streaming event;
- 原生 SDK 才能正确处理;
- Tool Call、reasoning 或 usage 形状无法通过现有 adapter 归一;
- 需要专门的请求签名、region/profile 或 OAuth 生命周期。
这时需要:
- 实现
LLMProvider子类; - 至少实现
chat()和get_default_model(); - 必要时覆盖
chat_stream(); - 在
ProviderSpec.backend声明新 backend; - 在
nanobot/providers/factory.py::_make_provider_core()增加构造分支; - 更新导出、配置、测试和文档。
6. 必须归一化的响应
Provider 最终要构造 LLMResponse。关键内容包括:
contenttool_callsfinish_reasonusagereasoning_content- error status/code/retry metadata
- stream stall 等恢复线索。
Runner 不应该知道上游把工具调用叫 function_call、content_block 还是其他名称。适配层的价值正是把差异收敛在 Provider 边界。
7. Tool Call 测试
至少覆盖:
- 发送 nanobot function schema;
- 解析一个完整 Tool Call;
- 流式 arguments 分片能正确拼接;
- 多个 Tool Call 保持稳定 id/name;
- tool result history 能再次发送;
- 非法 arguments 产生可诊断错误,不静默丢失。
只测试“你好 → 一段文本”不能证明 Provider 能用于 Agent。
8. reasoning 与 thinking
模型可能:
- 用独立
reasoning_content; - 把 thinking 放 content blocks;
- 要求请求中显式开关;
- 拒绝 OpenAI
reasoning_effort; - 要求历史保留或删除 reasoning 字段。
先用官方 API 文档和实际 fixture 确定 wire shape,再选择 ProviderSpec 字段。不能根据模型名字猜测 thinking 兼容性。
9. 错误和重试
Provider 应尽量填充结构化信息:
- HTTP status;
- provider error code/type;
- retry-after;
error_should_retry。
这样 LLMProvider._run_with_retry() 和 FallbackProvider 才能区分:
- 暂时性 429/5xx;
- 认证失败;
- 配额/账单;
- 内容过滤;
- context length;
- malformed request。
把所有异常都改写成普通字符串,会损失重试和 fallback 决策。
10. 配置与 UI 同步
最小 OpenAI-compatible Provider 通常涉及:
ProviderSpecProvidersConfig- registry/config tests
- configuration/provider docs
若要专属品牌、模型列表、OAuth 或特殊设置,还可能涉及:
nanobot/webui/settings_api.pywebui/src/lib/provider-brand.ts- 对应 Python/TypeScript tests
- i18n 文案。
只在产品确实需要特殊 UI 时增加这些分支;通用 Provider 应尽量由 registry 驱动。
11. 测试参考
简单 registry Provider:
tests/providers/test_novita_provider.pytests/providers/test_longcat_provider.pytests/providers/test_mistral_provider.py
通用适配:
tests/providers/test_openai_compat_timeout.pytests/providers/test_provider_retry.pytests/providers/test_reasoning_content.py
原生 backend:
tests/providers/test_azure_openai_provider.pytests/providers/test_bedrock_provider.pytests/providers/test_openai_codex_provider.py
12. 完成条件
- config 能解析;
- factory 选择预期 backend;
- API key/base/model 正确;
- 非流式和流式文本正确;
- Tool Call 往返正确;
- reasoning/usage 正确;
- 错误 metadata 可驱动重试/fallback;
- 不发真实 key 的单元测试通过;
- 最后再用一个最小真实请求 smoke test。
自检
- 一个 OpenAI-compatible endpoint 为什么可能仍不能直接用于 Agent?
ProviderSpec的顺序为什么重要?- 哪些差异应在 Provider 内归一,而不是让 Runner 分支处理?
- 为什么必须测试 Tool Call,而不只测试文本回答?
下一篇:新增 Channel