ExLLM.Instructor (ex_llm v0.1.0)

View Source

Structured output support for ExLLM using instructor_ex.

This module provides integration with the instructor library to enable structured outputs with validation when using ExLLM. It allows you to define expected response structures using Ecto schemas and automatically validates and retries LLM responses.

Requirements

This module requires the optional instructor dependency:

{:instructor, "~> 0.1.0"}

Usage

Basic Example

defmodule EmailClassification do
  use Ecto.Schema
  use Instructor.Validator

  @llm_doc "Classification of an email as spam or not spam"

  @primary_key false
  embedded_schema do
    field :classification, Ecto.Enum, values: [:spam, :not_spam]
    field :confidence, :float
    field :reason, :string
  end

  @impl true
  def validate_changeset(changeset) do
    changeset
    |> Ecto.Changeset.validate_required([:classification, :confidence, :reason])
    |> Ecto.Changeset.validate_number(:confidence, 
        greater_than_or_equal_to: 0.0,
        less_than_or_equal_to: 1.0
      )
  end
end

# Use with ExLLM
{:ok, result} = ExLLM.Instructor.chat(:anthropic, [
  %{role: "user", content: "Is this spam? 'You won a million dollars!'"}
], response_model: EmailClassification)

# result is now an EmailClassification struct
# %EmailClassification{classification: :spam, confidence: 0.95, reason: "..."}

With Retries

{:ok, result} = ExLLM.Instructor.chat(:anthropic, messages,
  response_model: UserProfile,
  max_retries: 3,
  temperature: 0.7
)

With Simple Maps

# Define expected structure
response_model = %{
  name: :string,
  age: :integer,
  tags: {:array, :string}
}

{:ok, result} = ExLLM.Instructor.chat(:anthropic, messages,
  response_model: response_model
)

Integration with ExLLM

The structured output functionality is also available through the main ExLLM module when instructor is installed:

{:ok, response} = ExLLM.chat(:anthropic, messages,
  response_model: EmailClassification,
  max_retries: 2
)

Summary

Functions

Check if instructor is available.

Send a chat request with structured output validation.

Transform a regular ExLLM response into a structured output.

Create a simple schema module at runtime.

Functions

available?()

@spec available?() :: boolean()

Check if instructor is available.

Returns

true if the instructor library is available, false otherwise.

Examples

if ExLLM.Instructor.available?() do
  # Use structured outputs
else
  # Fall back to regular chat
end

chat(provider, messages, options)

@spec chat(ExLLM.provider(), ExLLM.messages(), keyword()) ::
  {:ok, struct() | map()} | {:error, term()}

Send a chat request with structured output validation.

Parameters

  • provider - The LLM provider to use
  • messages - List of conversation messages
  • options - Options including :response_model and standard chat options

Options

  • :response_model - Required. Ecto schema module or simple type specification
  • :max_retries - Number of retries for validation errors (default: 0)
  • All standard ExLLM.chat/3 options

Returns

  • {:ok, struct} where struct matches the response_model
  • {:error, reason} on failure

Examples

# With Ecto schema
{:ok, classification} = ExLLM.Instructor.chat(:anthropic, messages,
  response_model: EmailClassification,
  max_retries: 3
)

# With simple type spec
{:ok, data} = ExLLM.Instructor.chat(:openai, messages,
  response_model: %{name: :string, age: :integer}
)

parse_response(response, response_model)

@spec parse_response(ExLLM.Types.LLMResponse.t(), module() | map()) ::
  {:ok, struct() | map()} | {:error, term()}

Transform a regular ExLLM response into a structured output.

This function is useful when you already have a response from ExLLM and want to parse it into a structured format.

Parameters

  • response - An ExLLM.Types.LLMResponse struct
  • response_model - The expected structure (Ecto schema or type spec)

Returns

  • {:ok, struct} on successful parsing and validation
  • {:error, reason} on failure

Examples

{:ok, response} = ExLLM.chat(:anthropic, messages)
{:ok, structured} = ExLLM.Instructor.parse_response(response, UserProfile)

simple_schema(fields, validations \\ [])

@spec simple_schema(
  map(),
  keyword()
) :: module() | {:error, term()}

Create a simple schema module at runtime.

This is a convenience function for creating simple schemas without defining a full module.

Parameters

  • fields - Map of field names to types
  • validations - Optional list of validation functions

Examples

schema = ExLLM.Instructor.simple_schema(%{
  name: :string,
  age: :integer,
  email: :string
}, [
  {:validate_format, :email, ~r/@/}
])

{:ok, result} = ExLLM.Instructor.chat(:anthropic, messages,
  response_model: schema
)