Introducción
En nuestra infraestructura de IA con K3s, LiteLLM sirve como la puerta de enlace central de modelos: un proxy que unifica múltiples proveedores de modelos tras una única API compatible con OpenAI. Combinado con el Model Context Protocol (MCP), se convierte en la columna vertebral de la comunicación entre agentes y modelos. Este post documenta nuestra configuración de producción y las lecciones aprendidas a lo largo del camino.
Resumen de la arquitectura
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Hermes │────▶│ LiteLLM │────▶│ NVIDIA │
│ Agents │ │ Gateway │ │ Nemotron │
└──────────────┘ │ │ └──────────────┘
┌──────────────┐ │ (puerto 4000)│ ┌──────────────┐
│ Cron Jobs │────▶│ │────▶│ Mistral │
└──────────────┘ └──────────────┘ └──────────────┘
┌──────────────┐ ▲ ┌──────────────┐
│ Webhooks │───────────┘ │ OpenAI │
└──────────────┘ Endpoint MCP └──────────────┘
/mcp
Despliegue de LiteLLM en K3s
Configuración
Nuestro despliegue de LiteLLM usa una configuración de lista de modelos que enruta las peticiones a diferentes proveedores según la tarea:
# litellm-config.yaml
model_list:
# Modelo principal para tareas de código
- model_name: hermes-coder
litellm_params:
model: nvidia/nemotron-3-ultra-550b-a55b
api_base: https://integrate.api.nvidia.com/v1
api_key: ${NVIDIA_API_KEY}
timeout: 7200
# Modelos Mistral para investigación y análisis
- model_name: mistral-reasoning
litellm_params:
model: mistral/devstral-latest
api_base: https://api.mistral.ai/v1
api_key: ${MISTRAL_API_KEY}
timeout: 3600
# Modelo ligero para tareas rápidas
- model_name: hermes-lean
litellm_params:
model: nvidia/nemotron-3-nano-omni-30b-a3b-reasoning
api_base: https://integrate.api.nvidia.com/v1
api_key: ${NVIDIA_API_KEY}
timeout: 7200
Manifiesto de Kubernetes
apiVersion: apps/v1
kind: Deployment
metadata:
name: litellm-gateway
namespace: ia-services-payed
spec:
replicas: 2
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
selector:
matchLabels:
app: litellm
template:
metadata:
labels:
app: litellm
version: main-stable
spec:
containers:
- name: litellm
image: ghcr.io/anthropics/litellm:main-stable
ports:
- containerPort: 4000
env:
- name: MODEL_LIST
valueFrom:
secretKeyRef:
name: litellm-config
key: model-list.yaml
- name: PROXY_SERVER_KEY
valueFrom:
secretKeyRef:
name: litellm-secrets
key: api-key
- name: HTTP_TIMEOUT
value: "7200"
- name: REQUEST_TIMEOUT
value: "3600"
- name: LOG_PII
value: "false"
resources:
requests:
memory: "2Gi"
cpu: "500m"
limits:
memory: "4Gi"
cpu: "1"
livenessProbe:
httpGet:
path: /health
port: 4000
initialDelaySeconds: 30
periodSeconds: 15
readinessProbe:
httpGet:
path: /health
port: 4000
initialDelaySeconds: 10
periodSeconds: 10
restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
name: litellm
namespace: ia-services-payed
spec:
selector:
app: litellm
ports:
- port: 4000
targetPort: 4000
type: ClusterIP
Integración de MCP
Configuración del endpoint MCP
LiteLLM expone el endpoint MCP en http://litellm.ia-services-payed.svc.cluster.local:4000/mcp. Los agentes y los trabajos programados (cron jobs) se conectan a este endpoint para acceder a herramientas y modelos:
# Ejemplo de conexión de cliente MCP
from mcp import ClientConnection
# Conexión a través del DNS del servicio en K3s
connection = await ClientConnection.connect(
"litellm.ia-services-payed.svc.cluster.local",
port=4000,
path="/mcp",
)
# Listar las herramientas disponibles
tools = await connection.list_tools()
for tool in tools:
print(f"{tool.name}: {tool.description[:80]}...")
Registro del servidor MCP
Cada servidor MCP se registra con la puerta de enlace de LiteLLM:
# Registrar un nuevo servidor MCP
curl -X POST http://litellm.ia-services-payed.svc.cluster.local:4000/mcp/register \
-H "Authorization: Bearer ${LITE...KEY}" \
-H "Content-Type: application/json" \
-d '{
"name": "kubernetes-mcp",
"url": "http://mcp-k8s.forgejo-runners.svc.cluster.local:8080/mcp",
"timeout": 300
}'
Estrategia de enrutamiento multi-modelo
Reglas de enrutamiento
Usamos un enfoque de enrutamiento por niveles:
| Tipo de tarea | Modelo principal | Alternativa | Justificación |
|---|---|---|---|
| Generación de código | hermes-coder (Nemotron) | devstral | Nemotron destaca en código |
| Investigación/análisis | devstral | nemotron-35b | El razonamiento de Mistral |
| Tareas rápidas | nemotron-3-nano | devstral | Rápido y económico |
| Razonamiento complejo | devstral | hermes-coder | El mejor razonamiento global |
| Redacción creativa | hermes-coder | devstral | Calidad de estilo |
Enrutamiento basado en el estado de salud
LiteLLM enruta automáticamente hacia los modelos sanos:
# Si el modelo principal no está sano, LiteLLM usa la alternativa
# Comprobar el estado del modelo
import httpx
async def check_model_health(model_name: str) -> bool:
try:
async with httpx.AsyncClient(timeout=5.0) as client:
response = await client.post(
f"{API_BASE}/v1/models",
headers={"Authorization": f"Bearer {API_KEY}"},
)
return response.status_code == 200
except httpx.TimeoutException:
return False
except httpx.RequestError:
return False
Lecciones operativas
Lección 1: la configuración de los timeouts importa
La API de NVIDIA puede ser lenta con los modelos grandes. Configuramos:
HTTP_TIMEOUT=7200s # 2 horas — para la carga del modelo
REQUEST_TIMEOUT=3600s # 1 hora — para peticiones individuales
Sin estos valores, las peticiones superan el tiempo de espera durante el arranque en frío del modelo.
Lección 2: limitación de tasa en la capa de proxy
Configura los límites de tasa de LiteLLM para impedir que un solo consumidor desborde el backend:
model_aliases:
"nvidia/nemotron-3-ultra-550b-a55b": "nemotron-35b"
litellm_settings:
model_fallbacks:
"nemotron-35b": ["nemotron-35b", "devstral-large"]
num_retries: 3
retry_after: 5
Lección 3: registro y observabilidad
Habilita el registro estructurado para la depuración:
litellm_settings:
success_callback: ["langsmith", "opentelemetry"]
failure_callback: ["langsmith", "opentelemetry"]
cache: true
cache_params:
type: "redis"
host: "redis-monitoring.svc.cluster.local"
port: 6379
Consideraciones de seguridad
Gestión de claves de API
Nunca codifiques claves de API en texto plano. Usa secretos de Kubernetes:
# Crear el secreto a partir de variables de entorno existentes
kubectl create secret generic litellm-secrets \
--from-literal=api-key="${PROXY_SERVER_KEY}" \
--namespace=ia-services-payed
kubectl create secret generic litellm-config \
--from-file=model-list.yaml \
--namespace=ia-services-payed
Políticas de red
Restringe quién puede acceder a la puerta de enlace de LiteLLM:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: litellm-ingress
namespace: ia-services-payed
spec:
podSelector:
matchLabels:
app: litellm
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: forgejo-runners
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: cicd
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: flux-system
ports:
- port: 4000
policyTypes:
- Ingress
Monitorización de LiteLLM
Métricas clave a seguir:
- Latencia de la petición — P50, P95, P99 por modelo
- Uso de tokens — entrada/salida por modelo y consumidor
- Tasa de error — por código de estado y tipo de error
- Estado del modelo — tiempo activo y tiempo de respuesta por backend
- Tasa de aciertos de caché — eficacia de la caché de respuestas
Consultas del panel de Grafana (Prometheus):
# Tasa de peticiones por modelo
rate(litellm_proxy_request_count[5m])
# Latencia media por modelo
litellm_proxy_latency_seconds / 1000
# Tasa de error
sum(rate(litellm_proxy_request_error_count[5m])) / sum(rate(litellm_proxy_request_count[5m]))
Conclusión
LiteLLM + MCP proporciona una puerta de enlace de modelos robusta y escalable para infraestructuras de IA basadas en K3s. Las principales conclusiones:
- Configura tiempos de espera generosos para la carga del modelo
- Usa secretos de Kubernetes para la gestión de claves de API
- Implementa alternativas de modelo basadas en el estado de salud
- Monitoriza el uso de tokens y la latencia por modelo
- Restringe el acceso con NetworkPolicies
Con estas prácticas en su lugar, tu puerta de enlace de modelos gestionará la complejidad del enrutamiento multi-modelo mientras tus agentes se centran en sus tareas reales.