Lightweight Elixir client for LLM APIs.
Supports 4 dialects covering 99% of providers:
- OpenAI Chat Completions —
/v1/chat/completions(also works with Ollama, Groq, OpenRouter, DeepSeek, xAI, etc.) - OpenAI Responses —
/v1/responses - Anthropic Messages —
/v1/messages - Gemini —
/v1beta/models/{model}:generateContent
Quick Start
# Simple text generation
{:ok, response} = LLM.generate("What is Elixir?",
provider: :openai,
model: "gpt-4"
)
response.message.content #=> "Elixir is a..."
# Streaming
{:ok, stream} = LLM.stream("Tell me a story",
provider: :anthropic,
model: "claude-sonnet-4-5-20250514"
)
{:ok, response} = LLM.Stream.collect(stream, on_chunk: &IO.write/1)
# Custom provider (runtime)
{:ok, response} = LLM.generate("Hello",
provider: %{
dialect: LLM.Dialect.Anthropic,
base_url: "https://my-proxy.com",
api_key: "sk-ant-..."
},
model: "claude-sonnet-4-5-20250514"
)
# With tools
{:ok, response} = LLM.generate("Read mix.exs",
provider: :openai,
model: "gpt-4",
tools: [MyApp.ReadFileTool]
)Configuration
# config/config.exs
config :llm, :providers,
openai: [api_key: "sk-..."],
anthropic: [api_key: "sk-ant-..."]
# Or at runtime
LLM.Provider.Presets.put_key(:openai, "sk-...")Provider
A provider can be:
- An atom preset (
:openai,:anthropic,:gemini,:openai_responses) - A map with
:dialect,:base_url, and optionally:api_key - A module implementing
LLM.Providerbehaviour
Summary
Functions
Generate text (non-streaming). Returns the final response.
Generate text, raising on error.
List available provider presets.
Store an API key at runtime.
Stream a prompt, returning a stream handle.
Types
@type stream_option() :: {:provider, atom() | map() | module()} | {:model, String.t()} | {:max_tokens, non_neg_integer()} | {:temperature, float()} | {:thinking, atom() | map()} | {:tools, [module() | LLM.Tool.t() | {module(), map()}]} | {:auto_tools, boolean()} | {:max_rounds, non_neg_integer()} | {:on_chunk, (LLM.Stream.chunk_type() -> any())} | {:system, String.t()}
Functions
@spec generate(String.t() | LLM.Context.t(), [stream_option()]) :: {:ok, LLM.Response.t()} | {:error, term()}
Generate text (non-streaming). Returns the final response.
Automatically collects the stream and executes tool calls if present.
@spec generate!(String.t() | LLM.Context.t(), [stream_option()]) :: LLM.Response.t()
Generate text, raising on error.
@spec providers() :: [atom()]
List available provider presets.
Store an API key at runtime.
@spec stream(String.t() | LLM.Context.t(), [stream_option()]) :: {:ok, LLM.Stream.t()} | {:error, term()}
Stream a prompt, returning a stream handle.
Returns {:ok, stream} on success, {:error, reason} on failure.
The stream can be consumed with LLM.Stream.next/1 and LLM.Stream.collect/2.