跳到内容

多任务和流式处理

结构化提取的一个常见用例是定义一个单一的 schema 类,然后创建另一个 schema 来生成一个列表以进行多次提取。

from typing import List
from pydantic import BaseModel


class User(BaseModel):
    name: str
    age: int


class Users(BaseModel):
    users: List[User]


print(Users.model_json_schema())
"""
{
    '$defs': {
        'User': {
            'properties': {
                'name': {'title': 'Name', 'type': 'string'},
                'age': {'title': 'Age', 'type': 'integer'},
            },
            'required': ['name', 'age'],
            'title': 'User',
            'type': 'object',
        }
    },
    'properties': {
        'users': {'items': {'$ref': '#/$defs/User'}, 'title': 'Users', 'type': 'array'}
    },
    'required': ['users'],
    'title': 'Users',
    'type': 'object',
}
"""

定义一个任务并创建类的列表是一个足够常见的模式,我们通过利用 Iterable[T] 使其变得方便。这使得我们可以动态地创建一个新的类,该类

  1. 具有基于任务的动态 docstrings 和类名
  2. 通过收集令牌直到任务被返回来支持流式处理。

使用 Iterable 提取任务

通过使用 Iterable,您可以获得一个非常方便的类,其提示和名称会自动定义。

import instructor
from openai import OpenAI
from typing import Iterable
from pydantic import BaseModel

client = instructor.from_openai(OpenAI(), mode=instructor.function_calls.Mode.JSON)


class User(BaseModel):
    name: str
    age: int


users = client.chat.completions.create(
    model="gpt-3.5-turbo-1106",
    temperature=0.1,
    response_model=Iterable[User],
    stream=False,
    messages=[
        {
            "role": "user",
            "content": "Consider this data: Jason is 10 and John is 30.\
                         Correctly segment it into entitites\
                        Make sure the JSON is correct",
        },
    ],
)
for user in users:
    print(user)
    #> name='Jason' age=10
    #> name='John' age=30

流式任务

我们还可以通过定义 Iterable[T] 类型来在令牌流进来时生成任务。

让我们看一个使用相同类的实际示例。

import instructor
import openai
from typing import Iterable
from pydantic import BaseModel

client = instructor.from_openai(openai.OpenAI(), mode=instructor.Mode.TOOLS)


class User(BaseModel):
    name: str
    age: int


users = client.chat.completions.create(
    model="gpt-4",
    temperature=0.1,
    stream=True,
    response_model=Iterable[User],
    messages=[
        {
            "role": "system",
            "content": "You are a perfect entity extraction system",
        },
        {
            "role": "user",
            "content": (f"Extract `Jason is 10 and John is 10`"),
        },
    ],
    max_tokens=1000,
)

for user in users:
    print(user)
    #> name='Jason' age=10
    #> name='John' age=10

异步流式处理

我还想在这个例子中指出,instructor 也支持异步流式处理。当您想要流式传输响应模型并在结果到达时处理它们时,这非常有用,但您需要使用 async for 语法来迭代结果。

import instructor
import openai
from typing import Iterable
from pydantic import BaseModel

client = instructor.from_openai(openai.AsyncOpenAI(), mode=instructor.Mode.TOOLS)


class UserExtract(BaseModel):
    name: str
    age: int


async def print_iterable_results():
    model = await client.chat.completions.create(
        model="gpt-4",
        response_model=Iterable[UserExtract],
        max_retries=2,
        stream=True,
        messages=[
            {"role": "user", "content": "Make two up people"},
        ],
    )
    async for m in model:
        print(m)
        #> name='John Doe' age=35
        #> name='Jane Smith' age=28


import asyncio

asyncio.run(print_iterable_results())