Outlines 快速入门:用 Python 类型系统实现 LLM 结构化输出
【免费下载链接】outlinesStructured Outputs项目地址: https://gitcode.com/GitHub_Trending/ou/outlines
导读
Outlines 是一个生成式模型编程框架(Generative Model Programming Framework),其核心理念是:用定义函数返回类型注解的方式,为 LLM 的输出指定严格的结构。本文基于docs/guide/getting_started.md快速入门指南,完整演示如何安装 Outlines、初始化各类推理后端(Transformers、vLLM、Ollama、OpenAI、llama.cpp 等)、调用模型生成文本、使用五类结构化输出类型(基础类型、多选、JSON Schema、正则、上下文无关文法)以及用Generator复用"模型 + 输出类型"组合。读完本文,你将掌握一套与 Python 类型系统无缝对齐的结构化生成工作流,并理解其底层如何通过输出类型编译与 logits 处理器实现约束生成。
安装 Outlines
Outlines 建议使用现代 Python 依赖管理工具uv进行安装:
uv pip install 'outlines[transformers]'也可以使用经典的pip:
pip install 'outlines[transformers]'其中[transformers]是 extras 标记,用于同时安装本地transformers推理所需的依赖。更完整的安装方式与可选依赖说明见 安装指南。
可选依赖:按需安装推理引擎
Outlines 本身只提供统一封装层,具体的模型后端依赖按需安装,避免为用不到的引擎背负冗余依赖。在安装指南中,各模型对应的附加依赖如下(节选自 installation.md):
| 模型 | 附加安装命令 |
|---|---|
| Anthropic | pip install anthropic |
| Dottxt | pip install dottxt |
| Gemini | pip install google-generativeai |
| Llamacpp | pip install llama-cpp-python |
| Mlx-lm | pip install mlx mlx-lm |
| Ollama | pip install ollama |
| OpenAI | pip install openai |
| SGLang / vLLM(在线服务) | pip install openai |
| TGI | pip install huggingface_hub |
| Transformers / TransformersMultiModal | pip install transformers |
| vLLM(离线) | pip install vllm |
硬件注意:若使用本地模型,需关注其硬件要求。
vllm、llama-cpp-python通常需要兼容 GPU;mlx-lm专为 Apple Silicon 设计,在其他平台不适用。详细说明见 安装指南。
创建模型:从from_*加载器开始
Outlines 中,模型是"包装了推理引擎或客户端"的对象,统一提供结构化文本生成接口。每个模型类都有一个对应的加载函数,命名规律为from_加模型小写名称,例如Transformers对应from_transformers。完整的模型清单见 模型文档。
下面逐一给出所有受支持后端的初始化示例(均来自原文档,已保留完整参数)。
vLLM(在线服务)
需要先独立启动 vLLM 服务,再通过 OpenAI 客户端接入:
import outlines from openai import OpenAI # 你需要单独运行一个 vLLM server # 创建一个以 VLLM server 地址为 base_url 的 OpenAI 客户端 openai_client = OpenAI(base_url="http://localhost:11434/v1") # 创建 Outlines 模型 model = outlines.from_vllm(openai_client, "microsoft/Phi-3-mini-4k-instruct")Ollama
本地 Ollama 服务上的模型,通过ollama客户端接入:
import outlines from ollama import Client # 创建 Ollama 客户端 ollama_client = Client() # 创建 Outlines 模型,模型必须已存在于本机 model = outlines.from_ollama(ollama_client, "tinyllama")OpenAI
远程 API 模型:
import outlines from openai import OpenAI # 创建 OpenAI 客户端实例 openai_client = OpenAI() # 创建 Outlines 模型 model = outlines.from_openai(openai_client, "gpt-4o")Transformers(本地)
本地 Transformers 模型,直接传入 Hugging Face 模型与分词器实例:
import outlines from transformers import AutoModelForCausalLM, AutoTokenizer # 定义要使用的模型 model_name = "HuggingFaceTB/SmolLM2-135M-Instruct" # 创建 HuggingFace 模型与分词器 hf_model = AutoModelForCausalLM.from_pretrained(model_name) hf_tokenizer = AutoTokenizer.from_pretrained(model_name) # 创建 Outlines 模型 model = outlines.from_transformers(hf_model, hf_tokenizer)llama.cpp
GGUF 格式的本地模型,模型会自动从 Hugging Face Hub 下载:
import outlines from llama_cpp import Llama # 要使用的模型,将从 HuggingFace hub 下载 repo_id = "TheBloke/Llama-2-13B-chat-GGUF" file_name = "llama-2-13b-chat.Q4_K_M.gguf" # 创建 Llama.cpp 模型 llama_cpp_model = Llama.from_pretrained(repo_id, file_name) # 创建 Outlines 模型 model = outlines.from_llamacpp(llama_cpp_model)Gemini
Google Gemini 服务:
import outlines from google.generativeai import GenerativeModel # 创建 Gemini 客户端 gemini_client = GenerativeModel() # 创建 Outlines 模型 model = outlines.from_gemini(gemini_client, "gemini-1-5-flash")mlx-lm(Apple Silicon)
使用mlx_lm.load的返回值(模型与分词器)直接构造:
import outlines import mlx_lm # 用 mlx_lm.load 的输出创建 MLXLM 模型,模型将从 HuggingFace hub 下载 model = outlines.from_mlxlm( *mlx_lm.load("mlx-community/SmolLM-135M-Instruct-4bit") )SGLang(在线服务)
与 vLLM 一样,先启动独立 SGLang 服务,再用 OpenAI 客户端接入:
import outlines from openai import OpenAI # 你需要单独运行一个 SGLang server # 创建以 SGLang server 地址为 base_url 的 OpenAI 客户端 openai_client = OpenAI(base_url="http://localhost:11434/v1") # 创建 Outlines 模型 model = outlines.from_sglang(openai_client)TGI(Hugging Face Text Generation Inference)
通过huggingface_hub的InferenceClient接入独立 TGI 服务:
import outlines from huggingface_hub import InferenceClient # 你需要单独运行一个 TGI server # 创建以 TGI server 地址为 base_url 的 InferenceClient 客户端 tgi_client = InferenceClient("http://localhost:8080") # 创建 Outlines 模型 model = outlines.from_tgi(tgi_client)vLLM(离线模式)
不启动服务器,直接在进程内用 vLLM 推理:
import outlines from vllm import LLM # 创建 vLLM 模型 vllm_model = LLM("microsoft/Phi-3-mini-4k-instruct") # 创建 Outlines 模型 model = outlines.from_vllm_offline(vllm_model)模型分类:本地(可引导)模型与服务端(黑盒)模型
从源码 src/outlines/models/init.py 可以看到,模型被划分为两类:
SteerableModel(本地模型,可引导):包含LlamaCpp、MLXLM、Transformers。文本生成发生在本地推理库对象内部,Outlines 可以通过logits processor直接介入生成过程,因此所有结构化输出类型(基础类型、JSON Schema、多选、正则、文法)都可用。BlackBoxModel(服务端模型,黑盒):包含Anthropic、Dottxt、Gemini、LMStudio、Ollama、OpenAI、Mistral、SGLang、TGI、VLLM、VLLMOffline等。模型通过客户端向服务器发请求完成生成,Outlines 无法直接控制生成过程,只能把输出类型以各服务支持的格式(如response_format)交给对方,因此部分输出类型不可用。
每个模型类都要求实例化时绑定一个ModelTypeAdapter(见 src/outlines/models/base.py),它负责两件事:format_input把用户输入(字符串、Chat 消息等)格式化为模型期望的格式;format_output_type把输出类型格式化为该模型能识别的约束参数。这就是"同一个 Python 输出类型能跨不同后端使用"的底层机制。
生成文本:调用模型与流式输出
创建好模型后即可直接调用。所有模型都是可调用对象,传入提示词即可生成文本:
model = <your_model_as_defined_above> # 调用模型生成文本 result = model("Write a short story about a cat.") print(result) # 'In a quiet village where the cobblestones hummed softly beneath the morning mist...'多数模型还支持流式输出,通过streaming(部分文档与实现中也写作stream)方法,以迭代器方式逐块返回:
model = <your_model_as_defined_above> # 流式生成文本 for chunk in model.streaming("Write a short story about a cat."): print(chunk) # 'In ...'提示:原文档流式示例的
for语句在代码块中省略了末尾冒号,实际使用时请补全。另外,从源码看,Model基类(src/outlines/models/base.py)除__call__与stream外还统一提供batch方法,用于一次处理多条提示词并返回结果列表;__call__/batch/stream内部都会基于output_type临时构造一个Generator再调用,这与直接使用Generator是等价的。
结构化生成:把类型注解变成生成约束
Outlines 遵循一个与 Python 类型系统高度对称的模式:你在调用时像写函数返回类型注解一样,把期望的输出类型传给模型,Outlines 保证生成结果严格匹配该结构。
支持的五类输出类型(详见 输出类型文档):
- 基础类型(Basic Types):
int、float、bool等 - 多选(Multiple Choices):使用
Literal或Enum - JSON Schema(JSON Schemas):包括 Pydantic 模型、dataclass 等多种对象
- 正则(Regex Patterns):通过
Regex对象 - 上下文无关文法(Context-free Grammars):通过
CFG对象
下面逐个演示五类输出类型的用法。
基础类型:生成int
model = <your_model_as_defined_above> # 生成一个整数 result = model("How many countries are there in the world?", int) print(result) # '200'多选:Enum或Literal
from enum import Enum # 定义多选输出类型 class PizzaOrBurger(Enum): pizza = "pizza" burger = "burger" model = <your_model_as_defined_above> # 生成两个选项之一 result = model("What do you want to eat, a pizza or a burger?", PizzaOrBurger) print(result) # 'pizza'也可以直接使用Literal["pizza", "burger"]。当选项列表是动态生成时,还可以使用 Outlines 专有的Choice类型(见 src/outlines/types/init.py 导出的Choice),其入参为选项列表。
JSON Schema:Pydantic 模型
from datetime import date from typing import Dict, List, Union from pydantic import BaseModel model = <your_model_as_defined_above> # 定义用作输出类型的类 class Character(BaseModel): name: str birth_date: date skills: Union[Dict, List[str]] # 生成一个角色 result = model("Create a character", Character) print(result) # '{"name": "Aurora", "birth_date": "1990-06-15", "skills": ["Stealth", "Diplomacy"]}' print(Character.model_validate_json(result)) # name=Aurora birth_date=datetime.date(1990, 6, 15) skills=['Stealth', 'Diplomacy']除 Pydantic 类外,dataclass、TypedDict、GenSON 的SchemaBuilder以及"函数签名"(参数名作键、类型注解定类型)都可以作为 JSON Schema 类输出类型。注意:生成器始终返回字符串,需要你自行用Character.model_validate_json(result)之类的方式完成类型转换——这与函数类型注解只在编译期生效不同,见 输出类型文档。
对于裸的 JSON Schema 字符串或字典,为避免与普通字符串/字典歧义,必须用outlines.types.JsonSchema包装(可选参数whitespace_pattern控制 JSON 空白模式,ensure_ascii控制json.dumps的对应参数)。
正则:Regex
from outlines.types import Regex model = <your_model_as_defined_above> # 定义一个 3 位数字的正则 output_type = Regex(r"[0-9]{3}") # 生成数字 result = model("Write a 3 digit number", output_type) print(result) # '236'outlines.types模块还内置了一批常用正则类型可直接作为输出类型导入使用,例如sentence、paragraph、email、isbn、ipv4、ipv6、uuid4、semver、hex_color、credit_card等(定义见 src/outlines/types/init.py)。例如:
from outlines.types import sentence print(type(sentence)) # outlines.types.dsl.Regex print(sentence.pattern) # [A-Z].*\s*[.!?]构建复杂正则时,可借助 正则 DSL(either、optional、zero_or_more、between等函数)。
上下文无关文法:CFG(Lark 文法)
from outlines.types import CFG model = <your_model_as_defined_above> # 以字符串形式定义 Lark 文法 arithmetic_grammar = """ ?start: sum ?sum: product | sum "+" product -> add | sum "-" product -> sub ?product: atom | product "*" atom -> mul | product "/" atom -> div ?atom: NUMBER -> number | "-" atom -> neg | "(" sum ")" %import common.NUMBER %import common.WS_INLINE %ignore WS_INLINE """ # 生成一个算术表达式 result = model("Write an arithmetic operation", CFG(arithmetic_grammar)) print(result) # '2 + 3'仓库中同样提供了若干 Lark 文法示例文件,如 算术文法、JSON 文法、公共文法,以及对应的测试样例 tests/cfg_samples/arithmetic 与 tests/cfg_samples/json。
输出类型的后端可用性差异
并非所有输出类型在所有模型上都可用——这取决于底层推理引擎的能力。各模型对输出类型的支持情况汇总在 模型文档 的Features Matrix特性矩阵中,例如:Transformers、MLXLM、VLLMOffline等本地模型支持全部五类输出类型;而Anthropic、Ollama、OpenAI等服务端模型在基础类型、Regex 等维度为 ❌,仅通过服务端的response_format能力支持 JSON Schema。使用前请对照矩阵确认。
底层原理:输出类型如何变成生成约束
从源码 src/outlines/types/dsl.py 可以梳理出输出类型的处理链路,共三步:
- 定义:
Term类及其子类(Regex、CFG、JsonSchema以及正则 DSL 的Alternatives、KleeneStar等)承载输出类型定义; - 转换:
python_types_to_terms把int、Literal、Pydantic 模型等 Python 类型归一化为Term实例; - 编译:
to_regex把Term编译为正则字符串;CFG直接取 Lark 文法;JsonSchema则通过outlines_core的build_regex_from_schema把 JSON Schema 转成对应的正则约束。
最终在 src/outlines/generator.py 的SteerableGenerator中,这些编译结果被交给后端工厂(get_regex_logits_processor/get_cfg_logits_processor/get_json_schema_logits_processor,后端实现见 src/outlines/backends)生成一个logits processor。生成时该 processor 在每一步解码时屏蔽掉不符合约束的 token,从而在数学上保证输出必然匹配目标结构。outlines_core、xgrammar、llguidance三个后端实现了不同的编译与执行策略(见 后端文档)。
Generators:复用"模型 + 输出类型"
Generator是 Outlines 中另一类核心对象,用于封装一个模型与一个输出类型。创建后可以像调用模型一样调用它,而生成结果始终满足最初给定的输出类型:
from typing import Literal from outlines import Generator model = <your_model_as_defined_above> # 创建 generator generator = Generator(model, Literal["pizza", "burger"]) # 像调用模型一样调用它 result = generator("What do you want to eat, a pizza or a burger?") print(result) # pizza为什么用 Generator?
当需要针对同一"模型 + 输出类型"组合反复生成文本时,Generator有两个关键收益:
- 不必在每次调用时重复传输出类型;
- 输出类型只编译一次。对于本地模型,把 Python 类型编译为 logits processor 是相对昂贵的操作,复用 Generator 可显著减少开销。
Generator 的三种形态
从 src/outlines/generator.py 的Generator工厂函数可以看出,它根据模型类型自动分派:
SteerableGenerator:用于本地SteerableModel,在构造时把output_type编译为 logits processor 并缓存,__call__/batch/stream每次调用前会reset()处理器状态再生成;BlackBoxGenerator:用于服务端BlackBoxModel,不做本地编译,直接以输出类型调用model.generate(...);AsyncBlackBoxGenerator:用于异步黑盒模型,返回await结果与异步迭代器。
另外,output_type与processor两个参数互斥:同时传入会抛出ValueError("At most one of output_type or processor can be provided")。高级用户可以为本地模型传入已构建好的 logits processor(processor=参数),从已有处理器直接创建 Generator。
更详细的说明见 Generators 文档。
其他特性与下一步
getting_started.md仅是 Outlines 的入口。在 Features 文档 中还有更多能力,包括:
- Applications:面向具体应用场景的高级封装(见 src/outlines/applications.py 与 应用文档);
- Prompt Templates:提示词模板系统(见 src/outlines/templates.py 与 模板文档);
- 正则 DSL:组合式构建复杂正则(见 正则 DSL 文档);
- logits processors:自定义约束处理器(见 logits_processors.md);
- 多模态输入:通过
outlines.inputs模块的Audio、Image、Video、Chat等输入类型(见 输入文档)。
如果你对架构感兴趣,可以继续阅读 架构指南 了解各组件如何协同;对应开发环境的搭建可参考 贡献指南。
小结
- 安装:
uv pip install 'outlines[transformers]'或pip install 'outlines[transformers]',其余引擎按需安装; - 模型:通过
from_<engine>系列加载器统一创建,本地模型(可引导)支持全部输出类型,服务端模型(黑盒)受限于引擎能力; - 生成:直接调用模型(可带
output_type)、stream/streaming流式输出、batch批量输出; - 结构化输出:五类输出类型(基础类型、多选、JSON Schema、Regex、CFG),底层编译为 logits processor 实现约束采样;
- 复用:
Generator(model, output_type)把"模型 + 输出类型"编译一次、多次使用,是高频场景下的推荐写法。
【免费下载链接】outlinesStructured Outputs项目地址: https://gitcode.com/GitHub_Trending/ou/outlines
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考