# 提供商管理

本页覆盖提供商目录加载、模型元数据、别名、路由、成本控制、后备行为、REST 端点、频道命令和安全说明。

## 包含的主题

- 动态提供商加载
- 模型目录
- 模型别名
- 每个 Agent 的模型覆盖
- 模型路由
- 成本追踪
- 后备提供商
- API 端点
- 频道命令
- 环境变量汇总
- 安全说明

---

## 动态提供商加载

官方提供商定义从注册表预安装到 `~/.librefang/providers/`。要添加或覆盖提供商，请在同一目录下放置自定义 `.toml` 文件。每个文件定义一个提供商：

```toml
# ~/.librefang/providers/my-endpoint.toml
id = "my-endpoint"
display_name = "My Private Endpoint"
driver = "openai_compatible"
base_url = "https://llm.internal.company.com/v1"
api_key_env = "MY_ENDPOINT_KEY"
key_required = true

[[models]]
id = "my-model-7b"
display_name = "My Model 7B"
tier = "Balanced"
context_window = 32768
max_output_tokens = 4096
input_cost_per_m = 0.0
output_cost_per_m = 0.0
supports_tools = true
supports_vision = false
```

`~/.librefang/providers/` 中的文件在启动时加载，并与内置提供商一起合并到目录中。

### 自定义图像生成 provider

不在内置列表（`openai`、`gemini`、`elevenlabs`、`minimax`、`google_tts`）的媒体驱动名以前会失败 `"Unknown media provider"`。现在配置了 URL 的自定义 provider 会落到通用 OpenAI 兼容图像驱动：

```toml
# config.toml
[provider_urls]
volcengine = "https://open.volcengineapi.com/v1"
tongyi     = "https://dashscope.aliyuncs.com/compatible-mode/v1"
```

```bash
export VOLCENGINE_API_KEY="sk-..."
export TONGYI_API_KEY="sk-..."
```

驱动期望标准的 OpenAI Images API 请求/响应形状（`/images/generations` 端点，返回 `b64_json` 或 `url`）。设 `[media] image_provider = "volcengine"`（或在 `[provider_urls]` 里用的任何 id）把图像生成调用路由过去。

### 驱动侧文件上传

Moonshot（Kimi）驱动在转发请求到 `/v1/chat/completions` 之前先把附件上传到 `/v1/files`，所以带 image / PDF / text 附件的消息端到端就能工作，不用你按附件做封送。文件写到 `std::env::temp_dir()`，上传前做了 content-type 校验、大小限制、文件名净化。这是透明的 — 不需要额外配置；像平时一样通过 `POST /api/agents/{id}/upload` 或 dashboard 聊天附文件即可。

### 提供商区域

部分提供商提供区域特定的端点。区域在注册表 TOML 文件中定义，并支持可选的 `api_key_env` 覆盖：

```toml
# 在提供商的注册表 TOML 中：
[provider.regions.intl]
base_url = "https://dashscope-intl.aliyuncs.com/compatible-mode/v1"

[provider.regions.china]
base_url = "https://api.minimaxi.com/v1"
api_key_env = "MINIMAX_CN_API_KEY"    # 可选：覆盖默认的 API 密钥环境变量
```

在 `config.toml` 中选择区域：

```toml
[provider_regions]
qwen = "intl"
minimax = "china"
```

**优先级：** 区域选择在显式的 `[provider_urls]` 条目*之前*应用。如果同一提供商同时设置了两者，`provider_urls` 优先。

---

## 模型目录

所有 230+ 个内置模型的完整目录，按提供商排序。价格单位为每百万 token。

| # | 模型 ID | 显示名称 | 提供商 | 层级 | 上下文窗口 | 最大输出 | 输入 $/M | 输出 $/M | 工具 | 视觉 |
|---|----------|-------------|----------|------|---------------|------------|-----------|------------|-------|--------|
| 1 | `claude-opus-4-20250514` | Claude Opus 4 | anthropic | 旗舰 | 200,000 | 32,000 | $15.00 | $75.00 | 是 | 是 |
| 2 | `claude-sonnet-4-20250514` | Claude Sonnet 4 | anthropic | 智能 | 200,000 | 64,000 | $3.00 | $15.00 | 是 | 是 |
| 3 | `claude-haiku-4-5-20251001` | Claude Haiku 4.5 | anthropic | 快速 | 200,000 | 8,192 | $0.25 | $1.25 | 是 | 是 |
| 4 | `gpt-4.1` | GPT-4.1 | openai | 旗舰 | 1,047,576 | 32,768 | $2.00 | $8.00 | 是 | 是 |
| 5 | `gpt-4o` | GPT-4o | openai | 智能 | 128,000 | 16,384 | $2.50 | $10.00 | 是 | 是 |
| 6 | `o3-mini` | o3-mini | openai | 智能 | 200,000 | 100,000 | $1.10 | $4.40 | 是 | 否 |
| 7 | `gpt-4.1-mini` | GPT-4.1 Mini | openai | 平衡 | 1,047,576 | 32,768 | $0.40 | $1.60 | 是 | 是 |
| 8 | `gpt-4o-mini` | GPT-4o Mini | openai | 快速 | 128,000 | 16,384 | $0.15 | $0.60 | 是 | 是 |
| 9 | `gpt-4.1-nano` | GPT-4.1 Nano | openai | 快速 | 1,047,576 | 32,768 | $0.10 | $0.40 | 是 | 否 |
| 10 | `gemini-2.5-pro` | Gemini 2.5 Pro | gemini | 旗舰 | 1,048,576 | 65,536 | $1.25 | $10.00 | 是 | 是 |
| 11 | `gemini-2.5-flash` | Gemini 2.5 Flash | gemini | 智能 | 1,048,576 | 65,536 | $0.15 | $0.60 | 是 | 是 |
| 12 | `gemini-2.0-flash` | Gemini 2.0 Flash | gemini | 快速 | 1,048,576 | 8,192 | $0.10 | $0.40 | 是 | 是 |
| 13 | `deepseek-chat` | DeepSeek V3 | deepseek | 智能 | 64,000 | 8,192 | $0.27 | $1.10 | 是 | 否 |
| 14 | `deepseek-reasoner` | DeepSeek R1 | deepseek | 智能 | 64,000 | 8,192 | $0.55 | $2.19 | 否 | 否 |
| 15 | `llama-3.3-70b-versatile` | Llama 3.3 70B | groq | 平衡 | 128,000 | 32,768 | $0.059 | $0.079 | 是 | 否 |
| 16 | `mixtral-8x7b-32768` | Mixtral 8x7B | groq | 平衡 | 32,768 | 4,096 | $0.024 | $0.024 | 是 | 否 |
| 17 | `llama-3.1-8b-instant` | Llama 3.1 8B | groq | 快速 | 128,000 | 8,192 | $0.05 | $0.08 | 是 | 否 |
| 18 | `gemma2-9b-it` | Gemma 2 9B | groq | 快速 | 8,192 | 4,096 | $0.02 | $0.02 | 否 | 否 |
| 19 | `openrouter/google/gemini-2.5-flash` | Gemini 2.5 Flash (OpenRouter) | openrouter | 智能 | 1,048,576 | 65,536 | $0.15 | $0.60 | 是 | 是 |
| 20 | `openrouter/anthropic/claude-sonnet-4` | Claude Sonnet 4 (OpenRouter) | openrouter | 智能 | 200,000 | 64,000 | $3.00 | $15.00 | 是 | 是 |
| 21 | `openrouter/openai/gpt-4o` | GPT-4o (OpenRouter) | openrouter | 智能 | 128,000 | 16,384 | $2.50 | $10.00 | 是 | 是 |
| 22 | `openrouter/deepseek/deepseek-chat` | DeepSeek V3 (OpenRouter) | openrouter | 智能 | 128,000 | 32,768 | $0.14 | $0.28 | 是 | 否 |
| 23 | `openrouter/meta-llama/llama-3.3-70b-instruct` | Llama 3.3 70B (OpenRouter) | openrouter | 平衡 | 128,000 | 32,768 | $0.39 | $0.39 | 是 | 否 |
| 24 | `openrouter/qwen/qwen-2.5-72b-instruct` | Qwen 2.5 72B (OpenRouter) | openrouter | 平衡 | 128,000 | 32,768 | $0.36 | $0.36 | 是 | 否 |
| 25 | `openrouter/google/gemini-2.5-pro` | Gemini 2.5 Pro (OpenRouter) | openrouter | 旗舰 | 1,048,576 | 65,536 | $1.25 | $10.00 | 是 | 是 |
| 26 | `openrouter/mistralai/mistral-large-latest` | Mistral Large (OpenRouter) | openrouter | 智能 | 128,000 | 8,192 | $2.00 | $6.00 | 是 | 否 |
| 27 | `openrouter/google/gemma-2-9b-it` | Gemma 2 9B (OpenRouter) | openrouter | 快速 | 8,192 | 4,096 | $0.00 | $0.00 | 否 | 否 |
| 28 | `openrouter/deepseek/deepseek-r1` | DeepSeek R1 (OpenRouter) | openrouter | 旗舰 | 128,000 | 32,768 | $0.55 | $2.19 | 否 | 否 |
| 29 | `mistral-large-latest` | Mistral Large | mistral | 智能 | 128,000 | 8,192 | $2.00 | $6.00 | 是 | 否 |
| 30 | `codestral-latest` | Codestral | mistral | 智能 | 32,000 | 8,192 | $0.30 | $0.90 | 是 | 否 |
| 31 | `mistral-small-latest` | Mistral Small | mistral | 快速 | 128,000 | 8,192 | $0.10 | $0.30 | 是 | 否 |
| 32 | `meta-llama/Meta-Llama-3.1-405B-Instruct-Turbo` | Llama 3.1 405B (Together) | together | 旗舰 | 130,000 | 4,096 | $3.50 | $3.50 | 是 | 否 |
| 33 | `Qwen/Qwen2.5-72B-Instruct-Turbo` | Qwen 2.5 72B (Together) | together | 智能 | 32,768 | 4,096 | $0.20 | $0.60 | 是 | 否 |
| 34 | `mistralai/Mixtral-8x22B-Instruct-v0.1` | Mixtral 8x22B (Together) | together | 平衡 | 65,536 | 4,096 | $0.60 | $0.60 | 是 | 否 |
| 35 | `accounts/fireworks/models/llama-v3p1-405b-instruct` | Llama 3.1 405B (Fireworks) | fireworks | 旗舰 | 131,072 | 16,384 | $3.00 | $3.00 | 是 | 否 |
| 36 | `accounts/fireworks/models/mixtral-8x22b-instruct` | Mixtral 8x22B (Fireworks) | fireworks | 平衡 | 65,536 | 4,096 | $0.90 | $0.90 | 是 | 否 |
| 37 | `llama3.2` | Llama 3.2 (Ollama) | ollama | 本地 | 128,000 | 4,096 | $0.00 | $0.00 | 是 | 否 |
| 38 | `mistral:latest` | Mistral (Ollama) | ollama | 本地 | 32,768 | 4,096 | $0.00 | $0.00 | 是 | 否 |
| 39 | `phi3` | Phi-3 (Ollama) | ollama | 本地 | 128,000 | 4,096 | $0.00 | $0.00 | 否 | 否 |
| 40 | `vllm-local` | vLLM Local Model | vllm | 本地 | 32,768 | 4,096 | $0.00 | $0.00 | 是 | 否 |
| 41 | `lmstudio-local` | LM Studio Local Model | lmstudio | 本地 | 32,768 | 4,096 | $0.00 | $0.00 | 是 | 否 |
| 42 | `sonar-pro` | Sonar Pro | perplexity | 智能 | 200,000 | 8,192 | $3.00 | $15.00 | 否 | 否 |
| 43 | `sonar` | Sonar | perplexity | 平衡 | 128,000 | 8,192 | $1.00 | $5.00 | 否 | 否 |
| 44 | `command-r-plus` | Command R+ | cohere | 智能 | 128,000 | 4,096 | $2.50 | $10.00 | 是 | 否 |
| 45 | `command-r` | Command R | cohere | 平衡 | 128,000 | 4,096 | $0.15 | $0.60 | 是 | 否 |
| 46 | `jamba-1.5-large` | Jamba 1.5 Large | ai21 | 智能 | 256,000 | 4,096 | $2.00 | $8.00 | 是 | 否 |
| 47 | `cerebras/llama3.3-70b` | Llama 3.3 70B (Cerebras) | cerebras | 平衡 | 128,000 | 8,192 | $0.06 | $0.06 | 是 | 否 |
| 48 | `cerebras/llama3.1-8b` | Llama 3.1 8B (Cerebras) | cerebras | 快速 | 128,000 | 8,192 | $0.01 | $0.01 | 是 | 否 |
| 49 | `sambanova/llama-3.3-70b` | Llama 3.3 70B (SambaNova) | sambanova | 平衡 | 128,000 | 8,192 | $0.06 | $0.06 | 是 | 否 |
| 50 | `grok-2` | Grok 2 | xai | 智能 | 131,072 | 32,768 | $2.00 | $10.00 | 是 | 是 |
| 51 | `grok-2-mini` | Grok 2 Mini | xai | 快速 | 131,072 | 32,768 | $0.30 | $0.50 | 是 | 否 |
| 52 | `hf/meta-llama/Llama-3.3-70B-Instruct` | Llama 3.3 70B (HF) | huggingface | 平衡 | 128,000 | 4,096 | $0.30 | $0.30 | 否 | 否 |
| 53 | `replicate/meta-llama-3.3-70b-instruct` | Llama 3.3 70B (Replicate) | replicate | 平衡 | 128,000 | 4,096 | $0.40 | $0.40 | 否 | 否 |

**模型层级：**

| 层级 | 描述 | 典型用途 |
|------|------------|------------|
| **旗舰** | 能力最强，成本最高 | 编排、架构设计、安全审计 |
| **智能** | 推理能力强，成本适中 | 编码、代码审查、研究、分析 |
| **平衡** | 性价比好 | 规划、写作、DevOps、日常任务 |
| **快速** | 云端推理最便宜 | 运维、翻译、简单问答、健康检查 |
| **本地** | 自托管，零成本 | 隐私优先、离线使用、开发环境 |

**说明：**
- 本地提供商（Ollama、vLLM、LM Studio）在运行时自动发现模型。你下载并启动的任何模型都会以 `Local` 层级和零成本合并到目录中。
- 以上条目是 230+ 个内置模型的代表性子集。完整目录包含每个提供商的更多模型，以及因安装环境而异的运行时自动发现模型。

---

## 模型别名

全部 23 个别名解析为规范模型 ID。别名不区分大小写。

| 别名 | 解析为 |
|-------|------------|
| `sonnet` | `claude-sonnet-4-20250514` |
| `claude-sonnet` | `claude-sonnet-4-20250514` |
| `haiku` | `claude-haiku-4-5-20251001` |
| `claude-haiku` | `claude-haiku-4-5-20251001` |
| `opus` | `claude-opus-4-20250514` |
| `claude-opus` | `claude-opus-4-20250514` |
| `gpt4` | `gpt-4o` |
| `gpt4o` | `gpt-4o` |
| `gpt4-mini` | `gpt-4o-mini` |
| `flash` | `gemini-2.5-flash` |
| `gemini-flash` | `gemini-2.5-flash` |
| `gemini-pro` | `gemini-2.5-pro` |
| `deepseek` | `deepseek-chat` |
| `llama` | `llama-3.3-70b-versatile` |
| `llama-70b` | `llama-3.3-70b-versatile` |
| `mixtral` | `mixtral-8x7b-32768` |
| `mistral` | `mistral-large-latest` |
| `codestral` | `codestral-latest` |
| `grok` | `grok-2` |
| `grok-mini` | `grok-2-mini` |
| `sonar` | `sonar-pro` |
| `jamba` | `jamba-1.5-large` |
| `command-r` | `command-r-plus` |

你可以在任何接受模型 ID 的地方使用别名：配置文件、REST API 调用、聊天命令以及模型路由配置。

---

## 每个 Agent 的模型覆盖

`config.toml` 中的每个 Agent 都可以指定自己的模型，覆盖全局默认值：

```toml
# 全局默认模型
[agents.defaults]
model = "claude-sonnet-4-20250514"

# 逐 Agent 覆盖：使用别名或完整模型 ID
[[agents]]
name = "orchestrator"
model = "opus"                      # claude-opus-4-20250514 的别名

[[agents]]
name = "ops"
model = "llama-3.3-70b-versatile"   # 便宜的 Groq 模型，用于简单运维

[[agents]]
name = "coder"
model = "gemini-2.5-flash"          # 快速 + 便宜 + 100 万上下文

[[agents]]
name = "researcher"
model = "sonar-pro"                 # Perplexity，内置网页搜索

# 也可以在 agent manifest TOML 中固定模型
[[agents]]
name = "production-bot"
pinned_model = "claude-sonnet-4-20250514"  # 永不自动路由
```

当 Agent manifest 设置了 `pinned_model` 时，该 Agent 始终使用指定模型，忽略路由配置。此功能用于**稳定模式**（`KernelMode::Stable`），在该模式下模型被冻结以确保生产可靠性。

---

## 模型路由

LibreFang 可以自动为每个查询选择能够处理该查询的最便宜模型。这通过 `ModelRoutingConfig` 在逐 Agent 级别配置。

### 工作原理

1. **ModelRouter** 根据启发式规则对每个传入的 `CompletionRequest` 进行评分
2. 评分映射到一个 **TaskComplexity** 层级：`Simple`、`Medium` 或 `Complex`
3. 每个层级有一个预配置的模型

### 评分启发式规则

| 信号 | 权重 | 逻辑 |
|--------|--------|-------|
| 总消息长度 | 每 ~4 个字符 1 分 | 粗略的 token 近似 |
| 工具可用性 | 每个定义的工具 +20 | 有工具意味着多步骤工作 |
| 代码标记 | 每个标记 +30 | 反引号、`fn`、`def`、`class`、`import`、`function`、`async`、`await`、`struct`、`impl`、`return` |
| 对话深度 | 每条超过 10 条的消息 +15 | 深层上下文 = 更难的推理 |
| 系统提示长度 | 每 10 个字符（超过 500）+1 | 长系统提示意味着复杂任务 |

### 阈值

| 复杂度 | 分数范围 | 默认模型 |
|-----------|-------------|---------------|
| Simple | `score < 100` | `claude-haiku-4-5-20251001` |
| Medium | `100 <= score < 500` | `claude-sonnet-4-20250514` |
| Complex | `score >= 500` | `claude-sonnet-4-20250514` |

### 配置

模型路由**仅在 agent manifest 中逐 Agent 配置**，不是 `~/.librefang/config.toml` 的顶层字段。如果把 `[routing]` 放到 `config.toml` 顶层会被忽略（内核日志会打印 `Unknown config field (ignored) field="routing"`）。

```toml
# 在 agent manifest 文件中
[routing]
simple_model = "claude-haiku-4-5-20251001"
medium_model = "gemini-2.5-flash"
complex_model = "claude-sonnet-4-20250514"
simple_threshold = 100
complex_threshold = 500
```

路由器还与模型目录集成：
- **`validate_models()`** 检查所有配置的模型 ID 是否存在于目录中
- **`resolve_aliases()`** 将别名展开为规范 ID（例如 `"sonnet"` 变为 `"claude-sonnet-4-20250514"`）

---

## 成本追踪

LibreFang 追踪每次 LLM 调用的成本，并可以强制执行逐 Agent 的消费配额。

### 每次响应的成本估算

每次 LLM 调用后，成本按以下公式计算：

```
cost = (input_tokens / 1,000,000) * input_rate + (output_tokens / 1,000,000) * output_rate
```

`MeteringEngine` 首先检查**模型目录**获取精确定价。如果未找到模型，则回退到模式匹配的启发式规则。

### 成本费率（每百万 token）

| 模型匹配模式 | 输入 $/M | 输出 $/M |
|--------------|-----------|------------|
| `*haiku*` | $0.25 | $1.25 |
| `*sonnet*` | $3.00 | $15.00 |
| `*opus*` | $15.00 | $75.00 |
| `gpt-4o-mini` | $0.15 | $0.60 |
| `gpt-4o` | $2.50 | $10.00 |
| `gpt-4.1-nano` | $0.10 | $0.40 |
| `gpt-4.1-mini` | $0.40 | $1.60 |
| `gpt-4.1` | $2.00 | $8.00 |
| `o3-mini` | $1.10 | $4.40 |
| `gemini-2.5-pro` | $1.25 | $10.00 |
| `gemini-2.5-flash` | $0.15 | $0.60 |
| `gemini-2.0-flash` | $0.10 | $0.40 |
| `deepseek-reasoner` / `deepseek-r1` | $0.55 | $2.19 |
| `*deepseek*` | $0.27 | $1.10 |
| `*cerebras*` | $0.06 | $0.06 |
| `*sambanova*` | $0.06 | $0.06 |
| `*replicate*` | $0.40 | $0.40 |
| `*llama*` / `*mixtral*` | $0.05 | $0.10 |
| `*qwen*` | $0.20 | $0.60 |
| `mistral-large*` | $2.00 | $6.00 |
| `*mistral*`（其他） | $0.10 | $0.30 |
| `command-r-plus` | $2.50 | $10.00 |
| `command-r` | $0.15 | $0.60 |
| `sonar-pro` | $3.00 | $15.00 |
| `*sonar*`（其他） | $1.00 | $5.00 |
| `grok-2-mini` / `grok-mini` | $0.30 | $0.50 |
| `*grok*`（其他） | $2.00 | $10.00 |
| `*jamba*` | $2.00 | $8.00 |
| 默认（未知） | $1.00 | $3.00 |

### 配额强制执行

每次 LLM 调用都会检查配额。如果 Agent 超出每小时限额，调用会被拒绝并返回 `QuotaExceeded` 错误。

```toml
# config.toml 中的逐 Agent 配额
[[agents]]
name = "chatbot"
[agents.resources]
max_cost_per_hour_usd = 5.00   # 每小时上限 $5
```

使用量页脚（启用时）会在每次响应后附加成本信息：

```
> Cost: $0.0042 | Tokens: 1,200 in / 340 out | Model: claude-sonnet-4-20250514
```

---

## 后备提供商

`FallbackDriver` 将多个 LLM 驱动包装成一个链。如果主驱动失败，会自动尝试链中的下一个驱动。

### 行为

- 成功时：立即返回
- **速率限制/过载**错误（`429`、`529`）：向上冒泡以进行重试逻辑（不进行故障转移，因为主驱动应在退避后重试）
- **所有其他错误**：记录警告并尝试链中的下一个驱动
- 所有驱动都失败时：返回最后一个错误

### 配置

后备链在 Agent manifest 或 `config.toml` 中配置。当 Agent 处于**稳定模式**（`KernelMode::Stable`）或为提高可靠性配置了多个提供商时，`FallbackDriver` 会自动使用。

```toml
# 示例：主用 Anthropic，后备 Gemini，然后 Groq
[[agents]]
name = "production-bot"
model = "claude-sonnet-4-20250514"
fallback_models = ["gemini-2.5-flash", "llama-3.3-70b-versatile"]
```

后备驱动创建的链为：`AnthropicDriver -> GeminiDriver -> OpenAIDriver(Groq)`。

---

## API 端点

### 列出所有模型

```
GET /api/models
```

返回包含元数据、定价和功能标志的完整模型目录。

**响应：**
```json
[
  {
    "id": "claude-sonnet-4-20250514",
    "display_name": "Claude Sonnet 4",
    "provider": "anthropic",
    "tier": "Smart",
    "context_window": 200000,
    "max_output_tokens": 64000,
    "input_cost_per_m": 3.0,
    "output_cost_per_m": 15.0,
    "supports_tools": true,
    "supports_vision": true,
    "supports_streaming": true,
    "aliases": ["sonnet", "claude-sonnet"]
  }
]
```

### 获取指定模型

```
GET /api/models/{id}
```

返回单个模型条目。支持规范 ID 和别名。

```
GET /api/models/sonnet
GET /api/models/claude-sonnet-4-20250514
```

### 列出别名

```
GET /api/models/aliases
```

返回所有别名到规范 ID 的映射。

**响应：**
```json
{
  "sonnet": "claude-sonnet-4-20250514",
  "haiku": "claude-haiku-4-5-20251001",
  "flash": "gemini-2.5-flash",
  "grok": "grok-2"
}
```

### 列出提供商

```
GET /api/providers
```

返回所有 49 个提供商及其认证状态和模型数量。

**响应：**
```json
[
  {
    "id": "anthropic",
    "display_name": "Anthropic",
    "api_key_env": "ANTHROPIC_API_KEY",
    "base_url": "https://api.anthropic.com",
    "key_required": true,
    "auth_status": "Configured",
    "model_count": 3
  },
  {
    "id": "ollama",
    "display_name": "Ollama",
    "api_key_env": "OLLAMA_API_KEY",
    "base_url": "http://localhost:11434/v1",
    "key_required": false,
    "auth_status": "NotRequired",
    "model_count": 5
  }
]
```

认证状态值：`Configured`（已配置）、`Missing`（缺失）、`NotRequired`（无需配置）。

### 设置提供商 API 密钥

```
POST /api/providers/{name}/key
Content-Type: application/json

{ "api_key": "sk-..." }
```

在运行时为提供商配置 API 密钥（存储为 `Zeroizing<String>`，值被丢弃时自动从内存中擦除）。

### 删除提供商 API 密钥

```
DELETE /api/providers/{name}/key
```

删除提供商已配置的 API 密钥。

### 测试提供商连接

```
POST /api/providers/{name}/test
```

发送一个最小化的测试请求，以验证提供商可达且 API 密钥有效。

---

## 频道命令

在任何频道中均可使用以下两个聊天命令来检查模型和提供商：

### `/models`

列出所有可用模型及其层级、提供商和上下文窗口。仅显示已配置认证（或无需认证）的提供商下的模型。

```
/models
```

示例输出：
```
Available models (12):

Frontier:
  claude-opus-4-20250514 (Anthropic) — 200K ctx
  gemini-2.5-pro (Google Gemini) — 1M ctx

Smart:
  claude-sonnet-4-20250514 (Anthropic) — 200K ctx
  gemini-2.5-flash (Google Gemini) — 1M ctx
  deepseek-chat (DeepSeek) — 64K ctx

Balanced:
  llama-3.3-70b-versatile (Groq) — 128K ctx

Fast:
  claude-haiku-4-5-20251001 (Anthropic) — 200K ctx
  gemini-2.0-flash (Google Gemini) — 1M ctx

Local:
  llama3.2 (Ollama) — 128K ctx
```

### `/providers`

列出所有 49 个提供商及其认证状态。

```
/providers
```

示例输出：
```
LLM Providers (49):

  Anthropic          ANTHROPIC_API_KEY       Configured    3 models
  OpenAI             OPENAI_API_KEY          Missing       6 models
  Google Gemini      GEMINI_API_KEY          Configured    3 models
  DeepSeek           DEEPSEEK_API_KEY        Missing       2 models
  Groq               GROQ_API_KEY            Configured    4 models
  Ollama             (no key needed)         Ready         3 models
  vLLM               (no key needed)         Ready         1 model
  LM Studio          (no key needed)         Ready         1 model
  ...
```

---

## 环境变量汇总

所有提供商环境变量的快速参考：

| 提供商 | 环境变量 | 是否必需 |
|----------|---------|----------|
| Anthropic | `ANTHROPIC_API_KEY` | 是 |
| OpenAI | `OPENAI_API_KEY` | 是 |
| Google Gemini | `GEMINI_API_KEY` 或 `GOOGLE_API_KEY` | 是 |
| DeepSeek | `DEEPSEEK_API_KEY` | 是 |
| Groq | `GROQ_API_KEY` | 是 |
| OpenRouter | `OPENROUTER_API_KEY` | 是 |
| Mistral AI | `MISTRAL_API_KEY` | 是 |
| Together AI | `TOGETHER_API_KEY` | 是 |
| Fireworks AI | `FIREWORKS_API_KEY` | 是 |
| Ollama | `OLLAMA_API_KEY` | 否 |
| vLLM | `VLLM_API_KEY` | 否 |
| LM Studio | `LMSTUDIO_API_KEY` | 否 |
| Perplexity AI | `PERPLEXITY_API_KEY` | 是 |
| Cohere | `COHERE_API_KEY` | 是 |
| AI21 Labs | `AI21_API_KEY` | 是 |
| Cerebras | `CEREBRAS_API_KEY` | 是 |
| SambaNova | `SAMBANOVA_API_KEY` | 是 |
| Hugging Face | `HF_API_KEY` | 是 |
| xAI | `XAI_API_KEY` | 是 |
| Replicate | `REPLICATE_API_TOKEN` | 是 |
| Claude Code | `ANTHROPIC_API_KEY` | 是 |
| NVIDIA NIM | `NVIDIA_API_KEY` | 是 |
| Voyage AI | `VOYAGE_API_KEY` | 是 |
| Anyscale | `ANYSCALE_API_KEY` | 是 |
| DeepInfra | `DEEPINFRA_API_KEY` | 是 |
| Azure OpenAI | `AZURE_OPENAI_API_KEY`、`AZURE_OPENAI_ENDPOINT` | 是 |
| Amazon Bedrock | `AWS_ACCESS_KEY_ID`、`AWS_SECRET_ACCESS_KEY`、`AWS_REGION` | 是 |
| Google Vertex AI | `GOOGLE_APPLICATION_CREDENTIALS`、`VERTEX_PROJECT`、`VERTEX_LOCATION` | 是 |

---

## 安全说明

- 所有 API 密钥存储为 `Zeroizing<String>` -- 当值从内存中丢弃时，密钥内容会被自动用零覆盖。
- 认证检测（`detect_auth()`）仅检查 `std::env::var()` 是否存在 -- 不会读取或记录实际的密钥值。
- 通过 REST API 设置的提供商 API 密钥（`POST /api/providers/{name}/key`）遵循相同的零化策略。
- 健康检查端点（`/api/health`）不会暴露提供商认证状态或 API 密钥。详细信息位于 `/api/health/detail`，需要认证才能访问。
- 所有 `DriverConfig` 和 `KernelConfig` 结构体的 `Debug` 实现均包含密钥脱敏 -- API 密钥在日志中显示为 `"***"`。

---

## Provider 故障转移链

**源码：** `librefang-llm-drivers/src/drivers/fallback_chain.rs`

`FallbackChain` 允许你配置一个按顺序尝试的 LLM Provider 列表。当某个 provider 失败时，运行时会对失败类型分类，决定是切换到下一个 provider 还是立即返回错误。

### 故障转移原因

LibreFang 在决定是否向前切换之前，会对每次失败进行分类：

| `FailoverReason` | 说明 | 是否转移？ |
|---|---|---|
| `RateLimit` | HTTP 429 或 `x-ratelimit-remaining: 0` | 是 — 尝试下一个 provider |
| `Timeout` | 请求超过配置的超时时限 | 是 |
| `ServerError` | HTTP 5xx 响应 | 是 |
| `ModelNotFound` | 请求的模型 ID 返回 HTTP 404 | 是 |
| `AuthError` | HTTP 401 / 403 | 否 — 密钥配置错误，立即停止 |
| `Unknown` | 其他任何错误 | 是 |

`AuthError` 故意不向前转移——密钥缺失或被吊销需要运维人员处理，静默重试会掩盖问题。

### 配置

在 `~/.librefang/config.toml` 中通过 `[[providers.fallback_chain]]` 定义链：

```toml
[[providers.fallback_chain]]
name = "anthropic"
model = "claude-sonnet-4-5"

[[providers.fallback_chain]]
name = "openai"
model = "gpt-4o"

[[providers.fallback_chain]]
name = "openai-compatible"
base_url = "http://localhost:11434/v1"
model = "llama3.1:8b"
```

LibreFang 按顺序尝试列表中的每个 provider。若所有 provider 均因可转移原因失败，则返回最后一个 provider 的错误。

### 与 Credential Pool 的交互

故障转移链中的每个条目都可以拥有由 [Credential Pool](#credential-pool) 管理的多个密钥。当一个密钥的速率限制耗尽时，pool 会在链切换到下一个 provider 之前先轮转到该 provider 的下一个密钥。

---

## Credential Pool

**源码：** `librefang-llm-drivers/src/credential_pool.rs`

`CredentialPool` 管理单个 provider 的多个 API Key，并自动在它们之间轮转。这可以在无需手动干预的情况下扩展有效速率限制，并在个别密钥临时耗尽时保持服务连续性。

### 轮转策略

| 策略 | 行为 |
|---|---|
| `FillFirst` | 始终使用第一个未耗尽的密钥，按顺序跳过已耗尽的密钥。 |
| `RoundRobin` | 按固定循环依次轮换密钥，跳过已耗尽的密钥。 |
| `Random` | 每次请求随机选择一个未耗尽的密钥。 |
| `LeastUsed` | 选择总请求次数最少的未耗尽密钥。 |

默认策略为 `RoundRobin`。

### 配置

```toml
[providers.anthropic]
rotation_strategy = "round_robin"  # fill_first | round_robin | random | least_used

[[providers.anthropic.keys]]
key = "sk-ant-key-1"

[[providers.anthropic.keys]]
key = "sk-ant-key-2"

[[providers.anthropic.keys]]
key = "sk-ant-key-3"
```

### 耗尽与冷却

当响应头报告剩余配额为零时（`x-ratelimit-remaining-requests: 0` 或 `x-ratelimit-remaining-tokens: 0`），密钥被标记为**已耗尽**，所有轮转策略均会跳过它。

**1 小时**后，已耗尽的密钥自动重新加入活跃池。此冷却时长在当前版本不可配置；与大多数 OpenAI 兼容 provider 使用的标准窗口对应。

若池中所有密钥同时耗尽，`CredentialPool` 返回 `RateLimit` 错误，触发向故障转移链中下一个 provider 切换（如已配置）。

### 用量追踪

池中每个密钥追踪：
- 总请求次数
- 总 token 数（提示词 + 补全）
- 耗尽时间戳（如当前已耗尽）

这些计数器仅保存在内存中，守护进程重启后重置。持久用量追踪通过预算账本（`/api/providers/{name}/usage`）提供。

---

## 速率限制追踪器

**源码：** `librefang-llm-drivers/src/rate_limit_tracker.rs`

每次 LLM API 响应后，LibreFang 将 provider 的速率限制响应头解析为 `RateLimitSnapshot`。该快照供 Credential Pool 检测耗尽状态，并在控制台和 CLI 中展示给运维人员。

### 解析的响应头

LibreFang 识别主流 provider 的 **21 种响应头变体**：

| 响应头 | 含义 |
|---|---|
| `x-ratelimit-limit-requests` | 窗口请求上限 |
| `x-ratelimit-remaining-requests` | 当前窗口剩余请求数 |
| `x-ratelimit-reset-requests` | 请求配额重置时间 |
| `x-ratelimit-limit-tokens` | 窗口 token 上限 |
| `x-ratelimit-remaining-tokens` | 当前窗口剩余 token 数 |
| `x-ratelimit-reset-tokens` | token 配额重置时间 |
| `ratelimit-limit` | 通用综合限制（部分 provider） |
| `ratelimit-remaining` | 通用综合剩余 |
| `ratelimit-reset` | 通用重置时间 |
| `retry-after` | 安全重试等待秒数（429 响应） |
| `x-rate-limit-limit-requests` | 备用拼写变体 |
| `x-rate-limit-remaining-requests` | 备用拼写变体 |
| … 以及 9 个 provider 专属变体 | |

### ASCII 进度条

CLI 和控制台为每个活跃 provider 显示紧凑进度条：

```
anthropic  [████████░░░░░░░░░░░░]  req: 847/1000  tok: 42.3K/90K
openai     [██████████████░░░░░░]  req: 712/1000  tok: 61.1K/90K
```

进度条宽度为 20 字符，每个填充块（`█`）代表 5% 的已用配额。空进度条表示该 provider 未返回配额数据。

### 访问快照

```bash
# Current rate-limit snapshot for all providers
curl http://127.0.0.1:4545/api/providers/rate-limits
```

```json
{
  "anthropic": {
    "requests": { "limit": 1000, "remaining": 153, "reset_in_seconds": 34 },
    "tokens":   { "limit": 90000, "remaining": 47700, "reset_in_seconds": 34 }
  }
}
```

provider 未返回对应响应头时，字段值为 `null`。
