# LiteLLM — Proxy LLM unifié (storage-01)

LiteLLM tourne en service systemd sur **storage-01** (`127.0.0.1:4000`).
Il route les requêtes OpenAI-compatibles vers le bon backend selon le modèle demandé.

---

## Flux

```
Hermes / ask-agent / Open WebUI / n8n
        │
        ▼  http://127.0.0.1:4000/v1  (Authorization: Bearer lm-studio)
   LiteLLM Proxy
        ├── hermes-default       →  qwen3-8b            →  llama-server gpu-01 :1234  (GPU)
        ├── qwen3-8b             →  llama-server gpu-01 :1234  (GPU, gratuit)
        ├── qwen3-1.7b-system    →  llama-server gpu-01 :1236  (CPU 14 threads, gratuit)
        ├── qwen3-1.7b-monitor   →  llama-server gpu-01 :1237  (CPU 14 threads, gratuit)
        ├── claude-sonnet-4-6    →  api.anthropic.com           (cloud, payant)
        └── claude-opus-4-7      →  api.anthropic.com           (cloud, payant)
```

---

## Service systemd

```bash
# Depuis storage-01
sudo systemctl status litellm
sudo systemctl restart litellm
sudo journalctl -u litellm -f
sudo journalctl -u litellm -n 50
```

---

## Modèles disponibles

| Nom dans l'API | Backend | Coût |
|---|---|---|
| `hermes-default` | qwen3-8b sur gpu-01 :1234 (GPU) | Gratuit |
| `qwen3-8b` | llama-server gpu-01 :1234 (ROCm 7.x) | Gratuit |
| `qwen3-1.7b-system` | llama-server gpu-01 :1236 (CPU, 14 threads) | Gratuit |
| `qwen3-1.7b-monitor` | llama-server gpu-01 :1237 (CPU, 14 threads) | Gratuit |
| `claude-sonnet-4-6` | Anthropic API | ~$3/$15 par million tokens in/out |
| `claude-opus-4-7` | Anthropic API | Plus cher, meilleur raisonnement |

> `qwen3-1.7b-system` et `qwen3-1.7b-monitor` sont utilisés par `ask-agent system` et
> `ask-agent monitor` — voir [hermes.md](hermes.md).

---

## Switch rapide avec hermes-switch

Script déployé sur storage-01 :

```bash
sudo hermes-switch status    # voir le modèle actuel de hermes-default
sudo hermes-switch qwen      # Qwen3-8B local GPU (gratuit, ~60 tok/s)
sudo hermes-switch claude    # Claude Sonnet 4.6 (payant, ~1-2$ par session debug)
```

Le script modifie `/etc/litellm/config.yaml` et redémarre litellm automatiquement.
Source : `roles/litellm/files/hermes-switch`.

### Coût Claude

| Session type | Tokens input | Coût estimé |
|---|---|---|
| Debug simple (5 échanges) | ~80k | ~$0.24 |
| Debug complexe (10 échanges) | ~375k | ~$1.12 |
| Utilisation courante | — | Utiliser Qwen |

---

## Validation API

```bash
# Depuis storage-01 — master_key = lm-studio
curl http://127.0.0.1:4000/v1/models \
  -H "Authorization: Bearer lm-studio" | python3 -m json.tool

# Test inférence Qwen (local)
curl http://127.0.0.1:4000/v1/chat/completions \
  -H "Authorization: Bearer lm-studio" \
  -H "Content-Type: application/json" \
  -d '{"model": "qwen3-8b", "messages": [{"role": "user", "content": "Dis bonjour"}], "max_tokens": 30}'

# Test inférence Claude
curl http://127.0.0.1:4000/v1/chat/completions \
  -H "Authorization: Bearer lm-studio" \
  -H "Content-Type: application/json" \
  -d '{"model": "claude-sonnet-4-6", "messages": [{"role": "user", "content": "Dis bonjour"}], "max_tokens": 30}'
```

---

## Configuration

Fichier : `/etc/litellm/config.yaml` (géré par Ansible, propriété `litellm:litellm`, mode `0640`)

La clé API Anthropic est injectée via `ANTHROPIC_API_KEY` dans l'unit systemd —
elle vient du vault Ansible (`vault_anthropic_api_key`). Jamais en clair dans config.yaml.

**master_key** : `lm-studio` — doit correspondre à `LM_API_KEY` dans le `.env` Hermes.

---

## ⚠️ Gap IaC — modèles CPU absents du template Ansible

`ansible/roles/litellm/templates/config.yaml.j2` n'inclut que 4 modèles :
`hermes-default`, `qwen3-8b`, `claude-sonnet-4-6`, `claude-opus-4-7`.

Les entrées `qwen3-1.7b-system` (:1236) et `qwen3-1.7b-monitor` (:1237) ont été ajoutées
**manuellement** dans `/etc/litellm/config.yaml` sur storage-01.

Un `make apply-storage` sur un hôte vierge ne déploierait PAS les routes CPU nécessaires
à `ask-agent system` et `ask-agent monitor`.

**Axe d'amélioration** : ajouter les 2 entrées CPU dans `config.yaml.j2` avec des variables
dans `defaults/main.yml` (`litellm_cpu_system_url`, `litellm_cpu_monitor_url`).

---

## Ajouter un modèle

1. Modifier `roles/litellm/templates/config.yaml.j2` :
   ```yaml
   - model_name: claude-haiku-4-5
     litellm_params:
       model: anthropic/claude-haiku-4-5-20251001
       api_key: os.environ/ANTHROPIC_API_KEY
   ```

2. Redéployer :
   ```bash
   ansible-playbook -i inventory.yml playbooks/storage-01.yml --tags litellm
   ```

---

## Points d'attention

| Sujet | Détail |
|---|---|
| Accès réseau | `127.0.0.1` uniquement — pour exposer au cluster, changer `litellm_host: 0.0.0.0` + ouvrir firewall |
| master_key | `lm-studio` — doit correspondre exactement à `LM_API_KEY` dans le `.env` Hermes |
| Clé Anthropic | `ANTHROPIC_API_KEY` dans l'env systemd — vault Ansible |
| Coût Claude | Surveiller la consommation sur console.anthropic.com |
| 404 /api/v1/models | Hermes appelle `/api/v1/models` à l'init (retourne 404) — normal, ne bloque pas |
| hermes-switch status | Utilise `grep -A3` — si le bloc hermes-default a une structure différente, ajuster |


---

## État vérifié — 2026-06-05  
- **Service litellm** : Actif (running) depuis 3 jours, 404 Not Found sur /api/tags, /v1/props, /props, /version (probablement des requêtes mal formées ou routes absentes)  
- **Config.yaml** : Modèle hermes-default pointe vers Qwen3-8B (http://192.168.10.20:1234/v1) avec api_key=lm-studio ; modèles Claude (sonnet-4-6, opus-4-7) configurés via api_key=os.environ/ANTHROPIC_API_KEY  
- **Divergence** : Aucune incohérence détectée entre la config documentée et l'état réel du service  
- **Éléments opérationnels** : Logs montrent des requêtes vers des endpoints inexistantes (404), suggérant une possible configuration incomplète des routes LiteLLM