LiteLLM on the Homelab: One Proxy, Every Model, Waterfall Routing Included
LiteLLM transforms your homelab into a flexible AI gateway with fallback chains, load balancing, and cost control across local and remote LLMs.
The Problem: LLM Endpoint Sprawl in the Homelab
As your homelab AI ecosystem grows, endpoint management becomes painful:
Before LiteLLM: The Fragmented Approach
- Ollama: http://homelab:11434 - For qwen2.5-coder:14b, deepseek-r1:14b
- Llama.cpp server: http://homelab:8080 - For specialized GGUF models
- Text Generation WebUI: http://homelab:7860 - For experimental models
- OpenAI API: https://api.openai.com/v1 - For GPT-4 when local isn't enough
- Anthropic API: https://api.anthropic.com - For Claude access
- Groq API: https://api.groq.com - For fast inference
- Each requires: Different API keys, different endpoints, different SDKs
The Result: Integration Nightmare
- Code duplication: Every application needs conditional logic for each provider
- Configuration hell: Managing 6+ sets of credentials and endpoints
- No fallback: When Ollama is down, your app crashes
- No load balancing: Can't distribute load across multiple instances
- Usage tracking: Manual logging required for any cost visibility
- Rate limiting: No built-in protection against API abuse
- Observer pattern: Difficult to add monitoring or tracing
The LiteLLM Solution:
One proxy to rule them all:
- Single endpoint: All applications talk to http://homelab:4000/v1/*
- OpenAI-compatible: Works with any OpenAI SDK or wrapper
- Model abstraction: "gpt-4o-mini" might route to local or remote
- Automatic fallback: Try local first, then paid APIs
- Load balancing: Distribute across multiple Ollama instances
- Usage tracking: Built-in token counting and cost estimation
- Rate limiting: Per-model or global request limits
- Retry logic: Exponential backoff with jitter
Core LiteLLM Concepts: Models, Providers, and Routing
Understanding the building blocks:
Providers: Where the Magic Happens
Local Providers (Homelab Resident)
- ollama: Communicates with Ollama API (recommended for most)
- llama_cpp: Direct connection to llama.cpp server
- vllm: For high-throughput serving (more complex setup)
- tgi: Text Generation Inference from Hugging Face
- sagemaker: For local SageMaker endpoints
- bedrock: AWS Bedrock local emulator
- vertex_ai: Google Vertex AI local
- azure_ai: Azure AI Studio local
Remote Providers (Cloud/API Based)
- openai: OpenAI API (GPT-3.5, GPT-4, etc.)
- anthropic: Anthropic API (Claude family)
- groq: Groq LPU inference engine
- cohere: Cohere API
- mistralai: Mistral AI API
- ali_bailian: Alibaba Cloud BaiLian
- volcengine: ByteDance VolcEngine
- predibase: Predibase fine-tuned models
- replicate: Replicate model hosting
- huggingface: Hugging Face Inference API
- azure: Azure OpenAI Service
- aws: Amazon Bedrock
Routing Strategies: How LiteLLM Decides Where to Send Requests
Simple List (First Working)
Try models in order until one succeeds:
model_list:
- model_name: ollama_qwen
litellm_provider: ollama
model_name: qwen2.5-coder:14b
api_base: http://localhost:11434
- model_name: ollama_deepseek
litellm_provider: ollama
model_name: deepseek-r1:14b
api_base: http://localhost:11434
- model_name: openai_fallback
litellm_provider: openai
model: gpt-4o-mini
api_key: ${OPENAI_API_KEY}
# With this config, a request for "ollama_qwen" will:
# 1. Try Ollama with qwen2.5-coder:14b
# 2. If that fails, try Ollama with deepseek-r1:14b
# 3. If that fails, fall back to OpenAI gpt-4o-mini
Load Balancing (Distribute Load)
Spread requests across multiple instances:
model_list:
- model_name: ollama_pool_1
litellm_provider: ollama
model_name: qwen2.5-coder:14b
api_base: http://ollama1.local:11434
rpm: 30 # Requests per minute limit
- model_name: ollama_pool_2
litellm_provider: ollama
model_name: qwen2.5-coder:14b
api_base: http://ollama2.local:11434
rpm: 30
- model_name: ollama_pool_3
litellm_provider: ollama
model_name: qwen2.5-coder:14b
api_base: http://ollama3.local:11434
rpm: 30
# LiteLLM will distribute requests across the three instances
# Each respects its RPM limit to prevent overload
Fallback Chains (Waterfall Routing)
Try local, then increasingly expensive remote options:
model_list:
# Tier 1: Fast local (Ollama)
- model_name: local_fast
litellm_provider: ollama
model_name: qwen2.5-coder:14b
api_base: http://localhost:11434
tpm: 5000 # Tokens per minute
# Tier 2: Capable local (larger model)
- model_name: local_capable
litellm_provider: ollama
model_name: deepseek-r1:14b
api_base: http://localhost:11434
tpm: 3000
# Tier 3: Remote backup (cost-conscious)
- model_name: remote_backup
litellm_provider: openai
model: gpt-3.5-turbo
api_key: ${OPENAI_API_KEY}
tpm: 1000
# Tier 4: Premium remote (when quality is critical)
- model_name: remote_premium
litellm_provider: openai
model: gpt-4o
api_key: ${OPENAI_API_KEY}
tpm: 500
# With appropriate routing strategy, LiteLLM will:
# 1. Try fast local model first
# 2. If overloaded or unsuitable, try capable local model
# 3. If still inadequate or rate-limited, use gpt-3.5-turbo
# 4. Only use gpt-4 gpt-4o for complex reasoning
Deployment Options: From Simple to Sophisticated
How to run LiteLLM in your homelab environment:
Option 1: Docker Container (Recommended)
Easy, portable, and isolated:
# docker run command for LiteLLM
docker run -d \
--name litellm \
--restart unless-stopped \
-p 4000:4000 \
-v /mnt/nvme-pool/apps/litellm:/litellm \
-e OPENAI_API_KEY=${OPENAI_API_KEY} \
-e ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY} \
-e GROQ_API_KEY=${GROQ_API_KEY} \
-v /mnt/Storage_Pool/models:/models \
ghcr.io/berriai/litellm:main \
--config /litellm/config.yaml \
--port 4000 \
--host 0.0.0.0
# Alternative: Using docker-compose
# Create docker-compose.yml:
version: '3.8'
services:
litellm:
image: ghcr.io/berriai/litellm:main
container_name: litellm
restart: unless-stopped
ports:
- "4000:4000"
volumes:
- ./config:/litellm
- /mnt/Storage_Pool/models:/models
environment:
- OPENAI_API_KEY=${OPENAI_API_KEY}
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
- GROQ_API_KEY=${GROQ_API_KEY}
command: >
--config /litellm/config.yaml
--port 4000
--host 0.0.0.0
Option 2: Direct Installation (For Development)
When you want to modify or debug:
# Install LiteLLM directly
pip install litellm
# Create a basic config file (config.yaml)
cat > config.yaml << 'EOF'
model_list:
- model_name: ollama_qwen
litellm_provider: ollama
model_name: qwen2.5-coder:14b
api_base: http://localhost:11434
- model_name: openai_backup
litellm_provider: openai
model: gpt-4o-mini
api_key: ${OPENAI_API_KEY}
# Start LiteLLM
litellm --config config.yaml --port 4000 --host 0.0.0.0
Option 3: Kubernetes Helm Chart (For Advanced Users)
If you're running Kubernetes on TrueNAS SCALE:
# Add LiteLLM helm repo
helm repo add litellm https://berriai.github.io/litellm-helm-chart
helm repo update
# Install with custom values
helm install litellm litellm/litellm \
--namespace ai \
--create-namespace \
--set service.type=LoadBalancer \
--set service.port=4000 \
--set env.OPENAI_API_KEY=${OPENAI_API_KEY} \
--set env.ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY} \
--set config.modelList="[
{model_name: 'ollama_qwen', litellm_provider: 'ollama', model_name: 'qwen2.5-coder:14b', api_base: 'http://localhost:11434'},
{model_name: 'openai_backup', litellm_provider: 'openai', model: 'gpt-4o-mini', api_key: env.OPENAI_API_KEY}
]"
Configuration Deep Dive: The config.yaml File
Understanding the key sections of your LiteLLM configuration:
Essential Configuration Sections
Model List (The Heart of Configuration)
Define all your available models and their providers:
# Complete config.yaml example
model_list:
# === LOCAL OLLAMA MODELS ===
- model_name: ollama_qwen_coder
litellm_provider: ollama
model_name: qwen2.5-coder:14b
api_base: http://localhost:11434
# Optional: Set rate limits
tpm: 5000 # Tokens per minute
rpm: 60 # Requests per minute
max_parallel_calls: 10
- model_name: ollama_deepseek
litellm_provider: ollama
model_name: deepseek-r1:14b
api_base: http://localhost:11434
tpm: 3000
rpm: 40
- model_name: ollama_llama3
litellm_provider: ollama
model_name: llama3.1:8b
api_base: http://localhost:11434
# === LOCAL LLAMA.CPP MODELS ===
- model_name: local_phi3
litellm_provider: llama_cpp
model_path: /mnt/Storage_Pool/models/phi-3-mini-4k-instruct.q4_K_M.gguf
n_ctx: 4096
n_batch: 8
# For llama_cpp, you might need to specify server parameters
# if using a separate llama.cpp server instance
# === REMOTE API MODELS ===
- model_name: openai_gpt35
litellm_provider: openai
model: gpt-3.5-turbo
api_key: ${OPENAI_API_KEY}
tpm: 10000
rpm: 500
- model_name: openai_gpt4o
litellm_provider: openai
model: gpt-4o
api_key: ${OPENAI_API_KEY}
tpm: 5000
rpm: 200
- model_name: anthropic_claude
litellm_provider: anthropic
model: claude-3-haiku-20240307
api_key: ${ANTHROPIC_API_KEY}
tpm: 5000
rpm: 200
# === SPECIALIZED MODELS ===
- model_name: groq_mixtral
litellm_provider: groq
model: mixtral-8x7b-32768
api_key: ${GROQ_API_KEY}
# Groq is incredibly fast - higher limits
tpm: 50000
rpm: 1000
# === EMBEDDING MODELS ===
- model_name: nomic_embed_text
litellm_provider: ollama
model_name: nomic-embed-text
api_base: http://localhost:11434
# Embedding models often need different handling
# Some applications treat them specially
# === GLOBAL SETTINGS ===
# These apply to all models unless overridden
# Set default timeout for API calls
default_timeout: 120
# Enable retry logic with exponential backoff
num_retries: 3
max_retries: 6
# Set up caching (optional but recommended)
# Uncomment to enable Redis caching
# caching:
# type: redis
# host: localhost
# port: 6379
# Enable usage tracking to CSV file (great for homelabs)
# Uncomment to enable
# bandwidth: redis
# host: localhost
# port: 6379
# callbacks:
# - csv_logger
# csv_logging_file: /litellm/logs/usage.csv
# Set up logging level
# Options: DEBUG, INFO, WARNING, ERROR, CRITICAL
logging_level: INFO
# Enable budget controls (prevent runaway costs)
# budget:
# duration: interval # interval, daily, weekly, monthly
# interval: 1 # For interval=1, duration=daily means check every day
# max_budget: 10.0 # $10 max per period
# excludes: [] # List of model names to exclude from budget tracking
# # Optional: add callbacks for when budget is exceeded
# # callbacks: [slack_alert, email_alert]
# Custom headers to pass through to API calls
# default_headers:
# Authorization: "Bearer ${API_KEY}"
# X-Custom-Header: "homelab-litellm"
# Enable telemetry (helps improve LiteLLM)
# Set to false to disable
enable_telemetry: true
Advanced Configuration Features
- Model aliases: Multiple names pointing to same underlying model
- Dynamic model loading: Load models based on request patterns
- Providers-specific parameters: Pass special flags to each backend
- Input/output transformers: Modify requests/responses on the fly
- Guardrails: Integrate with NeMo Guardrails or similar for safety
- Streaming support: Properly handle streaming responses
- Function calling: OpenAI-style function calling across providers
- Vision models: Handle image inputs for multimodal models
Practical Routing Patterns for Common Homelab Scenarios
Ready-to-use configurations for typical use cases:
Scenario 1: Cost-Conscious Development Assistant
Maximize local usage, minimize paid API calls:
# config.yaml for development assistant
model_list:
# Primary: Fast local model for coding help
- model_name: dev_primary
litellm_provider: ollama
model_name: qwen2.5-coder:14b
api_base: http://localhost:11434
tpm: 8000
rpm: 100
# Secondary: Capable local model for complex reasoning
- model_name: dev_secondary
litellm_provider: ollama
model_name: deepseek-r1:14b
api_base: http://localhost:11434
tpm: 4000
rpm: 60
# Tertiary: Small local model for simple tasks (faster, less capable)
- model_name: dev_tertialy
litellm_provider: ollama
model_name: llama3.1:8b
api_base: http://localhost:11434
tpm: 10000
rpm: 200
# Emergency fallback: Only use when local is truly inadequate
- model_name: dev_emergency
litellm_provider: openai
model: gpt-3.5-turbo
api_key: ${OPENAI_API_KEY}
tpm: 500
rpm: 20
# Use LLMSingleAgent routing strategy (try in order until success)
# This creates a waterfall: try dev_primary -> dev_secondary -> dev_tertialy -> dev_emergency
Scenario 2: Quality-Focused Content Generation
Prioritize output quality, use local for drafting:
# config.yaml for content generation workflow
model_list:
# Drafting: Use capable local models
- model_name: content_draft
litellm_provider: ollama
model_name: qwen2.5-coder:14b
api_base: http://localhost:11434
tpm: 6000
rpm: 80
- model_name: content_draft_alt
litellm_provider: ollama
model_name: deepseek-r1:7b
api_base: http://localhost:11434
tpm: 4000
rpm: 60
# Polishing: Use better models for final output
- model_name: content_polish
litellm_provider: openai
model: gpt-4o
api_key: ${OPENAI_API_KEY}
tpm: 2000
rpm: 50
# Budget-conscious alternative for polishing
- model_name: content_polish_alt
litellm_provider: openai
model: gpt-3.5-turbo
api_key: ${OPENAI_API_KEY}
tpm: 3000
rpm: 80
# Specialized: For creative writing tasks
- model_name: content_creative
litellm_provider: anthropic
model: claude-3-sonnet-20240229
api_key: ${ANTHROPIC_API_KEY}
tpm: 3000
rpm: 40
# Different routing strategies for different workflow stages
# Drafting: LLMSingleAgent (try local models first)
# Polishing: LLMSingleAgent with cost preference (try cheaper OpenAI first)
# Creative: LLMSingleAgent (try claude sonnet then fall back)
Scenario 3: Budget-Controlled Production Service
Strict cost limits with graceful degradation:
# config.yaml for budget-conscious service
model_list:
# Local models: Free to run (after hardware investment)
- model_name: local_fast
litellm_provider: ollama
model_name: qwen2.5-coder:14b
api_base: http://localhost:11434
tpm: 10000
rpm: 120
- model_name: local_capable
litellm_provider: ollama
model_name: llama3.1:70b
api_base: http://localhost:11434
tpm: 3000
rpm: 30
# Remote models: Tracked against budget
- model_name: remote_tier1
litellm_provider: openai
model: gpt-3.5-turbo
api_key: ${OPENAI_API_KEY}
tpm: 2000
rpm: 100
- model_name: remote_tier2
litellm_provider: openai
model: gpt-4o-mini
api_key: ${OPENAI_API_KEY}
tpm: 1000
rpm: 50
- model_name: remote_tier3
litellm_provider: anthropic
model: claude-3-haiku-20240307
api_key: ${ANTHROPIC_API_KEY}
tpm: 1500
rpm: 75
# Global budget settings: $50/month maximum
budget:
duration: monthly
max_budget: 50.0
# Exclude local models from budget tracking (they're "free")
excludes: ["local_fast", "local_capable"]
# Optional: send alert when 80% of budget is used
# callbacks: [budget_alert_webhook]
# Use LLMPriority routing with cost weights
# Assign lower weights (higher priority) to cheaper/freer models
model_aliases:
# Local models get highest priority (lowest weight numbers)
fast_local: local_fast
capable_local: local_capable
# Remote models get lower priority (higher weight numbers)
tier1_remote: remote_tier1
tier2_remote: remote_tier2
tier3_remote: remote_tier3
# The routing will try models in priority order:
# 1. local_fast (weight 1 - highest priority)
# 2. local_capable (weight 2)
# 3. remote_tier1 (weight 3)
# 4. remote_tier2 (weight 4)
# 5. remote_tier3 (weight 5 - lowest priority)
Integration Examples: Using LiteLLM in Your Applications
How to actually use LiteLLM from code:
Example 1: Python with OpenAI SDK
The most common integration pattern:
# Python example using official OpenAI SDK
from openai import OpenAI
# Configure the client to point to your LiteLLM instance
client = OpenAI(
base_url="http://homelab.local:4000/v1", # Point to LiteLLM
api_key="sk-12345" # Can be any non-empty string for LiteLLM
)
# Now use it exactly as you would the real OpenAI API
def get_code_explanation(code_snippet):
"""Get explanation of code using locally-hosted models when possible"""
try:
response = client.chat.completions.create(
model="ollama_qwen_coder", # This gets routed by LiteLLM
messages=[
{"role": "system", "content": "You are an expert SAP ABAP developer."},
{"role": "user", "content": f"Explain this ABAP code snippet:\n\n{code_snippet}"}
],
temperature=0.3,
max_tokens=500
)
return response.choices[0].message.content
except Exception as e:
# LiteLLM will have already tried fallbacks, so this means all options failed
return f"Error generating explanation: {str(e)}"
def generate_content_outline(topic, audience="technical"):
"""Generate content outline using potentially different models"""
try:
response = client.chat.completions.create(
model="content_draft", # Routes to drafting model
messages=[
{"role": "system", "content": "You are an expert technical writer and content strategist."},
{"role": "user", "content": f"Create a detailed outline for a {audience}-focused article about {topic}. Include sections, subsections, and key points to cover."}
],
temperature=0.7,
max_tokens=800
)
return response.choices[0].message.content
except Exception as e:
return f"Error generating outline: {str(e)}"
# Example usage
if __name__ == "__main__":
sap_code = '''
REPORT z_sales_analysis.
SELECT vbeln, erdat, netwr, kitae
FROM vbap
INTO TABLE @DATA(items)
WHERE erdat >= @sy-date-30
AND venda IN ('DE', 'FR', 'UK').
LOOP AT items ASSIGNING FIELD-SYMBOL(- ).
WRITE: /
- -vbeln,
- -erdat,
- -netwr,
- -kitae.
ENDLOOP.
'''
explanation = get_code_explanation(sap_code)
print("Code Explanation:")
print(explanation)
print("\n" + "="*50 + "\n")
outline = generate_content_outline("SAP AI Units pricing model")
print("Content Outline:")
print(outline)
Example 2: JavaScript/TypeScript for Web Applications
Perfect for integrating AI into your web apps:
// JavaScript/TypeScript example
// Using the official OpenAI npm package
import { OpenAI } from "openai";
// Configure for LiteLLM endpoint
const client = new OpenAI({
baseURL: "http://homelab.local:4000/v1",
apiKey: "sk-12345" // Any non-empty string works with LiteLLM
});
// Function to generate SAP-inspired content
async function generateSAPBlogPost(topic) {
try {
const response = await client.chat.completions.create({
model: "content_draft", // Routes to appropriate local model
messages: [
{
role: "system",
content: "You are an expert technical writer specializing in SAP and enterprise AI. Write in a practical, skeptical-yet-hopeful tone."
},
{
role: "user",
content: `Write a comprehensive blog post about ${topic} for enterprise architects. Include practical examples, implementation considerations, and realistic timelines. Target length: 1200-1500 words.`
}
],
temperature: 0.6,
max_tokens: 1500
});
return response.choices[0].message.content;
} catch (error) {
console.error("Error generating blog post:", error);
throw new Error(`Failed to generate content: ${error.message}`);
}
}
// Function to get quick coding help
async function getCodingHelp(language, problem) {
try {
const response = await client.chat.completions.create({
model: "dev_primary", // Fast local model for coding help
messages: [
{
role: "system",
content: `You are an expert ${language} programmer. Provide clear, concise solutions to programming problems.`
},
{
role: "user",
content: `How do I solve this problem in ${language}: ${problem}`
}
],
temperature: 0.2,
max_tokens: 400
});
return response.choices[0].message.content;
} catch (error) {
console.error("Error getting coding help:", error);
throw new Error(`Failed to get coding help: ${error.message}`);
}
// Example usage in a web app context
async function handleUserRequest(userInput) {
try {
// Determine what kind of help the user needs
if (userInput.startsWith("/code ")) {
const [, language, ...problemParts] = userInput.split(" ");
const problem = problemParts.join(" ");
const help = await getCodingHelp(language || "javascript", problem);
return { type: "code_help", content: help };
} else if (userInput.startsWith("/write ")) {
const topic = userInput.substring(7).trim();
const blogPost = await generateSAPBlogPost(topic);
return { type: "blog_post", content: blogPost };
} else {
// General conversation
const response = await client.chat.completions.create({
model: "content_draft",
messages: [
{ role: "system", content: "You are a helpful AI assistant." },
{ role: "user", content: userInput }
],
temperature: 0.7,
max_tokens: 800
});
return { type: "conversation", content: response.choices[0].message.content };
}
} catch (error) {
return { type: "error", content: `Sorry, I encountered an error: ${error.message}` };
}
}
Example 3: curl and Command Line Usage
Great for testing and scripting:
# Basic health check
curl -s http://homelab.local:4000/health
# Should return:
# {"status": "OK"}
# List available models
curl -s http://homelab.local:4000/v1/models | jq '.data[].id'
# Generate text completion
curl -s -X POST http://homelab.local:4000/v1/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer sk-12345" \
-d '{
"model": "ollama_qwen_coder",
"prompt": "Explain the concept of thermal dynamics in simple terms:",
"max_tokens": 200,
"temperature": 0.3
}' | jq '.choices[0].text'
# Chat completion
curl -s -X POST http://homelab.local:4000/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer sk-12345" \
-d '{
"model": "content_draft",
"messages": [
{"role": "system", "content": "You are a helpful SAP consultant."},
{"role": "user", "content": "What are the key considerations when migrating from SAP ECC to S/4HANA?"}
],
"temperature": 0.5,
"max_tokens": 500
}' | jq '.choices[0].message.content'
# Embedding generation (useful for RAG)
curl -s -X POST http://homelab.local:4000/v1/embeddings \
-H "Content-Type: application/json" \
-H "Authorization: Bearer sk-12345" \
-d '{
"model": "nomic_embed_text",
"input": "How to optimize SQL queries for SAP BW"
}' | jq '.data[0].embedding[:5]' # Show first 5 dimensions
# Streaming response (for real-time UI)
curl -s -N -X POST http://homelab.local:4000/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer sk-12345" \
-d '{
"model": "dev_primary",
"messages": [{"role": "user", "content": "Write a haiku about debugging code"}],
"temperature": 0.8,
"max_tokens": 50,
"stream": true
}'
Advanced Features: Taking LiteLLM Further
Beyond the basics: caching, monitoring, and customization:
1. Response Caching (Reduce Redundant Calls)
Cache frequent requests to save tokens and improve response time:
# Add to config.yaml for caching
# Note: Requires redis instance running
caching:
type: redis
host: localhost
port: 6379
# Optional: requirepass: your_redis_password
# Optional: username: default
# Cache behavior:
# - Identical requests (same model, messages, parameters) return cached result
# - TTL defaults to 1 hour but can be configured
# - Especially useful for:
# * Frequently asked questions
# * Code snippet explanations
# * Standardized report sections
# * Translation of common phrases
# Example cache key generation:
#Request: model=ollama_qwen, messages=[{"role":"user","content":"What is 2+2?"}]
#Cache key includes: model, messages hash, parameters hash
#Result: Cached for subsequent identical requests
2. Usage Monitoring and Cost Tracking
Understand your AI spending and usage patterns:
Built-in CSV Logging
Enable in config.yaml:
# Add to config.yaml
callbacks:
- csv_logger
csv_logging_file: /litellm/logs/usage.csv
csv_logging_mode: append
# The CSV will contain:
# timestamp,model,call_type,prompt_tokens,completion_tokens,total_tokens,response_latency,success,error
# Example row:
# 2026-07-11T10:30:00Z,ollama_qwen_coder,chat_completion,125,78,203,1.25,true,
Custom Metadata and Tags
Add context to your requests for better tracking:
# In your application code
response = client.chat.completions.create(
model="content_draft",
messages=[
{"role": "user", "content": "Explain SAP Fiori elements"}
],
# LiteLLM-specific parameters for tracking
user="[email protected]", # Who made the request
tags=["sap-consulting", "content-creation"], # Categorization
metadata={ # Custom metadata for your use case
"session_id": "sess_abc123",
"project": "ayraix-content-pipeline",
"cost_center": "marketing"
}
)
# This metadata appears in:
# - CSV logs (if enabled)
# - LangFuse traces (if integrated)
# - Custom webhooks/callbacks
# - Response headers (in some configurations)
3. Custom Transformers (Request/Response Modification)
Modify requests/responses on the fly:
# Create a custom transformer module (transformers.py)
# Place in your LiteLLM config directory
def modify_params(params, model_alias, api_key, optional_params):
"""Modify request parameters before sending to provider"""
# Add system prompt for SAP-specific queries
if model_alias in ["content_draft", "content_polish"]:
if "messages" in params:
# Check if we already have a system message
has_system = any(msg.get("role") == "system" for msg in params["messages"])
if not has_system:
# Insert SAP-focused system message at the beginning
params["messages"].insert(0, {
"role": "system",
"content": "You are an expert SAP technical consultant with 20+ years of experience. Provide practical, implementation-focused advice."
})
# Adjust temperature based on model type
if model_alias.startswith("dev_"):
# Lower temperature for more deterministic code help
params["temperature"] = min(params.get("temperature", 0.7), 0.3)
elif model_alias.startswith("content_"):
# Slightly higher temperature for creative writing
params["temperature"] = min(params.get("temperature", 0.7), 0.8)
return params
def modify_response(response, model_alias, api_key, optional_params):
"""Modify response after receiving from provider"""
# Add usage hints for coding responses
if model_alias.startswith("dev_") and "choices" in response:
choice = response["choices"][0]
if choice["message"]["content"].strip():
# Add a helpful footer to code explanations
choice["message"]["content"] += "\n\n💡 Tip: Consider adding unit tests for this implementation."
# Add word count for content generation
if model_alias.startswith("content_") and "choices" in response:
choice = response["choices"][0]
word_count = len(choice["message"]["content"].split())
choice["message"]["content"] += f"\n\n*Word count: {word_count}*"
return response
# Then in config.yaml:
# custom_llm_provider:
# custom_handler: true
# params_modifier_fn: transformers.modify_params
# response_modifier_fn: transformers.modify_response
4. Integration with LangFuse for Observability
Get deep insights into your LLM usage:
# Install the LangFuse integration
pip install litellm-langfuse
# Configure LiteLLM to use LangFuse
# In config.yaml:
callbacks:
- langfuse
# Set LangFuse credentials as environment variables
# docker run -e LANGFUSE_PUBLIC_KEY=pk-lf-... \
# -e LANGFUSE_SECRET_KEY=sk-lf-... \
# -e LANGFUSE_HOST=http://langfuse.local:3100 \
# ...
# Once configured, you'll get:
# - Automatic tracing of all LLM calls
# - Token usage and latency metrics
# - Ability to trace complex chains and agents
# - Feedback collection UI
# - Cost tracking per project/user
# - Trace visualization in LangFuse dashboard
# Example of what you can do with LangFuse data:
# 1. See which models are used most frequently
# 2. Identify slow or failing requests
# 3. Track cost by project or user
# 4. Optimize routing based on actual usage patterns
# 5. Set up alerts for anomalies or budget overruns
Troubleshooting Common LiteLLM Issues
Solutions to problems you'll encounter:
Model Not Found Errors
- Cause: Model name in request doesn't match config
- Solutions:
# 1. Check spelling and exact matching
# "ollama_qwen" != "ollama_qwen_coder"
# 2. Use curl to list available models:
curl -s http://localhost:4000/v1/models | jq '.data[].id'
# 3. Check your config.yaml for typos:
# model_name: ollama_qwen_coder # Correct
# model_name: ollama_qwen_conoder # Typo!
# 4. Remember: LiteLLM is case-sensitive
# "OLLAMA_QWEN" ≠ "ollama_qwen"
Connection Refused/Timeout Errors
- Cause: LiteLLM can't reach the backend service
- Solutions:
# 1. Verify the backend service is running:
# docker ps | grep ollama
# curl -s http://localhost:11434/api/tags # Should return 200
# 2. Check network connectivity from LiteLLM container:
# docker exec litellm curl -s http://localhost:11434/api/tags
# 3. Verify API base URL in config:
# api_base: http://localhost:11434 # Correct for same-host
# api_base: http://host.docker.internal:11434 # For Docker Mac/Windows
# api_base: http://192.168.1.100:11434 # For specific IP
# 4. Check firewall/port blocking:
# sudo ufw status # On Ubuntu
# Get-NetFirewallRule -Port 11434 # On Windows
# 5. Increase timeout in config if needed:
# default_timeout: 300 # 5 minutes instead of 2 minutes
Authentication Errors
- Cause: Invalid or missing API keys for remote providers
- Solutions:
# 1. Verify environment variables are set:
# echo $OPENAI_API_KEY
# echo $ANTHROPIC_API_KEY
# echo $GROQ_API_KEY
# 2. Check that .env file is being read (if using):
# cat .env
# OPENAI_API_KEY=your_actual_key_here
# 3. Test the API key directly with the provider:
# curl -s -H "Authorization: Bearer $OPENAI_API_KEY" \
# https://api.openai.com/v1/models | head -5
# 4. Verify LiteLLM sees the environment variables:
# docker exec litellm env | grep OPENAI
# 5. Check for accidental whitespace:
# # api_key: " sk-abc123 " # Wrong - has spaces
# # api_key: "sk-abc123" # Correct
Rate Limiting Errors
- Cause: Exceeding RPM/TPM limits set in config
- Solutions:
# 1. Check your configured limits:
# Look for tpm (tokens per minute) and rpm (requests per minute)
# in your model_list entries
# 2. Monitor actual usage:
# If using CSV logging: tail -f /litellm/logs/usage.csv
# Or check LangFuse dashboard if integrated
# 3. Adjust limits based on actual capacity:
# # If Ollama can handle more, increase limits:
# tpm: 10000 # Was 5000
# rpm: 200 # Was 100
# 4. Implement exponential backoff in your application:
# # LiteLLM does this automatically with num_retries > 0
# # But you can add application-level retry too
# 5. Consider pooling for high-demand models:
# # Instead of one overloaded instance:
# - model_name: ollama_single
# litellm_provider: ollama
# model_name: qwen2.5-coder:14b
# api_base: http://localhost:11434
# tpm: 5000
#
# # Use multiple instances:
# - model_name: ollama_pool_1
# litellm_provider: ollama
# model_name: qwen2.5-coder:14b
# api_base: http://ollama1:11434
# tpm: 2000
# - model_name: ollama_pool_2
# litellm_provider: ollama
# model_name: qwen2.5-coder:14b
# api_base: http://ollama2:11434
# tpm: 2000
# - model_name: ollama_pool_3
# litellm_provider: ollama
# model_name: qwen2.5-coder:14b
# api_base: http://ollama3:11434
# tpm: 2000
Best Practices for Homelab LiteLLM Deployment
Guidelines for a reliable, maintainable setup:
Configuration Management
- Version control: Keep your config.yaml in Git
- Environment separation: Use different configs for dev/test/prod
- Template approach: Have a base config with overrides per environment
- Secrets management: Never commit API keys - use environment variables or secrets
- Documentation: Comment your config.yaml explaining non-obvious choices
- Testing: Validate config changes in staging before production
Monitoring and Alerting
- Basic health checks: Implement /health endpoint monitoring
- Resource usage: Track container CPU, memory, disk
- Error rates: Monitor 5xx responses and failed requests
- Latency metrics: Track p50, p95, p99 response times
- Usage analytics: Monitor token consumption and model distribution
- Alert thresholds: Set up notifications for:
Security Considerations
- Network exposure: By default, LiteLLM binds to 0.0.0.0 - consider restricting to specific interfaces
- Authentication: While LiteLLM uses a dummy API key, consider adding real auth via reverse proxy
- Secrets in containers: Use Docker secrets or Kubernetes secrets rather than environment variables when possible
- Input validation: Be aware that LiteLLM passes prompts through - don't trust user input blindly
- Output filtering: Consider adding profanity filters or content safety checks for public-facing apps
- Updates: Regularly check for and apply LiteLLM updates for security fixes
Performance Optimization
- Worker processes: Increase --num-workers if handling high concurrent load
- Connection pooling: LiteLLM uses HTTP connection pooling internally
- Model pre-loading: Keep frequently used models "warmed up" in VRAM
- Caching: Enable Redis caching for repetitive workloads
- GPU utilization: Monitor that your local models are actually using the GPU
- Request batching: For high-volume scenarios, consider batching similar requests
- HDD vs SSD: Place LiteLLM and logs on fast storage (NVMe preferred)
Real-World Homelab Use Cases
How actual users are applying LiteLLM in their setups:
AI-Powered Home Assistant
Setup: LiteLLM + Home Assistant + Custom Integrations
Capabilities:
- Natural language control of smart home devices
- Context-aware responses based on time, occupancy, weather
- Energy usage explanations and optimization suggestions
- Personalized reminders and schedule management
- Home maintenance recommendations based on sensor data
- Voice-controlled information queries (news, weather, calendars)
Developer Productivity Enhancer
Setup: LiteLLM + IDE Plugin + Custom Prompts
Capabilities:
- Real-time code explanation and documentation lookup
- Generating unit tests from function signatures
- Suggesting refactoring opportunities and code improvements
- Explaining error messages and stack traces
- Creating boilerplate code for common patterns
- Learning new programming languages through interactive examples
- Code review assistance: identifying potential bugs or issues
Content Creation Pipeline
Setup: LiteLLM + n8n + ComfyUI + Publishing Platforms
Capabilities:
- Research assistance: summarizing articles and extracting key points
- Generating outlines and drafts for blog posts, newsletters, documentation
- Creating social media variations from core content
- Generating custom illustrations and diagrams to accompany text
- Optimizing content for SEO, readability, and engagement
- Automated publishing to blogs, LinkedIn, Twitter, etc.
- Translation and localization of content for different audiences
Educational and Learning Aid
Setup: LiteLLM + Custom Frontend + Progress Tracking
Capabilities:
- Personalized explanations of complex topics at user's level
- Generating practice problems and solutions for math, science, programming
- Creating study guides and flashcards from source material
- Simulating conversations in foreign languages for practice
- Providing feedback on essays and written assignments
- Explaining code implementations in multiple programming languages
- Career guidance: suggesting skill development paths based on interests
Conclusion: One Gateway to Rule Them All
LiteLLM solves a fundamental problem in the modern AI landscape:
The Value Proposition:
- Simplicity: One endpoint, one API key pattern, consistent behavior
- Resilience: Automatic fallback prevents single points of failure
- Flexibility: Easy to add/remove providers without changing application code
- Cost Control: Visibility into usage and spending with optional budget enforcement
- Observability: Built-in tracking plus integrations with LangFuse, etc.
- Performance: Load balancing, caching, and smart routing optimize resource use
- Future-proof: Adding new models or providers is a configuration change, not code rewrite
Your Homelab AI Evolution Path:
- Start simple: Direct Ollama/OpenAI calls in your applications
- Feel the pain: As you add more models/providers, integration complexity grows
- Discover LiteLLM: One proxy to manage your growing AI ecosystem
- Configure carefully: Map your models to providers with appropriate fallbacks
- Integrate everywhere: Update all your applications to point to LiteLLM
- Add sophistication: Caching, monitoring, custom transformers as needed
- Expand confidently: Know you can safely add new models without breaking existing workflows
Final Thought:
The goal of LiteLLM isn't to reduce costs (though it often does) — it's to reduce complexity and increase reliability. By abstracting away the messy reality of multiple AI providers with different APIs, quotas, and failure modes, you free up mental energy to focus on what really matters: building useful applications and solving real problems. Your homelab becomes not just a collection of AI tools, but a coherent, resilient platform for innovation.