Outlines 使用教程:3 行代码让大模型只输出合法 JSON,告别解析报错

Outlines 使用教程:3 行代码让大模型只输出合法 JSON,告别解析报错

【免费下载链接】outlines Structured Outputs 【免费下载链接】outlines 项目地址: https://gitcode.com/GitHub_Trending/ou/outlines

你让大模型返回 JSON,十次里总有几次在末尾多出一段解释、把数字写成字符串,或者整段被 ``` 包裹,json.loads 当场崩掉。事后拿正则去"抢救"输出,是很多 LLM 应用的常态,也是最脆的一环。Outlines 是 .txt 团队做的一个 Python 库,思路正好反过来:它不修结果,而是在模型逐字生成的过程中就把不合法的 token 挡掉,你拿到手的就是能直接反序列化的结构。

别再事后"抢救"输出,从生成那一刻就锁死格式

先讲清楚 Outlines 和常见做法差在哪,这决定了你要不要为它花几分钟。

主流做法是"提示词求它给 JSON + 生成完再解析 + 出错就重试"。Outlines 的做法是"把你要的结构交给它,生成过程里非法路径根本走不通"。

对比维度事后解析(多数项目现状)Outlines
结构何时保证生成完再检查生成过程中就保证
出错的代价json.loads 抛异常,得整条重试不会产生非法结构
你要写多少胶水代码正则、清洗、重试逻辑只传一个 Python/Pydantic 类型
换模型解析逻辑可能也要跟着改同一份代码跨 OpenAI、Ollama、vLLM

一句话:Outlines 让你把"输出长什么样"这件事从提示词里挪到一个类型定义里,而且这个类型还能被后续代码直接当 Python 对象用。

三步完成安装和第一次结构化调用

这节带你从装包到拿到第一个结果,全程不到十分钟。装包时带上后端对应的 extra,这里用最常见的 Transformers 本地推理为例。

pip install 'outlines[transformers]'

装好之后接上模型,直接调用。Outlines 的用法很克制——model(提示词, 输出类型),第二个参数就是"契约"。

import outlines
from transformers import AutoModelForCausalLM, AutoTokenizer
from typing import Literal

name = "microsoft/Phi-3-mini-4k-instruct"
model = outlines.from_transformers(
    AutoModelForCausalLM.from_pretrained(name, device_map="auto"),
    AutoTokenizer.from_pretrained(name),
)
print(model("评论'完全改变了我的生活!'的情绪?", Literal["Positive","Negative","Neutral"]))

运行后你会直接看到 Positive——不是带引号的字符串、不是 JSON,而是一个符合你给的枚举的值。把第二个参数换成 int,就能拿到纯数字;换成 Pydantic 模型,就能拿到嵌套结构。接入方式不止 Transformers 一种,Ollama、OpenAI、vLLM、llama.cpp 各有 from_ 入口,完整清单在 模型接入文档,安装细节看 安装指南。

实战一:把一份财报直接变成能入库的结构化数据

这节用一个真实痛点演示:财报这种格式混乱的文本,人工写解析规则极痛苦,而它恰好能被"定义成类型"。

目标很直白:输入一段 markdown 形式的利润表,输出能直接进 CSV/数据库的结构化字段,而不是靠正则一行行抠。

做法分两步:先定义"我要哪些列、各是什么类型",再把文本喂给模型、把类型作为输出契约传进去。仓库里这个 财报解析示例用的就是 NVIDIA 的利润表,输入长这样:

Outlines 结构化输出将 NVIDIA 财报利润表解析为结构化数据的示例

输出的字段可以这样约束,表格比代码更直观:

输出字段类型约束作用
itemstr项目名称,如 Revenue、Net income
valueint金额(百万为单位),直接可数值运算
periodLiteral财年末日期,锁死成固定取值

结果是你不再需要维护一堆 re.findall,数字天然是数字、枚举天然是枚举,缺的列会体现在"没生成"而不是"生成了一坨脏数据"。对这种字段稳定、格式多变的抽取任务,这是它最能打的地方。

实战二:给自由文本定"输出契约",再留一个"不知道"的出口

真实输入经常信息不全,硬要模型填满字段,它就会瞎编。这节教你用 Union 给模型留一个体面的退路。

目标是:信息够就返回结构化对象,不够就老老实实说"不知道",而不是编造。

from typing import Union, Literal
from pydantic import BaseModel

class EventInfo(BaseModel):
    name: str
    date: str
    event_type: Literal["conference","webinar","meetup","other"]

Result = Union[EventInfo, Literal["I don't know"]]
ticket = model("DevCon 2023, 11月15日于旧金山,需注册。", Result, max_new_tokens=200)

Union 里放一个 Pydantic 模型加一个 Literal 兜底,模型会在两条路里选合法的一条,不会给出"半结构化"的中间态。信息不足时它返回字符串,信息充足时你拿到的就是一个字段齐全的 EventInfo 实例。提示词可以抽到模板里批量复用,outlines.Template 支持 {{ 变量 }} 和循环,见 模板工具文档。

它到底为什么能做到

原理一句话就能讲清,不必展开推导。Outlines 会把你给的结构(Pydantic 模型、正则或 JSON Schema)编译成一张"哪些 token 组合仍然合法"的状态表。模型每吐一个 token,它只放行还能走向合法结局的那些,把会导致跑偏的选项概率压到 0。所以不是生成完再体检,而是非法分支在第一步就被剪掉——这就是"100% 落在你要的结构里"的来源,仓库的 后端实现能看到几套具体编译器。

哪些坑要提前知道

✅ 结构保证 ≠ 内容正确。它锁的是格式,模型仍可能把 A 事件的日期填进 B 字段、把数字写错,只是"形状"一定对。

⚠️ 约束越复杂、max_new_tokens 给得越小,越容易在"写到一半被截断"处停下,导致结构不完整。要么给足 token,要么把 schema 拆简单。

  • 纯自由写作(小说、营销文案)用不上,硬套约束反而限制表达。
  • 后端能力要分清:本地可控的推理(Transformers、vLLM、llama.cpp)能做 token 级硬掩码;接远程 API 的模型约束强度取决于提供方,要"绝不跑偏"优先选本地后端。怎么选看 推理后端选型指南。

你下一步该做什么

你的目标建议动作
只想试一下按上面装包,用 from_transformers 跑一个 Literal 分类,10 分钟见结果
要长期集成进业务通读 快速上手 与 后端选型,按团队现有推理栈挑 from_ 入口
做批量抽取/财报/发票直接参考 财报示例,把字段定义成 Pydantic 就能进 CSV
想统一管理提示词用 Template 模板引擎 把变量和循环抽出来复用

从最简单的 Literal 分类开始,把跑通的第一版当基线,再逐步把字段换成 Pydantic 模型,就是你接入 Outlines 最稳的路径。

【免费下载链接】outlines Structured Outputs 【免费下载链接】outlines 项目地址: https://gitcode.com/GitHub_Trending/ou/outlines

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值