各工具解决的问题
📍 In One Sentence
结构化输出工具解决的是三个不同的问题——在生成时强制架构、生成后校验结果、修复格式损坏的输出——而多数技术栈只需要前两项。
💬 In Plain Terms
别照着功能清单选。先问你真正遇到的是哪种故障:模型无视你的格式,还是格式对了但值是错的,又或者返回的 JSON 根本无法解析。这三种情况的解法并不相同。
结构化输出需要解决三个相互依存的问题:模式定义、API强制和验证。 不同工具以不同方式解决这些问题。Instructor在Python中用重试处理全部三个。Outlines通过约束解码消除了验证步骤。Pydantic AI为Agent添加类型安全性。BAML把模式移入可编译文件并修复不完美的输出。LangChain封装Provider API。Marvin优先考虑开发速度。PromptQuorum验证所有模型的一致性。
问题 | Instructor | Outlines | Pydantic AI | BAML | LangChain | Marvin |
|---|---|---|---|---|---|---|
| 定义模式 | Pydantic模型 | JSON Schema / GBNF | Pydantic模型 | .baml类文件 | 工具定义 | Python类型提示 |
| API调用时强制执行 | 重试 + 验证 | Token级约束 | 原生 / 工具 / 提示词 | 生成的提示词 + 解析器 | Provider JSON模式 | Pydantic AI输出类型 |
| 验证响应 | 自动 | 生成时保证 | 类型检查 | Schema-aligned parsing | 手动 | 自动 |
Instructor:Pydantic提取
Instructor是采用最广泛的结构化输出库。它封装任何LLM API — OpenAI GPT-5.6、Claude Opus 5、Gemini 3.1 Pro、Ollama、vLLM — 并返回经验证的Pydantic模型而非原始文本。 Instructor在验证失败时自动处理重试,无需额外错误处理即可达到生产级别。
- 支持所有主流Provider(OpenAI、Anthropic、Google、Groq、Mistral)以及通过Ollama或vLLM运行的本地模型
- Pydantic v2模式:类型提示、验证规则、嵌入模式的docstring描述
- 验证失败时自动退避重试 — 无需手动错误处理
- 六个官方实现:Python、TypeScript、Ruby、Go、Elixir和Rust
- MIT许可开源,积极维护,目前为1.x系列
- 定价:免费(除LLM API调用外无额外费用)
import instructor
from pydantic import BaseModel
from openai import OpenAI
class User(BaseModel):
name: str
age: int
client = instructor.from_openai(OpenAI())
user = client.chat.completions.create(
model="gpt-5.6",
response_model=User,
messages=[{"role": "user", "content": "Extract: John is 25 years old"}]
)
# user.name == "John", user.age == 25Outlines:约束解码
Outlines通过约束解码在Token生成时强制执行模式合规性。不是生成Token后再验证,而是在每一步将有效Token限制为符合您模式的Token。 这保证输出一定能按您的模式解析,结构层面零幻觉风险——这正是它成为本地模型默认选择的原因。
- 本地后端:transformers、llama.cpp、MLX和任何Hugging Face模型
- 服务端后端:vLLM、Ollama和NVIDIA NIM
- 同样支持托管API(OpenAI、Gemini),同一份代码可在本地与云端之间迁移
- 模式可用Pydantic模型、JSON Schema、正则表达式、字面量选项或上下文无关文法表达
- 保证结构合规 — 无需后处理验证或重试
- Apache 2.0开源,目前为1.x系列,采用Rust内核(outlines-core)提升速度
Pydantic AI:类型安全Agent
Pydantic AI是Pydantic本体团队打造的Agent框架。它将Pydantic模型与多轮Agent对话的一级支持相结合,在每一轮强制执行结构化输出的同时,为Agent循环添加完整的类型安全性。 它已进入2.x系列并用于生产环境,不再是实验项目。
- Pydantic v2类型系统 — 完整的IDE支持,并对Agent返回值做静态类型检查
- 三种输出模式:Provider原生结构化输出、工具调用,以及作为兜底的提示词JSON
- 高吞吐量应用的Async-first设计
- 支持OpenAI、Anthropic、Google、Bedrock、Azure AI Foundry、Groq、Mistral、xAI和Ollama
- 持久化执行集成(Temporal、DBOS、Prefect),让长时间运行的Agent能挺过重启
- 内置工具调用 — 将工具定义为带类型提示的Python函数
- MIT许可且免费(除LLM API调用外无额外费用)
BAML:模式优先的提示词文件
BAML走的是与Python库相反的路线:模式和提示词写在受版本管理的.baml文件里,由编译器为你的语言生成类型化客户端。 它的模式对齐解析器会修复模型真正会犯的错误——JSON外围的Markdown代码块、多余的尾逗号、没有引号的键名、对象前面的推理文字——而不是直接报错并浪费一次重试。
- 模式与提示词共同存放在.baml文件中,像其他源码一样做版本管理和代码评审
- 原生为Python和TypeScript生成类型化客户端,并通过生成的OpenAPI客户端覆盖Go、Java、Ruby、PHP、Rust和C#
- schema-aligned parsing(SAP)能从不完美的输出中还原出有效对象,而不是直接失败
- 即使模型完全没有原生工具调用或JSON模式也能工作
- 类型安全的流式输出 — 部分对象带类型抵达,可以边生成边渲染字段
- Apache 2.0开源;托管的可观测性产品Boundary Studio为单独付费服务
LangChain:统一API
LangChain在所有主要聊天模型上提供with_structured_output(),把OpenAI、Anthropic、Google和本地模型的结构化输出统一到单一方法之下。 自1.x重写以来,它不再硬编码各Provider的原生结构化输出能力,而是从模型档案中读取;用create_agent构建的Agent也可以直接接收response_format。
- 统一API:一个.with_structured_output()方法适用于所有Provider
- 自动将LangChain工具定义转换为Provider特定的模式格式
- 用create_agent创建的Agent可为最终回答接收response_format
- 自1.1系列起,原生结构化输出支持按模型从Provider档案数据中读取
- 支持Pydantic模型、TypedDict、dataclass和原始JSON Schema
- 最适合已投入LangChain或LangGraph的团队
Marvin:任务式提取
Marvin 3.x是从非结构化文本到类型化Python对象的最短路径。它构建在Pydantic AI之上,因此你能以少得多的代码获得同样的Provider覆盖与验证能力。 请注意:Marvin 2的装饰器式API已经消失——@marvin.fn在3.0中被移除,取而代之的是顶层辅助函数和以任务为中心的Agent引擎。
- 一行式辅助函数:marvin.extract、marvin.cast、marvin.classify和marvin.generate
- 构建在Pydantic AI之上 — Provider支持与输出验证是继承而来,而非重新实现
- 面向多步骤工作的任务式引擎:marvin.run、marvin.Task、marvin.Agent、marvin.Thread
- Python类型提示即模式 — 提取与分类所需的样板代码极少
- 迁移提示:Marvin 2的@marvin.fn装饰器已不存在,相关调用需要改写
- Apache 2.0开源,由Prefect维护,免费使用
PromptQuorum:跨模型测试
PromptQuorum本身不是结构化输出库,而是用于验证跨模型结构化输出一致性的测试平台。 同时对GPT-5.6、Claude Opus 5、Gemini 3.1 Pro和20+其他模型运行相同的Prompt。测量每个模型的模式合规性、延迟和成本。
- 单次API调用中的多模型分发 — 对25+模型测试一个Prompt
- 结构化输出合规性指标 — 通过率、延迟、每个模型的成本
- 识别在您的模式上产生幻觉的模型 — 避免部署到不可靠的模型
- 共识模式 — 在独立模型运行之间找到一致性
- 与Instructor、Outlines、Pydantic AI、BAML、LangChain或原始LLM API配合使用
- 提供免费层,高容量测试提供企业定价
并排对比
工具 | 最佳用途 | 模式格式 | 语言 | 本地模型 | 许可证 | 学习曲线 |
|---|---|---|---|---|---|---|
| Instructor | Python API + 重试 | Pydantic模型 | Python, TS, Ruby, Go, Elixir, Rust | 支持(Ollama、vLLM) | MIT,免费 | 低 |
| Outlines | 本地模型部署 | Pydantic、JSON Schema、正则、CFG | Python | 支持(原生) | Apache 2.0,免费 | 中 |
| Pydantic AI | 类型安全Agent | Pydantic模型 | Python | 支持(Ollama) | MIT,免费 | 低 |
| BAML | 多语言团队、输出不稳定的模型 | .baml类文件 | Python、TS,另有6种经OpenAPI | 支持(OpenAI兼容) | Apache 2.0,可观测性付费 | 中 |
| LangChain | 链 + Agent | 工具定义 | Python、JS | 支持 | MIT,免费 | 中 |
| Marvin | 快速extract与classify | 类型提示 | Python | 支持 | Apache 2.0,免费 | 非常低 |
| PromptQuorum | 多模型测试 | API无关 | API优先 | 通过OpenAI代理 | 免费层 + 企业版 | 低 |
选择合适的工具
从回答三个问题开始:(1) 真正调用模型的服务是用什么语言写的?(2) 您需要本地模型支持吗?(3) 您的验证复杂度如何?
- 使用Instructor的情况: 构建Python API且需要验证失败时自动重试。最佳通用选择。
- 使用Outlines的情况: 部署本地模型(llama.cpp、vLLM、MLX)且希望在生成时保证模式合规性。
- 使用Pydantic AI的情况: 构建所有步骤都有类型安全性的多轮Agent工作流,或需要持久化执行。
- 使用BAML的情况: Python、TypeScript和Go服务必须共用一套模式,或者模型没有可靠的原生JSON模式。
- 使用LangChain的情况: 已经使用LangChain或LangGraph — with_structured_output()是最简单的添加。
- 使用Marvin的情况: 只想要一次extract或classify调用,且不需要自定义验证逻辑。
- 使用PromptQuorum的情况: 需要在生产前测试GPT、Claude和Gemini的结构化输出一致性。
逐步添加结构化输出
- 1定义输出模式 — 创建描述LLM应返回的字段、类型和约束的Pydantic模型(Python)、.baml类(BAML)、TypeScript接口或JSON Schema。
- 2选择库 — Python API选Instructor,本地模型选Outlines,Agent选Pydantic AI,多语言团队选BAML,已在使用则选LangChain,想一行提取选Marvin。
- 3安装并封装LLM调用 — `pip install instructor`(Python),然后将模式传递给API调用。Instructor处理验证和重试。
- 4使用PromptQuorum测试 — 部署到PromptQuorum,对GPT、Claude和Gemini运行您的Prompt。测量每个模型的模式合规性。
- 5根据失败改进模式 — 如果模型未通过验证,在Prompt中添加示例或调整模式约束。迭代直到所有模型通过。
结构化输出的常见错误
❌ 把任何JSON模式都当成模式保证
Why it hurts: 普通JSON模式(response_format json_object、Anthropic JSON控制)只保证回复是合法JSON,不保证它符合你的字段和类型。严格模式模式更进一步,能保证形状,但两者都不保证取值正确:一个格式完好的对象里,价格可能是编造的,日期可能是幻觉。
Fix: 无论如何都要在上面叠加验证:Instructor、Outlines、Pydantic AI或BAML。业务规则应写在Pydantic验证器里,而不是只靠模式。使用PromptQuorum逐模型测试合规失败情况。
❌ 设计过于严格的模式
Why it hurts: 过度约束的模式(小枚举列表、非常具体的正则表达式模式)导致LLM频繁验证失败。高重试次数浪费Token和金钱。
Fix: 使用PromptQuorum测试跨模型的模式严格性。放宽约束以实现95%以上的合规性。尽可能使用可选字段而不是必填字段。
❌ 不测试本地和API模型之间的差异
Why it hurts: llama.cpp上的Outlines与GPT-5.6上的Instructor行为不同。模式合规率因模型而异。只为前沿API模型构建,然后部署到小型本地模型,会导致生产失败。
Fix: 尽早测试所有预期的模型后端。使用PromptQuorum在本地(vLLM、Ollama)和托管(OpenAI、Anthropic、Google)模型上运行相同的Prompt。
❌ 忽略对延迟和Token成本的影响
Why it hurts: 带重试的结构化输出消耗更多Token。Instructor在失败时重试。Outlines的约束解码相比自由生成会增加每Token开销。没有测量每个模型的成本。
Fix: 使用PromptQuorum成本追踪。比较模型间的延迟。对于预算敏感的工作流,优先使用Outlines或BAML(没有重试循环)。在灵活模式下追求精度时,接受Instructor的重试成本。
❌ 混用验证方法(缺乏一致性)
Why it hurts: 部分请求使用Instructor,其他使用原始JSON解析。部分模型经过验证,其他没有。这导致生产中出现不一致的错误。
Fix: 在每个代码库中标准化一种验证方法。所有请求使用Instructor,或全部使用Outlines。一致性将调试时间减少10倍。
❌ 照抄针对已被取代的API写的教程
Why it hurts: 结构化输出库演进很快。Marvin在3.0移除了@marvin.fn装饰器,LangChain在1.x重写时重组了文档,Outlines在1.0改变了导入结构。从旧教程复制的代码在安装阶段就会失败。
Fix: 固定你所开发的主版本,并以最新文档确认API形态。优先参考官方仓库README而非博客文章,每次升级主版本时重新核对。
中国数据安全法与结构化输出合规
在中国大陆部署LLM结构化输出应用时,需要符合《数据安全法》(2021年)、《个人信息保护法》(PIPL)和网络安全法的相关要求。
- 《数据安全法》第36条: 向境外提供重要数据须经国家网信部门安全评估。使用Outlines或llama.cpp的本地模型部署可确保数据不出境,适用于金融、医疗、能源等重要行业数据处理。
- PIPL个人信息跨境规定: 通过LLM API处理个人信息需要满足数据出境安全评估或标准合同要求。本地模型部署绕过了这一合规负担。
- 金融行业合规: 银行、保险、证券机构在使用AI处理客户数据时需符合中国银保监会和证监会规定。Outlines与本地部署的Qwen3等国产模型结合,是合规的技术路径。
- 医疗和法律行业: 处理电子病历、法律文书等敏感数据时,推荐使用Outlines与本地部署组合,配合PromptQuorum进行一致性测试后再投入生产。
- BAML与私有化部署: BAML只要求OpenAI兼容端点,因此同一份.baml契约可以指向内网的vLLM部署——当Python与TypeScript服务需要共用模式、但数据不能出企业边界时尤其实用。
- 企业级推荐架构: 阿里云、腾讯云、华为云均提供符合等保2.0要求的私有化部署环境。在这些平台上运行Outlines和本地模型,既满足合规要求又保持技术灵活性。
LLM中的结构化输出是什么?
结构化输出将LLM响应限制为特定模式——JSON格式、定义的字段、类型约束。不是自由文本,而是返回代码可以直接解析和验证的数据,无需错误处理。
Python开发者最好的工具是什么?
Instructor是最受欢迎的Python选择。它使用Pydantic模型定义模式,自动处理重试和验证,支持所有主流LLM API以及通过Ollama或vLLM运行的本地模型。如果还需要类型安全的多轮Agent对话,Pydantic AI更合适;如果只需要一行的extract或classify调用,Marvin最快。
可以与Llama等本地模型一起使用吗?
可以。Outlines专门用于本地模型约束解码——支持transformers、llama.cpp、MLX、vLLM和Ollama,并在生成时保证输出能按你的模式解析。Instructor和Pydantic AI在把Ollama或vLLM作为API运行时同样支持,BAML则可对接任何OpenAI兼容端点。
Instructor和Marvin有什么区别?
Instructor封装你自己的LLM客户端,返回带自动重试的已验证Pydantic模型,调用过程由你掌控。Marvin 3.x构建在Pydantic AI之上,提供的是一行式辅助函数:marvin.extract、marvin.cast、marvin.classify。Instructor更明确,适合复杂验证;Marvin更简洁,适合直接的提取任务。请注意,Marvin 2的@marvin.fn装饰器已在Marvin 3中移除。
LangChain支持结构化输出吗?
是的。LangChain在ChatOpenAI、ChatAnthropic、ChatGoogleGenerativeAI等聊天模型类上提供with_structured_output(),用create_agent构建的Agent也接受response_format。自1.x系列起,各Provider的原生结构化输出支持是从模型档案数据中读取,而非硬编码。如果已使用LangChain或LangGraph且希望不换库添加模式强制,使用这个方法。
如何测试结构化输出的可靠性?
使用PromptQuorum在多个模型上运行相同的Prompt并测量模式合规性。GPT-5.6、Claude Opus 5、Gemini 3.1 Pro等模型的可靠性各不相同,小型本地模型差异更大。在部署到生产前进行测试,并在本地用Instructor或Pydantic做验证。
"约束解码"是什么意思?
约束解码将Token生成限制为仅符合您模式的有效值。Outlines通过计算每一步的有效下一个Token集来实现。这保证输出无需后处理验证或重试即可按模式解析,比普通的API级JSON模式更可靠。它约束的是结构而非真实性:字段会正确,取值仍需核对。
BAML是什么?什么时候该用它而不是Instructor?
BAML是一种模式优先的语言:你在.baml文件里写模式和提示词,再编译出面向你所用语言的类型化客户端。当同一个提示词被多种语言调用时(例如Python工作进程和TypeScript前端共用一份契约),或者模型返回的JSON"几乎合法"时,它比Instructor更合适——因为BAML的模式对齐解析器会修复Markdown代码块、尾逗号和开头的推理文字,而不是浪费一次重试。如果技术栈只有Python,并且希望把模式保留为普通Pydantic代码,继续用Instructor即可。
可以不用任何库使用结构化输出吗?
从技术上可以——您可以提示模型返回JSON并自己解析。但模型仍会产出格式错误的内容导致解析失败,而且没有任何机制强制你的字段名和类型。这7个工具分别通过重试验证(Instructor、Marvin)、解码时强制(Outlines)、解析时修复(BAML)或封装Provider API(LangChain、Pydantic AI)来解决。
哪个工具的文档最好?
LangChain和Pydantic AI因企业支持拥有最全面的文档。BAML的文档对一个年轻项目而言好得反常,因为这门语言本身需要被讲清楚。Instructor虽然是社区维护但有很好的教程和示例。Outlines的文档很技术性但很全面。Marvin的文档较简洁——请专门查看3.x的页面,因为Marvin 2的旧资料仍在流传。
需要全部7个工具还是只需要一个?
从一个开始。Python开发者试试Instructor或Pydantic AI。本地模型团队试试Outlines。多语言团队试试BAML。LangChain用户试试with_structured_output()。用PromptQuorum验证跨模型一致性。大多数团队使用一个工具加PromptQuorum进行测试。
在中国部署LLM结构化输出需要符合哪些数据安全要求?
主要需要符合《数据安全法》(2021年)和PIPL。处理个人信息或重要数据的LLM应用应优先考虑本地部署方案,使用Outlines结合Qwen3等本地模型可避免数据出境合规问题。金融、医疗等关键行业还需符合行业监管机构的具体要求。
企业级结构化输出合规架构的最佳实践是什么?
推荐使用阿里云、腾讯云或华为云提供的私有化部署环境,在等保2.0合规的基础设施上运行Outlines和本地模型。配合PromptQuorum进行多模型一致性测试,选出最适合业务场景的模型后再推向生产。建立模式验证日志以满足审计要求。
参考来源
- Instructor GitHub仓库 — Instructor库的官方仓库和文档
- Outlines GitHub仓库 — 保证模式合规性的约束解码
- Pydantic AI文档 — 带结构化输出的类型安全Agent框架
- LangChain结构化输出指南 — LangChain统一结构化输出API
- BAML文档 — 模式优先的提示词语言与schema-aligned parsing
- Marvin GitHub仓库 — 构建在Pydantic AI之上的任务式提取库
