2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Instractor で LLM の返答を Ecto スキーマに格納する

Last updated at Posted at 2025-03-06

はじめに

Instractor は LLM への問い合わせ結果を Ecto のスキーマとして構造化してくれます

本記事では Livebook で Instractor を使用し、 Ollama からの応答を構造化します

Ollama はローカルマシン上で起動しており、 Livebook はコンテナで起動しているものとします

実装したノートブックはこちら

セットアップ

セットアップセルで Instractor をインストールします

Mix.install([
  {:instructor, "~> 0.1.0"}
])

スキーマ定義

Ollama からの応答を格納するスキーマを定義します

@llm_doc で各フィールドの説明を書くことで、 LLM が説明に沿った内容を格納してくれます

また、バリデーションによって正しいスキーマになっているか検証し、間違っていればリトライします

defmodule Judgement do
  use Ecto.Schema
  use Instructor

  @llm_doc """
  ## Field Descriptions:
  - class: 文章が肯定的か否定的か.
  - reason: 判定した理由.
  - score: 肯定的の度合いを示す 0.0 から 1.0 の値.
  """
  @primary_key false
  embedded_schema do
    field(:class, Ecto.Enum, values: [:positive, :negative])
    field(:reason, :string)
    field(:score, :float)
  end

  @impl true
  def validate_changeset(changeset) do
    changeset
    |> Ecto.Changeset.validate_number(:score,
      greater_than_or_equal_to: 0.0,
      less_than_or_equal_to: 1.0
    )
  end
end

LLM への問い合わせ

モデル、応答を格納するスキーマ、メッセージを指定して LLM を呼び出します

第2引数のキーワードリストで Ollama を使うように指定しています

また、今回は Livebook をコンテナ上で起動しているため、 api_url"http://host.docker.internal:11434" を指定しています

モデルには日本語も理解できる Phi-4 を使用します

judge = fn text ->
  Instructor.chat_completion(
    [
      model: "phi4",
      mode: :json,
      response_model: Judgement,
      max_retries: 3,
      messages: [
        %{
          role: "user",
          content: """
          文章が肯定的か否定的か判定してください
  
          <文章>
            #{text}
          </文章>
          """
        }
      ]
    ],
    [ 
      adapter: Instructor.Adapters.Ollama,
      api_url: "http://host.docker.internal:11434"
    ]
  )
end

「出掛けるのも吝かではない」という文章が肯定的か、否定的か判定してもらいましょう

judge.("出掛けるのも吝かではない")

実行結果

{:ok,
 %Judgement{
   class: :positive,
   reason: "文章は「出掛けるのも吝かではない」とあり、外に出ることや行動を肯定的に捉えています。この表現から前向きで楽観的なニュアンスが感じられます。",
   score: 0.8
 }}

結果は :positive で、正しく判定できています

しっかりスキーマにも格納されています

続いて「あなたの希望には添えかねます」という文章が肯定的か、否定的か判定してもらいましょう

judge.("あなたの希望には添えかねます")

実行結果

{:ok,
 %Judgement{
   class: :negative,
   reason: "文章は、願いや要求が叶うことを明示的に否定する形で提示されており、「希望には添えかねます」という表現から否定的な印象が生まれるため。",
   score: 0.2
 }}

こちらも正しく判定でき、指定したスキーマの通りに返ってきました

まとめ

Instractor を使うことで LLM の応答をスキーマに格納することができました

システムに LLM を組み込む場合、出力形式が安定することは必須条件と言えます

Ecto スキーマに格納することで、単なる JSON 形式ではなく、各フィールドの型や選択肢、範囲なども制約できるのは良いですね

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?