综合介绍
Outlines 是一个由 dottxt-ai 开发的开源库,旨在通过结构化文本生成来提升大语言模型(LLM)的应用能力。该库支持多种模型集成,包括 OpenAI、transformers、llama.cpp 等,提供简单而强大的提示原语,基于 Jinja 模板引擎。Outlines 允许用户通过正则表达式、JSON 模式或 Pydantic 模型进行快速生成,并支持多种采样算法,如贪婪算法、多项式采样和束搜索。该项目还提供了缓存生成、批量推理等功能,旨在提高模型的推理速度和性能。Outlines 已被主流推理框架(如 VLLM、TGI)用于函数调用。
功能列表
- 多模型集成:支持 OpenAI、transformers、llama.cpp 等模型
- 简单而强大的提示原语:基于 Jinja 模板引擎
- 正则表达式结构生成:快速生成符合正则表达式的文本
- JSON 生成:根据 JSON 模式或 Pydantic 模型生成文本
- 语法结构生成:支持循环、条件和自定义 Python 函数的生成
- 生成缓存:缓存生成结果,提高效率
- 批量推理:支持批量处理,提高推理速度
- 多种采样算法:支持贪婪、多项式和束搜索等采样算法
- Docker 支持:提供官方 Docker 镜像,方便部署
使用帮助
安装流程
- 确保已安装 Python 环境。
- 使用 pip 安装 Outlines:
pip install outlines
- 如果需要使用 Rust 版本的核心功能,可以安装 outlines-core:
pip install outlines-core
使用指南
基本使用
- 导入 Outlines 库:
import outlines
- 选择并加载模型:
model = outlines.models.transformers("openai/gpt-3.5-turbo")
- 创建提示并生成文本:
prompt = "生成一个关于AI技术的简短介绍。"
generated_text = model.generate(prompt)
print(generated_text)
高级功能
- 使用正则表达式生成结构化文本:
import outlines
generator = outlines.generate.regex("^[A-Z][a-z]+$")
result = generator("生成一个符合正则表达式的单词")
print(result)
- 使用 JSON 模式生成文本:
import outlines
from pydantic import BaseModel
class Person(BaseModel):
name: str
age: int
generator = outlines.generate.json(Person)
result = generator({"name": "Alice", "age": 30})
print(result)
- 使用多种采样算法:
import outlines
generator = outlines.generate.choice(model, ["选项1", "选项2", "选项3"])
result = generator("请选择一个选项:")
print(result)
- 部署 Docker 镜像:
docker pull outlinesdev/outlines
docker run -p 8000:8000 outlinesdev/outlines
常见问题
- 如何提高生成速度? 使用批量推理和生成缓存功能可以显著提高生成速度。
- 如何集成自定义函数? 可以在生成过程中使用自定义 Python 函数来处理复杂逻辑。
大模型的非结构化输出带来的问题
问题
大语言模型(LLM)具有强大的文本生成能力,但在生成结构化数据时表现不够可靠。这对以 Agent 为核心的 AI 应用造成了严重的困扰。
核心问题
- 输出不一致性:当从邮件中提取航班信息时,理想情况是输出一致的 JSON 对象,但 LLM 往往失败,导致诸如 "JSON decode errors" 的问题。
- 缺乏可靠性:这种不可预测性使得基于 LLM 构建复杂模块化系统变得困难。
影响
没有可靠的结构化输出,开发者需要通过繁琐的后处理(如正则表达式)提取信息,导致开发效率低下且易出错。
结构化输出的好处
数据的普遍结构性
即使是看似无结构的数据(如 GSM 数据集),也常常有内在的结构可利用。
保证输出格式
通过定义特定的结构(如 JSON 或正则表达式),可以保证输出的有效性,避免繁琐的后处理。
提升性能与效率
- 提升 JSON 有效率:使用结构化生成后,JSON 有效率从 17.7% 提升至 99.9%。
- 减少示例需求:在 GSM8K 基准测试中,一次性结构化生成的性能几乎与八次非结构化生成相当。
- 提升开放模型性能:在函数调用基准测试中,性能从 86% 提升至 96.5%,甚至超越 GPT-4。
结构化输出与非结构化输出的对比
为了更好地理解结构化输出的优势,我们可以通过以下例子来对比结构化与非结构化输出的差异。
假设我们需要从一封电子邮件中提取航班信息:
非结构化输出
当大模型生成的输出没有严格的格式时,可能会得到如下文本:
飞往巴黎的航班在下周二,可能是早上10点,飞机是法国航空。
这个输出虽然包含了我们需要的信息(目的地、日期、时间、航空公司等),但它并没有明确的结构。要从中提取这些信息,开发者需要使用正则表达式或其他文本处理方法来解析每个字段,这既繁琐又容易出错。例如,模型有可能在不同的输入中给出不同格式的输出,导致系统处理时出错或出现“JSON decode errors”。
结构化输出
如果使用结构化生成,模型将返回符合预定义格式的数据,例如:
{
"destination": "巴黎",
"departure_date": "2024-11-25",
"time": "10:00",
"airline": "法国航空"
}
在这种情况下,输出是统一的、标准化的。开发者不再需要额外处理或解析信息,因为所有关键字段都已经按预期格式返回。这不仅节省了开发时间,还大大减少了出错的概率。
通过这个对比,我们可以清楚地看到,结构化输出不仅可以保证数据的一致性和可靠性,而且能显著提高处理效率,特别是在需要从大模型中提取和处理大量信息时。
使用 Outlines 会给大模型带来性能问题吗?
Outlines 是如何工作的?
基本原理
- Logit 处理:模型生成 logits 后,Outlines 会检查每个可能的下一个 token,屏蔽那些违反定义结构的 token。
- 效率优化:通过高效的屏蔽实现极低的额外开销。
示例
"如果生成的 token 会破坏结构,则立即屏蔽,确保生成过程严格遵循预定义结构。"
结构化输出会减慢输出速度吗?
不会。相反,结构化生成通常加速生成过程:
- 减少无用 token:通过提前定义结构,避免生成多余的字段名或括号。
- 减少生成长度:结构化输出的 token 数通常更少,速度更快,且更清晰。
Outlines 与其他结构化生成库的对比
- 与 Guidance 比较:Outlines 在推理阶段的开销几乎为零,而 Guidance 在生成大量 token 时可能显著减慢。
- 与 LMQL 比较:Outlines 的核心优势在于其轻量化设计和效率。
代码示例
以下是使用 Outlines 生成结构化事件数据的示例:
from datetime import datetime
from pydantic import BaseModel, Field
from outlines import generate, models
# 加载模型
model = models.mlxlm("mlx-community/Hermes-3-Llama-3.1-8B-8bit")
# 使用 Pydantic 定义事件结构
class Event(BaseModel):
title: str = Field(description="title of the event")
location: str
start: datetime = Field(
default=None, description="date of the event if available in iso format"
)
# 获取当前时间
now = datetime.now().strftime("%A %d %B %Y and it's %H:%M")
# 定义提示
prompt = f"""
Today's date and time are {now}
Given a user message, extract information of the event like date and time in iso format, location and title.
If the given date is relative, think step by step to find the right date.
Here is the message:
"""
# 示例消息
message = """Hello Kitty, my grandmother will be here , I think it's better to postpone our
appointment to review math lessons to next Friday at 2pm at the same place, 3 avenue des tanneurs, I think that one hour will be enough
see you 😘 """
# 创建生成器
generator = generate.json(model, Event)
# 提取事件信息
event = generator(prompt + message)
# 输出结果
print(f"Today: {now}")
print(event.json())
生成的事件信息如下:
{
"title": "Math Review",
"location": "3 avenue des tanneurs",
"start": "2024-11-22T14:00:00Z"
}
结论与展望
结构化生成不再只是一个利基功能,而是大模型应用的未来:
- 更高的可靠性与效率:通过结构化生成,LLM 的性能得到了显著提升。
- 开源的潜力:Outlines 的成功证明了开源模型在与专有模型竞争中的潜力。
未来,随着结构化生成的普及,Outlines 有望成为开发者工具箱中的关键组件。