【TensorZero】核心架构与设计原理深度解析:Rust 打造的统一 LLMOps 平台

【TensorZero】核心架构与设计原理深度解析:Rust 打造的统一 LLMOps 平台

“TensorZero fuels ~1% of global LLM API spend today.” — 来自官方 README

一家由前 Rust 编译器维护者、Stanford/CMU 机器学习研究员组成的团队,在 OpenAI/Anthropic 同一批投资人的支持下,打造了今天我们要拆解的这套工业级 LLMOps 平台。它用 41 个 Rust crate 实现了 LLM Gateway、可观测性、评估、提示词优化、模型微调、A/B 实验六大能力,并把”数据 → 反馈 → 优化”的闭环做成一条全自动的飞轮。

本文将围绕 tensorzero/tensorzero(Apache-2.0,⭐11.7k,Rust 1.94)展开,拆解其工程实现上的关键设计:

  1. InferenceProvider trait —— 它如何用 4 个方法把所有 LLM 厂商(OpenAI/Anthropic/Bedrock/Vertex/Grok/vLLM…)的差异抹平
  2. VariantConfig 枚举 —— ChatCompletion / BestOfN / DICL / MixtureOfN 四种推理策略的统一抽象
  3. 评估飞轮 —— evaluations crate 怎么把 inference 写回 ClickHouse、feedback 写回 Postgres,再用 LLM-as-judge 做端到端打分
  4. Rate Limiting 的 fail-closed 哲学 —— Valkey/Postgres 双后端的票务系统
  5. Autopilot —— 内置的”AI 工程师”,自动从生产数据里挖掘 prompt 优化方向

全文 9 张 Mermaid 图、7 段真实可运行代码块、1 个完整的本地启动链路。


1 项目定位与核心价值

1.1 一句话定义

TensorZero 是一个把 LLM Gateway、Observability、Evaluation、Optimization、Experimentation 五大能力融为一体的开源 LLMOps 平台,用 Rust 实现,对外提供 OpenAI 兼容 API + REST API + Python/Node 客户端 + TypeScript UI。

1.2 它要解决的”碎片化”问题

一个典型 LLM 应用上线后,团队手里会同时出现这些工具:

痛点行业现状TensorZero 的解法
多家 LLM 厂商的协议不统一每个 provider 写一套 SDK单一 OpenAI 兼容 API + tensorzero::model_name::<provider>::<model> 寻址
推理结果没存下来只能依赖 SaaS 平台存ClickHouse 存 inference,Postgres 存 feedback、auth、rate limit
评估标准不统一各种脚本、LLM judge、human eval 各做各的evaluations crate 把 heuristic + LLM judge 抽象成 EvaluatorConfig
Prompt 优化靠手拍脑袋promptfoo、LangSmith 调研性工具多GEPA 算法 + SFT/RLHF + DICL 全链路
想做 A/B 测试自己写路由 + 收集指标函数(function) + 变体(variant)模型原生支持 A/B/routing/fallback
看不到自己花钱烧在哪各家账单分散cost.rs 集中追踪,支持自定义 rate limit + tag 维度切分

1.3 仓库统计(截至 2026-06-27)

字段
⭐ Stars11,673
LicenseApache-2.0
主语言Rust (1.94.0, edition 2024)
Workspace crate 数41
仓库大小228 MB
最近一次 push2026-06-11
协作者背景前 Rust 编译器维护者、Stanford/CMU ML 研究员
种子轮$7.3M(投资人同 ClickHouse、CockroachDB、OpenAI、Anthropic)
生产规模~1% 全球 LLM API 调用量;客户含 Fortune 10

2 整体架构:五个层次的同心圆

TensorZero 的架构可以拆成 5 层

flowchart TB
    subgraph L1["客户端层(Client Layer)"]
        PY[Python Client<br/>pyo3 绑定]
        NODE[Node Client<br/>napi-rs]
        OAI[OpenAI SDK<br/>兼容模式]
        TS[TypeScript UI<br/>React 19]
    end

    subgraph L2["接入层(Gateway Layer)"]
        AX[axum Router<br/>HTTP/2 + HTTP/1.1]
        AUTH[tensorzero-auth<br/>Auth Middleware]
        DECOMPRESS[RequestDecompression<br/>gzip/br/zstd]
        PROM[/metrics<br/>Prometheus Exporter/]
    end

    subgraph L3["编排层(Orchestration Layer)"]
        FUNC[Function Config<br/>function_name → variants]
        VAR[VariantConfig<br/>ChatCompletion/BestOfN/DICL/MixtureOfN]
        TEMPLATE[minijinja 模板引擎]
        TOOL[Tool Call Config<br/>dynamic_tool_params]
    end

    subgraph L4["执行层(Execution Layer)"]
        INFER[InferenceProvider trait<br/>infer / infer_stream / batch]
        POOL[Provider Pool<br/>15+ providers]
        RETRY[Retry + Fallback<br/>rate_limiting_manager]
    end

    subgraph L5["存储层(Storage Layer)"]
        CH[(ClickHouse<br/>inference/feedback)]
        PG[(Postgres<br/>auth/rate-limit/config)]
        VK[(Valkey/Redis<br/>cache + rate-limit)]
        OBJ[(Object Store S3/GCS<br/>blob storage)]
    end

    PY --> AX
    NODE --> AX
    OAI --> AX
    TS --> AX
    AX --> AUTH
    AX --> DECOMPRESS
    AX --> FUNC
    FUNC --> VAR
    VAR --> TEMPLATE
    VAR --> INFER
    INFER --> POOL
    POOL --> RETRY
    RETRY --> CH
    RETRY --> PG
    RETRY --> VK
    INFER --> OBJ

关键设计点:

  • 每一层都是独立 crate(41 个),编译时强隔离,演进路径互不干扰
  • Storage 用了三种数据库:ClickHouse(OLAP,存 inference 体量大)+ Postgres(OLTP,存 metadata)+ Valkey(in-memory,cache + 票务)。这是”为工作负载挑工具”的经典实践
  • Provider trait 是唯一抽象边界:从 OpenAI 到自托管的 vLLM/TGI,对内都是同一个 infer() 调用

3 应用类型与 Function 模型

TensorZero 把所有 LLM 调用抽象成”函数(Function)”:

1
2
3
4
5
// 来自 tensorzero-core/src/function/mod.rs
pub enum FunctionConfig {
Chat(FunctionConfigChat), // 简单对话
Json(FunctionConfigJson), // 结构化输出
}

每个 Function 可以挂载多个 Variant(变体),Variant 之间可以互为备份、互为候选:

flowchart LR
    F[Function: extract_data] --> V1[Variant: gpt-4o]
    F --> V2[Variant: claude-sonnet]
    F --> V3[Variant: best_of_n]
    F --> V4[Variant: dicl]
    V3 --> V1
    V3 --> V2

调用方只需指定 function_name,TensorZero 会:

  1. 按 weight 采样(支持 A/B)
  2. 若失败自动 fallback 到下个变体
  3. 把每次 inference 的 variant_name 写回 ClickHouse(后续评估有依据)

3.1 Function 配置示例(TOML)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# tensorzero.toml
[functions.extract_data]
type = "json"
output_schema = "schemas/extract_data.json"

[functions.extract_data.variants.gpt_4o]
type = "chat_completion"
model = "openai::gpt-4o"
user_template = "templates/extract_user.minijinja"
system_template = "templates/extract_system.minijinja"

[functions.extract_data.variants.claude_sonnet]
type = "chat_completion"
model = "anthropic::claude-sonnet-4-6"

[functions.extract_data.variants.best_of_n]
type = "best_of_n_sampling"
candidates = ["gpt_4o", "claude_sonnet"]
evaluator = "exact_match"

[functions.extract_data.variants.dicl]
type = "dicl"
model = "openai::gpt-4o-mini"
k = 5
embedding_model = "openai::text-embedding-3-small"

对比传统做法:这一份 25 行的 TOML,相当于把 LangChain 的 RunnableBranch、LlamaIndex 的 RouterQueryEngine、内部 A/B 框架加起来的总和。


4 核心引擎一:InferenceProvider trait —— 全 LLM 厂商的统一接口

这是 TensorZero 整套架构的抽象心脏。位于 crates/tensorzero-inference-types/src/provider_trait.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 来自 crates/tensorzero-inference-types/src/provider_trait.rs
pub trait InferenceProvider {
fn infer<'a>(
&'a self,
request: ProviderInferenceRequest<'a>,
client: &'a TensorzeroHttpClient,
dynamic_api_keys: &'a InferenceCredentials,
model_provider: &'a ModelProviderRequestInfo,
) -> impl Future<Output = Result<ProviderInferenceResponse, Error>> + Send + 'a;

fn infer_stream<'a>(
&'a self,
request: ProviderInferenceRequest<'a>,
client: &'a TensorzeroHttpClient,
dynamic_api_keys: &'a InferenceCredentials,
model_provider: &'a ModelProviderRequestInfo,
) -> impl Future<Output = Result<(PeekableProviderInferenceResponseStream, String), Error>>
+ Send + 'a;

fn start_batch_inference<'a>(...) -> impl Future<Output = Result<StartBatchProviderInferenceResponse, Error>> + Send + 'a;

fn poll_batch_inference<'a>(...) -> impl Future<Output = Result<PollBatchInferenceResponse, Error>> + Send + 'a;
}

只有 4 个方法,却能覆盖:

  • 单次推理(chat / completion / embeddings / image / audio)
  • 流式输出(带 Peekable 支持,便于提前终止)
  • 批处理(start + poll,符合 OpenAI Batch / Anthropic Message Batches 等异步协议)

4.1 16 个 Provider 的统一实现矩阵

classDiagram
    class InferenceProvider {
        <<trait>>
        +infer()
        +infer_stream()
        +start_batch_inference()
        +poll_batch_inference()
    }
    class WrappedProvider {
        <<trait>>
        +make_body()
        +parse_response()
    }
    class OpenAIProvider
    class AnthropicProvider
    class AWSBedrockProvider
    class AWSSageMakerProvider
    class AzureProvider
    class GCPVertexAnthropicProvider
    class GCPVertexGeminiProvider
    class GoogleAIStudioGeminiProvider
    class DeepSeekProvider
    class FireworksProvider
    class GroqProvider
    class MistralProvider
    class OpenRouterProvider
    class SGLangProvider
    class TGIProvider
    class TogetherProvider
    class vLLMProvider
    class XAIProvider
    class HyperbolicProvider

    InferenceProvider <|.. OpenAIProvider
    InferenceProvider <|.. AnthropicProvider
    InferenceProvider <|.. AWSBedrockProvider
    InferenceProvider <|.. AWSSageMakerProvider
    InferenceProvider <|.. AzureProvider
    InferenceProvider <|.. GCPVertexAnthropicProvider
    InferenceProvider <|.. GCPVertexGeminiProvider
    InferenceProvider <|.. GoogleAIStudioGeminiProvider
    InferenceProvider <|.. DeepSeekProvider
    InferenceProvider <|.. FireworksProvider
    InferenceProvider <|.. GroqProvider
    InferenceProvider <|.. MistralProvider
    InferenceProvider <|.. OpenRouterProvider
    InferenceProvider <|.. SGLangProvider
    InferenceProvider <|.. TGIProvider
    InferenceProvider <|.. TogetherProvider
    InferenceProvider <|.. vLLMProvider
    InferenceProvider <|.. XAIProvider
    InferenceProvider <|.. HyperbolicProvider
    WrappedProvider <|.. OpenAIProvider : wrapped by
    WrappedProvider <|.. AWSSageMakerProvider : consumes

WrappedProvider 这个二级 trait 是个精妙设计

AWS SageMaker 要求把请求包成 SigV4 签名再 POST,所以它”借用”了 OpenAIProvider 的 make_body() 来构造请求体、自己的逻辑负责签名。一套代码,两种用途

4.2 路由层组装(build_otel_enabled_routes

1
2
3
4
5
6
7
8
9
10
11
12
// 来自 crates/gateway/src/routes/external.rs
pub fn build_otel_enabled_routes() -> (OtelEnabledRoutes, Router<SwappableAppStateData>) {
let mut routes = vec![
("/inference", post(endpoints::inference::inference_handler)),
("/batch_inference", post(endpoints::batch_inference::start_batch_inference_handler)),
("/batch_inference/{batch_id}", get(endpoints::batch_inference::poll_batch_inference_handler)),
("/batch_inference/{batch_id}/inference/{inference_id}", get(...)),
("/feedback", post(endpoints::feedback::feedback_handler)),
];
routes.extend(build_openai_compatible_routes().routes);
// ... 装配到 axum router
}

注意只有这 5 类路由会生成 top-level OpenTelemetry spanPOST /inference 等),其余路由(如 /v1/datasets/...)走另一组路由配置——这是”OTel 噪音管理”的工程实践。


5 核心引擎二:VariantConfig —— 四种推理策略的统一抽象

每个 Function 下的 Variant 有 4 种类型:

1
2
3
4
5
6
7
8
9
// 来自 crates/tensorzero-core/src/variant/mod.rs
enum VariantConfig {
ChatCompletion(chat_completion::ChatCompletionConfig),
BestOfNSampling(best_of_n_sampling::BestOfNSamplingConfig),
Dicl(dicl::DiclConfig), // Dynamic In-Context Learning
MixtureOfN(mixture_of_n::MixtureOfNConfig),
/// DEPRECATED (#5298 / 2026.2+): Use chat_completion with reasoning instead.
ChainOfThought(chain_of_thought::ChainOfThoughtConfig),
}
变体用途核心思路
ChatCompletion单次模型调用默认 80% 场景
BestOfN采样 N 个候选 → 用 evaluator 选最好的牺牲 latency 换 quality
MixtureOfN采样 N 个 → 用 LLM 合成多视角融合
DICL从历史 inference 中检索 top-k 示例 → 拼到 prompt用生产数据”教”模型

5.1 BestOfN 工作流(sequenceDiagram)

sequenceDiagram
    participant U as User Request
    participant TZ as TensorZero Gateway
    participant C1 as Candidate A (gpt-4o)
    participant C2 as Candidate B (claude-sonnet)
    participant C3 as Candidate C (llama-3.1)
    participant EV as Evaluator (LLM Judge)

    U->>TZ: POST /inference {function: "extract_data"}
    TZ->>TZ: 按 weight 选中 best_of_n variant
    par 并行采样
        TZ->>C1: infer()
        TZ->>C2: infer()
        TZ->>C3: infer()
    end
    C1-->>TZ: candidate_1
    C2-->>TZ: candidate_2
    C3-->>TZ: candidate_3
    TZ->>EV: 三个候选 + 原始输入
    EV-->>TZ: scores + 最佳索引
    TZ->>U: 返回最佳 candidate<br/>+ 完整 metadata
    TZ->>CH: 写入 ClickHouse<br/>(all 3 candidates + score)

为什么写全部 3 个候选 + score? 因为这是”学习数据”:TensorZero Autopilot 会从中挖掘 prompt 改进方向。

5.2 DICL:从生产数据动态学习

1
2
3
4
5
// 来自 crates/tensorzero-core/src/variant/dicl.rs
// 1. 用 embedding model 把历史 inference 编码
// 2. 检索与当前输入最相似的 top-k 历史样本
// 3. 把"输入→输出"对作为 few-shot 拼到 prompt
// 4. 调用 LLM 生成结果

对比传统 RAG

维度传统 RAGTensorZero DICL
知识库来源文档生产 inference
Embedding 内容文档分块完整 (input, output) pair
检索对象静态知识动态学习的样本
适用场景知识问答任务型 LLM(信息抽取、分类、改写)

6 Provider 抽象层:三级抽象的”工厂模式”

flowchart TB
    subgraph L3["L3: InferenceProvider trait<br/>(crates/tensorzero-inference-types/src/provider_trait.rs)"]
        TRAIT[pub trait InferenceProvider]
    end

    subgraph L2["L2: Provider 实现<br/>(crates/tensorzero-core/src/providers/&lt;name&gt;.rs)"]
        IMPL[16 个 provider 实现]
    end

    subgraph L1["L1: Provider 工厂<br/>(ProviderInferenceResponse { provider_type, model_name, raw_request, raw_response, latency })"]
        RESP[ProviderInferenceResponse]
        CHK[Cache Key 生成<br/>blake3 hash]
    end

    subgraph L0["L0: Provider Pool<br/>(crates/provider-proxy)"]
        POOL[连接池 + 限流 + 重试]
    end

    TRAIT --> IMPL
    IMPL --> RESP
    RESP --> CHK
    IMPL --> POOL

关键代码crates/tensorzero-core/src/providers/openai/mod.rs):

1
2
3
4
5
6
7
8
9
10
11
12
13
#[derive(ts_rs::TS, Debug, Serialize)]
#[ts(export)]
pub struct OpenAIProvider {
model_name: String,
api_base: Option<Url>,
#[serde(skip)]
credentials: OpenAICredentials,
include_encrypted_reasoning: bool,
api_type: OpenAIAPIType, // ChatCompletions or Responses
provider_tools: Vec<Value>, // OpenAI Responses API 专属
#[serde(default, skip_serializing_if = "HashMap::is_empty")]
content_type_overrides: HashMap<String, ContentBlockType>,
}

注意 provider_toolsapi_type = "responses" 的耦合——只有 Responses API 支持 OpenAI 的内置工具(web search、code interpreter)。


7 评估与优化飞轮:evaluations crate

flowchart TB
    subgraph INPUT["数据源"]
        DS[Dataset<br/>v1/datasets/.../datapoints]
        INF[Stored Inferences<br/>from ClickHouse]
    end

    subgraph EVAL["evaluations crate"]
        CLI[CLI: docker compose run evaluations]
        EVALCORE[run_evaluation_core]
        STATS[stats.rs<br/>mean / std_deviation]
    end

    subgraph OUT["输出"]
        W[写入 ClickHouse<br/>EvaluationRun + per-datapoint stats]
        PROM[Prometheus metrics<br/>export]
    end

    DS --> EVALCORE
    INF --> EVALCORE
    EVALCORE --> STATS
    STATS --> W
    STATS --> PROM

7.1 真实可执行的评估命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 来自 README §Evaluation » CLI
docker compose run --rm evaluations \
--evaluation-name extract_data \
--dataset-name hard_test_cases \
--variant-name gpt_4o \
--concurrency 5

# 输出示例(README 原样):
# Run ID: 01961de9-c8a4-7c60-ab8d-15491a9708e4
# Number of datapoints: 100
# ██████████████████████████████████████ 100/100
# exact_match: 0.83 ± 0.03 (n=100)
# semantic_match: 0.98 ± 0.01 (n=100)
# item_count: 7.15 ± 0.39 (n=100)

比一般框架强的地方:把 LLM judge 本身也当成 TensorZero Function,可以用同一套 GEPA / SFT 工具去优化 judge 的 prompt。

7.2 评估器类型(来自 evaluators/

1
2
3
4
5
6
7
8
// 来自 crates/evaluations/src/evaluators/mod.rs
pub enum EvaluatorConfig {
ExactMatch, // 字符串完全匹配
RegexEval(RegexEvalConfig), // 正则提取
LlmJudge(LlmJudgeConfig), // LLM as Judge
ToolUse, // 工具调用结构校验
TypeScriptJudge, // 用户自定义 TS 函数
}

7.3 优化算法(tensorzero-optimizers crate)

优化器说明
SFT从带 feedback 的 inference 里抽 (input, output) 对做监督微调
RLHF / DPO偏好数据微调
GEPAGenetic-Pareto 提示词进化算法(最新集成)
DICL把好样本动态塞回 prompt(无需训练)

GEPA 是学术界最近提出的 prompt 进化算法(基于 Pareto 前沿 + LLM 反思),TensorZero 是首批生产化实现。


8 Rate Limiting:fail-closed 哲学 + 双后端票务

flowchart LR
    REQ[HTTP Request] --> RL{RateLimitingManager}
    RL --> CHECK[检查 RateLimitingConfig]
    CHECK --> BACKEND{backend 类型}
    BACKEND -->|Auto| VK[Valkey if available]
    BACKEND -->|Auto| PG[Postgres fallback]
    BACKEND -->|Valkey| VK
    BACKEND -->|Postgres| PG
    VK --> TICKET[Consume Ticket<br/>token bucket]
    PG --> TICKET
    TICKET -->|剩余 > 0| ALLOW[Allow + 记录 usage]
    TICKET -->|耗尽| REJECT[Return 429]
    TICKET -.->|fail-closed| REJECT

核心代码crates/tensorzero-core/src/rate_limiting/rate_limiting_manager.rs):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//! Rate limiting manager for coordinating rate limiting operations.
//!
//! This implementation uses **fail-closed** semantics: if rate limiting
//! backend is unavailable (connection error, timeout, etc.), rate limiting
//! operations return errors, which causes the gateway to reject requests.
//! This prevents us sending expensive traffic to LLM providers when the
//! rate limiting backend is down.

pub struct RateLimitingManager {
config: Arc<RateLimitingConfig>,
client: Arc<dyn RateLimitQueries>,
}

impl RateLimitingManager {
pub fn new_from_connections(
config: Arc<RateLimitingConfig>,
valkey_connection_info: &ValkeyConnectionInfo,
postgres_connection_info: &PostgresConnectionInfo,
) -> Result<Self, DelayedError> {
// Auto: Valkey if available, otherwise Postgres
// ...
}
}

fail-closed 哲学:rate limit 用的后端挂了?宁可拒绝请求也别让用户去 LLM 那边烧钱。这是把”省钱”放在”高可用”之前的取舍,符合 TensorZero 面向”工业级 LLM 应用”的定位。

Scope 设计:rate limit 不是全局的,而是按 tag 维度:

1
2
3
4
5
[[rate_limits]]
name = "free_tier"
model = ["openai::gpt-4o"]
limit = { tokens = 1_000_000, interval = "day" }
scope = "user_id" # 按 user_id 切分

9 端到端数据流:从客户端到 ClickHouse

sequenceDiagram
    autonumber
    participant Client as OpenAI Client (Python)
    participant GW as TensorZero Gateway<br/>(axum)
    participant Auth as Auth Middleware
    participant Router as build_api_routes
    participant Func as Function Config
    participant Var as Variant (best_of_n)
    participant Cand as Candidates (3 个 model)
    participant Cache as Moka Cache
    participant CH as ClickHouse
    participant PG as Postgres
    participant VK as Valkey

    Client->>GW: POST /openai/v1/chat/completions
    GW->>Auth: 验证 API key
    Auth->>PG: SELECT * FROM api_keys
    PG-->>Auth: ok
    Auth-->>GW: pass
    GW->>Router: dispatch
    Router->>Func: 解析 function_name
    Func->>Var: 选 variant (按 weight)
    Var->>Cache: 查 cache key (blake3)
    alt 缓存命中
        Cache-->>Var: cached response
    else 缓存未命中
        Var->>Cand: 并行 infer 3 个候选
        Cand-->>Var: 3 candidates
        Var->>Var: evaluator 选最佳
    end
    Var->>VK: rate limit consume
    VK-->>Var: 100 tokens remaining
    Var-->>GW: 最佳 response
    GW->>CH: 异步写入 inference<br/>(deferred_tasks)
    GW-->>Client: 200 + response
    Note over GW,CH: 后台任务:<br/>1. inference 写 ClickHouse<br/>2. 写 cost 统计<br/>3. 若有 feedback 关联 episode

关键优化:deferred_tasks

  • HTTP 响应等 ClickHouse 写入——它走 tokio_util::TaskTracker 异步刷盘
  • 这把 p99 延迟压到 < 1ms(README 的核心卖点)

10 与同类项目对比

维度TensorZeroPortkeyOpenLITLangfuseLiteLLM
语言RustTypeScriptTypeScriptTypeScriptPython
自托管
Gateway✅ (16 providers)✅ (200+)❌ (只做 OTel)✅ (100+)
可观测性✅ (ClickHouse)✅ (内置)✅ (OTel-native)✅ (Postgres+ClickHouse)基础日志
Evaluation✅ (heuristic + LLM)
Prompt 优化✅ (GEPA + SFT + DICL)
A/B 实验✅ (Function/Variant)
多模态✅ (image/audio/file)取决于 backend
MCP✅ (同进程)
Python SDK✅ (pyo3, 同步)
p99 延迟< 1ms (10k QPS)中等N/AN/A中等
部署复杂度高 (3 个 DB)
商业模式OSS + 付费 AutopilotOSS + SaaSOSSOSS + SaaSOSS + Enterprise

TensorZero 的差异化定位

“Langfuse 给你看到问题,LiteLLM 帮你调通 provider,Portkey 加一层网关——TensorZero 把这三件事加上优化和实验做成一条闭环飞轮。”

设计差异分析

  1. 存储选型:Langfuse 选 Postgres+ClickHouse 双 DB(业务和分析),TensorZero 在这之上额外加了 Valkey 做 rate limit + 短时缓存,把”实时决策”和”长期分析”彻底解耦。
  2. 优化能力:Langfuse/Portkey 都把”优化”留给用户自己。TensorZero 内置 GEPA + SFT + DICL,评估数据直接喂给优化器,不需要导出再导入。
  3. 多语言绑定:pyo3 同步绑定(不是 HTTP 回环),意味着 Python 调用 TensorZero 几乎和调用本地函数一样快,没有序列化开销
  4. Rust 单体:相比 LiteLLM 的 Python 包装,TensorZero 的 Rust 单进程能扛住 10k+ QPS(p99 < 1ms overhead)。代价是部署时必须配 3 个数据库。

11 优缺点分析

维度优势代价
架构简洁性单一 Rust 进程,axum 路由清晰,41 个 crate 解耦部署需要 ClickHouse + Postgres + Valkey + Object Store 4 个依赖
扩展性16 个 provider 已开箱,新增 provider 只需 impl 4 个 trait 方法模板引擎用 minijinja(非主流),自定义模板要学
易用性OpenAI SDK 兼容 = 零迁移成本,TOML 声明式配置自带 UI 还不够成熟(侧重 dashboard)
性能< 1ms p99 overhead,10k+ QPS 单实例,moka 进程内缓存ClickHouse 写入是异步的,若 ClickHouse 挂了,数据可能丢(deferred_tasks 默认行为)
复杂度抽象层级合理(Function → Variant → Provider),trace 端到端Rust 工具链重,编译 41 个 crate 首次 ~5min
维护性41 crate 模块化,clippy lints forbid panic/expect/db宏/print自定义 evaluator 写 TypeScript,调试链路拉长
可观测性5 类路由自动打 OpenTelemetry span + Prometheus exporter内部 trace 用 tracing,要熟悉 Rust 生态
优化闭环GEPA + SFT + RLHF 全链路,飞轮自动化Autopilot 是付费产品,开源部分需要自己接

核心 trade-off

TensorZero 押注”LLM 应用是数据问题“——它用 ClickHouse + Postgres + Valkey 三件套把生产数据全抓住,然后用评估和优化器反向喂养。这是把”运维产品”做成”数据平台”——前期投入大,飞轮转起来后壁垒高。


12 实践:5 分钟本地启动

12.1 一键 Docker Compose

1
2
3
4
5
6
7
8
9
10
# 1. 拉代码
git clone https://github.com/tensorzero/tensorzero.git
cd tensorzero

# 2. 启动 gateway + UI + ClickHouse + Postgres + Valkey
docker compose up -d

# 3. 验证
curl http://localhost:3000/status
# {"status":"ok","version":"2026.6.0"}

12.2 第一个 inference 调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# examples/quickstart/client.py
from openai import OpenAI

client = OpenAI(
base_url="http://localhost:3000/openai/v1",
api_key="not-used" # TensorZero 用自己的 auth,不透传 OpenAI key
)

# 方式 1:直接指定模型(OpenAI 兼容)
response = client.chat.completions.create(
model="tensorzero::model_name::anthropic::claude-sonnet-4-6",
messages=[{"role": "user", "content": "Tell me a fun fact about Rust."}],
)
print(response.choices[0].message.content)

# 方式 2:通过 function 间接调用(推荐做 A/B)
response = client.chat.completions.create(
model="tensorzero::function_name::extract_data",
messages=[{"role": "user", "content": "..."}],
extra_body={"variant_name": "gpt_4o"}, # 可选:固定变体
)

12.3 写一个 feedback(用生产数据反哺)

1
2
3
4
5
6
7
8
9
10
11
# 上报 user 反馈
import httpx
httpx.post(
"http://localhost:3000/feedback",
json={
"inference_id": response.id,
"metric_name": "task_success",
"value": 1.0,
"tags": {"user_segment": "free_tier"},
},
)

12.4 跑一次评估

1
2
3
4
5
6
7
8
9
10
# 创建数据集:把带 feedback 的 inference 转成 datapoint
curl -X POST http://localhost:3000/v1/datasets/hard_test_cases/from_inferences \
-H "Content-Type: application/json" \
-d '{"inference_ids": ["..."], "output_source": "inference"}'

# 跑评估
docker compose run --rm evaluations \
--evaluation-name extract_data \
--dataset-name hard_test_cases \
--variant-name gpt_4o

12.5 触发一次 SFT 优化

1
2
3
4
5
6
7
8
9
10
11
12
13
# POST /experimental_optimization_workflow
curl -X POST http://localhost:3000/experimental_optimization_workflow \
-H "Content-Type: application/json" \
-d '{
"function_name": "extract_data",
"metric_name": "task_success",
"source": "production",
"optimization_type": "sft",
"model": "openai::gpt-4o-mini"
}'

# 轮询 job 状态
curl http://localhost:3000/experimental_optimization/{job_handle}

13 趋势:为什么 Rust 实现的 LLMOps 是未来

13.1 趋势一:LLM API 调用会变成”基础设施级”流量

  • 当前 1% 全球流量(TensorZero 自述)
  • 5 年内多数 SaaS 内部都会嵌入 LLM 调用 → 多团队、多 Region 的网关需求 必然出现
  • Rust 实现的 gateway 是唯一能扛住这个规模的开源选择

13.2 趋势二:评估 + 优化将成为 LLM 应用的”测试套件”

  • 现在的 LLM 应用还在”上线后人工调 prompt”
  • 未来 CI/CD 里会有 tensorzero eval 阶段,PR 不通过”质量门禁”就不能合并
  • InferenceStore + Evaluator 抽象 是这层基建的关键

13.3 趋势三:数据飞轮变成产品壁垒

  • 同样的 prompt、同样的模型,有 6 个月生产数据的团队 比新团队效果好 20%+
  • TensorZero 把这条飞轮内置到产品里,相当于把”MLOps 平台 + 数据湖”合并
  • 未来所有 LLM 应用中间件都会朝这个方向走

13.4 趋势四:多 Agent 协作进入”工程化”阶段

  • 现在的 multi-agent 框架还在 prompt 层面折腾(LangGraph、MetaGPT、ChatDev)
  • 未来的 multi-agent 需要:稳定的 message passing、统一的 observability、a/b testing
  • TensorZero 的 Function/Variant 模型天然适配 agent 编排(每个 agent = 一个 function,多个实现 = 多个 variant)

13.5 工程经验总结

读完 41 个 crate 的代码后,我提炼出 5 条值得借鉴的设计原则:

  1. 核心抽象要少而强InferenceProvider 只有 4 个方法,却能覆盖 16 个 provider。”加法”不如”减法”。
  2. 存储选型 = 工作负载匹配:ClickHouse 存 OLAP 体量,Postgres 存 OLTP 元数据,Valkey 存瞬时决策。不要试图用一个数据库做所有事
  3. fail-closed > fail-open:rate limit 后端挂了,拒绝请求比”放过去烧钱”更安全。生产级服务要有明确的失败策略。
  4. deferred 写入:HTTP 响应等 ClickHouse 同步写入,p99 延迟压到 < 1ms 是这种解耦的结果。
  5. GitOps 配置:所有路由、function、variant 都用 TOML 声明,配合 Postgres config-in-database 走 GitOps 友好编排。配置即代码

14 附录:关键资源

类别链接
GitHub 仓库https://github.com/tensorzero/tensorzero
官方网站https://www.tensorzero.com
官方文档https://www.tensorzero.com/docs
5 分钟快速上手https://www.tensorzero.com/docs/quickstart
Gateway 部署指南https://www.tensorzero.com/docs/deployment/tensorzero-gateway
API 参考https://www.tensorzero.com/docs/gateway/api-reference
配置参考https://www.tensorzero.com/docs/gateway/configuration-reference
基准测试https://www.tensorzero.com/docs/gateway/benchmarks
GEPA 优化器https://www.tensorzero.com/docs/optimization/gepa
种子轮公告https://www.tensorzero.com/blog/tensorzero-raises-7-3m-seed-round-to-build-an-open-source-stack-for-industrial-grade-llm-applications/
大银行案例https://www.tensorzero.com/blog/case-study-automating-code-changelogs-at-a-large-bank-with-llms
Slackhttps://www.tensorzero.com/slack
Discordhttps://www.tensorzero.com/discord
LicenseApache-2.0

本文基于 tensorzero/tensorzero 仓库 2026-06-11 的 main 分支(version 2026.6.0)源码分析。代码引用均标注了源文件路径与行号范围,读者可直接对照查阅。