Skip to Content
API 参考CaMeL AI 三方接入技术指南

基于 @camelai/ai-sdk-providerdify-plugin-camelaicherry-studio 三个项目的核心实现逻辑,本文档为开发者提供快速接入 CaMeL AI 统一网关的技术指南。

1. 核心接入模式

1.1 统一鉴权与路由

// 核心逻辑:替换 API Key、Base URL,添加 APP-Code const config = { apiKey: 'your-camelai-api-key', // 替换为 CaMeL AI API Key baseURL: 'https://camel.kr777.top', // 替换为 CaMeL AI 网关 headers: { 'APP-Code': 'APP Code' // 应用Code可从https://camel.kr777.top/appstore获取 } }; // 模型路由规则 function routeModel(modelName: string) { if (modelName.startsWith('claude')) { // Claude 模型:使用 Anthropic SDK return 'anthropic'; } else if (modelName.startsWith('gemini') && !modelName.endsWith('-nothink') && !modelName.endsWith('-search')) { // Gemini 模型:使用 Google SDK,端点 https://camel.kr777.top/gemini return 'gemini'; } else { // 其他模型:使用 OpenAI 兼容接口 return 'openai'; } }

1.2 特殊处理要点

  • 空工具修复:当 tools=[] 且存在 tool_choice 时,自动移除 tool_choice
  • 文件扩展名:根据 mediaType 自动设置正确的文件扩展名
  • 缓存控制:支持 <cache> 标签实现缓存控制

2. 统一接入实现

2.1 核心客户端封装

class CaMeL AIModelClient { private config: { apiKey: string; baseURL: string; appCode: string; }; constructor(apiKey: string) { this.config = { apiKey, baseURL: 'https://camel.kr777.top', appCode: 'APP Code' }; } async chatCompletion(model: string, messages: any[], options: any = {}) { // 根据模型名称自动路由到对应的 SDK if (model.startsWith('claude')) { return this.claudeCompletion(model, messages, options); } else if (model.startsWith('gemini')) { return this.geminiCompletion(model, messages, options); } else { return this.openaiCompletion(model, messages, options); } } private async claudeCompletion(model: string, messages: any[], options: any) { const { Anthropic } = await import('@anthropic-ai/sdk'); const client = new Anthropic({ apiKey: this.config.apiKey, baseURL: this.config.baseURL, defaultHeaders: { 'APP-Code': this.config.appCode } }); return client.messages.create({ model, messages, ...options }); } private async geminiCompletion(model: string, messages: any[], options: any) { const { GoogleGenerativeAI } = await import('@google/generative-ai'); const genAI = new GoogleGenerativeAI(this.config.apiKey, { baseURL: `${this.config.baseURL}/gemini/v1beta`, defaultHeaders: { 'APP-Code': this.config.appCode } }); const genModel = genAI.getGenerativeModel({ model }); return genModel.generateContent(messages); } private async openaiCompletion(model: string, messages: any[], options: any) { const OpenAI = await import('openai'); const client = new OpenAI.default({ apiKey: this.config.apiKey, baseURL: `${this.config.baseURL}/v1`, defaultHeaders: { 'APP-Code': this.config.appCode } }); return client.chat.completions.create({ model, messages, ...options }); } } // 使用示例 const client = new CaMeL AIModelClient('your-camelai-api-key'); await client.chatCompletion('gpt-4o-mini', messages); await client.chatCompletion('claude-3-5-sonnet-20241022', messages); await client.chatCompletion('gemini-2.5-flash', messages);

2.2 特殊处理与工具函数

// 空工具修复 function fixToolChoice(requestBody: any): any { if (requestBody.tools?.length === 0 && requestBody.tool_choice) { delete requestBody.tool_choice; } return requestBody; } // 文件扩展名映射 function setFileExtension(mediaType: string): string { const mimeToExt: Record<string, string> = { 'audio/mpeg': 'mp3', 'audio/wav': 'wav', 'audio/flac': 'flac' }; return mimeToExt[mediaType] || 'bin'; } // 缓存控制 function processCacheTags(content: string): { content: string; cacheControl?: any } { if (content.includes('<cache>')) { return { content: content.replace('<cache>', ''), cacheControl: { type: 'ephemeral' } }; } return { content }; }

3. 部署与配置

3.1 环境变量

const config = { apiKey: process.env.CAMELAI_API_KEY || '', baseURL: process.env.CAMELAI_BASE_URL || 'https://camel.kr777.top', appCode: process.env.CAMELAI_APP_CODE || 'APP Code' };

3.2 错误处理

class CaMeL AIError extends Error { constructor(message: string, public code?: string, public status?: number) { super(message); this.name = 'CaMeL AIError'; } } function handleCaMeL AIErrors(error: any): CaMeL AIError { const message = error.message || 'Unknown error'; if (message.toLowerCase().includes('rate limit')) { return new CaMeL AIError('Rate limit exceeded', 'RATE_LIMIT', 429); } else if (message.toLowerCase().includes('unauthorized')) { return new CaMeL AIError('Authentication failed', 'AUTH_ERROR', 401); } else { return new CaMeL AIError(message, error.code, error.status); } }

4. 参考实现与对齐清单

4.1 cherry-studio 客户端参考(TypeScript)

下述要点来自 cherry-studioCamelaiAPIClient.ts,可作为第三方前端/桌面端在 TypeScript 侧接入 CaMeL AI 的落地范式:

  • 统一追加折扣码:在 Provider 级别合并 extra_headers 并设置 APP-Code(项目中为 MLTG2087
  • 多客户端路由
    • claude* → 使用 Anthropic 客户端
    • gemini*/imagen* 且不以 -nothink/-search 结尾且不包含 embedding → 使用 Gemini 客户端(apiHost: https://camel.kr777.top/gemini
    • OpenAI 系列(排除 gpt-oss)→ 使用 OpenAI 兼容响应客户端
    • 其他 → 回退到默认 OpenAI 客户端
  • BaseURL 获取:从当前已路由的具体客户端导出,保持各家端点差异

4.2 dify-plugin-camelai 参考(Python)

下述要点来自 dify-plugin-camelai 的实现,可作为第三方 Python 工具接入 CaMeL AI 的落地范式:

  • 统一追加折扣码:在 Provider 级别合并 extra_headers 并设置 APP-Code(项目中为 Dify2025
  • 多客户端路由
    • claude* → 使用 Anthropic 客户端
    • gemini*/imagen* 且不以 -nothink/-search 结尾且不包含 embedding → 使用 Gemini 客户端(apiHost: https://camel.kr777.top/gemini
    • OpenAI 系列(排除 gpt-oss)→ 使用 OpenAI 兼容响应客户端
    • 其他 → 回退到默认 OpenAI 客户端
  • BaseURL 获取:从当前已路由的具体客户端导出,保持各家端点差异

4.3 对齐清单

  • Provider 入口统一合并 extra_headers 并注入 APP-Code
  • Gemini 客户端使用 https://camel.kr777.top/gemini 作为 apiHost
  • 路由规则与 claude*gemini*/imagen*、OpenAI 系列(排除 gpt-oss)一致
  • 默认回退到 OpenAI 客户端,保持与 OpenAI 兼容接口行为
  • getBaseURL() 始终从当前路由客户端导出,避免硬编码

5. 迁移检查清单

  • 替换 API Key 为 CaMeL AI API Key
  • 替换 Base URL 为 https://camel.kr777.top
  • 添加 APP-Code header 享受折扣
  • 实现模型路由逻辑(claude/gemini/openai)
  • 处理空工具时的 tool_choice 修复
  • 配置文件上传的 MIME 类型处理
  • 测试各种模型调用
  • 配置错误处理和重试机制