npx skills add smithery/majiayu000 --skill provider-development
majiayu000/litellm-rs · Archived
provider-development
LiteLLM-RS Provider 开发指南。用于添加新 provider(Tier 1 catalog 条目或 Tier 2 代码实现)、统一错误处理,或把旧错误枚举迁移到 ProviderError。
Installation
npx skills add majiayu000/litellm-rs --skill provider-development
Stronger alternatives
This repository is archived — consider an actively maintained alternative.
Use when writing or updating a SpecRail product spec for a linked issue. Produces the numbered …
1 installsUse when comparing a SpecRail implementation, diff, or PR against its linked issue, product spe…
1 installsUse when triaging a GitHub issue or issue-like request in a SpecRail-governed repository. Handl…
1 installsUse when implementing a SpecRail-governed issue after the implementation gate. Executes the sco…
1 installsSimilar popular skills
Related neighbors and high-traction skills in the same topics — useful to compare before installing.
This skill should be used when the user asks to "create an agent", "add an agent", "write a sub…
18.1K installsThis skill should be used when the user wants to "create a skill", "add a skill to plugin", "wr…
18K installsThis skill should be used when the user asks to "create a slash command", "add a command", "wri…
13.5K installsThis skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/…
13.2K installsDevelop, debug, and deploy Apify Actors - serverless cloud programs for web scraping, automatio…
10.3K installsThis skill should be used when the user asks to "create an agent", "add an agent", "write a sub…
6.2K installsAlso in this package
Other skills from majiayu000/litellm-rs · top by installs.
npx skills add majiayu000/litellm-rs
More details
Agent compatibility
Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.
Also listed on
Alternate registries and mirrors of this skill.
Repository health
main
Package contents
Files included with this skill beyond the listing page.
-
skill md
SKILL.md15,098 B -
docs
SUMMARY.md208 B
History
- First seen on skills.sh
- First recorded snapshot · 1 installs
SKILL.md
LiteLLM-RS Provider 开发指南
架构概述
本项目采用统一错误 + 闭集 Provider 枚举派发。LLMProvider 统一各实现的方法签名,但路由部署存放的是具体 Provider 枚举,而不是 dyn LLMProvider trait object。
当前架构层次
┌────────────────────────────────────────────────────────┐
│ 网关层 (Gateway) │
│ LiteLLMError = GatewayError(18 个变体) │
│ - 别名定义: core/types/errors/litellm.rs │
│ - 枚举定义: utils/error/gateway_error/types.rs │
│ - 处理路由、配置、认证等网关级错误 │
└────────────────────────────────────────────────────────┘
↓
┌────────────────────────────────────────────────────────┐
│ Provider 层 │
│ ProviderError(经 unified_provider 模块导出, │
│ 定义于 unified_provider_error.rs) │
│ - 统一 provider 错误,24 个变体 │
│ - 每个变体包含 provider: &'static str 字段 │
│ - 丰富的工厂方法和上下文信息 │
└────────────────────────────────────────────────────────┘
↓
┌────────────────────────────────────────────────────────┐
│ 各 Provider 实现(两层结构) │
│ - Tier 1: registry/catalog.rs 目录条目(def_chat 等),│
│ 经 OpenAILikeProvider 路由,无专属代码 │
│ - Tier 2: 代码型 provider 目录, │
│ 实现 LLMProvider 并注册到闭集 Provider 枚举 │
└────────────────────────────────────────────────────────┘
Provider 数量随版本演进,不在此硬编码。枚举方法:
# 两个计数都会包含各自的 helper 定义,因此分别减 1
grep -c 'def_chat(' src/core/providers/registry/catalog.rs
grep -c 'def_local_chat(' src/core/providers/registry/catalog.rs
# 排除基础设施目录后再人工确认代码型 provider
ls -d src/core/providers/*/ | grep -vE '/(base|factory|macros|registry)/'
当前派发契约
Provider 定义在 src/core/providers/mod.rs,由本地 dispatchprovider! 宏把 方法转发给具体实现。宏分别维护 sync、asyncerr、value 和 async_direct 四类展开臂;Router 的 deployment 持有这个枚举,因此 Tier 2 provider 仅实现 LLMProvider 还不够;还必须添加枚举变体、dispatch/factory 分支及模块 注册。Tier 1 catalog provider 复用现有的 Provider::OpenAILike 变体,所以无需 为每个兼容端点增加枚举成员。
LLMProvider 使用原生 async fn 且没有关联错误类型;所有可失败的方法直接 返回 ProviderError。当前 trait 不是路由层的动态插件边界。真实的 trait object 仅出现在局部边界,例如 Box<dyn ErrorMapper<ProviderError>> 和 boxed streaming Stream。仓库没有可支持具体纳秒、二进制大小或编译耗时对比的基准,因此本文 不提供这些数字。
统一错误类型详解
ProviderError 变体
pub enum ProviderError {
// 认证与授权
Authentication { provider, message },
// 限流与配额
RateLimit { provider, message, retry_after, rpm_limit, tpm_limit, current_usage },
QuotaExceeded { provider, message },
// 模型与请求
ModelNotFound { provider, model },
InvalidRequest { provider, message },
// 网络与可用性
Network { provider, message },
Timeout { provider, message },
ProviderUnavailable { provider, message },
// 功能支持
NotSupported { provider, feature },
NotImplemented { provider, feature },
FeatureDisabled { provider, feature },
// 内容与长度
ContextLengthExceeded { provider, max, actual },
TokenLimitExceeded { provider, message },
ContentFiltered { provider, reason, policy_violations, potentially_retryable },
// 配置与序列化
Configuration { provider, message },
Serialization { provider, message },
// 高级错误
ApiError { provider, status, message },
DeploymentError { provider, deployment, message },
ResponseParsing { provider, message },
RoutingError { provider, attempted_providers, message },
TransformationError { provider, from_format, to_format, message },
Streaming { provider, stream_type, position, last_chunk, message },
Cancelled { provider, operation_type, cancellation_reason },
Other { provider, message },
}
工厂方法使用
// 基础工厂方法
ProviderError::authentication("openai", "Invalid API key")
ProviderError::rate_limit("anthropic", Some(60))
ProviderError::model_not_found("groq", "llama-invalid")
ProviderError::network("azure", "Connection timeout")
// 增强工厂方法
ProviderError::rate_limit_with_limits("openai", Some(60), Some(100), Some(40000), None)
ProviderError::context_length_exceeded("claude", 100000, 150000)
ProviderError::content_filtered("openai", "Violence detected", Some(vec!["violence"]), Some(false))
ProviderError::streaming_error("fireworks", "chat", Some(42), None, "Connection reset")
添加新 Provider
先判断 Tier
- Tier 1(OpenAI 兼容、无需定制逻辑):只需在
src/core/providers/registry/catalog.rs加一条defchat("name", "Display Name", "https://api.example.com/v1", "NAMEAPIKEY"),工厂自动经OpenAILikeProvider路由,无需新建目录(本地部署类用deflocal_chat)。 - Tier 2(自定义请求转换、认证签名、非 SSE 流式协议、专属模型元数据等):按下文创建代码目录。
目录结构
src/core/providers/my_provider/
├── mod.rs # 模块导出
├── config.rs # ProviderConfig 实现
├── provider.rs # LLMProvider 实现
├── model_info.rs # 模型定义和能力
└── streaming.rs # SSE 流解析(可选)
配置实现
实现 crate::core::traits::provider::ProviderConfig(定义于 src/core/traits/provider/config.rs,必需方法:validate / apikey / apibase / timeout / max_retries)。参考真实实现:src/core/providers/cloudflare/config.rs。
// config.rs
use crate::core::traits::provider::ProviderConfig;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MyProviderConfig {
pub api_key: Option<String>,
pub api_base: Option<String>,
#[serde(default = "default_timeout")]
pub timeout: u64,
#[serde(default = "default_max_retries")]
pub max_retries: u32,
}
fn default_timeout() -> u64 { 60 }
fn default_max_retries() -> u32 { 3 }
impl Default for MyProviderConfig {
fn default() -> Self {
Self {
api_key: std::env::var("MY_PROVIDER_API_KEY").ok(),
api_base: None,
timeout: default_timeout(),
max_retries: default_max_retries(),
}
}
}
impl ProviderConfig for MyProviderConfig {
fn validate(&self) -> Result<(), String> {
self.validate_standard("my_provider")
}
fn api_key(&self) -> Option<&str> { self.api_key.as_deref() }
fn api_base(&self) -> Option<&str> { self.api_base.as_deref() }
fn timeout(&self) -> std::time::Duration { std::time::Duration::from_secs(self.timeout) }
fn max_retries(&self) -> u32 { self.max_retries }
}
Provider 传输实现(使用统一错误)
LLMProvider trait(src/core/traits/provider/llmprovider/traitdefinition.rs)没有关联类型:方法签名直接使用 ProviderError,错误映射通过 geterrormapper() 提供;trait 方法是原生 async fn,实现时无需 #[asynctrait] 宏。下面是完整的传输 helper;chatcompletion 还需要把成功 JSON 转成 ChatResponse,可参考 cloudflare/provider.rs。
// provider.rs
use super::{get_models, MyProviderConfig};
use crate::core::providers::base::{header, BaseConfig, GlobalPoolManager, HttpMethod};
use crate::core::providers::unified_provider::ProviderError;
use crate::core::traits::provider::ProviderConfig;
use crate::core::types::{chat::ChatRequest, model::ModelInfo};
use serde_json::Value;
use std::sync::Arc;
const PROVIDER_NAME: &str = "my_provider";
#[derive(Debug, Clone)]
pub struct MyProvider {
config: MyProviderConfig,
pool_manager: Arc<GlobalPoolManager>,
models: Vec<ModelInfo>,
}
impl MyProvider {
pub async fn new(config: MyProviderConfig) -> Result<Self, ProviderError> {
config.validate()
.map_err(|e| ProviderError::configuration(PROVIDER_NAME, e))?;
let http_config = BaseConfig {
api_key: config.api_key.clone(),
api_base: config.api_base.clone(),
timeout: config.timeout,
max_retries: config.max_retries,
..BaseConfig::default()
};
let pool_manager = Arc::new(GlobalPoolManager::new_for_provider(
PROVIDER_NAME,
http_config,
)?);
Ok(Self { config, pool_manager, models: get_models() })
}
async fn execute_chat_json(&self, request: &ChatRequest) -> Result<Value, ProviderError> {
let api_key = self.config.api_key()
.ok_or_else(|| ProviderError::authentication(PROVIDER_NAME, "API key required"))?;
let api_base = self.config.api_base()
.ok_or_else(|| ProviderError::configuration(PROVIDER_NAME, "API base required"))?;
let url = format!("{}/chat/completions", api_base.trim_end_matches('/'));
let body = serde_json::to_value(request)
.map_err(|e| ProviderError::serialization(PROVIDER_NAME, e.to_string()))?;
let headers = vec![
header("Authorization", format!("Bearer {}", api_key)),
header("Content-Type", "application/json".to_string()),
];
let response = self.pool_manager
.execute_request(&url, HttpMethod::POST, headers, Some(body))
.await?;
let status = response.status();
if !status.is_success() {
let response_body = response.text().await
.map_err(|e| ProviderError::network(PROVIDER_NAME, e.to_string()))?;
return Err(self.map_http_error(status.as_u16(), &response_body));
}
let response_body = response.bytes().await
.map_err(|e| ProviderError::network(PROVIDER_NAME, e.to_string()))?;
serde_json::from_slice(&response_body)
.map_err(|e| ProviderError::response_parsing(PROVIDER_NAME, e.to_string()))
}
fn map_http_error(&self, status: u16, body: &str) -> ProviderError {
use crate::core::providers::shared::parse_retry_after_from_body;
match status {
401 => ProviderError::authentication(PROVIDER_NAME, "Invalid API key"),
404 => ProviderError::model_not_found(PROVIDER_NAME, body),
429 => ProviderError::rate_limit(PROVIDER_NAME, parse_retry_after_from_body(body)),
400 => ProviderError::invalid_request(PROVIDER_NAME, body),
500..=599 => ProviderError::provider_unavailable(PROVIDER_NAME, body),
_ => ProviderError::api_error(PROVIDER_NAME, status, body),
}
}
}
模型信息
// model_info.rs
use crate::core::types::model::{ModelInfo, ProviderCapability};
pub fn get_models() -> Vec<ModelInfo> {
vec![
ModelInfo {
id: "my-model-large".to_string(),
name: "My Model Large".to_string(),
provider: "my_provider".to_string(),
max_context_length: 128000,
max_output_length: Some(4096),
supports_streaming: true,
supports_tools: true,
supports_multimodal: false,
input_cost_per_1k_tokens: Some(0.01),
output_cost_per_1k_tokens: Some(0.03),
currency: "USD".to_string(),
capabilities: vec![
ProviderCapability::ChatCompletion,
ProviderCapability::ChatCompletionStream,
ProviderCapability::ToolCalling,
],
..Default::default()
},
]
}
注册 Provider
// src/core/providers/my_provider/mod.rs
mod config;
mod model_info;
mod provider;
pub use config::MyProviderConfig;
pub use provider::MyProvider;
pub use model_info::get_models;
Tier 2 provider 接入闭合枚举(无法运行时注册,需以下 crate 内改动,参考 cloudflare 的接线方式):
- 在
src/core/providers/mod.rs声明模块并给Provider增加带相同 feature gate 的变体。 - 把该变体加入
dispatchprovider!的sync、asyncerr、value、asyncdirect四个@expand臂,并补齐Provider::name()和providertype()分支。 - 在
providertype.rs增加ProviderType变体,并加入allnoncustomprovider_types();字符串转换由 registry 元数据派生,不要另写一套别名表。 - 在
registry/types.rs的PROVIDERTYPEREGISTRY增加 canonical name、aliases、catalog_backed和正确的ProviderDispatchKind。
feature-gated 原生实现应复用或新增 cfg-sensitive dispatch-kind helper,分别表达启用与禁用时的模式;registry entry 本身没有 feature 字段。
- 在
factory/builder.rs增加配置构造器,在factory/registry.rs增加工厂 match 分支;module、Provider、dispatch 与 factory wiring 使用同步的 cfg gate。 - 更新 provider-type/registry lifecycle、factory support 与 feature-on/off 测试,确认别名解析、支持状态和构造路径一致。
References
- [reference/migration-and-checklists.md](reference/migration-and-checklists.md) — 迁移现有 provider 到统一错误的步骤、错误映射对照表与迁移检查清单
- [reference/industry-notes-and-faq.md](reference/industry-notes-and-faq.md) — 行业架构选择参考与常见问题解答