Current section
Files
Jump to
Current section
Files
lib/examples/instructor_demo.ex
defmodule Jido.Examples.InstructorDemo do
@moduledoc """
A demo module showcasing how to use Jido.AI with Instructor for structured prompting.
"""
alias Jido.AI.Prompt
alias Jido.AI.Actions.Instructor.{ChatCompletion, ChoiceResponse, BooleanResponse}
alias Jido.AI.Model
defmodule ResponseSchema do
use Ecto.Schema
use Instructor
@llm_doc """
A structured response from an AI assistant that includes:
- response: The main text response
- code_example: An optional code example
- references: List of relevant references or links
"""
@primary_key false
embedded_schema do
field(:response, :string)
field(:code_example, :string)
field(:references, {:array, :string})
end
end
def model do
{:ok, model} = Model.from({:anthropic, [model: "claude-3-haiku-20240307"]})
model
end
def chat do
# 1. Define a model using provider tuple format with model
# 2. Create a sophisticated prompt with history and template substitution
prompt =
Prompt.new(%{
messages: [
%{
role: :system,
content:
"You are a helpful AI assistant that provides clear, concise responses with code examples when relevant.",
engine: :none
},
%{
role: :user,
content: "Explain the concept of pure functions in Elixir with an example.",
engine: :none
}
]
})
# 3. Make the chat completion call
case Jido.Exec.run(ChatCompletion, %{
model: model(),
prompt: prompt,
response_model: ResponseSchema,
temperature: 0.7,
max_tokens: 1000
}) do
{:ok, %{result: %ResponseSchema{} = response}, _} ->
IO.puts("\n=== Response ===")
IO.puts(response.response)
IO.puts("\n=== Code Example ===")
IO.puts(response.code_example)
IO.puts("\n=== References ===")
Enum.each(response.references, &IO.puts/1)
{:error, reason, _} ->
IO.puts("\n=== Error ===")
IO.puts(inspect(reason))
unknown ->
IO.puts("\n=== Unknown ===")
IO.puts(inspect(unknown))
end
end
@doc """
Demonstrates using the ChatResponse action for simpler chat interactions
"""
def choice do
# Define available options for the multiple choice question
available_options = [
%{
id: "with_statement",
name: "With Statement",
description: "Use a with statement for handling multiple operations that can fail"
},
%{
id: "try_rescue",
name: "Try/Rescue",
description: "Use try/rescue blocks for handling exceptions"
},
%{
id: "ok_error_tuples",
name: "OK/Error Tuples",
description: "Return tagged tuples like {:ok, result} or {:error, reason}"
}
]
# Create prompt for multiple choice question
prompt =
Prompt.new(%{
messages: [
%{
role: :system,
content:
"You are a helpful AI assistant that helps users learn about Elixir programming.",
engine: :none
},
%{
role: :user,
content:
"What's the best way to handle errors when performing multiple operations that can fail in Elixir?",
engine: :none
}
]
})
# Make the choice response call
case Jido.Exec.run(ChoiceResponse, %{
prompt: prompt,
available_actions: available_options,
model: model()
}) do
{:ok, %{result: %{selected_option: option, explanation: explanation}}} ->
selected = Enum.find(available_options, &(&1.id == option))
IO.puts("\n=== Selected Option ===")
IO.puts("#{selected.name} (#{selected.id})")
IO.puts("\n=== Explanation ===")
IO.puts(explanation)
{:error, reason} ->
IO.puts("\n=== Error ===")
IO.puts(inspect(reason))
IO.puts("\nAvailable options:")
Enum.each(available_options, fn opt ->
IO.puts("- #{opt.id}: #{opt.name} (#{opt.description})")
end)
end
end
def boolean do
prompt =
Prompt.new(%{
messages: [
%{role: :user, content: "Is Elixir a functional programming language?", engine: :none}
]
})
case Jido.Exec.run(BooleanResponse, %{prompt: prompt, model: model()}) do
{:ok,
%{
result: response,
explanation: explanation,
confidence: confidence,
is_ambiguous: is_ambiguous
}} ->
IO.puts("\n=== Boolean Response ===")
IO.puts(response)
IO.puts("\n=== Explanation ===")
IO.puts(explanation)
IO.puts("\n=== Confidence ===")
IO.puts(confidence)
IO.puts("\n=== Is Ambiguous ===")
IO.puts(is_ambiguous)
end
end
end