pip install outlines
初次使用?请查看我们的安装指南
特性
- 🤖 多种模型集成:OpenAI、transformers、llama.cpp、exllama2、mamba
- 🖍️ 基于 Jinja 模板引擎 的简单而强大的提示原语
- 🚄 多项选择、类型约束 和动态停止
- ⚡ 快速 正则表达式结构化生成
- 🔥 根据 JSON schema 或 Pydantic 模型快速 JSON 生成
- 📝 使用上下文无关文法引导生成
- 🐍 将补全与循环、条件和自定义 Python 函数交织在一起
- 💾 生成结果缓存
- 🗂️ 批量推理
- 🎲 支持贪婪、多项式和束搜索采样算法(更多即将推出!)
- 🚀 使用 vLLM 提供服务,官方 Docker 镜像
outlinesdev/outlines
!
Outlines 〰 每周都有新版本和新功能发布。请务必 ⭐ 星标并 👀 关注此仓库,关注 @dottxtai 以获取最新更新!
为什么要使用结构化生成?
- 在推理过程中不会增加任何开销(零成本)
- 它使开源模型能够击败闭源模型(Mistral、GPT-4)
- 它能加速推理
- 它能提高基础模型的性能(GSM8K)
- 它能提高微调模型的性能(CoNNL)
- 它能提高模型效率(所需示例更少)
.txt 公司
我们创立了一家公司,以持续推动结构化生成的边界。了解更多关于 .txt 的信息,如果您需要托管解决方案,请尝试我们的 .json API ✨
结构化生成
包含大型语言模型的系统可靠性的第一步是确保其输出与用户定义代码之间存在明确定义的接口。Outlines 提供了控制语言模型生成的方法,使其输出更加可预测。
多项选择
您可以将补全限制为多个可能性之间的选择:
import outlines
model = outlines.models.transformers("microsoft/Phi-3-mini-4k-instruct")
prompt = """你是一个情感标注助手。
以下评论是积极的还是消极的?
评论:这家餐厅简直太棒了!
"""
generator = outlines.generate.choice(model, ["积极", "消极"])
answer = generator(prompt)
类型约束
您可以指示模型仅返回整数或浮点数:
import outlines
model = outlines.models.transformers("WizardLM/WizardMath-7B-V1.1")
prompt = "<s>9 + 9 的结果 = 18</s><s>1 + 2 的结果 = "
answer = outlines.generate.format(model, int)(prompt)
print(answer)
# 3
prompt = "sqrt(2)="
generator = outlines.generate.format(model, float)
answer = generator(prompt, max_tokens=10)
print(answer)
# 1.41421356
高效的正则表达式结构化生成
Outlines 还提供快速的正则表达式结构化生成。事实上,上面的 choice
和 format
函数底层都使用了正则表达式结构化生成:
import outlines
model = outlines.models.transformers("microsoft/Phi-3-mini-4k-instruct")
prompt = "Google DNS 服务器的 IP 地址是什么?"
generator = outlines.generate.text(model)
unstructured = generator(prompt, max_tokens=30)
generator = outlines.generate.regex(
model,
r"((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)",
)
structured = generator(prompt, max_tokens=30)
print(unstructured)
# Google DNS 服务器的 IP 地址是什么?
#
# 被动 DNS 服务器是私有的 DNS 服务器。
# 换句话说,两个 IP 服务器都是私有的。数据库
# 不包含切尔西·曼宁
print(structured)
# Google DNS 服务器的 IP 地址是什么?
# 2.2.6.1
与其他库不同,Outlines 中的正则表达式结构化生成几乎与非结构化生成一样快。
根据 Pydantic 模型高效生成 JSON
Outlines 〰 允许引导生成过程,使输出保证遵循 JSON schema 或 Pydantic 模型:
from enum import Enum
from pydantic import BaseModel, constr
import outlines
import torch
class Weapon(str, Enum):
sword = "剑"
axe = "斧"
mace = "狼牙棒"
spear = "矛"
bow = "弓"
crossbow = "弩"
class Armor(str, Enum):
leather = "皮甲"
chainmail = "锁子甲"
plate = "板甲"
class Character(BaseModel):
name: constr(max_length=10)
age: int
armor: Armor
weapon: Weapon
strength: int
model = outlines.models.transformers("microsoft/Phi-3-mini-4k-instruct")
# 构建结构化序列生成器
generator = outlines.generate.json(model, Character)
# 抽取样本
seed = 789001
character = generator("给我一个角色描述", seed=seed)
print(repr(character))
# Character(name='安德森', age=28, armor=<Armor.chainmail: '锁子甲'>, weapon=<Weapon.sword: '剑'>, strength=8)
character = generator("给我一个有趣的角色描述", rng=rng)
print(repr(character))
# Character(name='薇薇安·瑟', age=44, armor=<Armor.plate: '板甲'>, weapon=<Weapon.crossbow: '弩'>, strength=125)
该方法适用于联合类型、可选类型、数组、嵌套模式等。某些字段约束尚未支持,但其他所有内容都应该正常工作。
根据 JSON Schema 高效生成 JSON
有时您只想传递 JSON Schema 而不是 Pydantic 模型。我们也支持这种情况:
import outlines
schema = '''{
"title": "Character",
"type": "object",
"properties": {
"name": {
"title": "Name",
"maxLength": 10,
"type": "string"
},
"age": {
"title": "Age",
"type": "integer"
},
"armor": {"$ref": "#/definitions/Armor"},
"weapon": {"$ref": "#/definitions/Weapon"},
"strength": {
"title": "Strength",
"type": "integer"
}
},
"required": ["name", "age", "armor", "weapon", "strength"],
"definitions": {
"Armor": {
"title": "Armor",
"description": "An enumeration.",
"enum": ["leather", "chainmail", "plate"],
"type": "string"
},
"Weapon": {
"title": "Weapon",
"description": "An enumeration.",
"enum": ["sword", "axe", "mace", "spear", "bow", "crossbow"],
"type": "string"
}
}
}'''
model = outlines.models.transformers("microsoft/Phi-3-mini-4k-instruct")
generator = outlines.generate.json(model, schema)
character = generator("给我一个角色描述")
使用上下文无关文法引导生成
形式语法主宰世界,而Outlines使它们也能主宰大型语言模型。你可以传入任何EBNF格式的上下文无关文法,Outlines就会生成符合该文法的有效输出:
import outlines
arithmetic_grammar = """
?start: expression
?expression: term (("+" | "-") term)*
?term: factor (("*" | "/") factor)*
?factor: NUMBER
| "-" factor
| "(" expression ")"
%import common.NUMBER
"""
model = outlines.models.transformers("WizardLM/WizardMath-7B-V1.1")
generator = outlines.generate.cfg(model, arithmetic_grammar)
sequence = generator("爱丽丝有4个苹果,鲍勃吃了2个。写一个表达式表示爱丽丝的苹果数量:")
print(sequence)
# (8-2)
这只是一个非常简单的语法,你可以使用outlines.generate.cfg
来生成符合语法的Python、SQL,甚至更多。实际上,任何类型的结构化文本都可以。你只需在网上搜索"X EBNF语法",然后查看Outlines的grammars
模块。
开放函数
Outlines可以从函数签名推断输出结构。结果是一个字典,可以使用常见的字典展开语法**
直接传递给函数:
import outlines
def add(a: int, b: int):
return a + b
model = outlines.models.transformers("WizardLM/WizardMath-7B-V1.1")
generator = outlines.generate.json(model, add)
result = generator("返回一个json,包含两个整数,分别命名为a和b。a是奇数,b是偶数。")
print(add(**result))
# 3
直接传递函数来指定结构的一大优势是,LLM的结构会随函数定义的变化而变化。无需在多处修改代码!
提示工程
构建提示可能会变得混乱。Outlines通过将模板封装在"模板函数"中,使编写和管理提示变得更加容易。
这些函数可以将提示逻辑与一般程序逻辑清晰分离;它们可以从其他模块和库中导入。
模板函数不需要多余的抽象,它们使用Jinja2模板引擎以简洁的方式帮助构建复杂的提示:
import outlines
examples = [
("这食物太难吃了", "负面"),
("我们度过了一个美妙的夜晚", "正面"),
("推荐", "正面"),
("服务员很粗鲁", "负面")
]
@outlines.prompt
def labelling(to_label, examples):
"""你是一个情感标注助手。
{% for example in examples %}
{{ example[0] }} // {{ example[1] }}
{% endfor %}
{{ to_label }} //
"""
model = outlines.models.transformers("microsoft/Phi-3-mini-4k-instruct")
prompt = labelling("太棒了", examples)
answer = outlines.generate.text(model)(prompt, max_tokens=100)
加入我们
引用Outlines
@article{willard2023efficient,
title={Efficient Guided Generation for LLMs},
author={Willard, Brandon T and Louf, R{\'e}mi},
journal={arXiv preprint arXiv:2307.09702},
year={2023}
}