Proposal for new Instructor API ahead of 1.0 #544
Replies: 11 comments 11 replies
-
from typing import Any, Self
import openai
import instructor
from typing import Type, TypeVar
from pydantic import BaseModel
T = TypeVar("T", bound=BaseModel)
class Instructor:
client: Any
def __init__(
self,
client,
default_model: str | None = None,
mode: instructor.Mode = instructor.Mode.TOOLS,
):
self.client = client
self.default_model = default_model
self.mode = mode
@classmethod
def from_openai(
cls,
client: openai.OpenAI,
default_model: str | None = None,
mode: instructor.Mode = instructor.Mode.TOOLS,
):
return cls(
client=instructor.patch(client).chat.completions,
default_model=default_model,
mode=mode,
)
@property
def chat(self) -> Self:
return self
@property
def completions(self) -> Self:
return self
def create(self, response_model: Type[T], *args, **kwargs) -> T:
if self.default_model is not None:
kwargs["model"] = self.default_model
return self.client.create(response_model=response_model, *args, **kwargs)
if __name__ == "__main__":
class User(BaseModel):
name: str
age: int
client = Instructor.from_openai(openai.OpenAI())
user = client.create(
response_model=User,
messages=[{"role": "user", "content": "Jason is 10"}],
temperature=0,
)
print(user)
user = client.chat.completions.create(
response_model=User,
messages=[{"role": "user", "content": "Jason is 10"}],
temperature=0,
)
print(user) |
Beta Was this translation helpful? Give feedback.
-
with this we can also do smarter things like add better rate limiting |
Beta Was this translation helpful? Give feedback.
-
The SDK should strictly adhere to one of the major inference API vendors, e.g., OpenAI. Otherwise, this risks creating additional standards. For transparency, it would be nice to have a mapping from various API services to Instructor/OpenAI. This would minimize user confusion, especially during debugging. |
Beta Was this translation helpful? Give feedback.
-
I haven't used instructor yet but I'm planning to use it in next month and I hope it'll fully type safe if isn't. BTW I'm glad to see instrucutor and how smartly it solve the issues related prompts. |
Beta Was this translation helpful? Give feedback.
-
Love this direction. Since you brought up metrics - suggest exporting metrics with the OpenTelemetry protocol which is a standard widely adopted by observability vendors. Instructor users will be able to get out of the box metrics for monitoring in most production environments. |
Beta Was this translation helpful? Give feedback.
-
Hmm... doesn't this kind of contradict the ethos you shared here: When the next change to the API comes about (say image inputs, or video inputs, or something else) won't this add extra maintenance cost? |
Beta Was this translation helpful? Give feedback.
-
Please add a way to use list of types in response_mode for the case of LLM choosing a tool (in a more agentic workflow) - a replacement for https://github.com/jxnl/instructor/blob/main/examples/union/run.py - which creates a more complex schema. |
Beta Was this translation helpful? Give feedback.
-
Convenience suggestion: separate endpoints for events: on(event, lambda event: print(event)) and endpoint(s) that return just unwrapped objects, like I did for php port, e.g.: on_update(lambda updated_response: print(updated_response))
on_iterable(lambda updated_iterable: print(updated_iterable.last()) on_update - called on any change to response data |
Beta Was this translation helpful? Give feedback.
-
For consideration: # just return the object
object = Instructor.with_client(Anthropic()).request(...params...).get()
# return stream / partial generator
partials = Instructor.with_client(Anthropic()).request(...params...).partials()
# or
stream = Instructor.with_client(Anthropic()).request(...params...).stream()
# return async promise
promise = Instructor.with_client(Anthropic()).request(...params...).async()
# return raw completion response
response = Instructor.with_client(Anthropic()).request(...params...).raw()
# return the tuple of object + raw completion object (as in your proposal)
response_tuple = Instructor.with_client(Anthropic()).request(...params...).get_with_raw()
# + convenience endpoint
# just return the object - for convenience, the same as ...request(...).get()
response = Instructor.with_client(Anthropic()).respond(...params...) Also, user = Instructor.request(...).get()
# or
user = Instructor.respond(...) |
Beta Was this translation helpful? Give feedback.
-
Hey @jxnl curious, why not use litellm to help unify the format here?
|
Beta Was this translation helpful? Give feedback.
-
This looks great - when do you think you'll add this abstraction? I've been thinking of creating a similar abstraction for our project but would prefer to use yours :) |
Beta Was this translation helpful? Give feedback.
-
As the number of AI APIs from companies like Anthropic, Mistral, OpenAI, LiteLLM, and Bedrock continues to grow, it's becoming increasingly challenging to manage them effectively. To address this issue, we propose creating a unified API wrapper called
instructor
that simplifies the integration process and provides a consistent interface for developers.Take a look at this PR to see some more stuff: #546
The
instructor
library will offer the following features:Customizable properties:
client.allowed_modes = [...]
(can be set from thefrom_*
factory methods)Simplified handling of Anthropic's
system
kwarg for context setting.Event-driven architecture using an observer pattern:
By implementing this unified API wrapper, developers will be able to seamlessly switch between different AI providers, reduce integration complexity, and maintain a consistent codebase. The
instructor
library will abstract away the differences between the various APIs, making it easier to experiment with and compare different AI models.Additionally, the event-driven architecture will enable developers to easily monitor and respond to various events during the interaction with the AI models, such as raw responses, keyword arguments, model information, errors, and completions.
Overall, this proposal aims to simplify the integration process, improve developer experience, and promote interoperability among the growing number of AI APIs.
I have no faith that apis will be consistent in the future, and after 120k monthly downloads I'd like to think we've earned the right to create own sdk, I'd like plenty of pushback, and i expect we'll keep the old patch method simply because it'll likely power this new udk.
Before
After (Backwards Compat)
After (Backwards Compat)
Beta Was this translation helpful? Give feedback.
All reactions