Packages
llm_db
2026.7.3
2026.7.3
2026.7.2
2026.7.1
2026.7.0
2026.6.4
2026.6.3
2026.6.2
2026.6.1
2026.6.0
2026.5.2
2026.5.1
2026.5.0
2026.4.8
2026.4.7
2026.4.6
2026.4.5
2026.4.4
2026.4.3
2026.4.2
2026.4.1
2026.4.0
2026.3.3
2026.3.2
2026.3.1
2026.3.0
2026.2.9
2026.2.8
2026.2.7
2026.2.6
2026.2.5
2026.2.4
2026.2.3
2026.2.2
2026.2.1
2026.2.0
2026.1.5
2026.1.4
2026.1.3
2026.1.2
2026.1.1
2026.1.0
2025.12.4
2025.12.3
2025.12.2
2025.12.1
2025.11.18-preview
2025.11.14-preview
2025.11.7-preview
LLM model metadata catalog with fast, capability-aware lookups.
Current section
Files
Jump to
Current section
Files
guides/consumer-integration.md
# Consumer Integration Guide
Guide for libraries and applications consuming llm_db for model metadata.
## Overview
llm_db provides model metadata through a simple `model_spec` interface with alias resolution. This guide covers best practices for integrating llm_db into your library or application.
## Model Aliases and Canonical IDs
### Understanding the Alias System
llm_db uses **canonical IDs** with **alias resolution** to handle model naming variations:
- **Canonical ID**: The primary, immutable identifier for a model (typically the dated version)
- Example: `claude-haiku-4-5-20251001`
- **Aliases**: Alternative names that resolve to the canonical ID
- Examples: `claude-haiku-4-5`, `claude-haiku-4.5`, `claude-haiku-4-5@latest`
```elixir
# All of these resolve to the same model
LLMDB.model("anthropic:claude-haiku-4-5-20251001") #=> canonical
LLMDB.model("anthropic:claude-haiku-4-5") #=> alias → canonical
LLMDB.model("anthropic:claude-haiku-4.5") #=> alias → canonical
# All return: %LLMDB.Model{id: "claude-haiku-4-5-20251001", ...}
```
### Why Canonical IDs?
1. **Immutable**: Dated versions represent a single, specific model release
2. **Deduplication**: Prevents duplicate metadata/fixtures for the same model
3. **Clarity**: Explicit about which version you're using
4. **Stability**: Won't change when "latest" changes
### Alias Resolution Flow
```
User Request → Alias Resolution → Canonical Model → Metadata
"claude-haiku-4.5" → "claude-haiku-4-5-20251001" → %LLMDB.Model{...}
```
## Configuration: allow/deny Filters
### Critical Rule: Filters Use Canonical IDs Only
**Filters are applied BEFORE alias resolution**, so they match against canonical IDs, not aliases.
```elixir
# ✓ CORRECT - Use canonical IDs in filters
config :llm_db,
filter: %{
allow: %{
anthropic: [
"claude-haiku-4-5-20251001", # Canonical ID
"claude-opus-4-1-20250805", # Canonical ID
"claude-sonnet-4-5-20250929" # Canonical ID
]
},
deny: %{}
}
# ✗ INCORRECT - Aliases won't match
config :llm_db,
filter: %{
allow: %{
anthropic: [
"claude-haiku-4.5", # This is an alias - won't work!
"claude-opus-4.1", # This is an alias - won't work!
"claude-sonnet-4.5" # This is an alias - won't work!
]
},
deny: %{}
}
# This will eliminate ALL models because aliases don't match filters
```
### Using Glob Patterns
Glob patterns work with canonical IDs:
```elixir
config :llm_db,
filter: %{
allow: %{
anthropic: ["claude-haiku-*"], # Matches claude-haiku-4-5-20251001
openai: ["gpt-4o-*"] # Matches gpt-4o-2024-11-20, etc.
},
deny: %{
anthropic: ["*-thinking"] # Deny thinking modes
}
}
```
### Finding Canonical IDs
Use llm_db to discover canonical IDs for configuration:
```elixir
# List all models for a provider
anthropic_models = LLMDB.models(:anthropic)
Enum.each(anthropic_models, fn m ->
IO.puts("#{m.id} → aliases: #{inspect(m.aliases)}")
end)
# Output:
# claude-haiku-4-5-20251001 → aliases: ["claude-haiku-4-5", "claude-haiku-4.5"]
# claude-opus-4-1-20250805 → aliases: ["claude-opus-4-1", "claude-opus-4.1"]
```
## Fixture Management
### Best Practice: One Fixture Set per Canonical ID
Since aliases resolve to canonical IDs, you only need ONE fixture set per unique model.
**Example Directory Structure:**
```
fixtures/
├── anthropic/
│ ├── claude-haiku-4-5-20251001/ # ✓ One canonical fixture
│ │ ├── basic.json
│ │ ├── tools.json
│ │ └── streaming.json
│ ├── claude-opus-4-1-20250805/ # ✓ One canonical fixture
│ │ └── basic.json
│ └── claude-sonnet-4-5-20250929/ # ✓ One canonical fixture
│ └── basic.json
```
**Anti-pattern (duplicates):**
```
fixtures/
├── anthropic/
│ ├── claude-haiku-4-5-20251001/ # ✗ Duplicate
│ ├── claude-haiku-4-5/ # ✗ Duplicate (alias)
│ └── claude-haiku-4.5/ # ✗ Duplicate (alias)
```
### Fixture Lookup Strategy
When looking up fixtures, resolve to canonical ID first:
```elixir
defmodule MyApp.Fixtures do
def load_fixture(model_spec) do
# Resolve to canonical model
{:ok, model} = LLMDB.model(model_spec)
# Use canonical ID for fixture path
provider = model.provider
canonical_id = model.id
fixture_path = "test/fixtures/#{provider}/#{canonical_id}/basic.json"
File.read!(fixture_path)
end
end
# All of these load the same fixture
MyApp.Fixtures.load_fixture("anthropic:claude-haiku-4-5-20251001")
MyApp.Fixtures.load_fixture("anthropic:claude-haiku-4-5")
MyApp.Fixtures.load_fixture("anthropic:claude-haiku-4.5")
```
## Runtime Model Resolution
### Accept Any Variant, Use Canonical Internally
Allow users to specify models using aliases, but resolve to canonical IDs internally:
```elixir
defmodule MyApp.LLMClient do
def chat(model_spec, messages) do
# Resolve alias to canonical model
{:ok, model} = LLMDB.model(model_spec)
# Use canonical ID internally
provider = model.provider
canonical_id = model.id
# Make API call with metadata
request_body = %{
model: model.provider_model_id || canonical_id, # Use provider-specific ID
messages: messages,
max_tokens: model.limits.output
}
make_request(provider, request_body)
end
end
# All variants work
MyApp.LLMClient.chat("anthropic:claude-haiku-4.5", messages) # Alias
MyApp.LLMClient.chat("anthropic:claude-haiku-4-5-20251001", messages) # Canonical
```
## Migration: Consolidating Duplicates
If you have existing code/fixtures using aliases, migrate to canonical IDs:
### Step 1: Identify Duplicates
```elixir
# Find models with aliases
anthropic_models = LLMDB.models(:anthropic)
duplicates = Enum.filter(anthropic_models, fn m -> length(m.aliases) > 0 end)
Enum.each(duplicates, fn m ->
IO.puts("Canonical: #{m.id}")
IO.puts(" Aliases: #{inspect(m.aliases)}")
end)
```
### Step 2: Update Configuration
Replace aliases with canonical IDs in `config/*.exs`:
```elixir
# Before
config :my_app,
allowed_models: [
"anthropic:claude-haiku-4.5", # Alias
"anthropic:claude-opus-4.1" # Alias
]
# After
config :my_app,
allowed_models: [
"anthropic:claude-haiku-4-5-20251001", # Canonical
"anthropic:claude-opus-4-1-20250805" # Canonical
]
```
### Step 3: Consolidate Fixtures
Rename fixture directories to canonical IDs and remove duplicates:
```bash
# Rename to canonical
mv fixtures/anthropic/claude_haiku_4_5 fixtures/anthropic/claude-haiku-4-5-20251001
# Remove duplicates
rm -rf fixtures/anthropic/claude-haiku-4.5
rm -rf fixtures/anthropic/claude_haiku_4.5_20251001
```
### Step 4: Update Tests
Update test references to use canonical IDs:
```elixir
# Before
test "claude haiku generates text" do
response = MyApp.chat("anthropic:claude-haiku-4.5", "Hello")
assert response.text
end
# After (optional - aliases still work at runtime)
test "claude haiku generates text" do
response = MyApp.chat("anthropic:claude-haiku-4-5-20251001", "Hello")
assert response.text
end
# Or keep using aliases - both work!
test "claude haiku generates text" do
# This still works - llm_db resolves the alias
response = MyApp.chat("anthropic:claude-haiku-4.5", "Hello")
assert response.text
end
```
## Common Patterns
### Allow User Preferences, Resolve Internally
```elixir
defmodule MyApp.Config do
def get_preferred_model do
# Users configure with any variant
model_spec = Application.get_env(:my_app, :default_model, "anthropic:claude-haiku-4.5")
# Resolve to canonical for internal use
case LLMDB.model(model_spec) do
{:ok, model} -> {:ok, {model.provider, model.id}}
error -> error
end
end
end
```
### Validate Model Availability
```elixir
defmodule MyApp.Setup do
def validate_config! do
configured_models = Application.get_env(:my_app, :allowed_models, [])
Enum.each(configured_models, fn model_spec ->
case LLMDB.model(model_spec) do
{:ok, model} ->
unless LLMDB.allowed?(model) do
raise "Model #{model_spec} is filtered out by llm_db configuration"
end
IO.puts("✓ #{model_spec} → #{model.provider}:#{model.id}")
{:error, :not_found} ->
raise "Model #{model_spec} not found in llm_db catalog"
end
end)
end
end
```
## Recommendations Summary
1. **Filters**: Always use canonical IDs in allow/deny patterns
2. **Fixtures**: One fixture set per canonical model ID
3. **Configuration**: Use canonical IDs in application config
4. **Runtime**: Accept user input with aliases, resolve to canonical internally
5. **Documentation**: Document canonical IDs in user-facing docs, mention alias support
6. **Migration**: Consolidate duplicate fixtures to canonical IDs
7. **Validation**: Check both model existence and filter status at startup
## See Also
- [Using the Data](using-the-data.md) - Alias resolution examples
- [Runtime Filters](runtime-filters.md) - Filter configuration details
- [Schema System](schema-system.md) - Model alias field documentation