L'idée en 30 secondes
Containerizing Agents est une approche d'architecture où un agent s'exécute comme un service isolé et reproductible dans un conteneur.
Ce n'est pas seulement un Dockerfile. C'est une frontière contrôlée entre le code de l'agent et l'environnement de production : dépendances, config, secrets, ressources, health checks et mises à jour du service.
Quand c'est nécessaire : quand l'agent ne tourne pas seulement en local, mais dans un vrai service avec charge, mises à jour et exigences de fiabilité.
Un LLM ne doit pas piloter l'infrastructure seul. La couche conteneur impose des limites d'exécution pour que l'agent reste stable après le déploiement.
Problème
En local, l'agent fonctionne souvent bien, mais après le déploiement, des pannes instables commencent.
Problèmes typiques sans containerisation gouvernée :
- des environnements différents donnent des comportements différents pour le même code ;
- les dépendances ou bibliothèques système diffèrent selon les machines ;
- des secrets se retrouvent accidentellement dans l'image ou les logs ;
- pas de limites CPU/mémoire claires, donc OOMKill apparaît ;
- pas de checks readiness/health, et le trafic va vers une instance "non saine" ;
- rollout et rollback sont faits manuellement et lentement.
Résultat : le système semble "fonctionner", mais gère mal les pics, les mises à jour et les pannes partielles.
Solution
Ajouter Containerizing Agents comme couche opérationnelle explicite pour exécuter l'agent en production.
Cette couche fixe :
- une image reproductible ;
- config runtime et secrets hors de l'image ;
- limites de ressources et comportement de timeout ;
- checks health/readiness ;
- rollout/rollback contrôlé.
Analogie : comme un conteneur standardisé pour le transport de marchandises.
Ce qui compte, ce n'est pas seulement ce qu'il y a dedans, mais aussi des règles standard de transport, de sécurité et de vérification.
Containerizing Agents fait la même chose et rend l'exécution de l'agent prévisible dans n'importe quel environnement.
Comment fonctionne Containerizing Agents
Containerizing Agents est une couche gouvernée entre le code de l'agent et la plateforme d'exécution, qui définit comment l'agent est construit, lancé, vérifié et mis à jour.
Vue d'ensemble du flux complet : Build → Configure → Run → Observe → Recover
Build
Le code de l'agent et ses dépendances sont assemblés dans une image de conteneur reproductible.
Configure
Runtime reçoit env config, secrets, budgets et allowlist hors de l'image.
Run
L'agent s'exécute dans un processus isolé avec des limites CPU/mémoire et un comportement de timeout.
Observe
La plateforme lit les health checks, métriques, logs et stop reasons.
Recover
Si l'error-rate augmente, le système fait rollback, restart, ou active un kill switch pour les outils risqués.
Ce cycle réduit le chaos d'infrastructure et rend le comportement de l'agent prévisible sous charge.
Dans le code, cela ressemble à ceci
FROM python:3.12.2-slim AS builder
WORKDIR /build
COPY requirements.lock ./
RUN pip install --no-cache-dir --require-hashes -r requirements.lock --prefix=/install
FROM python:3.12.2-slim AS runner
RUN useradd --create-home --uid 10001 appuser
WORKDIR /app
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
COPY --from=builder /install /usr/local
COPY . .
USER appuser
EXPOSE 8080
CMD ["python", "main.py"]
.dockerignore est aussi critique : on exclut généralement .git, __pycache__, .venv, tests, les artefacts locaux et .env.
import os
class ContainerizedAgentApp:
def __init__(self, agent_runtime):
self.agent_runtime = agent_runtime
self.max_steps = int(os.getenv("AGENT_MAX_STEPS", "20"))
self.max_seconds = int(os.getenv("AGENT_MAX_SECONDS", "45"))
self.max_tool_calls = int(os.getenv("AGENT_MAX_TOOL_CALLS", "10"))
def run(self, task: str):
# La couche conteneur impose les budgets runtime.
result = self.agent_runtime.run(
task=task,
max_steps=self.max_steps,
max_tool_calls=self.max_tool_calls,
max_seconds=self.max_seconds,
)
return {
"ok": result.get("ok", False),
"result": result.get("result"),
"reason_code": result.get("reason_code", "runtime_unknown"),
}
def readiness(self):
# Vérifie que le service est prêt à recevoir du trafic.
return {"ok": True}
def liveness(self):
# Vérifie que le processus n'est pas bloqué.
return {"ok": True}
À quoi cela ressemble pendant l'exécution
Requête : "Mets à jour le statut de 500 commandes et génère un rapport"
Step 1
Ingress: envoie le trafic uniquement vers les conteneurs ready
Agent Container: démarre avec env config et secrets runtime
Agent Runtime: vérifie les budgets (steps/tool_calls/time)
Step 2
Tool Execution Layer: appelle l'API avec timeout et politique de retry
Observability: écrit metrics + trace + reason_code
Step 3
Deployment Control: détecte une hausse de l'error-rate
Deployment Control: arrête le rollout et effectue un rollback vers l'image précédente
Containerizing Agents ne change pas la logique de l'agent. Il la rend prévisible dans un environnement réel d'exécution.
Quand c'est adapté et quand ça ne l'est pas
Containerizing Agents est nécessaire là où l'agent fonctionne comme un service de production et doit supporter les mises à jour et la charge.
Adapté
| Situation | Pourquoi Containerizing Agents est adapté | |
|---|---|---|
| ✅ | L'agent tourne en production et a un SLA | L'isolation et les health checks améliorent la prévisibilité et la stabilité. |
| ✅ | Des déploiements sûrs et un rollback rapide sont requis | Les versions d'image et le contrôle du rollout permettent des mises à jour plus sûres du service. |
| ✅ | Risque de OOM, timeout et charge de pointe | Les limites de ressources et budgets runtime réduisent les crashs instables. |
Non adapté
| Situation | Pourquoi Containerizing Agents n'est pas adapté | |
|---|---|---|
| ❌ | Prototype local ponctuel sans charge de production | Une containerisation complète peut être excessive pour une courte expérience. |
| ❌ | Pas de monitoring, de processus de rollout ni de support de service | La containerisation ne remplace ni observability, ni les processus SRE/DevOps, ni la discipline de release. |
Dans les scénarios simples, une exécution locale suffit parfois :
result = local_agent.run(task)
Problèmes et pannes typiques
| Problème | Ce qui se passe | Comment prévenir |
|---|---|---|
| Secrets dans l'image | Les clés fuient via la registry ou les logs | Secrets uniquement via secret manager et runtime injection |
| Pas de limites de ressources | Une requête de pointe déclenche OOMKill et cascading failures | CPU/Memory requests+limits, budgets et backpressure |
| Image mutable / dépendances non épinglées | Aujourd'hui le conteneur démarre de façon stable, demain le même build se comporte autrement | Pinned versions, immutable tags/digests et reproducible builds |
| Readiness mal configuré | Le trafic arrive au conteneur avant disponibilité complète | Checks liveness/readiness séparés et warm-up avant le trafic |
| Tempête de retries (retry storm) | Les retries multiplient en même temps la charge API | Retry borné, jitter, circuit breaker et limites globales |
| Rollout raté sans rollback rapide | La nouvelle version dégrade l'error-rate de tout le service | Canary rollout, alertes SLO et rollback automatique |
La plupart de ces pannes se résolvent non pas par une "magie Docker", mais par des règles opérationnelles explicites autour du conteneur.
Comment cela se combine avec d'autres patterns
Containerizing Agents est la base d'infrastructure pour le fonctionnement stable des autres couches d'architecture.
- Agent Runtime — Runtime s'exécute dans le conteneur et reçoit des limites stables.
- Tool Execution Layer — les règles réseau et timeout des outils sont définies avec le démarrage en conteneur.
- Memory Layer — le conteneur ne doit généralement pas conserver de mémoire long terme localement ; le memory store doit être externe.
- Policy Boundaries — les policy checks restent une couche séparée, mais le conteneur garantit une exécution contrôlée.
- Orchestration Topologies — chaque agent d'une topologie tourne souvent comme service de conteneur séparé.
- Hybrid Workflow Agent — les commits workflow et étapes agent se scalent plus facilement quand les deux tournent dans des conteneurs contrôlés.
- Human-in-the-Loop Architecture — les services d'approval et conteneurs agent doivent avoir des timeout/SLA alignés pour un flux de revue stable.
Autrement dit :
- Containerizing Agents définit où et dans quelles limites l'agent s'exécute
- Les autres couches d'architecture définissent ce que fait l'agent et quelles actions sont autorisées
En bref
Containerizing Agents:
- isole l'agent dans un environnement d'exécution reproductible
- sépare code/image de la config runtime et des secrets
- ajoute des limites de ressources, health checks et contrôle de rollout
- rend le comportement en production plus stable sous charge
FAQ
Q: La containerisation garantit-elle que l'agent ne plantera pas ?
A: Non. Elle n'élimine pas toutes les erreurs, mais réduit fortement le chaos d'environnement et simplifie le recovery.
Q: Peut-on stocker des secrets dans le Dockerfile ou l'image ?
A: Mieux vaut éviter. Les secrets doivent arriver uniquement au runtime via un gestionnaire de secrets.
Q: Qu'est-ce qui est le plus important d'abord : Kubernetes ou de bonnes limites runtime ?
A: Pour la plupart des équipes, les limites, health checks et processus de rollback sont prioritaires. L'orchestrateur ne remplace pas ces règles de base.
Q: Peut-on exécuter plusieurs agents dans un seul conteneur ?
A: Oui, mais il est souvent plus difficile de gérer l'isolation, les métriques et le rollback. En général, un service séparé par rôle d'agent est plus simple.
Et Ensuite
Les conteneurs donnent un environnement stable. La suite utile est de voir comment controler cet environnement en production:
- Production Stack - comment reunir runtime, policy, memoire et ops dans un seul systeme.
- Multi-Tenant - comment isoler ressources, donnees et budgets entre clients.
- Tool Execution Layer - comment executer les actions en securite avec timeout, retry et audit.
- Human-in-the-Loop Architecture - ou ajouter une validation manuelle pour les actions a risque.