# `InstructorLite.Instruction`
[🔗](https://github.com/martosaur/instructor_lite/blob/v1.3.0/lib/instructor_lite/instruction.ex#L1)

`use InstructorLite.Instruction` is a way to make your Ecto schema into an Instruction, which provides additional callbacks used by InstructorLite.
  
## Example

```
defmodule SpamPrediction do
  use Ecto.Schema
  use InstructorLite.Instruction

  @notes """
  Field Descriptions:
  - class: Whether or not the email is spam.
  - reason: A short, less than 10-word rationalization for the classification.
  - score: A confidence score between 0.0 and 1.0 for the classification.
  """
  @primary_key false
  embedded_schema do
    field(:class, Ecto.Enum, values: [:spam, :not_spam])
    field(:reason, :string)
    field(:score, :float)
  end

  @impl InstructorLite.Instruction
  def validate_changeset(changeset, _opts) do
    Ecto.Changeset.validate_number(changeset, :score,
      greater_than_or_equal_to: 0.0,
      less_than_or_equal_to: 1.0
    )
  end
end
```
  
> #### `use InstructorLite.Instruction` {: .info}
>
> When you `use InstructorLite.Instruction`, the Instruction module will set `@behaviour InstructorLite.Instruction`, and define default implementations of `c:notes/0` and `c:json_schema/0` callbacks.

# `json_schema`

```elixir
@callback json_schema() :: map()
```

Defines JSON schema for the instruction.
  
By default, `InstructorLite.JSONSchema.from_ecto_schema/1` is called at runtime every time InstructorLite needs to convert an Ecto schema to JSON schema. However, you can bake your own JSON schema into the `c:json_schema/0` callback to eliminate the need to do it on every call.

> #### Tip {: .tip}
> 
> Take advantage of this callback! Most JSON schemas are known ahead of time, so there is no need to constantly build them at runtime. In addition, `InstructorLite.JSONSchema` module aims to generate one-size-fits-all schema, so it's very unlikely to take full advantage of JSON capabilities of your LLM of choice.   

# `notes`

```elixir
@callback notes() :: String.t() | nil
```

Defines an optional free-form description of the schema.
  
You can define a `@notes` attribute or `c:notes/0` callback to provide an additional free-form description to the schema. This description will be passed to the LLM together with the schema definition.

# `validate_changeset`
*optional* 

```elixir
@callback validate_changeset(Ecto.Changeset.t(), InstructorLite.opts()) ::
  Ecto.Changeset.t()
```

Called by `InstructorLite.consume_response/3` as part of changeset validation.

It has full access to all `opts`. If you need to pass an arbitrary term to this callback, use the `extra` key.

## Example

```
# Let's play a guessing game!
defmodule CoinGuess do
  use Ecto.Schema
  use InstructorLite.Instruction

  @primary_key false
  embedded_schema do
    field(:guess, Ecto.Enum, values: [:heads, :tails])
  end

  @impl InstructorLite.Instruction
  def validate_changeset(cs, opts) do
    target = Keyword.fetch!(opts, :extra)

    case Ecto.Changeset.fetch_field!(cs, :guess) do
      ^target -> cs
      _ -> Ecto.Changeset.add_error(cs, :guess, "Wrong! Try again")
    end
  end
end
```

---

*Consult [api-reference.md](api-reference.md) for complete listing*
