ExLLM Quick Start Guide

View Source

Get up and running with ExLLM in 5 minutes! This guide covers installation, basic configuration, and common usage patterns.

Installation

Add ExLLM to your mix.exs dependencies:

def deps do
  [
    {:ex_llm, "~> 0.7.0"}
  ]
end

Then run:

mix deps.get

Configuration

Environment Variables

Set API keys for the providers you want to use:

# Core providers
export ANTHROPIC_API_KEY="sk-ant-your-key"
export OPENAI_API_KEY="sk-your-key"
export GROQ_API_KEY="gsk_your-key"

# Additional providers (optional)
export GEMINI_API_KEY="your-gemini-key"
export MISTRAL_API_KEY="your-mistral-key"
export OPENROUTER_API_KEY="sk-or-your-key"
export PERPLEXITY_API_KEY="pplx-your-key"

Application Configuration (Optional)

# config/config.exs
config :ex_llm,
  # Default provider
  default_provider: :anthropic,
  
  # Cost tracking
  cost_tracking_enabled: true,
  
  # Test caching (speeds up tests 25x)
  test_cache: [
    enabled: true,
    cache_dir: "test/cache",
    ttl: 604_800_000  # 7 days in milliseconds
  ]

Basic Usage

Simple Chat Completion

# Start with a basic chat
{:ok, response} = ExLLM.chat(:anthropic, [
  %{role: "user", content: "What is the capital of France?"}
])

IO.puts(response.content)
# => "The capital of France is Paris."

# Access additional metadata
IO.puts("Model: #{response.model}")
IO.puts("Cost: $#{response.cost}")
IO.puts("Tokens used: #{response.usage.total_tokens}")

Different Providers

# Try different providers
{:ok, response1} = ExLLM.chat(:openai, [
  %{role: "user", content: "Explain quantum computing briefly"}
])

{:ok, response2} = ExLLM.chat(:groq, [
  %{role: "user", content: "Write a haiku about coding"}
])

{:ok, response3} = ExLLM.chat(:gemini, [
  %{role: "user", content: "What's 2+2?"}
])

Streaming Responses

# Stream responses in real-time
ExLLM.chat_stream(:openai, [
  %{role: "user", content: "Write a short story about a robot"}
], fn chunk ->
  IO.write(chunk.delta)
end)

Session Management

# Maintain conversation context
{:ok, session} = ExLLM.Session.new(:anthropic)

# First message
{:ok, session, response1} = ExLLM.Session.chat(session, "Hi, I'm learning Elixir")
IO.puts(response1.content)

# Continue the conversation
{:ok, session, response2} = ExLLM.Session.chat(session, "What are GenServers?")
IO.puts(response2.content)

# Session automatically tracks conversation history
IO.puts("Messages in session: #{length(session.messages)}")
IO.puts("Total cost: $#{session.total_cost}")

Advanced Features

Multimodal (Vision)

# Analyze images (with Gemini or OpenAI)
image_data = File.read!("image.jpg") |> Base.encode64()

{:ok, response} = ExLLM.chat(:gemini, [
  %{role: "user", content: [
    %{type: "text", text: "What's in this image?"},
    %{type: "image", image: %{
      data: image_data,
      media_type: "image/jpeg"
    }}
  ]}
])

IO.puts(response.content)

Function Calling

# Define tools
tools = [
  %{
    type: "function",
    function: %{
      name: "get_weather",
      description: "Get current weather for a location",
      parameters: %{
        type: "object",
        properties: %{
          location: %{type: "string", description: "City name"},
          unit: %{type: "string", enum: ["celsius", "fahrenheit"]}
        },
        required: ["location"]
      }
    }
  }
]

{:ok, response} = ExLLM.chat(:openai, [
  %{role: "user", content: "What's the weather in Paris?"}
], tools: tools)

# Handle function calls
case response.function_calls do
  [%{name: "get_weather", arguments: args}] ->
    # Call your weather API here
    weather_data = get_weather(args["location"])
    
    # Continue conversation with function result
    {:ok, final_response} = ExLLM.chat(:openai, [
      %{role: "user", content: "What's the weather in Paris?"},
      response.message,
      %{role: "function", name: "get_weather", content: Jason.encode!(weather_data)}
    ])
    
  _ ->
    IO.puts(response.content)
end

Model Discovery

# List available models
{:ok, models} = ExLLM.list_models(:anthropic)

Enum.each(models, fn model ->
  IO.puts("#{model.id} - Context: #{model.context_window} tokens")
end)

# Get specific model info
{:ok, model} = ExLLM.get_model(:openai, "gpt-4o")
IO.puts("Supports streaming: #{model.capabilities.supports_streaming}")
IO.puts("Supports vision: #{model.capabilities.supports_vision}")

Testing

Fast Testing with Caching

ExLLM includes intelligent test caching for 25x faster integration tests:

# Run tests with automatic caching
mix test

# Test specific providers
mix test.anthropic
mix test.openai --include live_api

# Manage cache
mix ex_llm.cache stats
mix ex_llm.cache clean --older-than 7d

Writing Tests

defmodule MyAppTest do
  use ExUnit.Case
  
  # Tag for automatic caching
  @moduletag :live_api
  @moduletag :requires_api_key
  @moduletag provider: :anthropic
  
  test "chat completion works" do
    {:ok, response} = ExLLM.chat(:anthropic, [
      %{role: "user", content: "Say hello"}
    ])
    
    assert response.content =~ "hello"
    assert response.cost > 0
  end
end

Local Models

Ollama

# Start Ollama
ollama serve

# Pull a model
ollama pull llama3.2
# Use local Ollama models
{:ok, response} = ExLLM.chat(:ollama, [
  %{role: "user", content: "Hello!"}
], model: "llama3.2")

LM Studio

# Start LM Studio server on localhost:1234
# Use LM Studio models
{:ok, response} = ExLLM.chat(:lmstudio, [
  %{role: "user", content: "Hello!"}
])

Bumblebee (Elixir Native)

# Add to deps for local inference
{:exla, "~> 0.7"}  # For CPU/GPU acceleration

# Use Bumblebee models
{:ok, response} = ExLLM.chat(:bumblebee, [
  %{role: "user", content: "Hello!"}
], model: "microsoft/DialoGPT-medium")

Error Handling

case ExLLM.chat(:anthropic, messages) do
  {:ok, response} ->
    IO.puts(response.content)
    
  {:error, {:api_error, %{status: 401}}} ->
    IO.puts("Invalid API key")
    
  {:error, {:api_error, %{status: 429}}} ->
    IO.puts("Rate limited - try again later")
    
  {:error, {:api_error, %{status: 400, body: body}}} ->
    IO.puts("Bad request: #{inspect(body)}")
    
  {:error, {:network_error, reason}} ->
    IO.puts("Network error: #{reason}")
    
  {:error, reason} ->
    IO.puts("Other error: #{inspect(reason)}")
end

Environment-Specific Configuration

Development

# config/dev.exs
config :ex_llm,
  log_level: :debug,
  log_components: [:http_client, :streaming],
  test_cache: [enabled: true]

Test

# config/test.exs
config :ex_llm,
  log_level: :warn,
  test_cache: [
    enabled: true,
    cache_dir: "test/cache",
    ttl: 604_800_000  # 7 days
  ]

Production

# config/prod.exs
config :ex_llm,
  log_level: :info,
  log_redaction: true,
  cost_tracking_enabled: true

Next Steps

  1. Read the User Guide for comprehensive documentation
  2. Check Provider Capabilities to compare features
  3. Review Testing Guide for advanced testing patterns and caching

Common Issues

"API key not found"

# Make sure you've set the environment variable
export ANTHROPIC_API_KEY="your-key"

"Model not found"

# Check available models
{:ok, models} = ExLLM.list_models(:anthropic)

"Rate limited"

# Use different providers or implement backoff
Process.sleep(1000)
{:ok, response} = ExLLM.chat(:groq, messages)  # Try Groq for speed

Tests running slowly

# Enable test caching
export EX_LLM_TEST_CACHE_ENABLED=true
mix test --include live_api

That's it! You're now ready to build amazing applications with ExLLM. 🚀