Instructor makes it easy to reliably get structured data like JSON from LLMs. With automatic tracing, you can easily monitor and visualize your LLMs traces while you enforce structured outputs.

Quickstart

python
pip install parea-ai instructor

First initialize Parea. Follow these steps to get an API key.

Python
import asyncio
from enum import Enum
from typing import List
from pydantic import BaseModel, Field, field_validator

# OpenAI
from openai import AsyncOpenAI
# Instructor
import instructor
# Parea
from parea import Parea, trace

# Initialize OpenAI client
client = AsyncOpenAI()
# Initialize Parea and Wrap the OpenAI client for automatic tracing
p = Parea(api_key="PAREA_API_KEY") # <--- Replace with your Parea API key
p.wrap_openai_client(client)
# Patch the client with instructor
client = instructor.patch(client)


class QuestionType(str, Enum):
    CONTACT = "CONTACT"
    TIMELINE_QUERY = "TIMELINE_QUERY"
    DOCUMENT_SEARCH = "DOCUMENT_SEARCH"
    COMPARE_CONTRAST = "COMPARE_CONTRAST"
    EMAIL = "EMAIL"
    PHOTOS = "PHOTOS"
    SUMMARY = "SUMMARY"


class QuestionClassification(BaseModel):
    """
    Predict the type of question that is being asked.
    Here are some tips on how to predict the question type:
    CONTACT: Searches for some contact information.
    TIMELINE_QUERY: "When did something happen?
    DOCUMENT_SEARCH: "Find me a document"
    COMPARE_CONTRAST: "Compare and contrast two things"
    EMAIL: "Find me an email, search for an email"
    PHOTOS: "Find me a photo, search for a photo"
    SUMMARY: "Summarize a large amount of data"
    """

    chain_of_thought: str = Field(..., description="The chain of thought that led to the classification")
    classification: List[QuestionType] = Field(
        description=f"An accuracy and correct prediction predicted class of question. Only allowed types: {[t.value for t in QuestionType]}, should be used",
    )

    @field_validator("classification", mode="before")
    def validate_classification(cls, v):
        # sometimes the API returns a single value, just make sure it's a list
        if not isinstance(v, list):
            v = [v]
        return v


sem = asyncio.Semaphore(5) # Rate limit the number of requests


@trace # <--- Add this decorator to any function you want to trace
async def classify_question(question: str) -> tuple[str, QuestionClassification]:
    """
    Perform multi-label classification on the input text.
    Change the prompt to fit your use case.

    Args:
        question (str): The input text to classify.
    """
    async with sem:
        return question, await client.chat.completions.create(
            model="gpt-4-turbo-preview",
            response_model=QuestionClassification,
            max_retries=2,
            messages=[
                {
                    "role": "user",
                    "content": f"Classify the following question: {question}",
                },
            ],
        )


@trace # <--- Add this decorator to any function you want to trace
async def classify(questions: List[str]) -> list[dict]:
    tasks = [classify_question(question) for question in questions]
    resps = []
    for task in asyncio.as_completed(tasks):
        question, label = await task
        resps.append(
            {
                "question": question,
                "classification": [c.value for c in label.classification],
                "chain_of_thought": label.chain_of_thought,
            }
        )
    return resps


if __name__ == "__main__":
    questions = [
        "What was that ai app that i saw on the news the other day?",
        "Can you find the trainline booking email?",
        "what did I do on Monday?",
        "Tell me about today's meeting and how it relates to the email on Monday",
    ]
    resp = asyncio.run(classify(questions))

    for r in resp:
        print("q:", r["question"])
        print("c:", r["classification"])

Visualizing your traces

In your Parea logs dashboard, you can visualize your traces and see the detailed steps the LLM took including examining the structured output and the “functions/tools” instructor attached to the LLM call.

InstructorTrace

Here is the QuestionClassification function schema we passed to OpenAI.

InstructorFunctionTrace