首页
/ LiteLLM Rust 核心五 Crate 架构与路由模块规范:深入 litellm-rust 工作区

LiteLLM Rust 核心五 Crate 架构与路由模块规范:深入 litellm-rust 工作区

2026-09-06 11:09:29作者:裴锟轩Denise

本文基于仓库中的 litellm-rust/AGENTS.md 及其配套文档,系统讲解 LiteLLM Rust 实现(litellm-rust)的五 crate 工作区划分、无环依赖方向、顶层路由(route)模块的目录组织规范、新增 crate 的约束机制,以及 Rust 风格约定。读完本文,你可以准确理解 litellm-rust 的分层设计意图,知道一个顶层 LiteLLM 调用在 Rust 侧由哪些文件承接、新 provider/路由应放在哪里,以及如何通过内置的 workspace 校验测试与 CI 检查约束代码结构。

工作区总览:五个 Crate,各司其职

litellm-rust 是 LiteLLM 的 Rust 核心实现工作区。litellm-rust/AGENTS.md 开宗明义地定义了一条核心原则:

一个 crate 是一个"层"(layer)或"共享基础"(shared foundation),而不是一条路由(route)。

路由(如 ocrrealtimechat)和 provider(如 mistralopenai)都是层内部的模块,不是独立的 crate。工作区恰好由以下五个 crate 组成(该表格为原文档的核心内容,逐条继承):

Crate 角色
litellm-core Rust 版 LiteLLM SDK。每个顶层调用一个公开入口(如 messages::messages()),拥有类型定义、请求/响应转换、provider 解析、鉴权以及 provider HTTP 调用本身。"调用它,拿到类型化响应。"
litellm-config 配置加载边界(config-loading boundary)。返回解析后的核心部署数据,可选地把加载过程委托给 Python。
litellm-ai-gateway axum 服务器(位于 server feature 之后)加 WebSocket hosts。负责把 HTTP/WS 请求翻译为 core 入口调用;不拥有任何 provider 逻辑,也不持有 handler
litellm-python-interop 领域无关(domain-neutral)的 PyO3 基础层,负责 GIL 处理与类型化的 Python/Serde 转换。
litellm-python-bridge 暴露 LiteLLM Rust API 给 Python SDK 的 PyO3 cdylib。拥有 API 注册、领域接线和 Python 异常映射。

无环依赖方向

原文档明确了五个 crate 之间的依赖方向,且保证无环(acyclic):

litellm-config        ──依赖──▶  litellm-core
litellm-ai-gateway    ──依赖──▶  litellm-config + litellm-core
litellm-python-bridge ──依赖──▶  领域层(core/config/ai-gateway) + litellm-python-interop
litellm-python-interop  不依赖任何 LiteLLM 领域 crate

这一点可以从 litellm-rust/Cargo.toml 中得到直接印证:workspace 的 members 恰好列出 crates/corecrates/configcrates/ai-gatewaycrates/python-interopcrates/python-bridge 五项(resolver = "2")。各 crate 的实际依赖声明与上述方向完全一致:

  • litellm-rust/crates/config/Cargo.tomllitellm-config 依赖 litellm-core,并通过可选 feature python = ["dep:pyo3"] 支持把配置加载委托给嵌入式 Python 解释器;
  • litellm-rust/crates/ai-gateway/Cargo.tomllitellm-ai-gateway 同时依赖 litellm-core(开启 bedrock-auth feature)与 litellm-config,axum 0.7 是可选依赖(feature server),二进制 litellm-ai-gateway 声明了 required-features = ["server"]——即"服务器代码藏在 feature 之后"在构建系统层面就得到了强制;
  • litellm-rust/crates/python-bridge/Cargo.tomlcrate-type = ["cdylib"]、库名 _native,依赖三个领域层与 litellm-python-interop,pyo3 0.29 并默认启用 abi3-py310,印证其"cdylib 边界"定位;
  • litellm-rust/crates/python-interop/Cargo.toml:仅依赖 pyo3pythonizeserde,不含任何 LiteLLM 领域 crate,满足"interop 不依赖领域层"的约束。

此外,workspace 级配置值得注意:litellm-rust/Cargo.toml 声明 edition = "2024"rust-version = "1.88",网络栈统一为 reqwest 0.12default-features = false 并显式启用 rustls-tls),release profile 采用 opt-level = 3lto = "thin"codegen-units = 1strip = "symbols"——这是一套面向发布轮子(portable wheels)与 Linux 镜像的完整构建优化。

路由(Route)在哪里:core/src/<route>/ 参考结构

litellm-rust 中,一个顶层 LiteLLM 调用对应 crates/core/src/<route>/ 下的一个模块,原文档以 messages(Anthropic Messages 调用,即 Python litellm.messages() 的 Rust 等价物)为参考样板,规定了如下文件布局:

core/src/messages/
  mod.rs             # pub async fn messages(..) -> CoreResult<..>  (+ messages_stream for SSE)
  types.rs           # 请求/响应类型,如 MessagesRequest
  transformation.rs  # provider 模板 trait
  prepare.rs         # provider 解析、鉴权头、URL
  handler.rs         # provider 调用
  client.rs          # 共享的 reqwest 客户端

litellm-rust/crates/core/src/messages/ 的实际文件列表可以看到,真实目录与规范完全吻合(另有一个 tests.rs 单元测试文件),并额外多出一个 common_utils.rs。入口函数在 litellm-rust/crates/core/src/messages/mod.rs 中一目了然:

pub async fn messages(request: MessagesRequest<'_>) -> Result<AnthropicMessagesResponse, Error> {
    execute_messages_provider_call(request).await
}

pub async fn messages_stream(request: MessagesRequest<'_>) -> Result<reqwest::Response, Error> {
    execute_messages_provider_stream(request).await
}

两个要点与原文档呼应:

  1. 同步/流式成对出现:非流式的 messages() 返回类型化响应;messages_stream() 返回上游的 reqwest::Response 原始流,由 host(网关)自行拼接(splice)到其调用者——这正是"core 拥有整个调用、host 只做翻译"的边界在 API 形状上的体现;
  2. 入口即语义:模块的公开函数与路由同名(messagesmessages_stream),与配套文档 litellm-rust/CLAUDE.md 中"route 级结构与 Python 侧职责镜像"的描述一致。

原文档还说明:handlers never live in ai-gateway。历史遗留的 ocraudio_transcriptionrealtime 路由此前仍托管在 ai-gateway 中,规则是"每次触碰它们时就将其搬入 core"。从 litellm-rust/crates/core/src/ 的当前目录结构可以看到迁移已在推进:audio_transcription/ 已完整落入 core(含 client.rshandler.rsmod.rsprepare.rstests.rstransformation.rstypes.rs),而 ocr/realtime/ 也已存在于 core 下(目前文件较少,可推断迁移仍在进行中)。

provider 侧的组织则镜像 Python 的 provider 树:core/src/providers/<provider>/<route>/transformation.rs。例如 litellm-rust/crates/core/src/providers/anthropic/messages/transformation.rs 承接 Anthropic Messages 的 provider 专属转换,azure_aibedrockmistralopenaireductovertex_ai 等 provider 目录均按同一形状组织(详见 litellm-rust/README.md 的 Layout 一节)。

新增 Crate 的约束:默认加模块,加 crate 必须"过审"

原文档给出了两条硬性规则:

  1. 默认加模块。新增 crate 必须有真实触发条件,且只能是以下四类之一:

    • 独立的构建产物(binary / cdylib);
    • proc-macro crate;
    • 共享基础层(shared foundation);
    • 可独立发布的 standalone crate。

    "一个新的 provider 或路由"不属于任何一类触发条件。

  2. 机制兜底:allowlist 测试。原文档明确写道:

    Adding a crate fails crates/core/tests/workspace_crate_allowlist.rs until you update its allowlist and this file — intentional.

    即:一旦有人擅自新增 crate,测试 litellm-rust/crates/core/tests/workspace_crate_allowlist.rs 会立即失败,迫使其同时更新该测试的 allowlist 与 AGENTS.md,并在评审中为"为什么要新 crate"给出正当理由——这是一个刻意为之的结构性防呆设计。

    从该测试源码可以确认其实现方式(workspace_crate_allowlist.rs):

    const EXPECTED_MEMBERS: &[&str] = &[
        "crates/core",
        "crates/config",
        "crates/ai-gateway",
        "crates/python-interop",
        "crates/python-bridge",
    ];
    

    它包含两个测试函数:workspace_members_match_allowlist 手工解析 workspace Cargo.tomlmembers = [...] 数组(刻意只用 std、不引入 toml crate)与期望集合比对;crates_directory_matches_allowlist 扫描 crates/ 目录,仅把"内含 Cargo.toml 的子目录"计为 crate,因此 crates/CODING_STANDARDS/ 这类纯文档目录不会触发误报。失败信息中直接写明了整改要求:"update this allowlist AND litellm-rust/AGENTS.md, and justify the crate"。

core 的职责边界:允许与禁止

litellm-core "拥有整个调用"这一条规则,在 litellm-rust/CLAUDE.md 的 Core Boundary 一节被展开为允许/禁止清单,是理解 AGENTS.md 中 crate 分工的直接依据:

允许出现在 core 中

  • 顶层 LiteLLM 调用的公开入口函数;
  • 请求/响应转换与流 chunk 归一化;
  • provider 解析、鉴权头构建、URL 拼接;
  • 通过共享复用客户端(带 connect 与请求超时)执行 provider HTTP 调用本身;
  • 共享数据类型与校验错误;
  • 确定性的 token/成本辅助逻辑。

禁止出现在 core 中

  • 提供 HTTP 服务(axum 路由、extractor、传输层关注点归 host);
  • 文件系统访问、数据库访问;
  • 配置文件读取与 rollout 状态;
  • 日志回调、花费(spend)写入或自定义回调;
  • 全局可变运行时状态。

一个细节值得注意:core 中被允许的唯一环境变量读取,是各路由 prepare.rs 中的凭据兜底(env_lookup 闭包)——镜像 Python SDK 在未传入 key 时从环境变量取 key 的行为;其余一切配置形态的东西都由 host 解析后传入。

此外,AGENTS.md 与 CLAUDE.md 共同界定了 rollout 策略:在 Rust 逐步引入期间,rollout 状态与 fallback 由 Python 持有,Rust 路径默认关闭,直到 parity 测试证明与 Python 等价;新 provider/路由也允许选择 rust-only 实现(无 Python 参照),但必须在 PR 中显式声明。

风格规范:rustfmt 默认风格 + 官方 Rust Style Guide

原文档 Style 一节的规则可以归纳为三点:

  1. litellm-rust/ 下所有 Rust 代码遵循官方 Rust Style Guiderustfmt 默认实现的就是该指南的格式化规则,因此提交前必须运行 cargo fmt,且 CI 对每个 PR 执行 cargo fmt --check 门禁
  2. 禁止与 rustfmt 对着干:不要手工格式化出与 rustfmt 不同的结果,也不要添加偏离默认风格的 rustfmt.toml——"默认风格就是指南本身";
  3. rustfmt 无法自动应用的命名与习惯约定需人工遵循
    • snake_case:项、函数、模块;
    • UpperCamelCase:类型、trait、枚举变体;
    • SCREAMING_SNAKE_CASE:常量与静态变量;缩写按一个单词处理,例如 HttpClient 而非 HTTPClient
    • 遵循指南规定的 import 分组(std / 外部 / 本 crate)与 item 排序;
    • 对过长的表达式,优先重构结构而非强行丑陋换行。

配套的 litellm-rust/CLAUDE.md 给出完整的 Checks 清单,与 GitHub Actions 对 litellm-rust/ 变更执行的检查一致,推送前应在本地运行:

cd litellm-rust
cargo fmt --check
cargo clippy --workspace --all-targets -- -D warnings
cargo clippy -p litellm-core --all-targets --features bedrock-auth -- -D warnings
# ai-gateway 的二进制与服务端代码在 `server` feature 之后
cargo clippy -p litellm-ai-gateway --all-targets --all-features -- -D warnings
cargo test --workspace
cargo test -p litellm-core --features bedrock-auth
# `auth`、`routes`、`state`、`realtime` 测试仅存在于 `server` feature 下
cargo test -p litellm-ai-gateway --features server

这套命令本身也再次印证了 feature 划分:bedrock-auth 是 core 的可选 feature(引入 aws-sigv4 等依赖做 SigV4 签名),server 是 ai-gateway 的可选 feature(引入 axum、subtle、sha2),测试必须与 feature 配套运行。

小结:从文档到代码的设计闭环

litellm-rust 的结构规范形成了一个完整的"文档—代码—测试"闭环:

  • AGENTS.md 声明意图:五 crate、无环依赖、route 目录形状、crate 触发条件、风格规则;
  • Cargo.toml 固化结构:workspace members、feature 门控(serverbedrock-authpython)在构建层面落实分层;
  • 测试强制守门workspace_crate_allowlist.rs 用零依赖的 std 扫描,把"crate 集合恰好是五个"变成一条可执行的测试断言;
  • CI 收敛风格cargo fmt --check 与 clippy -D warnings 对所有 PR 生效,消除格式化与 lint 上的自由度。

对于要在这个工作区中新增 provider、路由或接口的开发者,操作路径因此非常明确:先在 core/src/providers/<provider>/<route>/transformation.rs 与路由模块中按 messages 样板落模块(而非新 crate),遵守 Core Boundary 的允许/禁止清单,然后跑完上述 Checks 清单再推送。这正是该仓库"crate 是层、模块才是增长单位"这一核心设计原则在日常开发中的落地方式。

登录后查看全文
热门项目推荐
相关项目推荐