97e91a83f3
Ruff / Ruff (push) Has been cancelled
Test / Core Tests (push) Has been cancelled
Test / Offline Coverage Tests (Python 3.10) (push) Has been cancelled
Test / Offline Coverage Tests (Python 3.11) (push) Has been cancelled
Test / Offline Coverage Tests (Python 3.12) (push) Has been cancelled
Test / Offline Coverage Tests (Python 3.13) (push) Has been cancelled
Test / Offline Coverage Tests (Python 3.9) (push) Has been cancelled
Test / Full Coverage (Python 3.11) (push) Has been cancelled
Test / Core Provider Tests (OpenAI) (push) Has been cancelled
Test / Core Provider Tests (Anthropic) (push) Has been cancelled
Test / Core Provider Tests (Google) (push) Has been cancelled
Test / Core Provider Tests (Other) (push) Has been cancelled
Test / Anthropic Tests (push) Has been cancelled
Test / Gemini Tests (push) Has been cancelled
Test / Google GenAI Tests (push) Has been cancelled
Test / Vertex AI Tests (push) Has been cancelled
Test / OpenAI Tests (push) Has been cancelled
Test / Writer Tests (push) Has been cancelled
Test / Auto Client Tests (push) Has been cancelled
ty / type-check (push) Has been cancelled
269 lines
7.1 KiB
Markdown
269 lines
7.1 KiB
Markdown
---
|
|
title: Iterable Extraction with Instructor - Stream Multiple Objects
|
|
description: Use Iterable types to extract and stream multiple structured objects from LLM responses. Perfect for entity extraction and multi-task outputs.
|
|
---
|
|
|
|
# Multi-Task and Streaming
|
|
|
|
Using an `Iterable` lets you extract multiple structured objects from a single LLM call, streaming them as they arrive. This is useful for entity extraction, multi-task outputs, and more.
|
|
|
|
**We recommend using the `create_iterable` method for most use cases.** It's simpler and less error-prone than manually specifying `Iterable[...]` and `stream=True`.
|
|
|
|
Here's a simple example showing how to extract multiple users from a single sentence. You can use either the recommended `create_iterable` method or the `create` method with `Iterable[User]`:
|
|
|
|
=== "Using `create_iterable` (recommended)"
|
|
```python
|
|
import instructor
|
|
from pydantic import BaseModel
|
|
|
|
client = instructor.from_provider("openai/gpt-4.1-mini")
|
|
|
|
|
|
class User(BaseModel):
|
|
name: str
|
|
age: int
|
|
|
|
|
|
resp = client.create_iterable(
|
|
messages=[
|
|
{
|
|
"role": "user",
|
|
"content": "Ivan is 28, lives in Moscow and his friends are Alex, John and Mary who are 25, 30 and 27 respectively",
|
|
}
|
|
],
|
|
response_model=User,
|
|
)
|
|
|
|
for user in resp:
|
|
print(user)
|
|
#> name='Ivan' age=28
|
|
#> name='Alex' age=25
|
|
#> name='John' age=30
|
|
#> name='Mary' age=27
|
|
```
|
|
_Recommended for most use cases. Handles streaming and iteration for you._
|
|
|
|
=== "Using `create` with `Iterable[User]`"
|
|
```python
|
|
import instructor
|
|
from pydantic import BaseModel
|
|
from typing import Iterable
|
|
|
|
client = instructor.from_provider("openai/gpt-4.1-mini")
|
|
|
|
|
|
class User(BaseModel):
|
|
name: str
|
|
age: int
|
|
|
|
|
|
resp = client.create(
|
|
messages=[
|
|
{
|
|
"role": "user",
|
|
"content": "Ivan is 28, lives in Moscow and his friends are Alex, John and Mary who are 25, 30 and 27 respectively",
|
|
}
|
|
],
|
|
response_model=Iterable[User],
|
|
)
|
|
|
|
for user in resp:
|
|
print(user)
|
|
#> name='Ivan' age=28
|
|
#> name='Alex' age=25
|
|
#> name='John' age=30
|
|
#> name='Mary' age=27
|
|
```
|
|
_Use this if you need more manual control or compatibility with legacy code._
|
|
|
|
---
|
|
|
|
|
|
We also support more complex extraction patterns such as Unions as you'll see below out of the box.
|
|
|
|
???+ warning
|
|
|
|
Unions don't work with Gemini because the AnyOf is not supported in the current response schema.
|
|
|
|
## Synchronous Usage
|
|
|
|
=== "Using `create`"
|
|
|
|
```python
|
|
import instructor
|
|
from typing import Iterable, Union, Literal
|
|
from pydantic import BaseModel
|
|
|
|
|
|
class Weather(BaseModel):
|
|
location: str
|
|
units: Literal["imperial", "metric"]
|
|
|
|
|
|
class GoogleSearch(BaseModel):
|
|
query: str
|
|
|
|
|
|
client = instructor.from_provider("openai/gpt-4.1-mini", mode=instructor.Mode.TOOLS)
|
|
|
|
results = client.create(
|
|
messages=[
|
|
{"role": "system", "content": "You must always use tools"},
|
|
{
|
|
"role": "user",
|
|
"content": "What is the weather in toronto and dallas and who won the super bowl?",
|
|
},
|
|
],
|
|
response_model=Iterable[Union[Weather, GoogleSearch]],
|
|
stream=True,
|
|
)
|
|
|
|
for item in results:
|
|
print(item)
|
|
#> location='Toronto' units='metric'
|
|
#> location='Dallas' units='imperial'
|
|
#> query='Super Bowl winner'
|
|
```
|
|
|
|
=== "Using `create_iterable` (recommended)"
|
|
|
|
```python
|
|
import instructor
|
|
from typing import Union, Literal
|
|
from pydantic import BaseModel
|
|
|
|
|
|
class Weather(BaseModel):
|
|
location: str
|
|
units: Literal["imperial", "metric"]
|
|
|
|
|
|
class GoogleSearch(BaseModel):
|
|
query: str
|
|
|
|
|
|
client = instructor.from_provider("openai/gpt-4.1-mini", mode=instructor.Mode.TOOLS)
|
|
|
|
results = client.create_iterable(
|
|
messages=[
|
|
{"role": "system", "content": "You must always use tools"},
|
|
{
|
|
"role": "user",
|
|
"content": "What is the weather in toronto and dallas and who won the super bowl?",
|
|
},
|
|
],
|
|
response_model=Union[Weather, GoogleSearch],
|
|
)
|
|
|
|
for item in results:
|
|
print(item)
|
|
#> location='Toronto' units='metric'
|
|
#> location='Dallas' units='imperial'
|
|
#> query='Super Bowl winner'
|
|
```
|
|
|
|
---
|
|
|
|
## See Also
|
|
|
|
- [Streaming Lists](./lists.md) - Similar functionality with different API
|
|
- [Streaming Partial](./partial.md) - Stream partially completed objects
|
|
- [List Extraction Tutorial](../learning/patterns/list_extraction.md) - Step-by-step guide
|
|
- [Streaming Basics](../learning/streaming/basics.md) - Introduction to streaming
|
|
|
|
## Asynchronous Usage
|
|
|
|
=== "Using `create`"
|
|
|
|
```python
|
|
import instructor
|
|
from typing import Iterable, Union, Literal
|
|
from pydantic import BaseModel
|
|
import asyncio
|
|
|
|
|
|
class Weather(BaseModel):
|
|
location: str
|
|
units: Literal["imperial", "metric"]
|
|
|
|
|
|
class GoogleSearch(BaseModel):
|
|
query: str
|
|
|
|
|
|
aclient = instructor.from_provider(
|
|
"openai/gpt-4.1-mini", async_client=True, mode=instructor.Mode.TOOLS
|
|
)
|
|
|
|
|
|
async def main():
|
|
results = await aclient.create(
|
|
messages=[
|
|
{"role": "system", "content": "You must always use tools"},
|
|
{
|
|
"role": "user",
|
|
"content": "What is the weather in toronto and dallas and who won the super bowl?",
|
|
},
|
|
],
|
|
response_model=Iterable[Union[Weather, GoogleSearch]],
|
|
stream=True,
|
|
)
|
|
async for item in results:
|
|
print(item)
|
|
#> location='Toronto' units='metric'
|
|
#> location='Dallas' units='imperial'
|
|
#> query='Super Bowl winner'
|
|
|
|
|
|
asyncio.run(main())
|
|
```
|
|
|
|
=== "Using `create_iterable` (recommended)"
|
|
|
|
```python
|
|
import asyncio
|
|
from typing import Literal, Union
|
|
|
|
import instructor
|
|
from pydantic import BaseModel
|
|
|
|
|
|
class Weather(BaseModel):
|
|
location: str
|
|
units: Literal["imperial", "metric"]
|
|
|
|
|
|
class GoogleSearch(BaseModel):
|
|
query: str
|
|
|
|
|
|
aclient = instructor.from_provider(
|
|
"openai/gpt-4.1-mini", async_client=True, mode=instructor.Mode.TOOLS
|
|
)
|
|
|
|
|
|
async def iter_results():
|
|
async for item in aclient.create_iterable(
|
|
messages=[
|
|
{"role": "system", "content": "You must always use tools"},
|
|
{
|
|
"role": "user",
|
|
"content": "What is the weather in toronto and dallas and who won the super bowl?",
|
|
},
|
|
],
|
|
response_model=Union[Weather, GoogleSearch],
|
|
):
|
|
yield item
|
|
|
|
|
|
async def main():
|
|
async for item in iter_results():
|
|
print(item)
|
|
#> location='Toronto' units='metric'
|
|
#> location='Dallas' units='imperial'
|
|
#> query='Super Bowl winner'
|
|
|
|
|
|
asyncio.run(main())
|
|
```
|