开源项目

outlines

outlines

为 LLM 生成结构化输出(JSON、Pydantic 等)的 Python 库,在推理阶段通过约束解码确保输出格式正确,省去后处理解析烦恼。支持 transformers、vLLM、OpenAI 等 10+ 模型后端,统一接口切换模型无需改代码。由 .txt 团队维护,被 NVIDIA、Cohere、HuggingFace 等采用,稳定性和社区活跃度都高。

README

Outlines Logo Outlines Logo

🗒️ LLM 的结构化输出 🗒️

.txt 团队用 ❤👷️ 制作
受 NVIDIA、Cohere、HuggingFace、vLLM 等信任

PyPI 版本 下载量 星标

Discord 博客 Twitter


.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

用户 Logo 用户 Logo

模型集成

模型类型 描述 文档
服务端支持 vLLM 和 Ollama 服务端集成 →
本地模型支持 transformers 和 llama.cpp 模型集成 →
API 支持 OpenAI、Gemini 和 Dottxt API 集成 →

核心功能

功能 描述 文档
多项选择 将输出限制为预定义选项 多项选择指南 →
函数调用 从函数签名推断结构 函数指南 →
JSON / Pydantic 生成匹配 JSON schema 的输出 JSON 指南 →
正则表达式 生成遵循正则模式的文本 正则指南 →
文法 强制复杂输出结构 文法指南 →

其他功能

功能 描述 文档
提示模板 将复杂提示与代码分离 模板指南 →
自定义类型 直观的接口,用于构建复杂类型 Python 类型指南 →
应用 将模板和类型封装为函数 应用指南 →

关于 .txt

dottxt logo dottxt logo

Outlines 由 .txt 开发和维护,这是一家致力于让 LLM 在生产应用中更可靠的公司。

我们专注于通过以下方式推进结构化生成技术:

  • 🧪 前沿研究:我们在结构化生成方面发表研究成果
  • 🚀 企业级解决方案:你可以许可我们的企业级库
  • 🧩 开源协作:我们相信在公开环境中构建,并为社区做贡献

关注我们的 Twitter 或查看博客,了解我们在让 LLM 更可靠方面的最新进展。

社区

贡献者 星标 下载量 Discord 徽章

引用 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}
}
开源项目dottxt-ai2026-07-21原文

相关内容