# vLLM

Serveur d'inférence LLM à haut débit pour charges de production sur les GPU CLORE.AI.

{% hint style="success" %}
Tous les exemples peuvent être exécutés sur des serveurs GPU loués via [CLORE.AI Marketplace](https://clore.ai/marketplace).
{% endhint %}

{% hint style="info" %}
**Version actuelle : v0.7.x** — Ce guide couvre vLLM v0.7.3+. Les nouvelles fonctionnalités incluent la prise en charge de DeepSeek-R1, des sorties structurées avec choix automatique d'outil, le service multi-LoRA et une meilleure efficacité mémoire.
{% endhint %}

## Exigences du serveur

| Paramètre          | Minimum      | Recommandé |
| ------------------ | ------------ | ---------- |
| RAM                | **16Go**     | 32 Go+     |
| VRAM               | 16 Go (7B)   | 24 Go+     |
| Réseau             | 500 Mbps     | 1 Gbps+    |
| Temps de démarrage | 5-15 minutes | -          |

{% hint style="danger" %}
**Important :** vLLM nécessite beaucoup de RAM et de VRAM. Les serveurs avec moins de 16 Go de RAM ne pourront pas exécuter même des modèles 7B.
{% endhint %}

{% hint style="warning" %}
**Temps de démarrage :** Le premier lancement télécharge le modèle depuis HuggingFace (5-15 minutes selon la taille du modèle et la vitesse du réseau). Un HTTP 502 pendant cette période est normal.
{% endhint %}

## Pourquoi vLLM ?

* **Débit le plus rapide** - PagedAttention pour un débit 24x supérieur
* **Prêt pour la production** - API compatible OpenAI prête à l'emploi
* **Regroupement continu** - Service multi-utilisateurs efficace
* **Streaming** - Génération de tokens en temps réel
* **Multi-GPU** - Parallélisme tensoriel pour les grands modèles
* **Multi-LoRA** - Servir plusieurs adaptateurs fine-tunés simultanément (v0.7+)
* **Sorties structurées** - Application de schéma JSON et appel d'outils (v0.7+)

## Déploiement rapide sur CLORE.AI

**Image Docker :**

```
vllm/vllm-openai:v0.7.3
```

**Ports :**

```
22/tcp
8000/http
```

**Commande :**

```bash
vllm serve mistralai/Mistral-7B-Instruct-v0.2 --host 0.0.0.0 --port 8000
```

### Vérifiez que cela fonctionne

Après le déploiement, trouvez votre `http_pub` URL dans **Mes commandes**:

```bash
# Vérifier la santé (peut prendre 5-15 min au premier lancement)
curl https://your-http-pub.clorecloud.net/health

# Lister les modèles (ne fonctionne qu'après le chargement du modèle)
curl https://your-http-pub.clorecloud.net/v1/models
```

{% hint style="warning" %}
Si vous obtenez HTTP 502 pendant plus de 15 minutes, vérifiez :

1. Le serveur dispose de 16 Go+ de RAM
2. Le serveur dispose de suffisamment de VRAM pour le modèle
3. Le token HuggingFace est défini pour les modèles restreints
   {% endhint %}

## Accéder à votre service

Lorsqu'il est déployé sur CLORE.AI, accédez à vLLM via le `http_pub` URL :

```bash
# Complétion de chat
curl https://your-http-pub.clorecloud.net/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "mistralai/Mistral-7B-Instruct-v0.2",
    "messages": [{"role": "user", "content": "Bonjour !"}]
  }'
```

{% hint style="info" %}
Tous `localhost:8000` les exemples ci-dessous fonctionnent lorsqu'ils sont connectés via SSH. Pour un accès externe, remplacez par votre `https://your-http-pub.clorecloud.net/` URL.
{% endhint %}

## Installation

### Utilisation de Docker (recommandé)

```bash
docker run -d --gpus all \
    -p 8000:8000 \
    --ipc=host \
    vllm/vllm-openai:v0.7.3 \
    --model mistralai/Mistral-7B-Instruct-v0.2 \
    --host 0.0.0.0
```

### Utilisation de pip

```bash
pip install vllm==0.7.3

# Démarrer le serveur
python -m vllm.entrypoints.openai.api_server \
    --model mistralai/Mistral-7B-Instruct-v0.2
```

## Modèles pris en charge

| Modèle                        | Paramètres | VRAM requise        | RAM requise |
| ----------------------------- | ---------- | ------------------- | ----------- |
| Mistral 7B                    | 7B         | 14GB                | 16 Go+      |
| Llama 3.1 8B                  | 8B         | 16Go                | 16 Go+      |
| Llama 3.1 70B                 | 70B        | 140 Go (ou 2x80 Go) | 64 Go+      |
| Mixtral 8x7B                  | 47B        | 90 Go               | 32 Go+      |
| Qwen2.5 7B                    | 7B         | 14GB                | 16 Go+      |
| Qwen2.5 72B                   | 72B        | 145 Go              | 64 Go+      |
| DeepSeek-V3                   | 236B MoE   | Multi-GPU           | 128 Go+     |
| DeepSeek-R1-Distill-Qwen-7B   | 7B         | 14GB                | 16 Go+      |
| DeepSeek-R1-Distill-Qwen-32B  | 32B        | 64Go                | 32 Go+      |
| DeepSeek-R1-Distill-Llama-70B | 70B        | 140 Go              | 64 Go+      |
| Phi-4                         | 14B        | 28 Go               | 32 Go+      |
| Gemma 2 9B                    | 9B         | 18Go                | 16 Go+      |
| CodeLlama 34B                 | 34B        | 68 Go               | 32 Go+      |

## Options du serveur

### Serveur basique

```bash
vllm serve mistralai/Mistral-7B-Instruct-v0.2 \
    --host 0.0.0.0 \
    --port 8000
```

### Serveur de production

```bash
vllm serve mistralai/Mistral-7B-Instruct-v0.2 \
    --host 0.0.0.0 \
    --port 8000 \
    --tensor-parallel-size 1 \
    --max-model-len 8192 \
    --gpu-memory-utilization 0.9 \
    --max-num-seqs 256 \
    --enable-prefix-caching
```

### Avec quantification (moins de VRAM)

```bash
# Modèle quantifié AWQ (utilise moins de VRAM)
vllm serve TheBloke/Mistral-7B-Instruct-v0.2-AWQ \
    --host 0.0.0.0 \
    --quantization awq
```

### Sorties structurées et appels d'outils (v0.7+)

Activer le choix automatique d'outil et les sorties JSON structurées :

```bash
vllm serve mistralai/Mistral-7B-Instruct-v0.2 \
    --host 0.0.0.0 \
    --enable-auto-tool-choice \
    --tool-call-parser mistral
```

Utilisation en Python :

```python
from openai import OpenAI
import json

client = OpenAI(base_url="http://localhost:8000/v1", api_key="not-needed")

tools = [
    {
        "type": "function",
        "function": {
            "name": "get_weather",
            "description": "Obtenir la météo actuelle pour une ville",
            "parameters": {
                "type": "object",
                "properties": {
                    "city": {"type": "string", "description": "Nom de la ville"},
                    "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]}
                },
                "required": ["city"]
            }
        }
    }
]

response = client.chat.completions.create(
    model="mistralai/Mistral-7B-Instruct-v0.2",
    messages=[{"role": "user", "content": "Quelle est la météo à Paris ?"}],
    tools=tools,
    tool_choice="auto"
)

# Analyser l'appel d'outil
tool_call = response.choices[0].message.tool_calls[0]
args = json.loads(tool_call.function.arguments)
print(f"Outil : {tool_call.function.name}, Args : {args}")
```

Sortie JSON structurée via response\_format :

```python
response = client.chat.completions.create(
    model="mistralai/Mistral-7B-Instruct-v0.2",
    messages=[{"role": "user", "content": "Extraire : John Smith, 30 ans, ingénieur logiciel"}],
    response_format={
        "type": "json_schema",
        "json_schema": {
            "name": "person",
            "schema": {
                "type": "object",
                "properties": {
                    "name": {"type": "string"},
                    "age": {"type": "integer"},
                    "occupation": {"type": "string"}
                },
                "required": ["name", "age", "occupation"]
            }
        }
    }
)
print(response.choices[0].message.content)
```

### Service Multi-LoRA (v0.7+)

Servir un modèle de base avec plusieurs adaptateurs LoRA simultanément :

```bash
vllm serve meta-llama/Meta-Llama-3.1-8B-Instruct \
    --host 0.0.0.0 \
    --enable-lora \
    --lora-modules \
        sql-adapter=path/to/sql-lora \
        code-adapter=path/to/code-lora \
        chat-adapter=path/to/chat-lora \
    --max-lora-rank 64
```

Interroger un adaptateur LoRA spécifique par nom de modèle :

```python
# Utiliser l'adaptateur SQL
response = client.chat.completions.create(
    model="sql-adapter",
    messages=[{"role": "user", "content": "Écrire une requête SQL pour trouver les 10 meilleurs clients"}]
)

# Utiliser l'adaptateur code
response = client.chat.completions.create(
    model="code-adapter",
    messages=[{"role": "user", "content": "Écrire une fonction Python pour trier une liste"}]
)
```

## Prise en charge DeepSeek-R1 (v0.7+)

vLLM v0.7+ prend en charge nativement les modèles distillés DeepSeek-R1. Ces modèles de raisonnement produisent `<think>` des balises montrant leur processus de raisonnement.

### DeepSeek-R1-Distill-Qwen-7B (GPU unique)

```bash
vllm serve deepseek-ai/DeepSeek-R1-Distill-Qwen-7B \
    --host 0.0.0.0 \
    --port 8000 \
    --max-model-len 16384
```

### DeepSeek-R1-Distill-Qwen-32B (GPU double)

```bash
vllm serve deepseek-ai/DeepSeek-R1-Distill-Qwen-32B \
    --host 0.0.0.0 \
    --port 8000 \
    --tensor-parallel-size 2 \
    --max-model-len 32768 \
    --gpu-memory-utilization 0.90
```

### DeepSeek-R1-Distill-Llama-70B (Quad GPU)

```bash
vllm serve deepseek-ai/DeepSeek-R1-Distill-Llama-70B \
    --host 0.0.0.0 \
    --port 8000 \
    --tensor-parallel-size 4 \
    --max-model-len 32768
```

### Interroger DeepSeek-R1

```python
from openai import OpenAI

client = OpenAI(base_url="http://localhost:8000/v1", api_key="not-needed")

response = client.chat.completions.create(
    model="deepseek-ai/DeepSeek-R1-Distill-Qwen-32B",
    messages=[
        {
            "role": "user",
            "content": "Résoudre : Si un train parcourt 120 km en 1,5 heure, quelle est sa vitesse en m/s ?"
        }
    ],
    max_tokens=2048,
    temperature=0.6
)

content = response.choices[0].message.content
# La réponse inclut un bloc de raisonnement <think>...</think> suivi de la réponse
print(content)
```

Analyse des balises think :

```python
import re

def parse_deepseek_r1_response(content: str) -> dict:
    """Extraire la réflexion et la réponse de la réponse DeepSeek-R1."""
    think_match = re.search(r'<think>(.*?)</think>', content, re.DOTALL)
    thinking = think_match.group(1).strip() if think_match else ""
    answer = re.sub(r'<think>.*?</think>', '', content, flags=re.DOTALL).strip()
    return {"thinking": thinking, "answer": answer}

result = parse_deepseek_r1_response(content)
print("Thinking:", result["thinking"][:200], "...")
print("Answer:", result["answer"])
```

## Utilisation de l'API

### Chat Completions (compatible OpenAI)

```python
from openai import OpenAI

# Pour un accès externe, utilisez votre URL http_pub :
client = OpenAI(
    base_url="https://your-http-pub.clorecloud.net/v1",
    api_key="non-nécessaire"
)

# Ou via un tunnel SSH :
# client = OpenAI(base_url="http://localhost:8000/v1", api_key="not-needed")

response = client.chat.completions.create(
    model="mistralai/Mistral-7B-Instruct-v0.2",
    messages=[
        {"role": "user", "content": "Expliquer l'informatique quantique"}
    ],
    max_tokens=500,
    temperature=0.7
)

print(response.choices[0].message.content)
```

### Streaming

```python
stream = client.chat.completions.create(
    model="mistralai/Mistral-7B-Instruct-v0.2",
    messages=[{"role": "user", "content": "Écrire un poème"}],
    stream=True
)

for chunk in stream:
    if chunk.choices[0].delta.content:
        print(chunk.choices[0].delta.content, end="")
```

### cURL

```bash
curl https://your-http-pub.clorecloud.net/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "mistralai/Mistral-7B-Instruct-v0.2",
    "messages": [{"role": "user", "content": "Bonjour !"}],
    "max_tokens": 100
  }'
```

### Complétions de texte

```bash
curl https://your-http-pub.clorecloud.net/v1/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "mistralai/Mistral-7B-Instruct-v0.2",
    "prompt": "La capitale de la France est",
    "max_tokens": 50
  }'
```

## Référence complète de l'API

vLLM fournit des endpoints compatibles OpenAI ainsi que des endpoints utilitaires supplémentaires.

### Points de terminaison standard

| Point de terminaison   | Méthode | Description                                 |
| ---------------------- | ------- | ------------------------------------------- |
| `/v1/models`           | GET     | Lister les modèles disponibles              |
| `/v1/chat/completions` | POST    | Complétion de chat                          |
| `/v1/completions`      | POST    | Complétion de texte                         |
| `/health`              | GET     | Vérification de l'état (peut renvoyer vide) |

### Points de terminaison supplémentaires

| Point de terminaison | Méthode | Description                   |
| -------------------- | ------- | ----------------------------- |
| `/tokenize`          | POST    | Tokenizer le texte            |
| `/detokenize`        | POST    | Convertir les tokens en texte |
| `/version`           | GET     | Obtenir la version de vLLM    |
| `/docs`              | GET     | Documentation Swagger UI      |
| `/metrics`           | GET     | Métriques Prometheus          |

#### Tokenizer du texte

Utile pour compter les tokens avant d'envoyer des requêtes :

```bash
curl https://your-http-pub.clorecloud.net/tokenize \
  -H "Content-Type: application/json" \
  -d '{
    "model": "mistralai/Mistral-7B-Instruct-v0.2",
    "prompt": "Hello world"
  }'
```

Réponse :

```json
{"count": 2, "max_model_len": 32768, "tokens": [9707, 1879]}
```

#### Dé-tokenisation

Convertir les IDs de tokens en texte :

```bash
curl https://your-http-pub.clorecloud.net/detokenize \
  -H "Content-Type: application/json" \
  -d '{
    "model": "mistralai/Mistral-7B-Instruct-v0.2",
    "tokens": [9707, 1879]
  }'
```

Réponse :

```json
{"prompt": "Hello world"}
```

#### Obtenir la version

```bash
curl https://your-http-pub.clorecloud.net/version
```

Réponse :

```json
{"version": "0.7.3"}
```

#### Documentation Swagger

Ouvrez dans le navigateur pour une documentation API interactive :

```
https://your-http-pub.clorecloud.net/docs
```

#### Metrics Prometheus

Pour la surveillance :

```bash
curl https://your-http-pub.clorecloud.net/metrics
```

{% hint style="info" %}
**Modèles de raisonnement :** DeepSeek-R1 et des modèles similaires incluent `<think>` des balises dans les réponses montrant le processus de raisonnement du modèle avant la réponse finale.
{% endhint %}

## Benchmarks

### Débit (tokens/sec par utilisateur)

| Modèle             | RTX 3090 | RTX 4090 | A100 40GB | A100 80GB |
| ------------------ | -------- | -------- | --------- | --------- |
| Mistral 7B         | 100      | 170      | 210       | 230       |
| Llama 3.1 8B       | 95       | 150      | 200       | 220       |
| Llama 3.1 8B (AWQ) | 130      | 190      | 260       | 280       |
| Mixtral 8x7B       | -        | 45       | 70        | 85        |
| Llama 3.1 70B      | -        | -        | 25 (2x)   | 45 (2x)   |
| DeepSeek-R1 7B     | 90       | 145      | 190       | 210       |
| DeepSeek-R1 32B    | -        | -        | 40        | 70 (2x)   |

*Benchmarks mis à jour en janvier 2026.*

### Longueur de contexte vs VRAM

| Modèle   | Contexte 4K | Contexte 8K | Contexte 16K | Contexte 32K |
| -------- | ----------- | ----------- | ------------ | ------------ |
| 8B FP16  | 18Go        | 22Go        | 30Go         | 46 Go        |
| 8B AWQ   | 8 Go        | 10Go        | 14GB         | 22Go         |
| 70B FP16 | 145 Go      | 160Go       | 190 Go       | 250Go        |
| 70B AWQ  | 42GB        | 50GB        | 66 Go        | 98 Go        |

## Authentification Hugging Face

Pour les modèles restreints (Llama, etc.) :

```bash
# Définir le token dans la commande
vllm serve meta-llama/Meta-Llama-3.1-8B-Instruct \
    --host 0.0.0.0 \
    --env HUGGING_FACE_HUB_TOKEN=hf_xxxxx
```

Ou définir comme variable d'environnement :

```bash
export HUGGING_FACE_HUB_TOKEN=hf_xxxxx
```

## Exigences GPU

| Modèle | VRAM min | RAM min  | Recommandé            |
| ------ | -------- | -------- | --------------------- |
| 7-8B   | 16Go     | **16Go** | 24 Go VRAM, 32 Go RAM |
| 13B    | 26 Go    | 32Go     | 40 Go VRAM            |
| 34B    | 70Go     | 32Go     | 80 Go VRAM            |
| 70B    | 140 Go   | 64Go     | 2x80 Go               |

## Estimation des coûts

Tarifs typiques du marketplace CLORE.AI :

| GPU      | VRAM  | Prix/jour   | Idéal pour     |
| -------- | ----- | ----------- | -------------- |
| RTX 3090 | 24 Go | 0,30–1,00 $ | Modèles 7-8B   |
| RTX 4090 | 24 Go | 0,50–2,00 $ | 7-13B, rapide  |
| A100     | 40Go  | 1,50–3,00 $ | Modèles 13-34B |
| A100     | 80Go  | 2,00–4,00 $ | Modèles 34-70B |

*Prix en USD/jour. Les tarifs varient selon le fournisseur — vérifiez* [*CLORE.AI Marketplace*](https://clore.ai/marketplace) *pour les tarifs actuels.*

## Dépannage

### HTTP 502 pendant longtemps

1. **Vérifier la RAM :** Le serveur doit avoir 16 Go+ de RAM
2. **Vérifier la VRAM :** Doit correspondre au modèle
3. **Téléchargement du modèle :** Le premier lancement télécharge depuis HuggingFace (5-15 min)
4. **Token HF :** Les modèles restreints nécessitent une authentification

### Mémoire insuffisante

```bash
# Réduire l'utilisation de la mémoire
--gpu-memory-utilization 0.8
--max-model-len 4096
--max-num-seqs 64

# Ou utiliser la quantification
--quantization awq
```

### Échec du téléchargement du modèle

```bash
# Vérifier le token HF
echo $HUGGING_FACE_HUB_TOKEN

# Pré-télécharger le modèle
huggingface-cli download mistralai/Mistral-7B-Instruct-v0.2
```

## vLLM vs autres

| Fonction               | vLLM        | llama.cpp | composant Ollama |
| ---------------------- | ----------- | --------- | ---------------- |
| Débit                  | Meilleur    | Bon       | Bon              |
| Utilisation VRAM       | Élevé       | Faible    | Moyen            |
| Facilité d'utilisation | Moyen       | Moyen     | Facile           |
| Temps de démarrage     | 5-15 min    | 1-2 min   | 30 s             |
| Multi-GPU              | Natif       | Limité    | Limité           |
| Appel d'outils         | Oui (v0.7+) | Limité    | Limité           |
| Multi-LoRA             | Oui (v0.7+) | Non       | Non              |

**Utiliser vLLM quand :**

* Le haut débit est prioritaire
* Servir plusieurs utilisateurs
* Disposer de suffisamment de VRAM et de RAM
* Déploiement en production
* Besoin d'appels d'outils / sorties structurées

**Utiliser Ollama quand :**

* Configuration rapide nécessaire
* Utilisateur unique
* Moins de ressources disponibles

## Prochaines étapes

* [composant Ollama](https://docs.clore.ai/guides/guides_v2-fr/modeles-de-langage/ollama) - Alternative plus simple avec démarrage plus rapide
* [DeepSeek-R1](https://docs.clore.ai/guides/guides_v2-fr/modeles-de-langage/deepseek-r1) - Guide de modèle de raisonnement
* [DeepSeek-V3](https://docs.clore.ai/guides/guides_v2-fr/modeles-de-langage/deepseek-v3) - Meilleur modèle général
* [Qwen2.5](https://docs.clore.ai/guides/guides_v2-fr/modeles-de-langage/qwen25) - Modèles multilingues
* [Llama.cpp](https://docs.clore.ai/guides/guides_v2-fr/modeles-de-langage/llamacpp-server) - Option à VRAM plus faible
