摘要:从 Python 的 Pydantic 到 Rust 的 Serde+Schemars,本文探讨如何在生产环境中,利用 Rust 的类型系统强制约束 LLM 的输出,实现从“概率性文本”到“确定性数据”的完美转换。
一、 背景:智能体开发的“最后一公里”危机
过去一年是 AI Agent(智能体)概念的爆发期。Coze、Dify 等低代码平台的出现,极大地降低了 Demo 的构建门槛,让非开发者也能通过拖拽工作流(Workflow)快速验证想法。
然而,当我们将视角从 Demo 演示 转向 企业级生产环境 时,立刻会撞上“天花板”:
- 黑盒集成的痛苦:低代码平台难以无缝嵌入现有的复杂业务后端(如遗留的 Java/Go 微服务)。
- 复杂逻辑的泥潭:可视化的连线在处理多重循环、状态回滚、分布式事务时,维护成本呈指数级上升。
- 性能与成本的瓶颈:这是最致命的。生产环境对 延迟 (Latency) 和 吞吐量 (Throughput) 极其敏感,Python 的解释器开销在高并发场景下往往显得力不从心。
二、 为什么是 Rust?超越 Python 的工程化极限
Python 无疑是 AI 领域的“第一公民”。其生态中的 Pydantic 堪称神器,集类型定义、Schema 生成、数据验证于一身。
除了复杂智能体需要特定的编排方式,其余基本都算是后端开发的范畴,在高性能服务中Python 始终是不占太多优势的。原因不仅在于性能,更在于安全性:
- 编译期这一关:Python 的 Type Hint 只是提示,而 Rust 的类型系统是法律。
- 零成本抽象:Rust 允许我们在不牺牲性能的前提下,构建极高层级的抽象。
- 并发模型:Tokio 的异步运行时能够以极低的资源消耗处理海量 I/O,非常适合高频调用 LLM API 的网关层。
我们要在 Rust 中复刻甚至超越 Pydantic 的体验:不依赖臃肿的框架(如 LangChain),通过原生组合拳实现极致可控的结构化输出。
三、 核心挑战:非结构化智能 vs 结构化系统
智能体在内部思考时可以是发散的(Chain of Thought),但在对外交互时必须是严谨的。 有了规范的输出后续的处理中才不至于出错,或者说出错了不知道从哪里找,有了这种不稳定性和不确定性, 那么智能体服务就会很难维护。
智能体前面的节点的确定输出是后面智能体节点输出正确结果的保障。

目前主流的 JSON 输出控制有两种模式:
- JSON Object 模式:保证输出是合法的 JSON,但字段结构需要通过 Prompt 约束。
- JSON Schema 模式:严格遵循 Schema,但目前仅部分模型支持(如 qwen-plus),且配置较为繁琐。
本文采用一种更通用、兼容性更强的“组合拳”策略:
利用 Rust 的类型系统自动生成 Schema,注入到 System Prompt 中,并配合 json_object 模式。这既保证了灵活性,又能适配绝大多数支持 JSON Mode 的模型(OpenAI, Qwen, DeepSeek 等)。
技术栈映射表
| 核心能力 | Python 生态 (Reference) | Rust 生产级方案 | 优势 |
|---|---|---|---|
| 数据定义 | class Model(BaseModel) | **struct + serde** | 内存布局紧凑,无运行时开销 |
| Schema 生成 | .model_json_schema() | schemars | 编译期自动派生,SSOT (Single Source of Truth) |
| 网络层 | requests / httpx | reqwest | 极致的异步性能 |
| 解析验证 | .model_validate_json() | serde_json | 严格的反序列化,失败即 panic/err,绝不处理脏数据 |
💡 兼容性提示 虽然 OpenAI, Claude, Gemini 以及 Qwen-plus 等模型明确支持严格的 Schema 模式,但许多优秀的开源模型或 API(如 DeepSeek, GLM, MiniMax, MoonShot)目前主要支持
json_object模式。 本方案通过 Prompt 注入 Schema + JSON Mode 兜底,最大程度地兼容了这两种生态。
四、 实战代码:构建类型安全的提取器
假设我们需要一个智能体,从非结构化的技术需求文档中提取元数据,供下游的大数据 Pipeline(如 Spark/Flink)使用。
1. 极简依赖配置 (Cargo.toml)
拒绝过度封装,回归 HTTP 本质。
[dependencies]
tokio = { version = "1", features = ["full"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
schemars = { version = "0.8", features = ["derive"] } # 核心:将 Struct 转换为 JSON Schema
reqwest = { version = "0.11", features = ["json"] }
2. 定义“真理之源” (Single Source of Truth)
在 Rust 中,struct 就是契约。注意 #[schemars(description = "...")],这不仅仅是注释,它会被编译成 JSON Schema 注入给 LLM,实际上起到了 Prompt Engineering 的作用。
use serde::{Deserialize, Serialize};
use schemars::{schema_for, JsonSchema};
/// 数据流水线配置
/// Derive 宏解析:
/// - Serialize/Deserialize: 处理网络传输
/// - JsonSchema: 为 LLM 生成"说明书"
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
struct DataPipelineConfig {
#[schemars(description = "数据处理任务的唯一标识名称,建议使用蛇形命名法")]
job_name: String,
#[schemars(description = "任务优先级,1 为最高,10 为最低")]
priority: u8,
#[schemars(description = "数据源列表 (例如: s3://bucket/data)")]
sources: Vec<String>,
#[schemars(description = "集群资源配置详情")]
cluster_config: ClusterConfig,
}
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
struct ClusterConfig {
#[schemars(description = "