This commit is contained in:
musistudio
2026-01-01 22:11:21 +08:00
parent e7608ada4a
commit 4c5a84e028
17 changed files with 2092 additions and 388 deletions

View File

@@ -27,15 +27,15 @@
"message": "服务器 API 接口文档",
"description": "The generated-index page description for category 'API Reference' in sidebar 'tutorialSidebar'"
},
"sidebar.tutorialSidebar.category.Configuration": {
"sidebar.tutorialSidebar.category.server-configuration-category": {
"message": "配置",
"description": "The label for category 'Configuration' in sidebar 'tutorialSidebar'"
},
"sidebar.tutorialSidebar.category.Configuration.link.generated-index.title": {
"sidebar.tutorialSidebar.category.server-configuration-category.link.generated-index.title": {
"message": "服务器配置",
"description": "The generated-index page title for category 'Configuration' in sidebar 'tutorialSidebar'"
},
"sidebar.tutorialSidebar.category.Configuration.link.generated-index.description": {
"sidebar.tutorialSidebar.category.server-configuration-category.link.generated-index.description": {
"message": "服务器配置说明",
"description": "The generated-index page description for category 'Configuration' in sidebar 'tutorialSidebar'"
},
@@ -74,5 +74,17 @@
"sidebar.tutorialSidebar.category.Commands.link.generated-index.description": {
"message": "完整的命令参考",
"description": "The generated-index page description for category 'Commands' in sidebar 'tutorialSidebar'"
},
"sidebar.tutorialSidebar.category.cli-configuration-category": {
"message": "配置",
"description": "The label for category 'Configuration' in sidebar 'tutorialSidebar'"
},
"sidebar.tutorialSidebar.category.cli-configuration-category.link.generated-index.title": {
"message": "CLI 配置",
"description": "The generated-index page title for category 'Configuration' in sidebar 'tutorialSidebar'"
},
"sidebar.tutorialSidebar.category.cli-configuration-category.link.generated-index.description": {
"message": "CLI 配置指南",
"description": "The generated-index page description for category 'Configuration' in sidebar 'tutorialSidebar'"
}
}

View File

@@ -82,6 +82,115 @@ sidebar_position: 3
}
```
## 故障转移Fallback
当请求失败时,可以配置备用模型列表。系统会按顺序尝试每个模型,直到请求成功:
### 基本配置
```json
{
"Router": {
"default": "deepseek,deepseek-chat",
"background": "ollama,qwen2.5-coder:latest",
"think": "deepseek,deepseek-reasoner",
"longContext": "openrouter,google/gemini-2.5-pro-preview",
"longContextThreshold": 60000,
"webSearch": "gemini,gemini-2.5-flash"
},
"fallback": {
"default": [
"aihubmix,Z/glm-4.5",
"openrouter,anthropic/claude-sonnet-4"
],
"background": [
"ollama,qwen2.5-coder:latest"
],
"think": [
"openrouter,anthropic/claude-3.7-sonnet:thinking"
],
"longContext": [
"modelscope,Qwen/Qwen3-Coder-480B-A35B-Instruct"
],
"webSearch": [
"openrouter,anthropic/claude-sonnet-4"
]
}
}
```
### 工作原理
1. **触发条件**当某个路由场景的模型请求失败时HTTP 错误响应)
2. **自动切换**:系统自动检查该场景的 fallback 配置
3. **顺序尝试**:按照列表顺序依次尝试每个备用模型
4. **成功返回**:一旦某个模型成功响应,立即返回结果
5. **全部失败**:如果所有备用模型都失败,返回原始错误
### 配置说明
- **格式**:每个备用模型格式为 `provider,model`
- **验证**:备用模型必须在 `Providers` 配置中存在
- **灵活性**:可以为不同场景配置不同的备用列表
- **可选性**:如果某个场景不需要备用,可以不配置或使用空数组
### 使用场景
#### 场景一:主模型配额不足
```json
{
"Router": {
"default": "openrouter,anthropic/claude-sonnet-4"
},
"fallback": {
"default": [
"deepseek,deepseek-chat",
"aihubmix,Z/glm-4.5"
]
}
}
```
当主模型配额用完时,自动切换到备用模型。
#### 场景二:服务稳定性保障
```json
{
"Router": {
"background": "volcengine,deepseek-v3-250324"
},
"fallback": {
"background": [
"modelscope,Qwen/Qwen3-Coder-480B-A35B-Instruct",
"dashscope,qwen3-coder-plus"
]
}
}
```
当主服务商出现故障时,自动切换到其他服务商。
### 日志监控
系统会记录详细的 fallback 过程:
```
[warn] Request failed for default, trying 2 fallback models
[info] Trying fallback model: aihubmix,Z/glm-4.5
[warn] Fallback model aihubmix,Z/glm-4.5 failed: API rate limit exceeded
[info] Trying fallback model: openrouter,anthropic/claude-sonnet-4
[info] Fallback model openrouter,anthropic/claude-sonnet-4 succeeded
```
### 注意事项
1. **成本考虑**:备用模型可能产生不同的费用,请合理配置
2. **性能差异**:不同模型的响应速度和质量可能有差异
3. **配额管理**:确保备用模型有足够的配额
4. **测试验证**:定期测试备用模型的可用性
## 项目级路由
`~/.claude/projects/<project-id>/claude-code-router.json` 中为每个项目配置路由:

View File

@@ -5,7 +5,152 @@ sidebar_position: 4
# 转换器
转换器用于适配不同提供商之间的 API 差异
转换器适配不同 LLM 提供商 API 差异的核心机制。它们在不同格式之间转换请求和响应,处理认证,并管理提供商特定的功能
## 理解转换器
### 什么是转换器?
转换器是一个插件,它可以:
- **转换请求**:从统一格式转换为提供商特定格式
- **转换响应**:从提供商格式转换回统一格式
- **处理认证**:为提供商 API 处理认证
- **修改请求**:添加或调整参数
### 数据流
```
┌─────────────────┐
│ 传入请求 │ (来自 Claude Code 的 Anthropic 格式)
└────────┬────────┘
┌─────────────────────────────────┐
│ transformRequestOut │ ← 将传入请求解析为统一格式
└────────┬────────────────────────┘
┌─────────────────────────────────┐
│ UnifiedChatRequest │
└────────┬────────────────────────┘
┌─────────────────────────────────┐
│ transformRequestIn (可选) │ ← 在发送前修改统一请求
└────────┬────────────────────────┘
┌─────────────────────────────────┐
│ 提供商 API 调用 │
└────────┬────────────────────────┘
┌─────────────────────────────────┐
│ transformResponseIn (可选) │ ← 将提供商响应转换为统一格式
└────────┬────────────────────────┘
┌─────────────────────────────────┐
│ transformResponseOut (可选) │ ← 将统一响应转换为 Anthropic 格式
└────────┬────────────────────────┘
┌─────────────────┐
│ 传出响应 │ (返回给 Claude Code 的 Anthropic 格式)
└─────────────────┘
```
### 转换器接口
所有转换器都实现以下接口:
```typescript
interface Transformer {
// 将统一请求转换为提供商特定格式
transformRequestIn?: (
request: UnifiedChatRequest,
provider: LLMProvider,
context: TransformerContext
) => Promise<Record<string, any>>;
// 将提供商请求转换为统一格式
transformRequestOut?: (
request: any,
context: TransformerContext
) => Promise<UnifiedChatRequest>;
// 将提供商响应转换为统一格式
transformResponseIn?: (
response: Response,
context?: TransformerContext
) => Promise<Response>;
// 将统一响应转换为提供商格式
transformResponseOut?: (
response: Response,
context: TransformerContext
) => Promise<Response>;
// 自定义端点路径(可选)
endPoint?: string;
// 转换器名称(用于自定义转换器)
name?: string;
// 自定义认证处理器(可选)
auth?: (
request: any,
provider: LLMProvider,
context: TransformerContext
) => Promise<any>;
// Logger 实例(自动注入)
logger?: any;
}
```
### 关键类型
#### UnifiedChatRequest
```typescript
interface UnifiedChatRequest {
messages: UnifiedMessage[];
model: string;
max_tokens?: number;
temperature?: number;
stream?: boolean;
tools?: UnifiedTool[];
tool_choice?: any;
reasoning?: {
effort?: ThinkLevel; // "none" | "low" | "medium" | "high"
max_tokens?: number;
enabled?: boolean;
};
}
```
#### UnifiedMessage
```typescript
interface UnifiedMessage {
role: "user" | "assistant" | "system" | "tool";
content: string | null | MessageContent[];
tool_calls?: Array<{
id: string;
type: "function";
function: {
name: string;
arguments: string;
};
}>;
tool_call_id?: string;
thinking?: {
content: string;
signature?: string;
};
}
```
## 内置转换器
@@ -15,13 +160,20 @@ sidebar_position: 4
```json
{
"transformer": {
"use": ["anthropic"]
}
"transformers": [
{
"name": "anthropic",
"providers": ["deepseek", "groq"]
}
]
}
```
如果只使用这一个转换器,它将直接透传请求和响应(您可以用来接入其他支持 Anthropic 端点的服务商)。
**功能:**
- 在 Anthropic 消息格式和 OpenAI 格式之间转换
- 处理工具调用和工具结果
- 支持思考/推理内容块
- 管理流式响应
### deepseek
@@ -29,169 +181,421 @@ sidebar_position: 4
```json
{
"transformer": {
"use": ["deepseek"]
}
"transformers": [
{
"name": "deepseek",
"providers": ["deepseek"]
}
]
}
```
**功能:**
- DeepSeek 特定的推理格式
- 处理响应中的 `reasoning_content`
- 支持思考预算令牌
### gemini
用于 Google Gemini API 的转换器:
```json
{
"transformer": {
"use": ["gemini"]
}
}
```
### groq
用于 Groq API 的转换器:
```json
{
"transformer": {
"use": ["groq"]
}
}
```
### openrouter
用于 OpenRouter API 的转换器:
```json
{
"transformer": {
"use": ["openrouter"]
}
}
```
OpenRouter 转换器还支持 `provider` 路由参数,以指定 OpenRouter 应使用哪些底层提供商:
```json
{
"transformer": {
"use": ["openrouter"],
"moonshotai/kimi-k2": {
"use": [
["openrouter", {
"provider": {
"only": ["moonshotai/fp8"]
}
}]
]
"transformers": [
{
"name": "gemini",
"providers": ["gemini"]
}
}
]
}
```
### maxtoken
设置特定的 `max_tokens`
限制请求中的 max_tokens
```json
{
"transformer": {
"use": [
["maxtoken", { "max_tokens": 65536 }]
]
"transformers": [
{
"name": "maxtoken",
"options": {
"max_tokens": 8192
},
"models": ["deepseek,deepseek-chat"]
}
]
}
```
### customparams
向请求中注入自定义参数:
```json
{
"transformers": [
{
"name": "customparams",
"options": {
"include_reasoning": true,
"custom_header": "value"
}
}
]
}
```
## 创建自定义转换器
### 简单转换器:修改请求
最简单的转换器只修改发送到提供商之前的请求。
**示例:为所有请求添加自定义头**
```javascript
// custom-header-transformer.js
module.exports = class CustomHeaderTransformer {
name = 'custom-header';
constructor(options) {
this.headerName = options?.headerName || 'X-Custom-Header';
this.headerValue = options?.headerValue || 'default-value';
}
async transformRequestIn(request, provider, context) {
// 添加自定义头(将被 auth 方法使用)
request._customHeaders = {
[this.headerName]: this.headerValue
};
return request;
}
async auth(request, provider) {
const headers = {
'authorization': `Bearer ${provider.apiKey}`,
...request._customHeaders
};
return {
body: request,
config: { headers }
};
}
};
```
**在配置中使用:**
```json
{
"transformers": [
{
"name": "custom-header",
"path": "/path/to/custom-header-transformer.js",
"options": {
"headerName": "X-My-Header",
"headerValue": "my-value"
}
}
]
}
```
### 中级转换器:请求/响应转换
此示例展示如何在不同 API 格式之间转换。
**示例Mock API 格式转换器**
```javascript
// mockapi-transformer.js
module.exports = class MockAPITransformer {
name = 'mockapi';
endPoint = '/v1/chat'; // 自定义端点
// 从 MockAPI 格式转换为统一格式
async transformRequestOut(request, context) {
const messages = request.conversation.map(msg => ({
role: msg.sender,
content: msg.text
}));
return {
messages,
model: request.model_id,
max_tokens: request.max_tokens,
temperature: request.temp
};
}
// 从统一格式转换为 MockAPI 格式
async transformRequestIn(request, provider, context) {
return {
model_id: request.model,
conversation: request.messages.map(msg => ({
sender: msg.role,
text: typeof msg.content === 'string' ? msg.content : JSON.stringify(msg.content)
})),
max_tokens: request.max_tokens || 4096,
temp: request.temperature || 0.7
};
}
// 将 MockAPI 响应转换为统一格式
async transformResponseIn(response, context) {
const data = await response.json();
const unifiedResponse = {
id: data.request_id,
object: 'chat.completion',
created: data.timestamp,
model: data.model,
choices: [{
index: 0,
message: {
role: 'assistant',
content: data.reply.text
},
finish_reason: data.stop_reason
}],
usage: {
prompt_tokens: data.tokens.input,
completion_tokens: data.tokens.output,
total_tokens: data.tokens.input + data.tokens.output
}
};
return new Response(JSON.stringify(unifiedResponse), {
status: response.status,
statusText: response.statusText,
headers: { 'Content-Type': 'application/json' }
});
}
};
```
### 高级转换器:流式响应处理
此示例展示如何处理流式响应。
**示例:向流式响应添加自定义元数据**
```javascript
// streaming-metadata-transformer.js
module.exports = class StreamingMetadataTransformer {
name = 'streaming-metadata';
constructor(options) {
this.metadata = options?.metadata || {};
this.logger = null; // 将由系统注入
}
async transformResponseOut(response, context) {
const contentType = response.headers.get('Content-Type');
// 处理流式响应
if (contentType?.includes('text/event-stream')) {
return this.transformStream(response, context);
}
// 处理非流式响应
return response;
}
async transformStream(response, context) {
const decoder = new TextDecoder();
const encoder = new TextEncoder();
const transformedStream = new ReadableStream({
start: async (controller) => {
const reader = response.body.getReader();
let buffer = '';
try {
while (true) {
const { done, value } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
const lines = buffer.split('\n');
buffer = lines.pop() || '';
for (const line of lines) {
if (!line.trim() || !line.startsWith('data: ')) {
controller.enqueue(encoder.encode(line + '\n'));
continue;
}
const data = line.slice(6).trim();
if (data === '[DONE]') {
controller.enqueue(encoder.encode(line + '\n'));
continue;
}
try {
const chunk = JSON.parse(data);
// 添加自定义元数据
if (chunk.choices && chunk.choices[0]) {
chunk.choices[0].metadata = this.metadata;
}
// 记录日志以便调试
this.logger?.debug({
chunk,
context: context.req.id
}, '转换流式数据块');
const modifiedLine = `data: ${JSON.stringify(chunk)}\n\n`;
controller.enqueue(encoder.encode(modifiedLine));
} catch (parseError) {
// 如果解析失败,透传原始行
controller.enqueue(encoder.encode(line + '\n'));
}
}
}
} catch (error) {
this.logger?.error({ error }, '流式转换错误');
controller.error(error);
} finally {
controller.close();
reader.releaseLock();
}
}
});
return new Response(transformedStream, {
status: response.status,
statusText: response.statusText,
headers: {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive'
}
});
}
};
```
### 真实示例:推理内容转换器
这是基于代码库中实际的 `reasoning.transformer.ts`
```typescript
// reasoning-transformer.ts
import { Transformer, TransformerOptions } from "@musistudio/llms";
export class ReasoningTransformer implements Transformer {
static TransformerName = "reasoning";
enable: boolean;
constructor(private readonly options?: TransformerOptions) {
this.enable = this.options?.enable ?? true;
}
// 转换请求以添加推理参数
async transformRequestIn(request: UnifiedChatRequest): Promise<UnifiedChatRequest> {
if (!this.enable) {
request.thinking = {
type: "disabled",
budget_tokens: -1,
};
request.enable_thinking = false;
return request;
}
if (request.reasoning) {
request.thinking = {
type: "enabled",
budget_tokens: request.reasoning.max_tokens,
};
request.enable_thinking = true;
}
return request;
}
// 转换响应以将 reasoning_content 转换为 thinking 格式
async transformResponseOut(response: Response): Promise<Response> {
if (!this.enable) return response;
const contentType = response.headers.get("Content-Type");
// 处理非流式响应
if (contentType?.includes("application/json")) {
const jsonResponse = await response.json();
if (jsonResponse.choices[0]?.message.reasoning_content) {
jsonResponse.thinking = {
content: jsonResponse.choices[0].message.reasoning_content
};
}
return new Response(JSON.stringify(jsonResponse), {
status: response.status,
statusText: response.statusText,
headers: response.headers,
});
}
// 处理流式响应
if (contentType?.includes("stream")) {
// [流式转换代码在这里]
// 参见代码库中的完整实现
}
return response;
}
}
```
### tooluse
## 转换器注册
通过 `tool_choice` 参数优化某些模型的工具使用:
### 方法 1静态名称基于类
```json
{
"transformer": {
"use": ["tooluse"]
在 TypeScript/ES6 中创建转换器时使用:
```typescript
export class MyTransformer implements Transformer {
static TransformerName = "my-transformer";
async transformRequestIn(request: UnifiedChatRequest): Promise<any> {
// 转换逻辑
return request;
}
}
```
### reasoning
### 方法 2实例名称基于实例
用于处理 `reasoning_content` 字段
用于 JavaScript 转换器
```json
{
"transformer": {
"use": ["reasoning"]
```javascript
module.exports = class MyTransformer {
constructor(options) {
this.name = 'my-transformer';
this.options = options;
}
}
```
### sampling
用于处理采样信息字段,如 `temperature``top_p``top_k``repetition_penalty`
```json
{
"transformer": {
"use": ["sampling"]
async transformRequestIn(request, provider, context) {
// 转换逻辑
return request;
}
}
```
### enhancetool
对 LLM 返回的工具调用参数增加一层容错处理(注意:这会导致不再流式返回工具调用信息):
```json
{
"transformer": {
"use": ["enhancetool"]
}
}
```
### cleancache
清除请求中的 `cache_control` 字段:
```json
{
"transformer": {
"use": ["cleancache"]
}
}
```
### vertex-gemini
处理使用 Vertex 鉴权的 Gemini API
```json
{
"transformer": {
"use": ["vertex-gemini"]
}
}
};
```
## 应用转换器
### 全局应用
### 全局应用(提供商级别)
应用于提供商的所有请求:
提供商的所有请求应用
```json
{
"Providers": [
{
"name": "deepseek",
"api_base_url": "https://api.deepseek.com/chat/completions",
"api_key": "your-api-key",
"transformer": {
"use": ["deepseek"]
}
"NAME": "deepseek",
"HOST": "https://api.deepseek.com",
"APIKEY": "your-api-key",
"transformers": ["anthropic"]
}
]
}
@@ -199,84 +603,189 @@ OpenRouter 转换器还支持 `provider` 路由参数,以指定 OpenRouter 应
### 模型特定应用
应用于特定模型:
```json
{
"name": "deepseek",
"transformer": {
"use": ["deepseek"],
"deepseek-chat": {
"use": ["tooluse"]
}
}
}
```
### 传递选项
某些转换器接受选项:
```json
{
"transformer": {
"use": [
["maxtoken", { "max_tokens": 8192 }]
]
}
}
```
## 自定义转换器
创建自定义转换器插件:
1. 创建转换器文件:
```javascript
module.exports = {
name: 'my-transformer',
transformRequest: async (req, config) => {
// 修改请求
return req;
},
transformResponse: async (res, config) => {
// 修改响应
return res;
}
};
```
2. 在配置中加载:
应用于特定模型:
```json
{
"transformers": [
{
"path": "/path/to/transformer.js",
"name": "maxtoken",
"options": {
"key": "value"
"max_tokens": 8192
},
"models": ["deepseek,deepseek-chat"]
}
]
}
```
注意:模型格式为 `provider,model`(例如 `deepseek,deepseek-chat`)。
### 全局转换器(所有提供商)
将转换器应用于所有提供商:
```json
{
"transformers": [
{
"name": "custom-logger",
"path": "/path/to/custom-logger.js"
}
]
}
```
### 传递选项
某些转换器接受配置选项:
```json
{
"transformers": [
{
"name": "maxtoken",
"options": {
"max_tokens": 8192
}
},
{
"name": "customparams",
"options": {
"custom_param_1": "value1",
"custom_param_2": 42
}
}
]
}
```
## 实验性转换器
## 最佳实践
### gemini-cli实验性
### 1. 不可变性
通过 Gemini CLI 对 Gemini 的非官方支持。
始终创建新对象而不是修改现有对象:
### qwen-cli实验性
```javascript
// 不好的做法
async transformRequestIn(request) {
request.max_tokens = 4096;
return request;
}
通过 Qwen CLI 对 qwen3-coder-plus 的非官方支持。
// 好的做法
async transformRequestIn(request) {
return {
...request,
max_tokens: request.max_tokens || 4096
};
}
```
### rovo-cli实验性
### 2. 错误处理
通过 Atlassian Rovo Dev CLI 对 GPT-5 的非官方支持。
始终优雅地处理错误:
```javascript
async transformResponseIn(response) {
try {
const data = await response.json();
// 处理数据
return new Response(JSON.stringify(processedData), {
status: response.status,
headers: response.headers
});
} catch (error) {
this.logger?.error({ error }, '转换失败');
// 如果转换失败,返回原始响应
return response;
}
}
```
### 3. 日志记录
使用注入的 logger 进行调试:
```javascript
async transformRequestIn(request, provider, context) {
this.logger?.debug({
model: request.model,
provider: provider.name
}, '转换请求');
// 转换逻辑
return modifiedRequest;
}
```
### 4. 流处理
处理流式响应时,始终:
- 使用缓冲区处理不完整的数据块
- 正确释放 reader 锁
- 处理流中的错误
- 完成时关闭 controller
```javascript
const transformedStream = new ReadableStream({
start: async (controller) => {
const reader = response.body.getReader();
let buffer = '';
try {
while (true) {
const { done, value } = await reader.read();
if (done) break;
// 处理流...
}
} catch (error) {
controller.error(error);
} finally {
controller.close();
reader.releaseLock();
}
}
});
```
### 5. 上下文使用
`context` 参数包含有用信息:
```javascript
async transformRequestIn(request, provider, context) {
// 访问请求 ID
const requestId = context.req.id;
// 访问原始请求
const originalRequest = context.req.original;
// 转换逻辑
}
```
## 测试转换器
### 手动测试
1. 将转换器添加到配置
2. 启动服务器:`ccr restart`
3. 检查日志:`tail -f ~/.claude-code-router/logs/ccr-*.log`
4. 发出测试请求
5. 验证输出
### 调试技巧
- 添加日志记录以跟踪转换步骤
- 使用流式和非流式请求进行测试
- 使用无效输入验证错误处理
- 检查错误时是否返回原始响应
## 下一步
- [高级主题](/zh/docs/advanced/custom-router) - 高级路由自定义
- [Agent](/zh/docs/advanced/agents) - 使用 Agent 扩展功能
- [高级主题](/docs/server/advanced/custom-router) - 高级路由自定义
- [Agents](/docs/server/advanced/agents) - 使用 agents 扩展
- [核心包](/docs/server/intro) - 了解 @musistudio/llms

View File

@@ -11,17 +11,103 @@ Claude Code Router Server 是一个核心服务组件,负责将 Claude Code
## 架构概述
```
┌─────────────┐ ┌──────────────────┐ ┌──────────────┐
│ Claude Code │────▶│ CCR Server │────▶│ LLM Provider │
│ Client │ │ (Router + │ │ (OpenAI/ │
└─────────────┘ │ Transformer) │ │ Gemini/etc)│
└──────────────────┘ └──────────────┘
┌─────────────┐ ┌─────────────────────────────┐ ┌──────────────┐
│ Claude Code │────▶│ CCR Server │────▶│ LLM Provider │
│ Client │ │ ┌─────────────────────┐ │ │ (OpenAI/ │
└─────────────┘ │ │ @musistudio/llms │ │ │ Gemini/etc)│
│ │ (核心包) │ │ └──────────────┘
│ │ - 请求转换 │ │
│ │ - 响应转换 │ │
│ │ - 认证处理 │ │
│ └─────────────────────┘ │
│ │
│ - 路由逻辑 │
│ - Agent 系统 │
│ - 配置管理 │
└─────────────────────────────┘
├─ Web UI
├─ Config API
└─ Logs API
```
## 核心包:@musistudio/llms
服务器构建于 **@musistudio/llms** 之上,这是一个通用的 LLM API 转换库,提供了核心的请求/响应转换能力。
### 什么是 @musistudio/llms
`@musistudio/llms` 是一个独立的 npm 包(`@musistudio/llms`),负责处理:
- **API 格式转换**:在不同的 LLM 提供商 API 之间转换Anthropic、OpenAI、Gemini 等)
- **请求/响应转换**:将请求和响应转换为统一格式
- **认证处理**:管理不同提供商的认证方法
- **流式响应支持**:处理来自不同提供商的流式响应
- **转换器系统**:提供可扩展的架构来添加新的提供商
### 核心概念
#### 1. 统一请求/响应格式
核心包定义了统一格式(`UnifiedChatRequest``UnifiedChatResponse`),抽象了提供商特定的差异:
```typescript
interface UnifiedChatRequest {
messages: UnifiedMessage[];
model: string;
max_tokens?: number;
temperature?: number;
stream?: boolean;
tools?: UnifiedTool[];
tool_choice?: any;
reasoning?: {
effort?: ThinkLevel;
max_tokens?: number;
enabled?: boolean;
};
}
```
#### 2. 转换器接口
所有转换器都实现一个通用接口:
```typescript
interface Transformer {
transformRequestIn?: (request: UnifiedChatRequest, provider: LLMProvider, context: TransformerContext) => Promise<any>;
transformRequestOut?: (request: any, context: TransformerContext) => Promise<UnifiedChatRequest>;
transformResponseIn?: (response: Response, context?: TransformerContext) => Promise<Response>;
transformResponseOut?: (response: Response, context: TransformerContext) => Promise<Response>;
endPoint?: string;
name?: string;
auth?: (request: any, provider: LLMProvider, context: TransformerContext) => Promise<any>;
}
```
#### 3. 内置转换器
核心包包含以下转换器:
- **anthropic**Anthropic API 格式
- **openai**OpenAI API 格式
- **gemini**Google Gemini API 格式
- **deepseek**DeepSeek API 格式
- **groq**Groq API 格式
- **openrouter**OpenRouter API 格式
- 等等...
### 与 CCR Server 的集成
CCR server 通过以下方式集成 `@musistudio/llms`
1. **转换器服务**`packages/core/src/services/transformer.ts`):管理转换器的注册和实例化
2. **提供商配置**:将提供商配置映射到核心包的 LLMProvider 接口
3. **请求管道**:在请求处理过程中按顺序应用转换器
4. **自定义转换器**:支持加载外部转换器插件
### 版本和更新
`@musistudio/llms` 的当前版本是 `1.0.51`。它作为独立的 npm 包发布,可以独立使用或作为 CCR Server 的一部分使用。
## 核心功能
### 1. 请求路由

View File

@@ -8,11 +8,11 @@
"description": "The alt text of navbar logo"
},
"item.label.Documentation": {
"message": "Documentation",
"message": "文档",
"description": "Navbar item with label Documentation"
},
"item.label.Blog": {
"message": "Blog",
"message": "博客",
"description": "Navbar item with label Blog"
},
"item.label.GitHub": {