Déployer un agent IA en production
Apprenez à déployer un agent IA en production : Docker, VPS, monitoring et sécurité. Tutoriel complet pour un agent stable et autonome.
Introduction
Un agent IA qui tourne sur votre machine locale, c'est une preuve de concept. Un agent qui tourne en production, c'est un outil qui crée de la valeur. La différence entre les deux n'est pas seulement technique — elle impose de penser containerisation, supervision, sécurité et disponibilité.
Dans ce tutoriel, vous apprendrez à prendre un agent Python fonctionnel et à le transformer en service robuste qui tourne 24h/24 sur un VPS. Nous couvrons Docker, la configuration systemd, la gestion des secrets, le monitoring et les bonnes pratiques de sécurité. Pour aller plus loin sur ce dernier point, consultez notre guide dédié pour sécuriser un agent IA en production.
À la fin, vous aurez un agent prêt pour la production — pas une coquille fragile.
Résumé rapide
| Étape | Action | Outil |
|---|---|---|
| 1 | Rendre l'agent configurable via variables d'environnement | Python os.environ |
| 2 | Containeriser avec un Dockerfile slim | Docker |
| 3 | Choisir un VPS adapté (2 Go RAM minimum) | Hetzner / OVH / Scaleway |
| 4 | Déployer avec systemd ou Docker restart policy | systemd / docker-compose |
| 5 | Configurer le pare-feu et les secrets | UFW, .env |
| 6 | Mettre en place le monitoring et les alertes | Healthcheck, logs |
Choisir une option d'hébergement
Avant d'écrire la moindre ligne de configuration, il faut décider où l'agent va tourner. Trois grandes familles d'hébergement existent, chacune avec ses compromis.
| Option | Pour qui | Avantages | Limites |
|---|---|---|---|
| VPS (Hetzner, OVH, Scaleway) | Agent persistant, tâches longues, coût maîtrisé | Contrôle total, prix fixe, idéal pour un process 24h/24 | Maintenance OS à votre charge |
| Serverless (AWS Lambda, Cloud Run, Vercel Functions) | Agent déclenché à la demande (webhook, cron) | Scaling automatique, facturation à l'usage, zéro maintenance serveur | Cold start, timeout (souvent 15 min max), mal adapté aux process longs |
| Conteneurs managés (Cloud Run, ECS Fargate, Railway, Fly.io) | Entre les deux : conteneur Docker sans gérer de VM | Scaling horizontal, déploiement par image, pas de serveur à patcher | Plus cher qu'un VPS au repos |
Comment trancher ?
- Un agent qui doit rester éveillé en permanence (surveillance, boucle d'écoute, file de tâches) → VPS ou conteneur managé toujours actif.
- Un agent déclenché ponctuellement (réponse à un email, traitement d'un fichier uploadé, cron quotidien) → serverless, beaucoup moins cher car vous ne payez que le temps d'exécution.
- Un agent que vous voulez pouvoir déplacer et scaler facilement sans toucher à un OS → conteneur managé.
Ce tutoriel détaille le scénario le plus courant — un agent persistant sur VPS conteneurisé — mais les principes (configuration externalisée, secrets, monitoring) s'appliquent à toutes les options.
Préparer l'agent pour la production
Externaliser la configuration
La première étape consiste à retirer toutes les valeurs codées en dur. Un agent en production doit être configurable sans modifier le code.
import os
# Clés API — NE JAMAIS hardcoder
api_key = os.environ.get("OPENAI_API_KEY")
model = os.environ.get("MODEL_NAME", "gpt-4o")
max_tokens = int(os.environ.get("MAX_TOKENS", "2000"))
# Configuration du comportement
temperature = float(os.environ.get("TEMPERATURE", "0.7"))
max_steps = int(os.environ.get("MAX_AGENT_STEPS", "10"))
Placez ces variables dans un fichier .env et chargez-le au démarrage :
from dotenv import load_dotenv
load_dotenv()
Règle absolue : le fichier .env doit être dans .gitignore. Ne commitez jamais de clé API.
Prévoir le rechargement sans interruption
Votre agent doit pouvoir être reconfiguré sans redémarrage brutal. Un pattern courant : un fichier de configuration JSON rechargé périodiquement ou sur signal SIGUSR1.
import signal, json
def reload_config(signum, frame):
with open("agent_config.json") as f:
config = json.load(f)
print(f"Configuration rechargée : {config}")
signal.signal(signal.SIGUSR1, reload_config)
Containeriser avec Docker
Le Dockerfile
Choisissez une image Python slim pour minimiser la taille et la surface d'attaque :
FROM python:3.12-slim
WORKDIR /app
# Dépendances système minimales
RUN apt-get update && apt-get install -y --no-install-recommends \
curl \
&& rm -rf /var/lib/apt/lists/*
# Dépendances Python
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Code de l'agent
COPY agent.py .
# Utilisateur non-root (sécurité)
RUN useradd -m -u 1000 agent && chown -R agent:agent /app
USER agent
CMD ["python", "agent.py"]
docker-compose pour orchestrer
version: "3.9"
services:
agent:
build: .
restart: unless-stopped
env_file:
- .env
volumes:
- ./data:/app/data
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
interval: 30s
timeout: 10s
retries: 3
networks:
- agent_network
networks:
agent_network:
driver: bridge
L'option restart: unless-stopped garantit que l'agent redémarre automatiquement après un crash ou un reboot du serveur.
Choisir et configurer le VPS
Ressources minimales
Pour un agent Python léger (pas de modèle local) :
| Provider | Instance | RAM | vCPU | Prix/mois |
|---|---|---|---|---|
| Hetzner | CX21 | 4 Go | 2 | ~4 € |
| OVH | Starter | 2 Go | 1 | ~3 € |
| Scaleway | DEV1-S | 2 Go | 2 | ~3 € |
Pour un agent avec modèle local (Llama, Mistral), prévoyez un minimum de 16 Go RAM et un CPU correct — Hetzner AX42 (≈ 20 €/mois) ou équivalent.
Installation de Docker sur le VPS
# Connexion SSH
ssh root@adresse_ip
# Installation Docker
curl -fsSL https://get.docker.com | sh
# Activer Docker au démarrage
systemctl enable docker
# Ajouter l'utilisateur (votre login) au groupe docker
usermod -aG docker $USER
Transférez vos fichiers sur le VPS :
# Depuis votre machine
rsync -avz --exclude='.env' --exclude='.git' ./agent/ user@vps:/home/user/agent/
Déployer et maintenir le service actif
Option 1 : systemd (recommandé pour un seul agent)
Créez un service systemd :
# /etc/systemd/system/agent-ia.service
[Unit]
Description=Agent IA de production
After=network.target
[Service]
Type=simple
User=agent
WorkingDirectory=/home/agent/agent
EnvironmentFile=/home/agent/agent/.env
ExecStart=/usr/bin/python3 /home/agent/agent/agent.py
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
Activez et lancez :
systemctl enable agent-ia
systemctl start agent-ia
journalctl -u agent-ia -f # suivre les logs en temps réel
Option 2 : Docker directement
Si vous préférez Docker à systemd :
docker run -d \
--name mon_agent \
--restart unless-stopped \
--env-file .env \
-v $(pwd)/data:/app/data \
-p 8000:8000 \
mon_agent:latest
Vérifier que l'agent est vivant
Ajoutez un endpoint healthcheck dans votre agent :
from flask import Flask
app = Flask(__name__)
@app.route("/health")
def health():
return {"status": "ok", "agent": "production"}
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8000)
Testez depuis l'extérieur :
curl https://votre-domaine.com/health
Sécurité de base
Pare-feu avec UFW
ufw default deny incoming
ufw default allow outgoing
ufw allow ssh
ufw allow 80/tcp
ufw allow 443/tcp
ufw allow 8000/tcp # uniquement si le healthcheck est exposé
ufw enable
Gestion des secrets
Jamais dans le code ou dans un fichier commité.
# Variables d'environnement uniquement en production
# Le fichier .env reste en LOCAL, ne contient PAS de vraie clé
# Sur le VPS, définissez les variables dans systemd :
Environment=OPENAI_API_KEY=sk-...
Environment=MODEL_NAME=gpt-4o
Pour les environnements critiques, utilisez un gestionnaire de secrets comme Doppler ou HashiCorp Vault. Sur les plateformes managées (Cloud Run, Railway, Fly.io), passez plutôt par leur coffre-fort de secrets natif, qui injecte les variables au runtime sans jamais les écrire sur disque.
Accès SSH
- Désactivez l'authentification par mot de passe (clés SSH uniquement)
- Changez le port SSH par défaut (2222 par exemple)
- Installez
fail2banpour bloquer les tentatives d'attaque par force brute
apt install fail2ban
systemctl enable fail2ban
Monitoring et alertes
Logs structurés
Envoyez les logs dans un format lisible pour l'analyse :
import logging, sys
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s %(levelname)s %(name)s: %(message)s",
handlers=[
logging.FileHandler("/var/log/agent/agent.log"),
logging.StreamHandler(sys.stdout)
]
)
logger = logging.getLogger("agent_ia")
logger.info("Agent démarré", extra={"model": model, "max_steps": max_steps})
Surveillance avec healthcheck
# Script de surveillance
#!/bin/bash
if curl -sf http://localhost:8000/health > /dev/null; then
echo "OK"
exit 0
else
echo "FAIL"
exit 1
fi
Placez ce script dans /usr/local/bin/agent-healthcheck et exécutez-le depuis systemd :
[Service]
ExecStartPost=/usr/local/bin/agent-healthcheck
Alerte par email en cas de panne
Utilisez un service comme Healthchecks.io ou UptimeRobot pour pinguer votre endpoint /health toutes les minutes. Configurez une alerte email/SMS si le ping échoue pendant 2 minutes.
Scaling : encaisser la montée en charge
Un agent qui répond à une requête à la fois suffit en phase de lancement. Dès que le trafic augmente, il faut prévoir la montée en charge.
Scaling vertical (le plus simple)
Augmentez les ressources de la machine : plus de RAM et de vCPU. C'est immédiat et sans refonte du code, mais limité par le plafond matériel du provider et par le coût d'une grosse instance qui tourne en permanence.
Scaling horizontal (plusieurs instances)
Lancez plusieurs conteneurs identiques derrière un répartiteur de charge (nginx, Traefik, ou le load balancer du provider). Deux conditions pour que cela fonctionne :
- L'agent doit être stateless. Aucun état critique en mémoire locale : la conversation, la mémoire de l'agent et la file de tâches vivent dans un service externe (Redis, PostgreSQL).
- Le travail doit être distribuable. Pour des tâches longues, passez par une file de messages (Redis Queue, Celery, RabbitMQ) : un producteur empile les tâches, N workers les consomment en parallèle.
# docker-compose : 3 workers consommant une file Redis
services:
worker:
build: .
restart: unless-stopped
env_file: [.env]
deploy:
replicas: 3
depends_on:
- redis
redis:
image: redis:7-alpine
restart: unless-stopped
Goulot d'étranglement réel. Pour un agent appuyé sur une API LLM, la limite n'est presque jamais le CPU mais les rate limits du fournisseur (requêtes/minute, tokens/minute). Mettez en place une logique de retry avec back-off exponentiel avant de multiplier les machines.
Maîtriser les coûts LLM
En production, le poste de dépense numéro un d'un agent n'est pas le serveur — c'est la facture de tokens. Quelques leviers concrets :
- Choisir le bon modèle par tâche. Un modèle léger (gpt-4o-mini, Claude Haiku) pour le routage et la classification ; le gros modèle uniquement pour les étapes qui le justifient. Le rapport de prix entre les deux dépasse souvent un facteur 10.
- Plafonner les boucles. Un agent qui boucle, c'est une facture qui explose. Imposez un
MAX_AGENT_STEPSet un budget de tokens par requête. - Mettre en cache. Cachez les réponses aux requêtes identiques ou similaires (clé = hash du prompt). Beaucoup de fournisseurs proposent aussi un prompt caching natif qui réduit fortement le coût des préfixes répétés (system prompt, contexte).
- Compresser le contexte. N'envoyez pas tout l'historique à chaque appel : résumez les anciens tours, tronquez les documents, n'injectez que le strict nécessaire.
- Suivre la dépense. Loguez
prompt_tokensetcompletion_tokensà chaque appel et agrégez-les. Posez une alerte sur un seuil quotidien.
resp = client.chat.completions.create(model=model, messages=messages)
usage = resp.usage
logger.info(
"Appel LLM",
extra={
"prompt_tokens": usage.prompt_tokens,
"completion_tokens": usage.completion_tokens,
"total_tokens": usage.total_tokens,
},
)
CI/CD : déployer automatiquement
Plutôt que de transférer le code à la main à chaque modification, automatisez le déploiement avec un pipeline d'intégration et de déploiement continus. Exemple minimal avec GitHub Actions : à chaque push sur main, on construit l'image, on la pousse vers le registre, puis on redéploie sur le VPS via SSH.
# .github/workflows/deploy.yml
name: Deploy agent
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Lancer les tests
run: |
pip install -r requirements.txt
pytest
- name: Construire et pousser l'image
run: |
echo "${{ secrets.REGISTRY_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
docker build -t ghcr.io/${{ github.repository }}:latest .
docker push ghcr.io/${{ github.repository }}:latest
- name: Redéployer sur le VPS
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.VPS_HOST }}
username: ${{ secrets.VPS_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
cd /home/agent/agent
docker compose pull
docker compose up -d
Les secrets (SSH_PRIVATE_KEY, VPS_HOST, token de registre) se définissent dans Settings → Secrets and variables → Actions de votre dépôt — jamais dans le YAML. Faites systématiquement passer les tests avant le déploiement : un pipeline qui déploie du code cassé est pire que pas de pipeline du tout.
Checklist de mise en production
Avant de considérer l'agent comme « en prod », vérifiez chaque point :
- Aucune valeur sensible codée en dur ; configuration via variables d'environnement.
-
.envdans.gitignore; secrets injectés au runtime (systemd, coffre-fort, secrets CI). - Dockerfile basé sur une image slim, exécution en utilisateur non-root.
- Politique de redémarrage automatique (
restart: unless-stoppedouRestart=always). - Endpoint
/healthexposé et surveillé par un service externe (UptimeRobot, Healthchecks.io). - Logs structurés persistés et consultables (
journalctloudocker logs). - Pare-feu actif (UFW), SSH par clé uniquement,
fail2baninstallé. - Plafonds en place :
MAX_AGENT_STEPS, budget de tokens, retry avec back-off. - Suivi des coûts LLM (tokens logués) et alerte sur seuil quotidien.
- Procédure de mise à jour testée (rollback possible vers l'image précédente).
- Sauvegarde des données persistantes (
./data, base, mémoire de l'agent).
Tableau comparatif : systemd vs Docker restart
| Critère | systemd | Docker restart |
|---|---|---|
| Simplicité | Bon pour 1 agent | Bon pour plusieurs services |
| Portabilité | Lié à la machine | Portable entre machines |
| Supervision | journalctl natif | docker logs |
| Networking | Config réseau standard | Network mode intégré |
| Mise à jour | systemctl restart | docker pull && docker-compose up -d |
Pour un seul agent, systemd est souvent le choix le plus simple et le plus robuste.
Questions fréquentes
Comment mettre à jour l'agent sans interruption de service ?
Avec Docker : docker pull télécharge la nouvelle image, puis docker-compose up -d --no-deps agent remplace le conteneur. Le flag --no-deps évite de redémarrer les services dépendants.
Avec systemd : modifiez le code, transférez via rsync, puis systemctl restart agent-ia.
Un agent IA peut-il tourner sur un Raspberry Pi ?
Un agent utilisant une API externe (OpenAI, Anthropic) oui, sans problème. Un agent avec modèle local (Llama 3) nécessite un GPU ou beaucoup de RAM — pas adapté au Pi. Dans ce cas, hébergez le modèle sur une machine séparée et connectez l'agent via API.
Comment éviter d'exposer mes clés API sur le serveur ?
Définissez les variables d'environnement dans la configuration du service (systemd Environment=) ou utilisez un gestionnaire de secrets. Le fichier .env reste en local et n'est jamais transféré sur le VPS.
Comment dimensionner le VPS ?
Commencez avec 2 Go RAM / 1 vCPU pour un agent avec API externe. Surveillez avec htop après déploiement. En cas de fuite mémoire ou de charge élevée, montez à 4 Go. Pour un modèle local, partez sur 16 Go minimum.
Articles liés
Déployer un agent en production n'est que la dernière étape. Avant d'en arriver là, il faut avoir construit l'agent lui-même. Le pilier de ce tutoriel est la création d'agent — maîtriser ce processus est un prérequis indispensable.
Votre agent tourne désormais en continu. L'étape suivante logique consiste à lui confier des tâches métier récurrentes : veille concurrentielle, génération de contenu, qualification de leads. L'automatisation par agents IA est le terrain de jeu naturel de ce type de déploiement.
Restez informé sur les agents IA
Nouveaux tutoriels, comparatifs et guides pratiques directement dans votre boîte mail.