outlines
为 LLM 生成结构化输出(JSON、Pydantic 等)的 Python 库,在推理阶段通过约束解码确保输出格式正确,省去后处理解析烦恼。支持 transformers、vLLM、OpenAI 等 10+ 模型后端,统一接口切换模型无需改代码。由 .txt 团队维护,被 NVIDIA、Cohere、HuggingFace 等采用,稳定性和社区活跃度都高。
README
🗒️ LLM 的结构化输出 🗒️
由 .txt 团队用 ❤👷️ 制作
受 NVIDIA、Cohere、HuggingFace、vLLM 等信任
.txt API 目前处于早期访问阶段。在此申请访问 →
🚀 构建结构化生成的未来
我们正与精选合作伙伴共同开发结构化生成的新接口。
需要 XML、FHIR、自定义 schema 或 grammar?我们谈谈。
审计你的 schema:提交一个 schema,我们向你展示生成过程中哪些地方会出错、修复问题的约束条件,以及修复前后的合规率。在此注册 →。
目录

为什么选择 Outlines?
LLM 功能强大,但输出不可预测。大多数解决方案试图在生成后通过解析、正则表达式或脆弱的代码来修复不良输出,而这些代码很容易出错。
Outlines 在生成过程中保证结构化输出——直接来自任何 LLM。
- 适用于任何模型 - 同一份代码可在 OpenAI、Ollama、vLLM 等模型上运行
- 集成简单 - 只需传递所需的输出类型:
model(prompt, output_type) - 保证有效结构 - 不再有解析难题或损坏的 JSON
- 不受提供商限制 - 切换模型无需更改代码
Outlines 理念

Outlines 遵循一个简单的模式,类似于 Python 自己的类型系统。只需指定所需的输出类型,Outlines 将确保你的数据精确匹配该结构:
- 对于是/否响应,使用
Literal["Yes", "No"] - 对于数值,使用
int - 对于复杂对象,使用 Pydantic 模型 定义结构
快速开始
开始使用 Outlines 很简单:
1. 安装 outlines
pip install outlines
2. 连接到首选模型
import outlines
from transformers import AutoTokenizer, AutoModelForCausalLM
MODEL_NAME = "microsoft/Phi-3-mini-4k-instruct"
model = outlines.from_transformers(
AutoModelForCausalLM.from_pretrained(MODEL_NAME, device_map="auto"),
AutoTokenizer.from_pretrained(MODEL_NAME)
)
3. 从简单的结构化输出开始
from typing import Literal
from pydantic import BaseModel
# 简单分类
sentiment = model(
"分析:'这款产品完全改变了我的人生!'",
Literal["Positive", "Negative", "Neutral"]
)
print(sentiment) # "Positive"
# 提取特定类型
temperature = model("水的沸点是多少摄氏度?", int)
print(temperature) # 100
4. 创建复杂结构
from pydantic import BaseModel
from enum import Enum
class Rating(Enum):
poor = 1
fair = 2
good = 3
excellent = 4
class ProductReview(BaseModel):
rating: Rating
pros: list[str]
cons: list[str]
summary: str
review = model(
"评测:XPS 13 电池续航出色,屏幕惊艳,但运行发热,摄像头质量差。",
ProductReview,
max_new_tokens=200,
)
review = ProductReview.model_validate_json(review)
print(f"评分: {review.rating.name}") # "评分: good"
print(f"优点: {review.pros}") # "优点: ['电池续航出色', '屏幕惊艳']"
print(f"总结: {review.summary}") # "总结: 笔记本电脑不错,屏幕好但发热有问题"
真实世界示例
以下是生产就绪的示例,展示 Outlines 如何解决常见问题:
🙋♂️ 客户支持分类此示例展示如何将自由形式的客户邮件转换为结构化的服务工单。通过解析优先级、类别和升级标记等属性,代码能够自动路由和处理支持问题。
import outlines
from enum import Enum
from pydantic import BaseModel
from transformers import AutoTokenizer, AutoModelForCausalLM
from typing import List
MODEL_NAME = "microsoft/Phi-3-mini-4k-instruct"
model = outlines.from_transformers(
AutoModelForCausalLM.from_pretrained(MODEL_NAME, device_map="auto"),
AutoTokenizer.from_pretrained(MODEL_NAME)
)
def alert_manager(ticket):
print("警报!", ticket)
class TicketPriority(str, Enum):
low = "low"
medium = "medium"
high = "high"
urgent = "urgent"
class ServiceTicket(BaseModel):
priority: TicketPriority
category: str
requires_manager: bool
summary: str
action_items: List[str]
customer_email = """
主题:紧急 - 付款后无法访问账户
我三小时前支付了高级版费用,但仍然无法访问任何功能。
我尝试了多次注销和重新登录。这让我无法接受,因为一小时后
我要向客户做演示,需要使用分析仪表盘。
请立即修复此问题,否则退款。
"""
prompt = f"""
<|im_start|>user
分析此客户邮件:
{customer_email}
<|im_end|>
<|im_start|>assistant
"""
ticket = model(
prompt,
ServiceTicket,
max_new_tokens=500
)
# 使用结构化数据路由工单
ticket = ServiceTicket.model_validate_json(ticket)
if ticket.priority == "urgent" or ticket.requires_manager:
alert_manager(ticket)
📦 电商产品分类
此用例演示 Outlines 如何将产品描述转换为结构化分类数据(如主类别、子类别和属性),以简化库存管理等任务。每一条产品描述都会被自动处理,减少人工分类开销。
import outlines
from pydantic import BaseModel
from transformers import AutoTokenizer, AutoModelForCausalLM
from typing import List, Optional
MODEL_NAME = "microsoft/Phi-3-mini-4k-instruct"
model = outlines.from_transformers(
AutoModelForCausalLM.from_pretrained(MODEL_NAME, device_map="auto"),
AutoTokenizer.from_pretrained(MODEL_NAME)
)
def update_inventory(product, category, sub_category):
print(f"更新 {product.split(',')[0]} 在类别 {category}/{sub_category}")
class ProductCategory(BaseModel):
main_category: str
sub_category: str
attributes: List[str]
brand_match: Optional[str]
# 批量处理产品描述
product_descriptions = [
"Apple iPhone 15 Pro Max 256GB 钛金属,6.7 英寸 Super Retina XDR 显示屏,支持 ProMotion",
"有机棉 T 恤,男款中号,海军蓝,100% 可持续材料",
"KitchenAid 立式搅拌机,5 夸脱,红色,10 档速度,带面团钩附件"
]
template = outlines.Template.from_string("""
<|im_start|>user
分类以下产品:
{{ description }}
<|im_end|>
<|im_start|>assistant
""")
# 对所有产品进行结构化分类
categories = model(
[template(description=desc) for desc in product_descriptions],
ProductCategory,
max_new_tokens=200
)
# 使用分类结果进行库存管理
categories = [
ProductCategory.model_validate_json(category) for category in categories
]
for product, category in zip(product_descriptions, categories):
update_inventory(product, category.main_category, category.sub_category)
📊 从不完整数据解析事件详情
此示例使用 Outlines 将事件描述解析为结构化信息(如事件名称、日期、地点、类型和主题),即使数据不完整也能处理。它利用联合类型(union type)返回结构化事件数据或备用的“我不知道”答案,确保在不同场景下都能稳健提取。
import outlines
from typing import Union, List, Literal
from pydantic import BaseModel
from enum import Enum
from transformers import AutoTokenizer, AutoModelForCausalLM
MODEL_NAME = "microsoft/Phi-3-mini-4k-instruct"
model = outlines.from_transformers(
AutoModelForCausalLM.from_pretrained(MODEL_NAME, device_map="auto"),
AutoTokenizer.from_pretrained(MODEL_NAME)
)
class EventType(str, Enum):
conference = "conference"
webinar = "webinar"
workshop = "workshop"
meetup = "meetup"
other = "other"
class EventInfo(BaseModel):
"""关于技术活动的结构化信息"""
name: str
date: str
location: str
event_type: EventType
topics: List[str]
registration_required: bool
# 创建联合类型:可以是结构化的 EventInfo 或者 "I don't know"
EventResponse = Union[EventInfo, Literal["I don't know"]]
# 示例事件描述
event_descriptions = [
# 完整信息
"""
欢迎参加 DevCon 2023,这是 2023 年 11 月 15-17 日在旧金山会议中心
举行的顶级开发者大会。主题包括 AI/ML、云基础设施和 web3。需要注册。
""",
# 信息不足
"""
下周有技术活动。更多详情即将发布。
"""
]
# 处理事件
results = []
for description in event_descriptions:
prompt = f"""
<|im_start>system
你是一个有帮助的助手
<|im_end|>
<|im_start>user
提取此技术活动的结构化信息:
{description}
如果有足够信息,返回包含以下字段的 JSON 对象:
- name: 活动名称
- date: 活动举办日期
- location: 活动举办地点
- event_type: 可以是 'conference', 'webinar', 'workshop', 'meetup' 或 'other'
- topics: 活动主题列表
- registration_required: 布尔值,表示是否需要注册
如果可用信息不足以填充此 JSON,则回答 'I don't know'。
<|im_end|>
<|im_start|>assistant
"""
# 联合类型允许模型返回结构化数据或 "I don't know"
result = model(prompt, EventResponse, max_new_tokens=200)
results.append(result)
# 显示结果
for i, result in enumerate(results):
print(f"活动 {i+1}:")
if isinstance(result, str):
print(f" {result}")
else:
# 它是 EventInfo 对象
print(f" 名称: {result.name}")
print(f" 类型: {result.event_type}")
print(f" 日期: {result.date}")
print(f" 主题: {', '.join(result.topics)}")
print()
# 在后续处理中使用结构化数据
structured_count = sum(1 for r in results if isinstance(r, EventInfo))
print(f"成功提取了 {len(results)} 个活动中的 {structured_count} 个数据")
🗂️ 将文档归类为预定义类型
在此案例中,Outlines 使用字面量类型(Literal type)将文档分类为预定义类别(例如“财务报告”、“法律合同”)。分类结果以表格形式和分类分布摘要展示,说明结构化输出如何简化内容管理。
import outlines
from typing import Literal, List
import pandas as pd
from transformers import AutoTokenizer, AutoModelForCausalLM
MODEL_NAME = "microsoft/Phi-3-mini-4k-instruct"
model = outlines.from_transformers(
AutoModelForCausalLM.from_pretrained(MODEL_NAME, device_map="auto"),
AutoTokenizer.from_pretrained(MODEL_NAME)
)
# 使用 Literal 定义分类类别
DocumentCategory = Literal[
"Financial Report",
"Legal Contract",
"Technical Documentation",
"Marketing Material",
"Personal Correspondence"
]
# 待分类的示例文档
documents = [
"第三季度财务总结:收入同比增长 15%,达 1240 万美元。EBITDA 利润率从去年同期的 19% 提高至 23%。运营费用...",
"本协议由甲方和乙方(以下简称“双方”)于... 日签署。",
"API 接受带有 JSON 负载的 POST 请求。必需参数包括 'user_id' 和 'transaction_type'。端点成功时返回 200 状态码。"
]
template = outlines.Template.from_string("""
<|im_start|>user
将以下文档分类为以下类别中的一类:
- 财务报告
- 法律合同
- 技术文档
- 营销材料
- 个人通信
文档:
{{ document }}
<|im_end|>
<|im_start|>assistant
""")
# 分类文档
def classify_documents(texts: List[str]) -> List[DocumentCategory]:
results = []
for text in texts:
prompt = template(document=text)
# 模型必须返回预定义类别之一
category = model(prompt, DocumentCategory, max_new_tokens=200)
results.append(category)
return results
# 执行分类
classifications = classify_documents(documents)
# 创建简单结果表
results_df = pd.DataFrame({
"文档": [doc[:50] + "..." for doc in documents],
"分类": classifications
})
print(results_df)
# 按类别统计文档数量
category_counts = pd.Series(classifications).value_counts()
print("\n分类分布:")
print(category_counts)
📅 通过函数调用安排会议
此示例演示 Outlines 如何理解自然语言会议请求,并将其转换为与预定义函数参数匹配的结构化格式。提取会议详情(如标题、日期、时长、参与者)后,用于自动排程会议。
import outlines
import json
from typing import List, Optional
from datetime import date
from transformers import AutoTokenizer, AutoModelForCausalLM
MODEL_NAME = "microsoft/phi-4"
model = outlines.from_transformers(
AutoModelForCausalLM.from_pretrained(MODEL_NAME, device_map="auto"),
AutoTokenizer.from_pretrained(MODEL_NAME)
)
# 定义带有类型化参数的函数
def schedule_meeting(
title: str,
date: date,
duration_minutes: int,
attendees: List[str],
location: Optional[str] = None,
agenda_items: Optional[List[str]] = None
):
"""按指定详情安排会议"""
# 在真实应用中,这会创建会议
meeting = {
"title": title,
"date": date,
"duration_minutes": duration_minutes,
"attendees": attendees,
"location": location,
"agenda_items": agenda_items
}
return f"会议 '{title}' 已安排于 {date},共 {len(attendees)} 名参与者"
# 自然语言请求
user_request = """
我需要安排下周二下午 2 点与工程团队进行产品路线图评审。
会议时长 90 分钟。请邀请 john@example.com、sarah@example.com
以及产品团队 product@example.com。
"""
# Outlines 自动从函数签名推断所需结构
prompt = f"""
<|im_start|>user
从以下请求中提取会议详情:
{user_request}
<|im_end|>
<|im_start|>assistant
"""
meeting_params = model(prompt, schedule_meeting, max_new_tokens=200)
# 结果是一个匹配函数参数的字典
meeting_params = json.loads(meeting_params)
print(meeting_params)
# 使用提取的参数调用函数
result = schedule_meeting(**meeting_params)
print(result)
# "会议 '产品路线图评审' 已安排于 2023-10-17,共 3 名参与者"
📝 使用可复用模板动态生成提示
此示例使用 Jinja 模板动态生成用于情感分析等任务的提示。它展示了如何轻松复用和定制提示——包括少样本学习策略——以适应不同类型的内容,同时保证输出结构化。
import outlines
from typing import List, Literal
from transformers import AutoTokenizer, AutoModelForCausalLM
MODEL_NAME = "microsoft/phi-4"
model = outlines.from_transformers(
AutoModelForCausalLM.from_pretrained(MODEL_NAME, device_map="auto"),
AutoTokenizer.from_pretrained(MODEL_NAME)
)
# 1. 创建可复用的 Jinja 模板
sentiment_template = outlines.Template.from_string("""
<|im_start>user
分析以下 {{ content_type }} 的情感:
{{ text }}
请将分析结果输出为 "Positive", "Negative" 或 "Neutral"。
<|im_end>
<|im_start>assistant
""")
# 2. 用不同参数生成提示
review = "这家餐厅超出了我所有的期望。服务太棒了!"
prompt = sentiment_template(content_type="评论", text=review)
# 3. 使用模板化提示进行结构化生成
result = model(prompt, Literal["Positive", "Negative", "Neutral"])
print(result) # "Positive"
# 模板也可以从文件加载
example_template = outlines.Template.from_file("templates/few_shot.txt")
# 用于少样本学习的示例
examples = [
("食物是冷的", "Negative"),
("员工很友好", "Positive")
]
few_shot_prompt = example_template(examples=examples, query="服务很慢")
print(few_shot_prompt)
他们使用了 Outlines
模型集成
| 模型类型 | 描述 | 文档 |
|---|---|---|
| 服务端支持 | vLLM 和 Ollama | 服务端集成 → |
| 本地模型支持 | transformers 和 llama.cpp | 模型集成 → |
| API 支持 | OpenAI、Gemini 和 Dottxt | API 集成 → |
核心功能
| 功能 | 描述 | 文档 |
|---|---|---|
| 多项选择 | 将输出限制为预定义选项 | 多项选择指南 → |
| 函数调用 | 从函数签名推断结构 | 函数指南 → |
| JSON / Pydantic | 生成匹配 JSON schema 的输出 | JSON 指南 → |
| 正则表达式 | 生成遵循正则模式的文本 | 正则指南 → |
| 文法 | 强制复杂输出结构 | 文法指南 → |
其他功能
| 功能 | 描述 | 文档 |
|---|---|---|
| 提示模板 | 将复杂提示与代码分离 | 模板指南 → |
| 自定义类型 | 直观的接口,用于构建复杂类型 | Python 类型指南 → |
| 应用 | 将模板和类型封装为函数 | 应用指南 → |
关于 .txt
Outlines 由 .txt 开发和维护,这是一家致力于让 LLM 在生产应用中更可靠的公司。
我们专注于通过以下方式推进结构化生成技术:
关注我们的 Twitter 或查看博客,了解我们在让 LLM 更可靠方面的最新进展。
社区
引用 Outlines
@article{willard2023efficient,
title={Efficient Guided Generation for Large Language Models},
author={Willard, Brandon T and Louf, R{\'e}mi},
journal={arXiv preprint arXiv:2307.09702},
year={2023}
}