如何扩展 LLM 提供商
本文档提供三个常见扩展场景的分步操作指南:添加新的预设模板、添加新的 API 格式、以及为提供商配置搜索能力。
文件位置
| 文件 | 路径 |
|---|---|
| Provider 模板 | packages/desktop/app/shared/llm-config.ts |
| Provider 预设 | packages/desktop/app/shared/provider-presets.ts |
| ProviderManager | packages/desktop/app/main/services/capabilities/llm/config-service/ProviderManager.ts |
| URL Builder | packages/desktop/app/main/services/capabilities/llm/completion/url-builder.ts |
| Header Builder | packages/desktop/app/main/services/capabilities/llm/completion/header-builder.ts |
| Message Converter | packages/desktop/app/main/services/capabilities/llm/completion/message-converter.ts |
| DirectApiHandler | packages/desktop/app/main/services/capabilities/llm/completion/DirectApiHandler.ts |
| StreamHandler | packages/desktop/app/main/services/capabilities/llm/completion/StreamHandler.ts |
| CompletionService | packages/desktop/app/main/services/capabilities/llm/completion/CompletionService.ts |
| Types | packages/desktop/app/main/services/capabilities/llm/completion/types.ts |
| ProviderSearchInjector | packages/desktop/app/main/services/capabilities/llm/completion/ProviderSearchInjector.ts |
| NativeSearchInjector | packages/desktop/app/main/services/capabilities/llm/completion/NativeSearchInjector.ts |
| IPC Router Schemas | packages/desktop/app/main/services/routers/llm/schemas.ts |
| 前端 i18n | packages/renderer/src/locales/{en,zh,ja}/providers/llm.json |
架构上下文
graph TB
subgraph 扩展点
direction TB
A["(1) 新预设模板<br/>provider-presets.ts"]
B["(2) 新 API 格式<br/>types + handlers"]
C["(3) 搜索配置<br/>PROVIDER_SEARCH_CONFIGS"]
end
subgraph 影响范围
direction TB
Shared[shared 层<br/>类型 + 预设]
Completion[completion 层<br/>Handlers + URL]
Config[config-service 层<br/>ProviderManager]
Router[router 层<br/>IPC Schemas]
Frontend[renderer 层<br/>UI + i18n]
end
A --> Shared
A --> Config
A --> Frontend
B --> Shared
B --> Completion
B --> Router
C --> Shared
C --> Completion
场景一:添加新的预设模板
当需要支持一个新的 LLM 提供商(如新的中国云厂商或国际提供商),需要创建预设模板,让用户在 UI 中一键添加。
数据结构
// 预设模板的完整接口
interface PresetProviderTemplate {
id: string; // 唯一 ID(小写,如 'minimax')
name: string; // 显示名称
apiFormat: ApiFormat; // API 格式
baseUrl: string; // Base URL
modelsEndpoint?: string; // 模型发现端点
models: string[]; // 支持的模型 ID 列表
modelConfigs: ModelConfig[]; // 模型详细配置
features: string[]; // 特性标签
icon?: string; // 图标
website?: string; // 官网
docsUrl?: string; // API 文档
defaultSettings?: CompletionSettings; // 默认补全参数
}
操作步骤
步骤 1:定义预设模板
在 packages/desktop/app/shared/provider-presets.ts 的 PROVIDER_PRESETS 数组中添加:
// 伪代码 - 添加新预设
{
id: 'newprovider',
name: 'NewProvider AI',
apiFormat: 'openai', // 多数中国厂商兼容 OpenAI 格式
baseUrl: 'https://api.newprovider.com/v1',
modelsEndpoint: '/models',
models: ['np-large', 'np-lite', 'np-vision'],
modelConfigs: [
{
id: 'np-large',
name: 'NP Large',
enabled: true,
category: 'chat',
contextLength: 128000,
maxTokens: 8192,
vision: false,
functionCall: true,
reasoning: false,
},
{
id: 'np-lite',
name: 'NP Lite',
enabled: true,
category: 'chat',
contextLength: 32000,
maxTokens: 4096,
},
{
id: 'np-vision',
name: 'NP Vision',
enabled: true,
category: 'chat',
contextLength: 64000,
maxTokens: 4096,
vision: true,
},
],
features: ['chat', 'function_call'],
website: 'https://newprovider.com',
docsUrl: 'https://docs.newprovider.com/api',
}
步骤 2(可选):添加为默认提供商
如果希望新提供商出现在所有用户的初始列表中:
在 ProviderManager.getDefaultProviders() 的 defaultTemplateIds 数组中添加 ID。
同时在 packages/desktop/app/shared/llm-config.ts 的 PROVIDER_TEMPLATES 中添加对应的 ProviderTemplate。
步骤 3(可选):添加 Coding Plan 支持
如果提供商支持 Coding Plan 专用 API:
// 在 CODING_PLAN_URL_PRESETS 中添加
CODING_PLAN_URL_PRESETS['newprovider'] = {
baseUrl: 'https://api.newprovider.com/coding/v1',
separateApiKey: false, // 是否需要单独的 API Key
};
步骤 4(可选):添加 Follow-Provider 模型映射
如果希望支持自动选择同一提供商的 background/vision 模型:
// 在 PROVIDER_MODEL_MAPPINGS 中添加
PROVIDER_MODEL_MAPPINGS['newprovider'] = {
primary: 'np-large',
background: 'np-lite',
vision: 'np-vision', // 无视觉模型时设为 null
};
步骤 5:添加前端 i18n
在 packages/renderer/src/locales/ 下的 en/zh/ja 的 providers/llm.json 中添加提供商名称翻译。
场景二:添加新的 API 格式
当遇到无法兼容现有格式(openai/anthropic/google/azure-openai/openai-response)的提供商 API 时,需要添加新的 API 格式。
步骤总览
flowchart TD
S1["(1) 定义格式标识<br/>types.ts"] --> S2["(2) URL 构建<br/>url-builder.ts"]
S2 --> S3["(3) Header 构建<br/>header-builder.ts"]
S3 --> S4["(4) 消息转换<br/>message-converter.ts"]
S4 --> S5["(5) 非流式 Handler<br/>DirectApiHandler.ts"]
S5 --> S6["(6) 流式 Handler<br/>StreamHandler.ts"]
S6 --> S7["(7) 注册分发<br/>CompletionService.ts"]
S7 --> S8["(8) Schema 更新<br/>schemas.ts"]
步骤 1:定义格式标识
在 packages/desktop/app/main/services/capabilities/llm/completion/types.ts 的 ApiFormat 中添加新值:
// 修改前
type ApiFormat = 'openai' | 'anthropic' | 'google' | 'azure-openai' | 'openai-response';
// 修改后
type ApiFormat = 'openai' | 'anthropic' | 'google' | 'azure-openai' | 'openai-response' | 'newformat';
同步更新 packages/desktop/app/main/services/capabilities/llm/config-service/schemas.ts 的 ApiFormatSchema:
const ApiFormatSchema = z.enum([
'openai', 'anthropic', 'google', 'azure-openai', 'openai-response', 'newformat'
]);
同步更新 packages/desktop/app/main/services/routers/llm/schemas.ts 的 llmProviderCreateSchema。
步骤 2:URL 构建
在 url-builder.ts 中添加构建函数:
// 伪代码
function buildNewFormatApiUrl(baseUrl: string): string {
// 根据提供商 API 文档构建正确的 endpoint URL
// 处理各种 baseUrl 输入格式
}
在 resolveApiFormat() 中添加新格式的识别逻辑(如果需要从 apiType 推导)。
在 buildProviderApiUrl() 中添加新格式的分支。
步骤 3:Header 构建
在 header-builder.ts 的 getProviderHeaders() 中处理新格式的认证头:
// 伪代码 - 不同提供商的认证方式
// OpenAI: Authorization: Bearer <key>
// Anthropic: x-api-key: <key>
// 新格式可能使用不同的头部
步骤 4:消息格式转换
在 message-converter.ts 中添加消息转换函数:
// 伪代码
function convertMessageToNewFormat(message: SimpleChatMessage): NewFormatMessage {
// 将通用消息格式转换为提供商特定格式
// 处理 role 映射、content 结构、images、tool calls 等
}
步骤 5:非流式 Handler
在 DirectApiHandler.ts 中添加:
// 伪代码
async function callNewFormatCompletion(
provider: LLMProvider,
apiKey: string,
options: CompletionOptions,
logger: LoggerService
): Promise<CompletionResult> {
// 构建请求体
// 发送请求
// 解析响应为 CompletionResult
}
步骤 6:流式 Handler
在 StreamHandler.ts 中添加:
// 伪代码
async function streamNewFormatCompletion(
provider: LLMProvider,
apiKey: string,
options: CompletionOptions,
messageId: string,
callbacks: StreamCallbacks,
logger: LoggerService
): Promise<void> {
// 构建流式请求体
// 使用 streamSSEResponse() 或自定义流解析
// 调用 callbacks 传递增量内容
}
步骤 7:注册分发
在 CompletionService 中注册新格式:
// 在 callDirectHandler 的 switch 中
case 'newformat':
return callNewFormatCompletion(provider, apiKey, options, this.logger);
// 在 callStreamHandler 的 switch 中
case 'newformat':
await streamNewFormatCompletion(provider, apiKey, options, messageId, callbacks, this.logger);
return;
步骤 8:Schema 更新
确保所有涉及 ApiFormat 枚举的 Zod Schema 都已更新:
capabilities/llm/config-service/schemas.ts→ApiFormatSchemarouters/llm/schemas.ts→llmProviderCreateSchema.apiFormat
场景三:为提供商添加搜索配置
当提供商支持网页搜索功能时,需要配置搜索注入方式。
搜索类型决策
flowchart TD
Start[提供商支持搜索?] --> Type{搜索实现方式}
Type -->|请求参数启用| ModelParam["model-param<br/>修改请求 body"]
Type -->|内置工具定义| BuiltinTool["builtin-tool<br/>注入 tools 数组"]
Type -->|MCP 服务器| MCP["mcp<br/>外部处理"]
Type -->|SDK 原生| SDKNative["sdk-native<br/>NativeSearchInjector"]
Type -->|不支持| None["none<br/>无需配置"]
步骤
步骤 1:确定搜索类型
| 搜索实现方式 | 判断标准 | 示例 |
|---|---|---|
model-param | API 通过请求参数启用搜索(如 enable_search: true) | DashScope, Baidu |
builtin-tool | API 需要在 tools 数组中注入特定工具定义 | Kimi, Volcengine |
mcp | 搜索通过外部 MCP 服务器提供 | 自定义部署 |
sdk-native | SDK 原生处理(如 Anthropic server-side tools) | Anthropic |
none | 不支持搜索 | Ollama |
步骤 2:添加搜索配置
在 packages/desktop/app/shared/provider-presets.ts 的 PROVIDER_SEARCH_CONFIGS 中添加:
model-param 类型(请求参数):
// 伪代码
PROVIDER_SEARCH_CONFIGS['newprovider'] = {
type: 'model-param',
paramName: 'enable_search', // 参数名
paramValue: true, // 参数值
extraParams: { // 额外参数(可选)
search_mode: 'auto',
},
applicableModels: null, // null 表示所有模型
};
builtin-tool 类型(内置工具):
// 伪代码
PROVIDER_SEARCH_CONFIGS['newprovider'] = {
type: 'builtin-tool',
toolDefinition: {
type: 'function',
function: {
name: 'web_search',
description: 'Search the web for information',
parameters: {
type: 'object',
properties: {
query: { type: 'string', description: 'Search query' },
},
required: ['query'],
},
},
},
conflictsWithFC: false, // 是否与函数调用冲突
applicableModels: ['np-large'], // 仅特定模型支持(null = 全部)
};
步骤 3:验证注入
ProviderSearchInjector 会自动通过 getSearchConfig() 检测提供商的搜索配置,并在 buildSearchAugmentation() 中构建注入内容。无需额外代码修改。
修改文件清单
场景一:新增预设模板
| 文件 | 修改内容 | 必需 |
|---|---|---|
shared/provider-presets.ts | 添加 PROVIDER_PRESETS 条目 | 是 |
shared/llm-config.ts | 添加 PROVIDER_TEMPLATES 条目(如需默认) | 可选 |
capabilities/llm/config-service/ProviderManager.ts | 添加到 defaultTemplateIds(如需默认) | 可选 |
shared/provider-presets.ts | CODING_PLAN_URL_PRESETS(如需) | 可选 |
shared/provider-presets.ts | PROVIDER_MODEL_MAPPINGS(如需) | 可选 |
shared/provider-presets.ts | PROVIDER_SEARCH_CONFIGS(如需搜索) | 可选 |
| i18n JSON 文件 (en/zh/ja) | 提供商名称翻译 | 建议 |
场景二:新增 API 格式
| 文件 | 修改内容 | 必需 |
|---|---|---|
capabilities/llm/completion/types.ts | ApiFormat 类型 | 是 |
capabilities/llm/completion/url-builder.ts | URL 构建函数 + resolveApiFormat + buildProviderApiUrl | 是 |
capabilities/llm/completion/header-builder.ts | 认证头部 | 是 |
capabilities/llm/completion/message-converter.ts | 消息格式转换 | 是 |
capabilities/llm/completion/DirectApiHandler.ts | 非流式 Handler | 是 |
capabilities/llm/completion/StreamHandler.ts | 流式 Handler | 是 |
capabilities/llm/completion/CompletionService.ts | switch 分支注册 | 是 |
capabilities/llm/config-service/schemas.ts | ApiFormatSchema | 是 |
routers/llm/schemas.ts | llmProviderCreateSchema | 是 |
场景三:添加搜索配置
| 文件 | 修改内容 | 必需 |
|---|---|---|
shared/provider-presets.ts | PROVIDER_SEARCH_CONFIGS 条目 | 是 |
测试指南
预设模板测试
-
单元测试:验证模板数据完整性
- 所有必填字段存在且有效
- modelConfigs 中每个模型 ID 在 models 数组中
- apiFormat 值在 ApiFormat 枚举范围内
-
集成测试:
- 从预设创建提供商 → 验证 Provider 数据正确
- 启用提供商 → 配置有效 API Key → 发送测试消息
- 模型发现 → 验证返回的模型列表
-
UI 测试:
- 在设置页面的预设列表中能看到新预设
- 点击添加后正确创建提供商
- 提供商配置页面显示正确的字段
API 格式测试
-
URL 构建测试:
- 各种 baseUrl 输入格式 → 正确的 API endpoint
- 带路径前缀的 URL → 不丢失前缀
-
消息转换测试:
- 纯文本消息 → 正确格式
- 带图片的消息 → 正确处理
- 带工具调用的消息 → 正确格式
-
Handler 测试:
- 非流式:发送请求 → 解析响应 → CompletionResult
- 流式:SSE 事件 → 正确触发 callbacks
- 错误处理:网络错误、API 错误、格式错误
-
端到端测试:
- 使用 testModel() 验证完整管线
- 流式对话 → 验证 onDelta/onDone 回调
搜索配置测试
-
注入测试:
getSearchConfig()能正确识别新提供商buildSearchAugmentation()生成正确的注入内容- model-param 类型:请求 body 包含正确参数
- builtin-tool 类型:tools 数组包含正确的工具定义
-
冲突测试:
conflictsWithFC为 true 时:搜索工具和函数调用不同时存在applicableModels限制:非适用模型不注入搜索
关联文件表
| 文件 | 关联方式 |
|---|---|
shared/llm-config.ts | PROVIDER_TEMPLATES、ApiFormat、核心类型 |
shared/provider-presets.ts | 预设模板、搜索配置、Coding Plan URL、模型映射 |
capabilities/llm/config-service/ProviderManager.ts | 默认提供商列表、模板创建逻辑 |
capabilities/llm/config-service/schemas.ts | ApiFormatSchema、验证 Schema |
capabilities/llm/completion/types.ts | ApiFormat 类型定义 |
capabilities/llm/completion/url-builder.ts | resolveApiFormat、URL 构建 |
capabilities/llm/completion/header-builder.ts | 认证头部 |
capabilities/llm/completion/message-converter.ts | 消息格式转换 |
capabilities/llm/completion/DirectApiHandler.ts | 非流式 API Handler |
capabilities/llm/completion/StreamHandler.ts | 流式 API Handler |
capabilities/llm/completion/CompletionService.ts | Handler 分发注册 |
capabilities/llm/completion/ProviderSearchInjector.ts | 搜索注入逻辑 |
routers/llm/schemas.ts | IPC 参数验证 Schema |
| i18n JSON 文件 | 前端翻译 |