JSON 结构生成
Outlines可以使任何开源模型返回一个遵循用户指定结构的JSON对象。当我们希望模型的输出被后续代码处理时,这非常有用:代码无法理解自然语言,而是理解它被编程理解的结构化语言。
有人想要从LLM获取格式为JSON的输出主要有两个原因:
- 解析答案(例如使用 Pydantic),将其存储在某处,返回给用户等。
- 用结果调用一个函数
在这两种情况下,Outlines 都能满足你的需求!确实,要定义你希望模型遵循的 JSON 结构,你可以提供一个 Pydantic 模型或一个函数。无需重复代码!
使用 Pydantic
Outlines 可以从 Pydantic 模型推断输出的结构。结果是一个模型实例,其中包含 LLM 返回的值:
from pydantic import BaseModel
from outlines import models, generate
class User(BaseModel):
name: str
last_name: str
id: int
model = models.transformers("microsoft/Phi-3-mini-4k-instruct")
generator = generate.json(model, User)
result = generator(
"Create a user profile with the fields name, last_name and id"
)
print(result)
# User(name="John", last_name="Doe", id=11)
JSON和空格
默认情况下,Outlines 防止模型生成带有语法性换行符、制表符或多个空格的 json。默认的 whitespace_pattern 是 r"[ ]?"。如果 whitespace_pattern 允许无限空格,小模型倾向于进入无限重复循环。如果您想允许模型生成多个制表符、换行符和空格,可以将空白模式设置如下:
性能
generation.json 计算一个帮助 Outlines 指导生成的索引。这可能需要一些时间,但只需做一次。如果您想使用相同的模式多次生成,请确保只调用一次 generate.json。
自定义类型
Outlines 提供了 自定义 Pydantic 类型,因此您不必为常见类型(例如电话号码或邮政编码)编写正则表达式。
使用 JSON Schema
您可以传递一个表示JSON Schema规范的字符串给generate.json,而不是Pydantic模型:
from pydantic import BaseModel
from outlines import models
from outlines import generate
model = models.transformers("microsoft/Phi-3-mini-4k-instruct")
schema = """
{
"title": "User",
"type": "object",
"properties": {
"name": {"type": "string"},
"last_name": {"type": "string"},
"id": {"type": "integer"}
},
"required": ["name", "last_name", "id"]
}
"""
generator = generate.json(model, schema)
result = generator(
"Create a user profile with the fields name, last_name and id"
)
print(result)
# User(name="John", last_name="Doe", id=11)
从函数的签名
Outlines可以根据函数的签名推断输出的结构。结果是一个字典, 可以使用通常的字典展开语法直接传递给函数**:
from outlines import models
from outlines import generate
def add(a: int, b: int):
return a + b
model = models.transformers("microsoft/Phi-3-mini-4k-instruct")
generator = generate.json(model, add)
result = generator("Return two integers named a and b respectively. a is odd and b even.")
print(add(**result))
# 3
直接传递函数以指定结构的一个重大优势是,LLM 的结构将随函数的定义而改变。不需要在多个地方更改代码!
来自动态 JSON 架构生成器 - GenSON
Outlines 集成了 GenSON 构建器,以能够动态声明 JSON 模式。可以按如下方式使用:
from genson import SchemaBuilder
from outlines import models
from outlines import generate
builder = SchemaBuilder()
builder.add_schema({"type": "object", "properties": {}})
builder.add_object({"name": "Toto", "age": 5})
model = models.transformers(
"HuggingFaceTB/SmolLM2-135M",
device="auto",
)
generator = generate.json(model, builder)
res = generator("Return a json of a young boy")
print(res)
# {"name": "Ben", "age": 10}
每当您通过构建器更新架构时,您需要重新定义大纲生成器以包含这些更改。根据之前的示例:
from genson import SchemaBuilder
from outlines import models
from outlines import generate
builder = SchemaBuilder()
builder.add_schema({"type": "object", "properties": {}})
builder.add_object({"name": "Toto", "age": 5})
model = models.transformers(
"HuggingFaceTB/SmolLM2-135M",
device="auto",
)
generator = generate.json(model, builder)
res = generator("Return a json of a young boy")
print(res)
# {"name": "Ben", "age": 10}
builder.add_object({"hobby": "sports"})
generator = generate.json(model, builder)
res = generator("Return a json of a youg boy whose hobby is coding")
print(res)
# {"name": "Ben", "age": 10, "hobby": "coding"}
注意
注意GenSON在通过其构建器动态修改架构时的行为。下面是一个示例,说明您如何可能丢失required信息,并生成缺少字段的json:
builder = SchemaBuilder()
builder.add_schema({"type": "object", "properties": {}})
builder.add_object({"name": "Toto", "age": 5})
print(builder.to_schema())
# {'$schema': 'http://json-schema.org/schema#', 'type': 'object', 'properties': {'name': {'type': 'string'}, 'age': {'type': 'integer'}}, 'required': ['age', 'name']}
builder.add_object({"hobby": "sport"})
print(builder.to_schema())
# {'name': {'type': 'string'}, 'age': {'type': 'integer'}, 'hobby': {'type': 'string'}}}