{"id":16069474,"url":"https://github.com/thmsmlr/instructor_ex","last_synced_at":"2025-10-21T17:47:12.956Z","repository":{"id":213227292,"uuid":"733373734","full_name":"thmsmlr/instructor_ex","owner":"thmsmlr","description":"Structured outputs for LLMs in Elixir","archived":false,"fork":false,"pushed_at":"2024-12-12T07:02:02.000Z","size":785,"stargazers_count":584,"open_issues_count":35,"forks_count":62,"subscribers_count":28,"default_branch":"main","last_synced_at":"2024-12-12T08:18:30.834Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://hexdocs.pm/instructor","language":"Elixir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/thmsmlr.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-12-19T07:22:34.000Z","updated_at":"2024-12-12T07:02:06.000Z","dependencies_parsed_at":"2023-12-30T04:27:48.259Z","dependency_job_id":"a0d3bd15-7987-4770-9e9d-a63677a413f0","html_url":"https://github.com/thmsmlr/instructor_ex","commit_stats":null,"previous_names":["thmsmlr/instructor_ex"],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thmsmlr%2Finstructor_ex","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thmsmlr%2Finstructor_ex/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thmsmlr%2Finstructor_ex/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thmsmlr%2Finstructor_ex/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/thmsmlr","download_url":"https://codeload.github.com/thmsmlr/instructor_ex/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":237707188,"owners_count":19353689,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-09T07:00:57.741Z","updated_at":"2025-10-21T17:47:12.950Z","avatar_url":"https://github.com/thmsmlr.png","language":"Elixir","funding_links":[],"categories":["LangChain-Style Components","LLM Clients and APIs","Elixir","Generative AI"],"sub_categories":["How to Join","LLM Tools"],"readme":"# instructor_ex\n\n_Structured, Ecto outputs with OpenAI (and OSS LLMs)_\n\n---\n\n[![Instructor version](https://img.shields.io/hexpm/v/instructor.svg)](https://hex.pm/packages/instructor)\n[![Hex Docs](https://img.shields.io/badge/hex-docs-lightgreen.svg)](https://hexdocs.pm/instructor/)\n[![Hex Downloads](https://img.shields.io/hexpm/dt/instructor)](https://hex.pm/packages/instructor)\n[![GitHub stars](https://img.shields.io/github/stars/thmsmlr/instructor_ex.svg)](https://github.com/thmsmlr/instructor_ex/stargazers)\n[![Twitter Follow](https://img.shields.io/twitter/follow/thmsmlr?style=social)](https://twitter.com/thmsmlr)\n[![Discord](https://img.shields.io/discord/1192334452110659664?label=discord)](https://discord.gg/bD9YE9JArw)\n\n\u003c!-- Docs --\u003e\n\nCheck out our [Quickstart Guide](https://hexdocs.pm/instructor/quickstart.html) to get up and running with Instructor in minutes.\n\nInstructor provides structured prompting for LLMs. It is a spiritual port of the great [Instructor Python Library](https://github.com/jxnl/instructor) by [@jxnlco](https://twitter.com/jxnlco).\n\nInstructor allows you to get structured output out of an LLM using Ecto.  \nYou don't have to define any JSON schemas.\nYou can just use Ecto as you've always used it.  \nAnd since it's just ecto, you can provide change set validations that you can use to ensure that what you're getting back from the LLM is not only properly structured, but semantically correct.\n\nTo learn more about the philosophy behind Instructor and its motivations, check out this Elixir Denver Meetup talk:\n\n\u003cdiv style=\"text-align: center\"\u003e\n\n[![Instructor: Structured prompting for LLMs](assets/youtube-thumbnail.png)](https://www.youtube.com/watch?v=RABXu7zqnT0)\n\n\u003c/div\u003e\n\nWhile Instructor is designed to be used with OpenAI, it also supports every major AI lab and open source LLM inference server:\n\n- OpenAI\n- Anthropic\n- Groq\n- Ollama\n- Gemini\n- vLLM\n- llama.cpp\n\nAt its simplest, usage is pretty straightforward: \n\n1. Create an ecto schema, with a `@llm_doc` string that explains the schema definition to the LLM. \n2. Define a `validate_changeset/1` function on the schema, and use the `use Instructor` macro in order for Instructor to know about it.\n2. Make a call to `Instructor.chat_completion/1` with an instruction for the LLM to execute.\n\nYou can use the `max_retries` parameter to automatically, iteratively go back and forth with the LLM to try fixing validation errorswhen they occur.\n\n```elixir\nMix.install([:instructor])\n\ndefmodule SpamPrediction do\n  use Ecto.Schema\n  use Validator\n\n  @llm_doc \"\"\"\n  ## Field Descriptions:\n  - class: Whether or not the email is spam.\n  - reason: A short, less than 10 word rationalization for the classification.\n  - score: A confidence score between 0.0 and 1.0 for the classification.\n  \"\"\"\n  @primary_key false\n  embedded_schema do\n    field(:class, Ecto.Enum, values: [:spam, :not_spam])\n    field(:reason, :string)\n    field(:score, :float)\n  end\n\n  @impl true\n  def validate_changeset(changeset) do\n    changeset\n    |\u003e Ecto.Changeset.validate_number(:score,\n      greater_than_or_equal_to: 0.0,\n      less_than_or_equal_to: 1.0\n    )\n  end\nend\n\nis_spam? = fn text -\u003e\n  Instructor.chat_completion(\n    model: \"gpt-4o-mini\",\n    response_model: SpamPrediction,\n    max_retries: 3,\n    messages: [\n      %{\n        role: \"user\",\n        content: \"\"\"\n        Your purpose is to classify customer support emails as either spam or not.\n        This is for a clothing retail business.\n        They sell all types of clothing.\n\n        Classify the following email: \n\n        \u003cemail\u003e\n          #{text}\n        \u003c/email\u003e\n        \"\"\"\n      }\n    ]\n  )\nend\n\nis_spam?.(\"Hello I am a Nigerian prince and I would like to send you money\")\n\n# =\u003e {:ok, %SpamPrediction{class: :spam, reason: \"Nigerian prince email scam\", score: 0.98}}\n```\n\n\u003c!-- Docs --\u003e\n\n## Installation\n\nIn your mix.exs,\n\n```elixir\ndef deps do\n  [\n    {:instructor, \"~\u003e 0.1.0\"}\n  ]\nend\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthmsmlr%2Finstructor_ex","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthmsmlr%2Finstructor_ex","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthmsmlr%2Finstructor_ex/lists"}