Custom Providers Guide
View SourceThis guide covers using the custom: provider prefix to connect to any OpenAI-compatible API endpoint.
Overview
The custom: provider is the recommended way to connect to LLM services that implement the OpenAI Chat Completions API. It works with:
- Cloud providers: Groq, Together AI, OpenRouter, Anyscale, Fireworks, etc.
- Local servers: LM Studio, Ollama, vLLM, SGLang, TGI, etc.
- Self-hosted endpoints: Your own OpenAI-compatible API
Note: The legacy
openai_compatible:prefix still works for backward compatibility, butcustom:is the recommended approach.
Quick Start
# Basic usage with explicit options
agent = Nous.new("custom:llama-3.1-70b",
base_url: "https://api.groq.com/openai/v1",
api_key: System.get_env("GROQ_API_KEY")
)
{:ok, result} = Nous.run(agent, "What is Elixir?")Configuration Methods
Configuration is loaded in precedence order (higher overrides lower):
1. Direct Options (Per-Request)
Pass options directly to Nous.new/2:
agent = Nous.new("custom:my-model",
base_url: "https://api.example.com/v1",
api_key: "sk-...",
receive_timeout: 120_000
)2. Environment Variables
Set environment variables for global defaults:
export CUSTOM_BASE_URL="https://api.example.com/v1"
export CUSTOM_API_KEY="sk-..."
Then use without options:
agent = Nous.new("custom:my-model")3. Application Config
Configure in config/config.exs or environment-specific config:
config :nous, :custom,
base_url: "https://api.example.com/v1",
api_key: "sk-..."Examples by Service
Groq
Fast inference with various open models:
# Via explicit options
agent = Nous.new("custom:llama-3.1-70b-versatile",
base_url: "https://api.groq.com/openai/v1",
api_key: System.get_env("GROQ_API_KEY")
)
# Or if using the built-in groq provider
agent = Nous.new("groq:llama-3.1-70b-versatile")Together AI
Wide model selection including Qwen, Llama, and more:
agent = Nous.new("custom:meta-llama/Llama-3-70b-chat-hf",
base_url: "https://api.together.xyz/v1",
api_key: System.get_env("TOGETHER_API_KEY")
)
# Or use the built-in together provider
agent = Nous.new("together:meta-llama/Llama-3-70b-chat-hf")OpenRouter
Unified API for many providers:
agent = Nous.new("custom:anthropic/claude-3.5-sonnet",
base_url: "https://openrouter.ai/api/v1",
api_key: System.get_env("OPENROUTER_API_KEY")
)
# Or use the built-in openrouter provider
agent = Nous.new("openrouter:anthropic/claude-3.5-sonnet")LM Studio
Local models with GUI (no API key needed):
agent = Nous.new("custom:qwen3",
base_url: "http://localhost:1234/v1"
)
# Or use the built-in lmstudio provider (same default URL)
agent = Nous.new("lmstudio:qwen3")Ollama
Local CLI-based models (no API key needed):
# Using custom with explicit base_url
agent = Nous.new("custom:llama2",
base_url: "http://localhost:11434/v1"
)
# Or use the built-in ollama provider
agent = Nous.new("ollama:llama2")vLLM
High-performance local inference:
# Using custom with explicit base_url
agent = Nous.new("custom:meta-llama/Llama-3-8B-Instruct",
base_url: "http://localhost:8000/v1"
)
# Or use the built-in vllm provider
agent = Nous.new("vllm:meta-llama/Llama-3-8B-Instruct",
base_url: "http://localhost:8000/v1"
)SGLang
Structured generation with RadixAttention:
# Using custom with explicit base_url
agent = Nous.new("custom:meta-llama/Llama-3-8B-Instruct",
base_url: "http://localhost:30000/v1"
)
# Or use the built-in sglang provider
agent = Nous.new("sglang:meta-llama/Llama-3-8B-Instruct")Custom Self-Hosted Endpoints
Point to your own OpenAI-compatible server:
agent = Nous.new("custom:my-custom-model",
base_url: "https://llm.internal.company.com/v1",
api_key: System.get_env("INTERNAL_API_KEY")
)Advanced Options
Custom Timeouts
Slow local models may need longer timeouts:
agent = Nous.new("custom:large-model",
base_url: "http://localhost:8000/v1",
receive_timeout: 300_000 # 5 minutes
)Organization Headers
Some providers support organization IDs:
agent = Nous.new("custom:model",
base_url: "https://api.openai.com/v1",
api_key: System.get_env("OPENAI_API_KEY"),
organization: "org-..."
)Using with Tools
The custom provider supports function calling if the underlying model supports it:
get_weather = fn _ctx, %{"city" => city} ->
%{temperature: 72, condition: "sunny"}
end
agent = Nous.new("custom:meta-llama/Llama-3-70b",
base_url: "https://api.together.xyz/v1",
api_key: System.get_env("TOGETHER_API_KEY"),
instructions: "You can check the weather.",
tools: [get_weather]
)
{:ok, result} = Nous.run(agent, "What's the weather in San Francisco?")Streaming
Streaming works the same as any other provider:
{:ok, stream} = Nous.run_stream(agent, "Write a haiku about Elixir")
stream
|> Enum.each(fn
{:text_delta, text} -> IO.write(text)
{:finish, _} -> IO.puts("")
_ -> :ok
end)Troubleshooting
Connection Refused
Ensure the server is running and accessible:
# LM Studio - check server is enabled in settings
# vLLM
vllm serve meta-llama/Llama-3.1-8B-Instruct
# SGLang
python -m sglang.launch_server --model meta-llama/Llama-3.1-8B-Instruct
# Ollama
ollama run llama2
ollama serve
Authentication Errors
Check your API key:
# With explicit key
agent = Nous.new("custom:model",
base_url: "...",
api_key: System.get_env("CORRECT_API_KEY")
)
# Or set env var
System.put_env("CUSTOM_API_KEY", "your-key")Base URL Format
Most servers expect the base URL to include /v1:
# Correct
base_url: "http://localhost:1234/v1"
base_url: "https://api.groq.com/openai/v1"
# Might not work
base_url: "http://localhost:1234" # missing /v1
base_url: "http://localhost:1234/v1/chat" # too specificBackward Compatibility
The openai_compatible: prefix still works and is equivalent to custom::
# Legacy (still works)
agent = Nous.new("openai_compatible:my-model", base_url: "...")
# Recommended
agent = Nous.new("custom:my-model", base_url: "...")See Also
Nous.Providers.Custom- The custom provider moduleNous.Providers.OpenAICompatible- Underlying implementation- vLLM & SGLang examples - High-performance local inference