Repository files navigation

Instructor: Structured LLM Outputs

Instructor is a Python library that makes it a breeze to work with structured outputs from large language models (LLMs). Built on top of Pydantic, it provides a simple, transparent, and user-friendly API to manage validation, retries, and streaming responses. Get ready to supercharge your LLM workflows!

Twitter FollowDiscordDownloads

Key Features

  • Response Models: Specify Pydantic models to define the structure of your LLM outputs
  • Retry Management: Easily configure the number of retry attempts for your requests
  • Validation: Ensure LLM responses conform to your expectations with Pydantic validation
  • Streaming Support: Work with Lists and Partial responses effortlessly
  • Flexible Backends: Seamlessly integrate with various LLM providers beyond OpenAI

Get Started in Minutes

Install Instructor with a single command:

pip install -U instructor

Now, let's see Instructor in action with a simple example:

importinstructorfrompydanticimportBaseModelfromopenaiimportOpenAI# Define your desired output structureclassUserInfo(BaseModel):
name: strage: int# Patch the OpenAI clientclient=instructor.from_openai(OpenAI())
# Extract structured data from natural languageuser_info=client.chat.completions.create(
model="gpt-3.5-turbo",
response_model=UserInfo,
messages=[{"role": "user", "content": "John Doe is 30 years old."}],
)
print(user_info.name)
#> John Doeprint(user_info.age)
#> 30

Using Anthropic Models

importinstructorfromanthropicimportAnthropicfrompydanticimportBaseModelclassUser(BaseModel):
name: strage: intclient=instructor.from_anthropic(Anthropic())
# note that client.chat.completions.create will also workresp=client.messages.create(
model="claude-3-opus-20240229",
max_tokens=1024,
messages=[
{
"role": "user",
"content": "Extract Jason is 25 years old.",
}
],
response_model=User,
)
assertisinstance(resp, User)
assertresp.name=="Jason"assertresp.age==25

Using Cohere Models

Make sure to install cohere and set your system environment variable with export CO_API_KEY=<YOUR_COHERE_API_KEY>.

pip install cohere
importinstructorimportcoherefrompydanticimportBaseModelclassUser(BaseModel):
name: strage: intclient=instructor.from_cohere(cohere.Client())
# note that client.chat.completions.create will also workresp=client.chat.completions.create(
model="command-r-plus",
max_tokens=1024,
messages=[
{
"role": "user",
"content": "Extract Jason is 25 years old.",
}
],
response_model=User,
)
assertisinstance(resp, User)
assertresp.name=="Jason"assertresp.age==25

Using Litellm

importinstructorfromlitellmimportcompletionfrompydanticimportBaseModelclassUser(BaseModel):
name: strage: intclient=instructor.from_litellm(completion)
resp=client.chat.completions.create(
model="claude-3-opus-20240229",
max_tokens=1024,
messages=[
{
"role": "user",
"content": "Extract Jason is 25 years old.",
}
],
response_model=User,
)
assertisinstance(resp, User)
assertresp.name=="Jason"assertresp.age==25

Type are inferred correctly

This was the dream of instructor but due to the patching of openai, it wasnt possible for me to get typing to work well. Now, with the new client, we can get typing to work well! We've also added a few create_* methods to make it easier to create iterables and partials, and to access the original completion.

Calling create

importopenaiimportinstructorfrompydanticimportBaseModelclassUser(BaseModel):
name: strage: intclient=instructor.from_openai(openai.OpenAI())
user=client.chat.completions.create(
model="gpt-4-turbo-preview",
messages=[
{"role": "user", "content": "Create a user"},
],
response_model=User,
)

Now if you use a IDE, you can see the type is correctly inferred.

type

Handling async: await create

This will also work correctly with asynchronous clients.

importopenaiimportinstructorfrompydanticimportBaseModelclient=instructor.from_openai(openai.AsyncOpenAI())
classUser(BaseModel):
name: strage: intasyncdefextract():
returnawaitclient.chat.completions.create(
model="gpt-4-turbo-preview",
messages=[
{"role": "user", "content": "Create a user"},
],
response_model=User,
)

Notice that simply because we return the create method, the extract() function will return the correct user type.

async

Returning the original completion: create_with_completion

You can also return the original completion object

importopenaiimportinstructorfrompydanticimportBaseModelclient=instructor.from_openai(openai.OpenAI())
classUser(BaseModel):
name: strage: intuser, completion=client.chat.completions.create_with_completion(
model="gpt-4-turbo-preview",
messages=[
{"role": "user", "content": "Create a user"},
],
response_model=User,
)

with_completion

Streaming Partial Objects: create_partial

In order to handle streams, we still support Iterable[T] and Partial[T] but to simply the type inference, we've added create_iterable and create_partial methods as well!

importopenaiimportinstructorfrompydanticimportBaseModelclient=instructor.from_openai(openai.OpenAI())
classUser(BaseModel):
name: strage: intuser_stream=client.chat.completions.create_partial(
model="gpt-4-turbo-preview",
messages=[
{"role": "user", "content": "Create a user"},
],
response_model=User,
)
foruserinuser_stream:
print(user)
#> name=None age=None#> name=None age=None#> name=None age=None#> name=None age=None#> name=None age=25#> name=None age=25#> name=None age=25#> name=None age=25#> name=None age=25#> name=None age=25#> name='John Doe' age=25# name=None age=None# name='' age=None# name='John' age=None# name='John Doe' age=None# name='John Doe' age=30

Notice now that the type inferred is Generator[User, None]

generator

Streaming Iterables: create_iterable

We get an iterable of objects when we want to extract multiple objects.

importopenaiimportinstructorfrompydanticimportBaseModelclient=instructor.from_openai(openai.OpenAI())
classUser(BaseModel):
name: strage: intusers=client.chat.completions.create_iterable(
model="gpt-4-turbo-preview",
messages=[
{"role": "user", "content": "Create 2 users"},
],
response_model=User,
)
foruserinusers:
print(user)
#> name='John' age=30#> name='Jane' age=25# User(name='John Doe', age=30)# User(name='Jane Smith', age=25)

iterable

We invite you to contribute to evals in pytest as a way to monitor the quality of the OpenAI models and the instructor library. To get started check out the evals for anthropic and OpenAI and contribute your own evals in the form of pytest tests. These evals will be run once a week and the results will be posted.

Contributing

If you want to help, checkout some of the issues marked as good-first-issue or help-wanted found here. They could be anything from code improvements, a guest blog post, or a new cookbook.

CLI

We also provide some added CLI functionality for easy convinience:

  • instructor jobs : This helps with the creation of fine-tuning jobs with OpenAI. Simple use instructor jobs create-from-file --help to get started creating your first fine-tuned GPT3.5 model

  • instructor files : Manage your uploaded files with ease. You'll be able to create, delete and upload files all from the command line

  • instructor usage : Instead of heading to the OpenAI site each time, you can monitor your usage from the cli and filter by date and time period. Note that usage often takes ~5-10 minutes to update from OpenAI's side

License

This project is licensed under the terms of the MIT License.

Contributors

About

structured outputs for llms

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

Instructor: Structured LLM Outputs

Instructor is a Python library that makes it a breeze to work with structured outputs from large language models (LLMs). Built on top of Pydantic, it provides a simple, transparent, and user-friendly API to manage validation, retries, and streaming responses. Get ready to supercharge your LLM workflows!

Twitter FollowDiscordDownloads

Key Features

  • Response Models: Specify Pydantic models to define the structure of your LLM outputs
  • Retry Management: Easily configure the number of retry attempts for your requests
  • Validation: Ensure LLM responses conform to your expectations with Pydantic validation
  • Streaming Support: Work with Lists and Partial responses effortlessly
  • Flexible Backends: Seamlessly integrate with various LLM providers beyond OpenAI

Get Started in Minutes

Install Instructor with a single command:

pip install -U instructor

Now, let's see Instructor in action with a simple example:

importinstructorfrompydanticimportBaseModelfromopenaiimportOpenAI# Define your desired output structureclassUserInfo(BaseModel):
name: strage: int# Patch the OpenAI clientclient=instructor.from_openai(OpenAI())
# Extract structured data from natural languageuser_info=client.chat.completions.create(
model="gpt-3.5-turbo",
response_model=UserInfo,
messages=[{"role": "user", "content": "John Doe is 30 years old."}],
)
print(user_info.name)
#> John Doeprint(user_info.age)
#> 30

Using Anthropic Models

importinstructorfromanthropicimportAnthropicfrompydanticimportBaseModelclassUser(BaseModel):
name: strage: intclient=instructor.from_anthropic(Anthropic())
# note that client.chat.completions.create will also workresp=client.messages.create(
model="claude-3-opus-20240229",
max_tokens=1024,
messages=[
{
"role": "user",
"content": "Extract Jason is 25 years old.",
}
],
response_model=User,
)
assertisinstance(resp, User)
assertresp.name=="Jason"assertresp.age==25

Using Cohere Models

Make sure to install cohere and set your system environment variable with export CO_API_KEY=<YOUR_COHERE_API_KEY>.

pip install cohere
importinstructorimportcoherefrompydanticimportBaseModelclassUser(BaseModel):
name: strage: intclient=instructor.from_cohere(cohere.Client())
# note that client.chat.completions.create will also workresp=client.chat.completions.create(
model="command-r-plus",
max_tokens=1024,
messages=[
{
"role": "user",
"content": "Extract Jason is 25 years old.",
}
],
response_model=User,
)
assertisinstance(resp, User)
assertresp.name=="Jason"assertresp.age==25

Using Litellm

importinstructorfromlitellmimportcompletionfrompydanticimportBaseModelclassUser(BaseModel):
name: strage: intclient=instructor.from_litellm(completion)
resp=client.chat.completions.create(
model="claude-3-opus-20240229",
max_tokens=1024,
messages=[
{
"role": "user",
"content": "Extract Jason is 25 years old.",
}
],
response_model=User,
)
assertisinstance(resp, User)
assertresp.name=="Jason"assertresp.age==25

Type are inferred correctly

This was the dream of instructor but due to the patching of openai, it wasnt possible for me to get typing to work well. Now, with the new client, we can get typing to work well! We've also added a few create_* methods to make it easier to create iterables and partials, and to access the original completion.

Calling create

importopenaiimportinstructorfrompydanticimportBaseModelclassUser(BaseModel):
name: strage: intclient=instructor.from_openai(openai.OpenAI())
user=client.chat.completions.create(
model="gpt-4-turbo-preview",
messages=[
{"role": "user", "content": "Create a user"},
],
response_model=User,
)

Now if you use a IDE, you can see the type is correctly inferred.

type

Handling async: await create

This will also work correctly with asynchronous clients.

importopenaiimportinstructorfrompydanticimportBaseModelclient=instructor.from_openai(openai.AsyncOpenAI())
classUser(BaseModel):
name: strage: intasyncdefextract():
returnawaitclient.chat.completions.create(
model="gpt-4-turbo-preview",
messages=[
{"role": "user", "content": "Create a user"},
],
response_model=User,
)

Notice that simply because we return the create method, the extract() function will return the correct user type.

async

Returning the original completion: create_with_completion

You can also return the original completion object

importopenaiimportinstructorfrompydanticimportBaseModelclient=instructor.from_openai(openai.OpenAI())
classUser(BaseModel):
name: strage: intuser, completion=client.chat.completions.create_with_completion(
model="gpt-4-turbo-preview",
messages=[
{"role": "user", "content": "Create a user"},
],
response_model=User,
)

with_completion

Streaming Partial Objects: create_partial

In order to handle streams, we still support Iterable[T] and Partial[T] but to simply the type inference, we've added create_iterable and create_partial methods as well!

importopenaiimportinstructorfrompydanticimportBaseModelclient=instructor.from_openai(openai.OpenAI())
classUser(BaseModel):
name: strage: intuser_stream=client.chat.completions.create_partial(
model="gpt-4-turbo-preview",
messages=[
{"role": "user", "content": "Create a user"},
],
response_model=User,
)
foruserinuser_stream:
print(user)
#> name=None age=None#> name=None age=None#> name=None age=None#> name=None age=None#> name=None age=25#> name=None age=25#> name=None age=25#> name=None age=25#> name=None age=25#> name=None age=25#> name='John Doe' age=25# name=None age=None# name='' age=None# name='John' age=None# name='John Doe' age=None# name='John Doe' age=30

Notice now that the type inferred is Generator[User, None]

generator

Streaming Iterables: create_iterable

We get an iterable of objects when we want to extract multiple objects.

importopenaiimportinstructorfrompydanticimportBaseModelclient=instructor.from_openai(openai.OpenAI())
classUser(BaseModel):
name: strage: intusers=client.chat.completions.create_iterable(
model="gpt-4-turbo-preview",
messages=[
{"role": "user", "content": "Create 2 users"},
],
response_model=User,
)
foruserinusers:
print(user)
#> name='John' age=30#> name='Jane' age=25# User(name='John Doe', age=30)# User(name='Jane Smith', age=25)

iterable

We invite you to contribute to evals in pytest as a way to monitor the quality of the OpenAI models and the instructor library. To get started check out the evals for anthropic and OpenAI and contribute your own evals in the form of pytest tests. These evals will be run once a week and the results will be posted.

Contributing

If you want to help, checkout some of the issues marked as good-first-issue or help-wanted found here. They could be anything from code improvements, a guest blog post, or a new cookbook.

CLI

We also provide some added CLI functionality for easy convinience:

  • instructor jobs : This helps with the creation of fine-tuning jobs with OpenAI. Simple use instructor jobs create-from-file --help to get started creating your first fine-tuned GPT3.5 model

  • instructor files : Manage your uploaded files with ease. You'll be able to create, delete and upload files all from the command line

  • instructor usage : Instead of heading to the OpenAI site each time, you can monitor your usage from the cli and filter by date and time period. Note that usage often takes ~5-10 minutes to update from OpenAI's side

License

This project is licensed under the terms of the MIT License.

Contributors

About

structured outputs for llms

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Instructor: Structured LLM Outputs

Instructor is a Python library that makes it a breeze to work with structured outputs from large language models (LLMs). Built on top of Pydantic, it provides a simple, transparent, and user-friendly API to manage validation, retries, and streaming responses. Get ready to supercharge your LLM workflows!

Twitter FollowDiscordDownloads

Key Features

  • Response Models: Specify Pydantic models to define the structure of your LLM outputs
  • Retry Management: Easily configure the number of retry attempts for your requests
  • Validation: Ensure LLM responses conform to your expectations with Pydantic validation
  • Streaming Support: Work with Lists and Partial responses effortlessly
  • Flexible Backends: Seamlessly integrate with various LLM providers beyond OpenAI

Get Started in Minutes

Install Instructor with a single command:

pip install -U instructor

Now, let's see Instructor in action with a simple example:

importinstructorfrompydanticimportBaseModelfromopenaiimportOpenAI# Define your desired output structureclassUserInfo(BaseModel):
name: strage: int# Patch the OpenAI clientclient=instructor.from_openai(OpenAI())
# Extract structured data from natural languageuser_info=client.chat.completions.create(
model="gpt-3.5-turbo",
response_model=UserInfo,
messages=[{"role": "user", "content": "John Doe is 30 years old."}],
)
print(user_info.name)
#> John Doeprint(user_info.age)
#> 30

Using Anthropic Models

importinstructorfromanthropicimportAnthropicfrompydanticimportBaseModelclassUser(BaseModel):
name: strage: intclient=instructor.from_anthropic(Anthropic())
# note that client.chat.completions.create will also workresp=client.messages.create(
model="claude-3-opus-20240229",
max_tokens=1024,
messages=[
{
"role": "user",
"content": "Extract Jason is 25 years old.",
}
],
response_model=User,
)
assertisinstance(resp, User)
assertresp.name=="Jason"assertresp.age==25

Using Cohere Models

Make sure to install cohere and set your system environment variable with export CO_API_KEY=<YOUR_COHERE_API_KEY>.

pip install cohere
importinstructorimportcoherefrompydanticimportBaseModelclassUser(BaseModel):
name: strage: intclient=instructor.from_cohere(cohere.Client())
# note that client.chat.completions.create will also workresp=client.chat.completions.create(
model="command-r-plus",
max_tokens=1024,
messages=[
{
"role": "user",
"content": "Extract Jason is 25 years old.",
}
],
response_model=User,
)
assertisinstance(resp, User)
assertresp.name=="Jason"assertresp.age==25

Using Litellm

importinstructorfromlitellmimportcompletionfrompydanticimportBaseModelclassUser(BaseModel):
name: strage: intclient=instructor.from_litellm(completion)
resp=client.chat.completions.create(
model="claude-3-opus-20240229",
max_tokens=1024,
messages=[
{
"role": "user",
"content": "Extract Jason is 25 years old.",
}
],
response_model=User,
)
assertisinstance(resp, User)
assertresp.name=="Jason"assertresp.age==25

Type are inferred correctly

This was the dream of instructor but due to the patching of openai, it wasnt possible for me to get typing to work well. Now, with the new client, we can get typing to work well! We've also added a few create_* methods to make it easier to create iterables and partials, and to access the original completion.

Calling create

importopenaiimportinstructorfrompydanticimportBaseModelclassUser(BaseModel):
name: strage: intclient=instructor.from_openai(openai.OpenAI())
user=client.chat.completions.create(
model="gpt-4-turbo-preview",
messages=[
{"role": "user", "content": "Create a user"},
],
response_model=User,
)

Now if you use a IDE, you can see the type is correctly inferred.

type

Handling async: await create

This will also work correctly with asynchronous clients.

importopenaiimportinstructorfrompydanticimportBaseModelclient=instructor.from_openai(openai.AsyncOpenAI())
classUser(BaseModel):
name: strage: intasyncdefextract():
returnawaitclient.chat.completions.create(
model="gpt-4-turbo-preview",
messages=[
{"role": "user", "content": "Create a user"},
],
response_model=User,
)

Notice that simply because we return the create method, the extract() function will return the correct user type.

async

Returning the original completion: create_with_completion

You can also return the original completion object

importopenaiimportinstructorfrompydanticimportBaseModelclient=instructor.from_openai(openai.OpenAI())
classUser(BaseModel):
name: strage: intuser, completion=client.chat.completions.create_with_completion(
model="gpt-4-turbo-preview",
messages=[
{"role": "user", "content": "Create a user"},
],
response_model=User,
)

with_completion

Streaming Partial Objects: create_partial

In order to handle streams, we still support Iterable[T] and Partial[T] but to simply the type inference, we've added create_iterable and create_partial methods as well!

importopenaiimportinstructorfrompydanticimportBaseModelclient=instructor.from_openai(openai.OpenAI())
classUser(BaseModel):
name: strage: intuser_stream=client.chat.completions.create_partial(
model="gpt-4-turbo-preview",
messages=[
{"role": "user", "content": "Create a user"},
],
response_model=User,
)
foruserinuser_stream:
print(user)
#> name=None age=None#> name=None age=None#> name=None age=None#> name=None age=None#> name=None age=25#> name=None age=25#> name=None age=25#> name=None age=25#> name=None age=25#> name=None age=25#> name='John Doe' age=25# name=None age=None# name='' age=None# name='John' age=None# name='John Doe' age=None# name='John Doe' age=30

Notice now that the type inferred is Generator[User, None]

generator

Streaming Iterables: create_iterable

We get an iterable of objects when we want to extract multiple objects.

importopenaiimportinstructorfrompydanticimportBaseModelclient=instructor.from_openai(openai.OpenAI())
classUser(BaseModel):
name: strage: intusers=client.chat.completions.create_iterable(
model="gpt-4-turbo-preview",
messages=[
{"role": "user", "content": "Create 2 users"},
],
response_model=User,
)
foruserinusers:
print(user)
#> name='John' age=30#> name='Jane' age=25# User(name='John Doe', age=30)# User(name='Jane Smith', age=25)

iterable

We invite you to contribute to evals in pytest as a way to monitor the quality of the OpenAI models and the instructor library. To get started check out the evals for anthropic and OpenAI and contribute your own evals in the form of pytest tests. These evals will be run once a week and the results will be posted.

Contributing

If you want to help, checkout some of the issues marked as good-first-issue or help-wanted found here. They could be anything from code improvements, a guest blog post, or a new cookbook.

CLI

We also provide some added CLI functionality for easy convinience:

  • instructor jobs : This helps with the creation of fine-tuning jobs with OpenAI. Simple use instructor jobs create-from-file --help to get started creating your first fine-tuned GPT3.5 model

  • instructor files : Manage your uploaded files with ease. You'll be able to create, delete and upload files all from the command line

  • instructor usage : Instead of heading to the OpenAI site each time, you can monitor your usage from the cli and filter by date and time period. Note that usage often takes ~5-10 minutes to update from OpenAI's side

License

This project is licensed under the terms of the MIT License.

Contributors

About

structured outputs for llms

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Instructor: Structured LLM Outputs

Instructor is a Python library that makes it a breeze to work with structured outputs from large language models (LLMs). Built on top of Pydantic, it provides a simple, transparent, and user-friendly API to manage validation, retries, and streaming responses. Get ready to supercharge your LLM workflows!

Twitter FollowDiscordDownloads

Key Features

  • Response Models: Specify Pydantic models to define the structure of your LLM outputs
  • Retry Management: Easily configure the number of retry attempts for your requests
  • Validation: Ensure LLM responses conform to your expectations with Pydantic validation
  • Streaming Support: Work with Lists and Partial responses effortlessly
  • Flexible Backends: Seamlessly integrate with various LLM providers beyond OpenAI

Get Started in Minutes

Install Instructor with a single command:

pip install -U instructor

Now, let's see Instructor in action with a simple example:

importinstructorfrompydanticimportBaseModelfromopenaiimportOpenAI# Define your desired output structureclassUserInfo(BaseModel):
name: strage: int# Patch the OpenAI clientclient=instructor.from_openai(OpenAI())
# Extract structured data from natural languageuser_info=client.chat.completions.create(
model="gpt-3.5-turbo",
response_model=UserInfo,
messages=[{"role": "user", "content": "John Doe is 30 years old."}],
)
print(user_info.name)
#> John Doeprint(user_info.age)
#> 30

Using Anthropic Models

importinstructorfromanthropicimportAnthropicfrompydanticimportBaseModelclassUser(BaseModel):
name: strage: intclient=instructor.from_anthropic(Anthropic())
# note that client.chat.completions.create will also workresp=client.messages.create(
model="claude-3-opus-20240229",
max_tokens=1024,
messages=[
{
"role": "user",
"content": "Extract Jason is 25 years old.",
}
],
response_model=User,
)
assertisinstance(resp, User)
assertresp.name=="Jason"assertresp.age==25

Using Cohere Models

Make sure to install cohere and set your system environment variable with export CO_API_KEY=<YOUR_COHERE_API_KEY>.

pip install cohere
importinstructorimportcoherefrompydanticimportBaseModelclassUser(BaseModel):
name: strage: intclient=instructor.from_cohere(cohere.Client())
# note that client.chat.completions.create will also workresp=client.chat.completions.create(
model="command-r-plus",
max_tokens=1024,
messages=[
{
"role": "user",
"content": "Extract Jason is 25 years old.",
}
],
response_model=User,
)
assertisinstance(resp, User)
assertresp.name=="Jason"assertresp.age==25

Using Litellm

importinstructorfromlitellmimportcompletionfrompydanticimportBaseModelclassUser(BaseModel):
name: strage: intclient=instructor.from_litellm(completion)
resp=client.chat.completions.create(
model="claude-3-opus-20240229",
max_tokens=1024,
messages=[
{
"role": "user",
"content": "Extract Jason is 25 years old.",
}
],
response_model=User,
)
assertisinstance(resp, User)
assertresp.name=="Jason"assertresp.age==25

Type are inferred correctly

This was the dream of instructor but due to the patching of openai, it wasnt possible for me to get typing to work well. Now, with the new client, we can get typing to work well! We've also added a few create_* methods to make it easier to create iterables and partials, and to access the original completion.

Calling create

importopenaiimportinstructorfrompydanticimportBaseModelclassUser(BaseModel):
name: strage: intclient=instructor.from_openai(openai.OpenAI())
user=client.chat.completions.create(
model="gpt-4-turbo-preview",
messages=[
{"role": "user", "content": "Create a user"},
],
response_model=User,
)

Now if you use a IDE, you can see the type is correctly inferred.

type

Handling async: await create

This will also work correctly with asynchronous clients.

importopenaiimportinstructorfrompydanticimportBaseModelclient=instructor.from_openai(openai.AsyncOpenAI())
classUser(BaseModel):
name: strage: intasyncdefextract():
returnawaitclient.chat.completions.create(
model="gpt-4-turbo-preview",
messages=[
{"role": "user", "content": "Create a user"},
],
response_model=User,
)

Notice that simply because we return the create method, the extract() function will return the correct user type.

async

Returning the original completion: create_with_completion

You can also return the original completion object

importopenaiimportinstructorfrompydanticimportBaseModelclient=instructor.from_openai(openai.OpenAI())
classUser(BaseModel):
name: strage: intuser, completion=client.chat.completions.create_with_completion(
model="gpt-4-turbo-preview",
messages=[
{"role": "user", "content": "Create a user"},
],
response_model=User,
)

with_completion

Streaming Partial Objects: create_partial

In order to handle streams, we still support Iterable[T] and Partial[T] but to simply the type inference, we've added create_iterable and create_partial methods as well!

importopenaiimportinstructorfrompydanticimportBaseModelclient=instructor.from_openai(openai.OpenAI())
classUser(BaseModel):
name: strage: intuser_stream=client.chat.completions.create_partial(
model="gpt-4-turbo-preview",
messages=[
{"role": "user", "content": "Create a user"},
],
response_model=User,
)
foruserinuser_stream:
print(user)
#> name=None age=None#> name=None age=None#> name=None age=None#> name=None age=None#> name=None age=25#> name=None age=25#> name=None age=25#> name=None age=25#> name=None age=25#> name=None age=25#> name='John Doe' age=25# name=None age=None# name='' age=None# name='John' age=None# name='John Doe' age=None# name='John Doe' age=30

Notice now that the type inferred is Generator[User, None]

generator

Streaming Iterables: create_iterable

We get an iterable of objects when we want to extract multiple objects.

importopenaiimportinstructorfrompydanticimportBaseModelclient=instructor.from_openai(openai.OpenAI())
classUser(BaseModel):
name: strage: intusers=client.chat.completions.create_iterable(
model="gpt-4-turbo-preview",
messages=[
{"role": "user", "content": "Create 2 users"},
],
response_model=User,
)
foruserinusers:
print(user)
#> name='John' age=30#> name='Jane' age=25# User(name='John Doe', age=30)# User(name='Jane Smith', age=25)

iterable

We invite you to contribute to evals in pytest as a way to monitor the quality of the OpenAI models and the instructor library. To get started check out the evals for anthropic and OpenAI and contribute your own evals in the form of pytest tests. These evals will be run once a week and the results will be posted.

Contributing

If you want to help, checkout some of the issues marked as good-first-issue or help-wanted found here. They could be anything from code improvements, a guest blog post, or a new cookbook.

CLI

We also provide some added CLI functionality for easy convinience:

  • instructor jobs : This helps with the creation of fine-tuning jobs with OpenAI. Simple use instructor jobs create-from-file --help to get started creating your first fine-tuned GPT3.5 model

  • instructor files : Manage your uploaded files with ease. You'll be able to create, delete and upload files all from the command line

  • instructor usage : Instead of heading to the OpenAI site each time, you can monitor your usage from the cli and filter by date and time period. Note that usage often takes ~5-10 minutes to update from OpenAI's side

License

This project is licensed under the terms of the MIT License.

Contributors

About

structured outputs for llms

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

Instructor: Structured LLM Outputs

Instructor is a Python library that makes it a breeze to work with structured outputs from large language models (LLMs). Built on top of Pydantic, it provides a simple, transparent, and user-friendly API to manage validation, retries, and streaming responses. Get ready to supercharge your LLM workflows!

Twitter FollowDiscordDownloads

Key Features

  • Response Models: Specify Pydantic models to define the structure of your LLM outputs
  • Retry Management: Easily configure the number of retry attempts for your requests
  • Validation: Ensure LLM responses conform to your expectations with Pydantic validation
  • Streaming Support: Work with Lists and Partial responses effortlessly
  • Flexible Backends: Seamlessly integrate with various LLM providers beyond OpenAI

Get Started in Minutes

Install Instructor with a single command:

pip install -U instructor

Now, let's see Instructor in action with a simple example:

importinstructorfrompydanticimportBaseModelfromopenaiimportOpenAI# Define your desired output structureclassUserInfo(BaseModel):
name: strage: int# Patch the OpenAI clientclient=instructor.from_openai(OpenAI())
# Extract structured data from natural languageuser_info=client.chat.completions.create(
model="gpt-3.5-turbo",
response_model=UserInfo,
messages=[{"role": "user", "content": "John Doe is 30 years old."}],
)
print(user_info.name)
#> John Doeprint(user_info.age)
#> 30

Using Anthropic Models

importinstructorfromanthropicimportAnthropicfrompydanticimportBaseModelclassUser(BaseModel):
name: strage: intclient=instructor.from_anthropic(Anthropic())
# note that client.chat.completions.create will also workresp=client.messages.create(
model="claude-3-opus-20240229",
max_tokens=1024,
messages=[
{
"role": "user",
"content": "Extract Jason is 25 years old.",
}
],
response_model=User,
)
assertisinstance(resp, User)
assertresp.name=="Jason"assertresp.age==25

Using Cohere Models

Make sure to install cohere and set your system environment variable with export CO_API_KEY=<YOUR_COHERE_API_KEY>.

pip install cohere
importinstructorimportcoherefrompydanticimportBaseModelclassUser(BaseModel):
name: strage: intclient=instructor.from_cohere(cohere.Client())
# note that client.chat.completions.create will also workresp=client.chat.completions.create(
model="command-r-plus",
max_tokens=1024,
messages=[
{
"role": "user",
"content": "Extract Jason is 25 years old.",
}
],
response_model=User,
)
assertisinstance(resp, User)
assertresp.name=="Jason"assertresp.age==25

Using Litellm

importinstructorfromlitellmimportcompletionfrompydanticimportBaseModelclassUser(BaseModel):
name: strage: intclient=instructor.from_litellm(completion)
resp=client.chat.completions.create(
model="claude-3-opus-20240229",
max_tokens=1024,
messages=[
{
"role": "user",
"content": "Extract Jason is 25 years old.",
}
],
response_model=User,
)
assertisinstance(resp, User)
assertresp.name=="Jason"assertresp.age==25

Type are inferred correctly

This was the dream of instructor but due to the patching of openai, it wasnt possible for me to get typing to work well. Now, with the new client, we can get typing to work well! We've also added a few create_* methods to make it easier to create iterables and partials, and to access the original completion.

Calling create

importopenaiimportinstructorfrompydanticimportBaseModelclassUser(BaseModel):
name: strage: intclient=instructor.from_openai(openai.OpenAI())
user=client.chat.completions.create(
model="gpt-4-turbo-preview",
messages=[
{"role": "user", "content": "Create a user"},
],
response_model=User,
)

Now if you use a IDE, you can see the type is correctly inferred.

type

Handling async: await create

This will also work correctly with asynchronous clients.

importopenaiimportinstructorfrompydanticimportBaseModelclient=instructor.from_openai(openai.AsyncOpenAI())
classUser(BaseModel):
name: strage: intasyncdefextract():
returnawaitclient.chat.completions.create(
model="gpt-4-turbo-preview",
messages=[
{"role": "user", "content": "Create a user"},
],
response_model=User,
)

Notice that simply because we return the create method, the extract() function will return the correct user type.

async

Returning the original completion: create_with_completion

You can also return the original completion object

importopenaiimportinstructorfrompydanticimportBaseModelclient=instructor.from_openai(openai.OpenAI())
classUser(BaseModel):
name: strage: intuser, completion=client.chat.completions.create_with_completion(
model="gpt-4-turbo-preview",
messages=[
{"role": "user", "content": "Create a user"},
],
response_model=User,
)

with_completion

Streaming Partial Objects: create_partial

In order to handle streams, we still support Iterable[T] and Partial[T] but to simply the type inference, we've added create_iterable and create_partial methods as well!

importopenaiimportinstructorfrompydanticimportBaseModelclient=instructor.from_openai(openai.OpenAI())
classUser(BaseModel):
name: strage: intuser_stream=client.chat.completions.create_partial(
model="gpt-4-turbo-preview",
messages=[
{"role": "user", "content": "Create a user"},
],
response_model=User,
)
foruserinuser_stream:
print(user)
#> name=None age=None#> name=None age=None#> name=None age=None#> name=None age=None#> name=None age=25#> name=None age=25#> name=None age=25#> name=None age=25#> name=None age=25#> name=None age=25#> name='John Doe' age=25# name=None age=None# name='' age=None# name='John' age=None# name='John Doe' age=None# name='John Doe' age=30

Notice now that the type inferred is Generator[User, None]

generator

Streaming Iterables: create_iterable

We get an iterable of objects when we want to extract multiple objects.

importopenaiimportinstructorfrompydanticimportBaseModelclient=instructor.from_openai(openai.OpenAI())
classUser(BaseModel):
name: strage: intusers=client.chat.completions.create_iterable(
model="gpt-4-turbo-preview",
messages=[
{"role": "user", "content": "Create 2 users"},
],
response_model=User,
)
foruserinusers:
print(user)
#> name='John' age=30#> name='Jane' age=25# User(name='John Doe', age=30)# User(name='Jane Smith', age=25)

iterable

We invite you to contribute to evals in pytest as a way to monitor the quality of the OpenAI models and the instructor library. To get started check out the evals for anthropic and OpenAI and contribute your own evals in the form of pytest tests. These evals will be run once a week and the results will be posted.

Contributing

If you want to help, checkout some of the issues marked as good-first-issue or help-wanted found here. They could be anything from code improvements, a guest blog post, or a new cookbook.

CLI

We also provide some added CLI functionality for easy convinience:

  • instructor jobs : This helps with the creation of fine-tuning jobs with OpenAI. Simple use instructor jobs create-from-file --help to get started creating your first fine-tuned GPT3.5 model

  • instructor files : Manage your uploaded files with ease. You'll be able to create, delete and upload files all from the command line

  • instructor usage : Instead of heading to the OpenAI site each time, you can monitor your usage from the cli and filter by date and time period. Note that usage often takes ~5-10 minutes to update from OpenAI's side

License

This project is licensed under the terms of the MIT License.

Contributors

About

structured outputs for llms

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Instructor: Structured LLM Outputs

Instructor is a Python library that makes it a breeze to work with structured outputs from large language models (LLMs). Built on top of Pydantic, it provides a simple, transparent, and user-friendly API to manage validation, retries, and streaming responses. Get ready to supercharge your LLM workflows!

Twitter FollowDiscordDownloads

Key Features

  • Response Models: Specify Pydantic models to define the structure of your LLM outputs
  • Retry Management: Easily configure the number of retry attempts for your requests
  • Validation: Ensure LLM responses conform to your expectations with Pydantic validation
  • Streaming Support: Work with Lists and Partial responses effortlessly
  • Flexible Backends: Seamlessly integrate with various LLM providers beyond OpenAI

Get Started in Minutes

Install Instructor with a single command:

pip install -U instructor

Now, let's see Instructor in action with a simple example:

importinstructorfrompydanticimportBaseModelfromopenaiimportOpenAI# Define your desired output structureclassUserInfo(BaseModel):
name: strage: int# Patch the OpenAI clientclient=instructor.from_openai(OpenAI())
# Extract structured data from natural languageuser_info=client.chat.completions.create(
model="gpt-3.5-turbo",
response_model=UserInfo,
messages=[{"role": "user", "content": "John Doe is 30 years old."}],
)
print(user_info.name)
#> John Doeprint(user_info.age)
#> 30

Using Anthropic Models

importinstructorfromanthropicimportAnthropicfrompydanticimportBaseModelclassUser(BaseModel):
name: strage: intclient=instructor.from_anthropic(Anthropic())
# note that client.chat.completions.create will also workresp=client.messages.create(
model="claude-3-opus-20240229",
max_tokens=1024,
messages=[
{
"role": "user",
"content": "Extract Jason is 25 years old.",
}
],
response_model=User,
)
assertisinstance(resp, User)
assertresp.name=="Jason"assertresp.age==25

Using Cohere Models

Make sure to install cohere and set your system environment variable with export CO_API_KEY=<YOUR_COHERE_API_KEY>.

pip install cohere
importinstructorimportcoherefrompydanticimportBaseModelclassUser(BaseModel):
name: strage: intclient=instructor.from_cohere(cohere.Client())
# note that client.chat.completions.create will also workresp=client.chat.completions.create(
model="command-r-plus",
max_tokens=1024,
messages=[
{
"role": "user",
"content": "Extract Jason is 25 years old.",
}
],
response_model=User,
)
assertisinstance(resp, User)
assertresp.name=="Jason"assertresp.age==25

Using Litellm

importinstructorfromlitellmimportcompletionfrompydanticimportBaseModelclassUser(BaseModel):
name: strage: intclient=instructor.from_litellm(completion)
resp=client.chat.completions.create(
model="claude-3-opus-20240229",
max_tokens=1024,
messages=[
{
"role": "user",
"content": "Extract Jason is 25 years old.",
}
],
response_model=User,
)
assertisinstance(resp, User)
assertresp.name=="Jason"assertresp.age==25

Type are inferred correctly

This was the dream of instructor but due to the patching of openai, it wasnt possible for me to get typing to work well. Now, with the new client, we can get typing to work well! We've also added a few create_* methods to make it easier to create iterables and partials, and to access the original completion.

Calling create

importopenaiimportinstructorfrompydanticimportBaseModelclassUser(BaseModel):
name: strage: intclient=instructor.from_openai(openai.OpenAI())
user=client.chat.completions.create(
model="gpt-4-turbo-preview",
messages=[
{"role": "user", "content": "Create a user"},
],
response_model=User,
)

Now if you use a IDE, you can see the type is correctly inferred.

type

Handling async: await create

This will also work correctly with asynchronous clients.

importopenaiimportinstructorfrompydanticimportBaseModelclient=instructor.from_openai(openai.AsyncOpenAI())
classUser(BaseModel):
name: strage: intasyncdefextract():
returnawaitclient.chat.completions.create(
model="gpt-4-turbo-preview",
messages=[
{"role": "user", "content": "Create a user"},
],
response_model=User,
)

Notice that simply because we return the create method, the extract() function will return the correct user type.

async

Returning the original completion: create_with_completion

You can also return the original completion object

importopenaiimportinstructorfrompydanticimportBaseModelclient=instructor.from_openai(openai.OpenAI())
classUser(BaseModel):
name: strage: intuser, completion=client.chat.completions.create_with_completion(
model="gpt-4-turbo-preview",
messages=[
{"role": "user", "content": "Create a user"},
],
response_model=User,
)

with_completion

Streaming Partial Objects: create_partial

In order to handle streams, we still support Iterable[T] and Partial[T] but to simply the type inference, we've added create_iterable and create_partial methods as well!

importopenaiimportinstructorfrompydanticimportBaseModelclient=instructor.from_openai(openai.OpenAI())
classUser(BaseModel):
name: strage: intuser_stream=client.chat.completions.create_partial(
model="gpt-4-turbo-preview",
messages=[
{"role": "user", "content": "Create a user"},
],
response_model=User,
)
foruserinuser_stream:
print(user)
#> name=None age=None#> name=None age=None#> name=None age=None#> name=None age=None#> name=None age=25#> name=None age=25#> name=None age=25#> name=None age=25#> name=None age=25#> name=None age=25#> name='John Doe' age=25# name=None age=None# name='' age=None# name='John' age=None# name='John Doe' age=None# name='John Doe' age=30

Notice now that the type inferred is Generator[User, None]

generator

Streaming Iterables: create_iterable

We get an iterable of objects when we want to extract multiple objects.

importopenaiimportinstructorfrompydanticimportBaseModelclient=instructor.from_openai(openai.OpenAI())
classUser(BaseModel):
name: strage: intusers=client.chat.completions.create_iterable(
model="gpt-4-turbo-preview",
messages=[
{"role": "user", "content": "Create 2 users"},
],
response_model=User,
)
foruserinusers:
print(user)
#> name='John' age=30#> name='Jane' age=25# User(name='John Doe', age=30)# User(name='Jane Smith', age=25)

iterable

We invite you to contribute to evals in pytest as a way to monitor the quality of the OpenAI models and the instructor library. To get started check out the evals for anthropic and OpenAI and contribute your own evals in the form of pytest tests. These evals will be run once a week and the results will be posted.

Contributing

If you want to help, checkout some of the issues marked as good-first-issue or help-wanted found here. They could be anything from code improvements, a guest blog post, or a new cookbook.

CLI

We also provide some added CLI functionality for easy convinience:

  • instructor jobs : This helps with the creation of fine-tuning jobs with OpenAI. Simple use instructor jobs create-from-file --help to get started creating your first fine-tuned GPT3.5 model

  • instructor files : Manage your uploaded files with ease. You'll be able to create, delete and upload files all from the command line

  • instructor usage : Instead of heading to the OpenAI site each time, you can monitor your usage from the cli and filter by date and time period. Note that usage often takes ~5-10 minutes to update from OpenAI's side

License

This project is licensed under the terms of the MIT License.

Contributors

About

structured outputs for llms

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Instructor: Structured LLM Outputs

Instructor is a Python library that makes it a breeze to work with structured outputs from large language models (LLMs). Built on top of Pydantic, it provides a simple, transparent, and user-friendly API to manage validation, retries, and streaming responses. Get ready to supercharge your LLM workflows!

Twitter FollowDiscordDownloads

Key Features

  • Response Models: Specify Pydantic models to define the structure of your LLM outputs
  • Retry Management: Easily configure the number of retry attempts for your requests
  • Validation: Ensure LLM responses conform to your expectations with Pydantic validation
  • Streaming Support: Work with Lists and Partial responses effortlessly
  • Flexible Backends: Seamlessly integrate with various LLM providers beyond OpenAI

Get Started in Minutes

Install Instructor with a single command:

pip install -U instructor

Now, let's see Instructor in action with a simple example:

importinstructorfrompydanticimportBaseModelfromopenaiimportOpenAI# Define your desired output structureclassUserInfo(BaseModel):
name: strage: int# Patch the OpenAI clientclient=instructor.from_openai(OpenAI())
# Extract structured data from natural languageuser_info=client.chat.completions.create(
model="gpt-3.5-turbo",
response_model=UserInfo,
messages=[{"role": "user", "content": "John Doe is 30 years old."}],
)
print(user_info.name)
#> John Doeprint(user_info.age)
#> 30

Using Anthropic Models

importinstructorfromanthropicimportAnthropicfrompydanticimportBaseModelclassUser(BaseModel):
name: strage: intclient=instructor.from_anthropic(Anthropic())
# note that client.chat.completions.create will also workresp=client.messages.create(
model="claude-3-opus-20240229",
max_tokens=1024,
messages=[
{
"role": "user",
"content": "Extract Jason is 25 years old.",
}
],
response_model=User,
)
assertisinstance(resp, User)
assertresp.name=="Jason"assertresp.age==25

Using Cohere Models

Make sure to install cohere and set your system environment variable with export CO_API_KEY=<YOUR_COHERE_API_KEY>.

pip install cohere
importinstructorimportcoherefrompydanticimportBaseModelclassUser(BaseModel):
name: strage: intclient=instructor.from_cohere(cohere.Client())
# note that client.chat.completions.create will also workresp=client.chat.completions.create(
model="command-r-plus",
max_tokens=1024,
messages=[
{
"role": "user",
"content": "Extract Jason is 25 years old.",
}
],
response_model=User,
)
assertisinstance(resp, User)
assertresp.name=="Jason"assertresp.age==25

Using Litellm

importinstructorfromlitellmimportcompletionfrompydanticimportBaseModelclassUser(BaseModel):
name: strage: intclient=instructor.from_litellm(completion)
resp=client.chat.completions.create(
model="claude-3-opus-20240229",
max_tokens=1024,
messages=[
{
"role": "user",
"content": "Extract Jason is 25 years old.",
}
],
response_model=User,
)
assertisinstance(resp, User)
assertresp.name=="Jason"assertresp.age==25

Type are inferred correctly

This was the dream of instructor but due to the patching of openai, it wasnt possible for me to get typing to work well. Now, with the new client, we can get typing to work well! We've also added a few create_* methods to make it easier to create iterables and partials, and to access the original completion.

Calling create

importopenaiimportinstructorfrompydanticimportBaseModelclassUser(BaseModel):
name: strage: intclient=instructor.from_openai(openai.OpenAI())
user=client.chat.completions.create(
model="gpt-4-turbo-preview",
messages=[
{"role": "user", "content": "Create a user"},
],
response_model=User,
)

Now if you use a IDE, you can see the type is correctly inferred.

type

Handling async: await create

This will also work correctly with asynchronous clients.

importopenaiimportinstructorfrompydanticimportBaseModelclient=instructor.from_openai(openai.AsyncOpenAI())
classUser(BaseModel):
name: strage: intasyncdefextract():
returnawaitclient.chat.completions.create(
model="gpt-4-turbo-preview",
messages=[
{"role": "user", "content": "Create a user"},
],
response_model=User,
)

Notice that simply because we return the create method, the extract() function will return the correct user type.

async

Returning the original completion: create_with_completion

You can also return the original completion object

importopenaiimportinstructorfrompydanticimportBaseModelclient=instructor.from_openai(openai.OpenAI())
classUser(BaseModel):
name: strage: intuser, completion=client.chat.completions.create_with_completion(
model="gpt-4-turbo-preview",
messages=[
{"role": "user", "content": "Create a user"},
],
response_model=User,
)

with_completion

Streaming Partial Objects: create_partial

In order to handle streams, we still support Iterable[T] and Partial[T] but to simply the type inference, we've added create_iterable and create_partial methods as well!

importopenaiimportinstructorfrompydanticimportBaseModelclient=instructor.from_openai(openai.OpenAI())
classUser(BaseModel):
name: strage: intuser_stream=client.chat.completions.create_partial(
model="gpt-4-turbo-preview",
messages=[
{"role": "user", "content": "Create a user"},
],
response_model=User,
)
foruserinuser_stream:
print(user)
#> name=None age=None#> name=None age=None#> name=None age=None#> name=None age=None#> name=None age=25#> name=None age=25#> name=None age=25#> name=None age=25#> name=None age=25#> name=None age=25#> name='John Doe' age=25# name=None age=None# name='' age=None# name='John' age=None# name='John Doe' age=None# name='John Doe' age=30

Notice now that the type inferred is Generator[User, None]

generator

Streaming Iterables: create_iterable

We get an iterable of objects when we want to extract multiple objects.

importopenaiimportinstructorfrompydanticimportBaseModelclient=instructor.from_openai(openai.OpenAI())
classUser(BaseModel):
name: strage: intusers=client.chat.completions.create_iterable(
model="gpt-4-turbo-preview",
messages=[
{"role": "user", "content": "Create 2 users"},
],
response_model=User,
)
foruserinusers:
print(user)
#> name='John' age=30#> name='Jane' age=25# User(name='John Doe', age=30)# User(name='Jane Smith', age=25)

iterable

We invite you to contribute to evals in pytest as a way to monitor the quality of the OpenAI models and the instructor library. To get started check out the evals for anthropic and OpenAI and contribute your own evals in the form of pytest tests. These evals will be run once a week and the results will be posted.

Contributing

If you want to help, checkout some of the issues marked as good-first-issue or help-wanted found here. They could be anything from code improvements, a guest blog post, or a new cookbook.

CLI

We also provide some added CLI functionality for easy convinience:

  • instructor jobs : This helps with the creation of fine-tuning jobs with OpenAI. Simple use instructor jobs create-from-file --help to get started creating your first fine-tuned GPT3.5 model

  • instructor files : Manage your uploaded files with ease. You'll be able to create, delete and upload files all from the command line

  • instructor usage : Instead of heading to the OpenAI site each time, you can monitor your usage from the cli and filter by date and time period. Note that usage often takes ~5-10 minutes to update from OpenAI's side

License

This project is licensed under the terms of the MIT License.

Contributors

About

structured outputs for llms

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

Instructor: Structured LLM Outputs

Instructor is a Python library that makes it a breeze to work with structured outputs from large language models (LLMs). Built on top of Pydantic, it provides a simple, transparent, and user-friendly API to manage validation, retries, and streaming responses. Get ready to supercharge your LLM workflows!

Twitter FollowDiscordDownloads

Key Features

  • Response Models: Specify Pydantic models to define the structure of your LLM outputs
  • Retry Management: Easily configure the number of retry attempts for your requests
  • Validation: Ensure LLM responses conform to your expectations with Pydantic validation
  • Streaming Support: Work with Lists and Partial responses effortlessly
  • Flexible Backends: Seamlessly integrate with various LLM providers beyond OpenAI

Get Started in Minutes

Install Instructor with a single command:

pip install -U instructor

Now, let's see Instructor in action with a simple example:

importinstructorfrompydanticimportBaseModelfromopenaiimportOpenAI# Define your desired output structureclassUserInfo(BaseModel):
name: strage: int# Patch the OpenAI clientclient=instructor.from_openai(OpenAI())
# Extract structured data from natural languageuser_info=client.chat.completions.create(
model="gpt-3.5-turbo",
response_model=UserInfo,
messages=[{"role": "user", "content": "John Doe is 30 years old."}],
)
print(user_info.name)
#> John Doeprint(user_info.age)
#> 30

Using Anthropic Models

importinstructorfromanthropicimportAnthropicfrompydanticimportBaseModelclassUser(BaseModel):
name: strage: intclient=instructor.from_anthropic(Anthropic())
# note that client.chat.completions.create will also workresp=client.messages.create(
model="claude-3-opus-20240229",
max_tokens=1024,
messages=[
{
"role": "user",
"content": "Extract Jason is 25 years old.",
}
],
response_model=User,
)
assertisinstance(resp, User)
assertresp.name=="Jason"assertresp.age==25

Using Cohere Models

Make sure to install cohere and set your system environment variable with export CO_API_KEY=<YOUR_COHERE_API_KEY>.

pip install cohere
importinstructorimportcoherefrompydanticimportBaseModelclassUser(BaseModel):
name: strage: intclient=instructor.from_cohere(cohere.Client())
# note that client.chat.completions.create will also workresp=client.chat.completions.create(
model="command-r-plus",
max_tokens=1024,
messages=[
{
"role": "user",
"content": "Extract Jason is 25 years old.",
}
],
response_model=User,
)
assertisinstance(resp, User)
assertresp.name=="Jason"assertresp.age==25

Using Litellm

importinstructorfromlitellmimportcompletionfrompydanticimportBaseModelclassUser(BaseModel):
name: strage: intclient=instructor.from_litellm(completion)
resp=client.chat.completions.create(
model="claude-3-opus-20240229",
max_tokens=1024,
messages=[
{
"role": "user",
"content": "Extract Jason is 25 years old.",
}
],
response_model=User,
)
assertisinstance(resp, User)
assertresp.name=="Jason"assertresp.age==25

Type are inferred correctly

This was the dream of instructor but due to the patching of openai, it wasnt possible for me to get typing to work well. Now, with the new client, we can get typing to work well! We've also added a few create_* methods to make it easier to create iterables and partials, and to access the original completion.

Calling create

importopenaiimportinstructorfrompydanticimportBaseModelclassUser(BaseModel):
name: strage: intclient=instructor.from_openai(openai.OpenAI())
user=client.chat.completions.create(
model="gpt-4-turbo-preview",
messages=[
{"role": "user", "content": "Create a user"},
],
response_model=User,
)

Now if you use a IDE, you can see the type is correctly inferred.

type

Handling async: await create

This will also work correctly with asynchronous clients.

importopenaiimportinstructorfrompydanticimportBaseModelclient=instructor.from_openai(openai.AsyncOpenAI())
classUser(BaseModel):
name: strage: intasyncdefextract():
returnawaitclient.chat.completions.create(
model="gpt-4-turbo-preview",
messages=[
{"role": "user", "content": "Create a user"},
],
response_model=User,
)

Notice that simply because we return the create method, the extract() function will return the correct user type.

async

Returning the original completion: create_with_completion

You can also return the original completion object

importopenaiimportinstructorfrompydanticimportBaseModelclient=instructor.from_openai(openai.OpenAI())
classUser(BaseModel):
name: strage: intuser, completion=client.chat.completions.create_with_completion(
model="gpt-4-turbo-preview",
messages=[
{"role": "user", "content": "Create a user"},
],
response_model=User,
)

with_completion

Streaming Partial Objects: create_partial

In order to handle streams, we still support Iterable[T] and Partial[T] but to simply the type inference, we've added create_iterable and create_partial methods as well!

importopenaiimportinstructorfrompydanticimportBaseModelclient=instructor.from_openai(openai.OpenAI())
classUser(BaseModel):
name: strage: intuser_stream=client.chat.completions.create_partial(
model="gpt-4-turbo-preview",
messages=[
{"role": "user", "content": "Create a user"},
],
response_model=User,
)
foruserinuser_stream:
print(user)
#> name=None age=None#> name=None age=None#> name=None age=None#> name=None age=None#> name=None age=25#> name=None age=25#> name=None age=25#> name=None age=25#> name=None age=25#> name=None age=25#> name='John Doe' age=25# name=None age=None# name='' age=None# name='John' age=None# name='John Doe' age=None# name='John Doe' age=30

Notice now that the type inferred is Generator[User, None]

generator

Streaming Iterables: create_iterable

We get an iterable of objects when we want to extract multiple objects.

importopenaiimportinstructorfrompydanticimportBaseModelclient=instructor.from_openai(openai.OpenAI())
classUser(BaseModel):
name: strage: intusers=client.chat.completions.create_iterable(
model="gpt-4-turbo-preview",
messages=[
{"role": "user", "content": "Create 2 users"},
],
response_model=User,
)
foruserinusers:
print(user)
#> name='John' age=30#> name='Jane' age=25# User(name='John Doe', age=30)# User(name='Jane Smith', age=25)

iterable

We invite you to contribute to evals in pytest as a way to monitor the quality of the OpenAI models and the instructor library. To get started check out the evals for anthropic and OpenAI and contribute your own evals in the form of pytest tests. These evals will be run once a week and the results will be posted.

Contributing

If you want to help, checkout some of the issues marked as good-first-issue or help-wanted found here. They could be anything from code improvements, a guest blog post, or a new cookbook.

CLI

We also provide some added CLI functionality for easy convinience:

  • instructor jobs : This helps with the creation of fine-tuning jobs with OpenAI. Simple use instructor jobs create-from-file --help to get started creating your first fine-tuned GPT3.5 model

  • instructor files : Manage your uploaded files with ease. You'll be able to create, delete and upload files all from the command line

  • instructor usage : Instead of heading to the OpenAI site each time, you can monitor your usage from the cli and filter by date and time period. Note that usage often takes ~5-10 minutes to update from OpenAI's side

License

This project is licensed under the terms of the MIT License.

Contributors

About

structured outputs for llms

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages