Aller au contenu
Développement medium

LiteLLM Router : DevOps Buddy en production

16 min de lecture

logo litellm

Fin du projet DevOps Buddy : notre assistant fonctionne en dev. Maintenant, on va le préparer pour la production : fallbacks multi-providers, caching pour réduire les coûts de 50%, et monitoring pour savoir quand ça va mal.

  • Configurer un Router avec plusieurs providers en fallback (OpenAI → Claude → Ollama)
  • Définir les priorités avec l’option order pour choisir quel provider utiliser en premier
  • Activer le cache en mémoire ou Redis pour économiser jusqu’à 50% des coûts
  • Monitorer les appels avec des callbacks custom (latence, erreurs, fallbacks)
  • Séparer la configuration du code avec un fichier YAML

En production, les problèmes arrivent :

ProblèmeImpactSolution Router
OpenAI downService indisponibleBascule sur Claude
Rate limitingRequêtes rejetéesRépartition de charge
Latence élevéeUX dégradéeTimeout + fallback
Coûts élevésBudget exploséCache des réponses

Configurons DevOps Buddy avec 3 providers en fallback :

16_router_basic.py
from litellm import Router
from dotenv import load_dotenv
import os
load_dotenv()
# Configuration des providers
model_list = [
{
"model_name": "devops-buddy", # Alias unique pour l'app
"litellm_params": {
"model": "openai/gpt-4.1-mini",
"api_key": os.getenv("OPENAI_API_KEY"),
"order": 1 # Provider principal
}
},
{
"model_name": "devops-buddy",
"litellm_params": {
"model": "anthropic/claude-3-5-haiku-latest",
"api_key": os.getenv("ANTHROPIC_API_KEY"),
"order": 2 # Premier fallback
}
},
{
"model_name": "devops-buddy",
"litellm_params": {
"model": "gemini/gemini-2.0-flash",
"api_key": os.getenv("GOOGLE_API_KEY"),
"order": 3 # Dernier recours
}
}
]
# Router avec retries et cooldowns
router = Router(
model_list=model_list,
num_retries=2, # Réessaie 2x avant fallback
retry_after=1, # 1s entre retries
timeout=30, # Max 30s par requête
allowed_fails=3, # Échecs avant cooldown
cooldown_time=60, # Désactive 60s si trop d'échecs
enable_pre_call_checks=True
)
# Test
response = router.completion(
model="devops-buddy",
messages=[
{"role": "system", "content": "Tu es DevOps Buddy, assistant DevOps expert."},
{"role": "user", "content": "Comment vérifier les logs d'un pod K8s ?"}
]
)
print(f"✅ Provider utilisé: {response.model}")
print(f"📝 Réponse: {response.choices[0].message.content[:200]}...")

Les mêmes questions reviennent souvent. Activez le cache :

17_router_cached.py
from litellm import Router
from dotenv import load_dotenv
import os
import time
load_dotenv()
model_list = [
{
"model_name": "devops-buddy",
"litellm_params": {
"model": "openai/gpt-4.1-mini",
"api_key": os.getenv("OPENAI_API_KEY")
}
}
]
# Cache en mémoire (dev/test)
router = Router(
model_list=model_list,
cache_responses=True
)
# Question fréquente
question = "Comment redémarrer un pod Kubernetes ?"
messages = [{"role": "user", "content": question}]
# Premier appel — va vers l'API
start = time.time()
response1 = router.completion(model="devops-buddy", messages=messages)
time1 = time.time() - start
print(f"1er appel: {time1:.2f}s (API)")
# Deuxième appel — du cache
start = time.time()
response2 = router.completion(model="devops-buddy", messages=messages)
time2 = time.time() - start
print(f"2e appel: {time2:.4f}s (cache) — {time1/max(time2, 0.001):.0f}x plus rapide")

En multi-instances, utilisez Redis :

18_router_redis.py
from litellm import Router
from dotenv import load_dotenv
import os
load_dotenv()
model_list = [
{
"model_name": "devops-buddy",
"litellm_params": {
"model": "openai/gpt-4.1-mini",
"api_key": os.getenv("OPENAI_API_KEY")
}
}
]
router = Router(
model_list=model_list,
redis_host=os.getenv("REDIS_HOST", "localhost"),
redis_port=int(os.getenv("REDIS_PORT", 6379)),
redis_password=os.getenv("REDIS_PASSWORD", None),
cache_responses=True
)

Ajoutez des callbacks pour surveiller les performances :

19_router_monitoring.py
from litellm import Router
from litellm.integrations.custom_logger import CustomLogger
from dotenv import load_dotenv
import os
from datetime import datetime
load_dotenv()
class DevOpsLogger(CustomLogger):
"""Logger custom pour DevOps Buddy."""
def __init__(self):
self.stats = {
"success": 0,
"failures": 0,
"total_latency": 0,
"fallbacks": 0
}
def log_success(self, kwargs, response, start_time, end_time):
model = kwargs.get("model", "unknown")
latency = end_time - start_time
tokens = response.usage.total_tokens if response.usage else 0
self.stats["success"] += 1
self.stats["total_latency"] += latency
print(f"✅ [{datetime.now().strftime('%H:%M:%S')}] "
f"{model} | {latency:.2f}s | {tokens} tokens")
def log_failure(self, kwargs, exception, start_time, end_time):
model = kwargs.get("model", "unknown")
self.stats["failures"] += 1
print(f"❌ [{datetime.now().strftime('%H:%M:%S')}] "
f"{model} | {type(exception).__name__}: {exception}")
def get_metrics(self) -> dict:
"""Retourne les métriques agrégées."""
total = self.stats["success"] + self.stats["failures"]
return {
"total_requests": total,
"success_rate": self.stats["success"] / max(total, 1) * 100,
"avg_latency": self.stats["total_latency"] / max(self.stats["success"], 1),
"fallback_rate": self.stats["fallbacks"] / max(total, 1) * 100
}
# Utilisation
logger = DevOpsLogger()
model_list = [
{
"model_name": "devops-buddy",
"litellm_params": {
"model": "openai/gpt-4.1-mini",
"api_key": os.getenv("OPENAI_API_KEY")
}
}
]
router = Router(
model_list=model_list,
callbacks=[logger]
)
# Test
for i in range(5):
router.completion(
model="devops-buddy",
messages=[{"role": "user", "content": f"Question {i + 1}"}]
)
print("\n📊 Métriques:")
for k, v in logger.get_metrics().items():
print(f" {k}: {v:.2f}")

Étape 4 : DevOps Buddy complet pour la production

Section intitulée « Étape 4 : DevOps Buddy complet pour la production »

Intégrons tout — RAG + Router + Monitoring :

20_buddy_production.py
from litellm import Router, embedding
from litellm.integrations.custom_logger import CustomLogger
from pathlib import Path
import json
import numpy as np
from dotenv import load_dotenv
import os
load_dotenv()
def cosine_similarity(v1, v2):
a, b = np.array(v1), np.array(v2)
return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))
class ProductionLogger(CustomLogger):
def log_success(self, kwargs, response, start_time, end_time):
latency = end_time - start_time
print(f"📡 {response.model} | {latency:.2f}s")
def log_failure(self, kwargs, exception, start_time, end_time):
print(f"⚠️ Fallback déclenché: {exception}")
class DevOpsBuddyProduction:
"""DevOps Buddy prêt pour la production."""
SYSTEM_PROMPT = """Tu es DevOps Buddy, l'assistant DevOps de l'équipe.
Utilise le contexte fourni pour répondre. Si le contexte ne suffit pas,
utilise tes connaissances générales mais précise-le.
Sois concis, donne des commandes concrètes."""
def __init__(self, knowledge_file: str = "devops_knowledge.json"):
# Router multi-providers
model_list = [
{
"model_name": "chat",
"litellm_params": {
"model": "openai/gpt-4.1-mini",
"api_key": os.getenv("OPENAI_API_KEY"),
"order": 1
}
},
{
"model_name": "chat",
"litellm_params": {
"model": "anthropic/claude-3-5-haiku-latest",
"api_key": os.getenv("ANTHROPIC_API_KEY"),
"order": 2
}
}
]
self.router = Router(
model_list=model_list,
num_retries=2,
timeout=30,
cache_responses=True,
callbacks=[ProductionLogger()]
)
# Base de connaissances
if Path(knowledge_file).exists():
data = json.loads(Path(knowledge_file).read_text())
self.docs = data["documents"]
self.vecs = data["vectors"]
else:
self.docs = []
self.vecs = []
def search_context(self, query: str, k: int = 2) -> str:
"""Recherche du contexte pertinent."""
if not self.docs:
return ""
resp = embedding(model="openai/text-embedding-3-small", input=[query])
qv = resp.data[0]["embedding"]
scored = [(d, cosine_similarity(qv, v)) for d, v in zip(self.docs, self.vecs)]
top = sorted(scored, key=lambda x: x[1], reverse=True)[:k]
return "\n\n".join([
f"**{d['title']}**\n{d['content']}"
for d, score in top if score > 0.5
])
def ask(self, question: str) -> str:
"""Pose une question avec RAG et fallbacks."""
context = self.search_context(question)
messages = [
{"role": "system", "content": self.SYSTEM_PROMPT},
{"role": "user", "content": f"""CONTEXTE:
{context or "(Pas de documentation interne pertinente)"}
QUESTION: {question}"""}
]
response = self.router.completion(
model="chat",
messages=messages
)
return response.choices[0].message.content
def main():
buddy = DevOpsBuddyProduction()
print("🚀 DevOps Buddy (Production Mode)")
print(" Fallbacks: OpenAI → Claude")
print(" Cache: activé")
print(" Tapez 'quit' pour quitter\n")
while True:
question = input("👤 > ").strip()
if question.lower() in ("quit", "exit", "q"):
break
if not question:
continue
answer = buddy.ask(question)
print(f"🤖 {answer}\n")
if __name__ == "__main__":
main()

Séparez la config du code :

litellm_config.yaml
model_list:
- model_name: devops-buddy
litellm_params:
model: openai/gpt-4.1-mini
api_key: os.environ/OPENAI_API_KEY
order: 1
- model_name: devops-buddy
litellm_params:
model: anthropic/claude-3-5-haiku-latest
api_key: os.environ/ANTHROPIC_API_KEY
order: 2
- model_name: embeddings
litellm_params:
model: openai/text-embedding-3-small
api_key: os.environ/OPENAI_API_KEY
router_settings:
num_retries: 2
timeout: 30
allowed_fails: 3
cooldown_time: 60
cache_responses: true

Chargement :

import yaml
from litellm import Router
with open("litellm_config.yaml") as f:
config = yaml.safe_load(f)
router = Router(
model_list=config["model_list"],
**config.get("router_settings", {})
)
lab-devops-buddy/
├── .env # Clés API
├── litellm_config.yaml # Config production
├── devops_knowledge.json # Base de connaissances
├── 01_question_simple.py # Guide 1: Bases
├── ...
├── 05_erreurs.py
├── 06_async_basic.py # Guide 2: Async
├── ...
├── 10_error_handling.py
├── 11_embedding_basic.py # Guide 3: RAG
├── ...
├── 15_buddy_interactive.py
├── 16_router_basic.py # Guide 4: Production
├── 17_router_cached.py
├── 18_router_redis.py
├── 19_router_monitoring.py
└── 20_buddy_production.py # Version finale
ÉlémentStatutAction
Multi-providers2-3 providers en fallback
Retriesnum_retries=2
Timeouttimeout=30
Cooldownscooldown_time=60
CacheRedis en multi-instances
MonitoringCallbacks + alertes
SecretsVariables d’environnement
LogsCentralisés (ELK, Loki…)
  • Router : abstrait les providers avec un alias unique
  • order : définit la priorité des fallbacks
  • cache_responses : économise jusqu’à 50% des coûts
  • Redis : obligatoire pour cache multi-instances
  • Callbacks : surveillez latence, erreurs, fallbacks
  • Config YAML : séparez config et code

En 4 guides, vous avez construit un assistant IA DevOps complet :

  1. Bases : chatbot interactif avec streaming et conversation
  2. Async : audit de fichiers DevOps en parallèle
  3. RAG : base de connaissances avec recherche sémantique
  4. Production : fallbacks, caching, monitoring

Félicitations ! Vous avez construit un assistant IA DevOps complet, prêt pour la production.

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracing. Aujourd'hui, ce site ne couvre même pas mes frais d'hébergement, d'électricité, de matériel, de logiciels, mais surtout de cafés.

Un soutien régulier, même symbolique, m'aide à garder ces ressources gratuites et à continuer de produire des guides de qualité. Merci pour votre appui.