L'idée en 30 secondes
Production Stack n'est pas un composant unique, mais un ensemble coordonné de couches d'architecture qui rendent ensemble un système d'agents gouvernable en production.
Ce n'est pas "plus de prompts". Ce sont des frontières explicites de responsabilité :
- qui prend les décisions ;
- qui autorise ou bloque une action ;
- où le state est stocké ;
- comment les risques, budgets et pannes sont contrôlés.
Quand c'est nécessaire : quand un agent doit tourner longtemps, exécuter des actions qui changent le state, servir de nombreux clients et rester prévisible sous charge.
Le LLM propose l'étape suivante, mais le Production Stack décide si cette étape peut être exécutée, où l'exécuter et comment arrêter le processus en sécurité.
Problème
Si on construit un agent comme "modèle + quelques tool calls", le système devient vite fragile.
Conséquences typiques :
- pas de stop conditions claires, donc l'agent reste bloqué dans des boucles ;
- pas de frontières de policy, donc des actions risquées passent sans contrôle ;
- pas de qualité mémoire, donc on voit des doublons, du bruit ou une personnalisation erronée ;
- pas d'isolation tenant, donc le risque de fuites cross-tenant augmente ;
- pas de discipline opérationnelle, donc rollout, rollback et réponse aux incidents deviennent chaotiques ;
- pas d'audit end-to-end, donc après une panne il est difficile d'expliquer ce qui s'est passé.
En production, cela signifie généralement incidents de sécurité, dépassements de budget et qualité de réponse instable.
Solution
Ajouter Production Stack comme schéma architectural explicite où chaque couche a un contrat clair et sa propre zone de responsabilité.
Composition typique du stack :
- Ingress + Auth (résolution actor/tenant) ;
- Orchestration Topology (route, handoff, stop) ;
- Agent Runtime (steps, limites, reason_code) ;
- Tool Execution Layer (validation et contrôle des side effects, c'est-à-dire changements d'état) ;
- Memory Layer (lecture/écriture mémoire gouvernée) ;
- Policy Boundaries + Human-in-the-Loop (autoriser, bloquer, approuver) ;
- Containerization + Observability + Operations (run reproductible, health checks, rollback) ;
- Multi-Tenant Isolation (isolation du contexte, des accès et des ressources).
Analogie : comme un aéroport moderne.
Il y a l'enregistrement, le contrôle de sécurité, le routage, la tour de contrôle, le journal d'événements et les procédures d'urgence.
Production Stack transforme de la même manière "un module intelligent" en système gouverné avec des règles d'exécution.
Comment fonctionne Production Stack
Production Stack relie toutes les frontières clés dans un cycle gouverné : de la requête entrante jusqu'à l'exécution contrôlée, l'audit et la récupération.
Vue d'ensemble du flux complet : Identify → Plan → Decide → Gate → Execute → Learn → Observe → Recover
Identify
Ingress résout actor, tenant, request_id et limites de départ.
Plan
Orchestration Topology choisit la route de la tâche : un agent, plusieurs agents ou pipeline.
Decide
Agent Runtime forme l'étape suivante selon le state courant et la mémoire.
Gate
Policy/HITL vérifie le risque, allowlist, scopes, budget et décide : allow, require_approval, deny.
Execute
Tool Execution Layer valide les arguments, exécute l'action et renvoie un résultat normalisé.
Learn
Memory Layer conserve uniquement les faits utiles et sûrs avec TTL, sans accumuler de bruit.
Observe
Trace et audit capturent décisions, reason_code, contexte et résultat d'exécution ou de blocage.
Recover
La couche Container/Ops fournit health checks, rollback, kill switch et restart contrôlé.
Ce cycle retire la "magie" du système d'agents et le rend prévisible sous charge réelle.
Dans le code, cela ressemble à ceci
class ProductionStack:
def __init__(self, ingress, topology, runtime, memory, policy, hitl, tools, audit):
self.ingress = ingress
self.topology = topology
self.runtime = runtime
self.memory = memory
self.policy = policy
self.hitl = hitl
self.tools = tools
self.audit = audit
def run(self, request, auth_token):
ctx = self.ingress.identify(request=request, auth_token=auth_token)
if not ctx.get("ok", False):
return {"ok": False, "reason_code": ctx.get("reason_code", "auth_failed")}
state = self.runtime.start(
request=request,
tenant_id=ctx["tenant_id"],
budgets=ctx["budgets"],
)
while not self.runtime.should_stop(state):
route = self.topology.next_step(state=state)
route_mode = route.get("mode")
if route_mode == "finish":
return {
"ok": True,
"result": route.get("final_answer", ""),
"reason_code": "completed",
}
if route_mode != "action":
return {"ok": False, "reason_code": "unknown_route_mode"}
memory_items = self.memory.retrieve(
tenant_id=ctx["tenant_id"],
query=route["query"],
top_k=4,
min_score=0.7,
exclude_expired=True,
)
action = self.runtime.decide(route=route, memory_items=memory_items)
decision = self.policy.check(action=action, context=ctx)
mode = decision.get("mode")
if mode == "deny":
self.audit.log(context=ctx, action=action, outcome="blocked", reason_code=decision.get("reason_code", "policy_denied"))
return {"ok": False, "reason_code": decision.get("reason_code", "policy_denied")}
elif mode == "require_approval":
approval = self.hitl.review(action=action, context=ctx)
if not approval.get("approved", False):
reason = approval.get("reason_code", "approval_rejected")
self.audit.log(context=ctx, action=action, outcome="blocked", reason_code=reason)
return {"ok": False, "reason_code": reason}
action = approval.get("action_override", action)
elif mode != "allow":
reason = decision.get("reason_code", "policy_mode_invalid")
self.audit.log(context=ctx, action=action, outcome="blocked", reason_code=reason)
return {"ok": False, "reason_code": reason}
result = self.tools.execute(action=action, context=ctx)
self.audit.log(
context=ctx,
action=action,
outcome="executed" if result.get("ok", False) else "failed",
reason_code=result.get("reason_code", "tool_unknown"),
)
self.runtime.observe(state=state, action=action, result=result)
self.memory.write_if_useful(
tenant_id=ctx["tenant_id"],
state=state,
result=result,
)
return {"ok": False, "reason_code": self.runtime.stop_reason(state)}
À quoi cela ressemble pendant l'exécution
Requête : "Prépare une proposition commerciale, aligne les points risqués et envoie la version finale au client"
Step 1
Ingress + Auth: résout actor, tenant, budgets et request_id
Orchestration Topology: découpe la tâche en étapes "collecte", "brouillon", "finalisation"
Step 2
Agent Runtime: forme action
Policy + HITL: active require_approval pour l'envoi au client
Human approuve la version finale
Step 3
Tool Execution Layer: exécute l'action approuvée
Memory Layer: stocke les faits importants avec TTL
Audit + Trace: enregistre decision, reason_code, outcome
Production Stack ne remplace pas les patterns individuels. Il les connecte en un système de production gouverné.
Quand c'est adapté et quand ça ne l'est pas
Production Stack est nécessaire là où un agent doit fonctionner comme un service, et non comme un script de démo one-shot.
Adapté
| Situation | Pourquoi Production Stack est adapté | |
|---|---|---|
| ✅ | L'agent exécute des actions state-changing dans des systèmes externes | Le stack ajoute des gates policy/HITL, le contrôle des side effects et l'audit. |
| ✅ | Le service fonctionne avec plusieurs clients et des droits d'accès différents | Les frontières multi-tenant, scoped credentials et limites par tenant réduisent le risque de fuite. |
| ✅ | Prévisibilité, SLO et postmortem clair après panne sont requis | Des stop reasons explicites, le trace et des règles opérationnelles rendent les pannes contrôlables. |
Non adapté
| Situation | Pourquoi Production Stack n'est pas adapté | |
|---|---|---|
| ❌ | Démo one-shot read-only avec un outil sûr | Le stack complet ajoute une complexité qui ne se rentabilise pas à ce stade. |
| ❌ | Prototype interne court sans exigences de compliance, d'audit et de SLA | Au départ, Runtime + limites de base suffisent souvent, puis on ajoute les autres couches progressivement. |
Pour un prototype minimal, une exécution simple suffit parfois :
result = runtime.run(task=request["text"], max_steps=8, max_seconds=20)
Problèmes et pannes typiques
| Problème | Ce qui se passe | Comment prévenir |
|---|---|---|
| Frontières de couches peu claires | La logique policy, memory et runtime se mélange au même endroit | Contrats explicites entre couches : qui décide, qui exécute, qui logge |
| Pas de limites globales | L'agent consomme trop de tokens, de steps ou de budget | Limites strictes sur steps/time/cost et stop_reason standardisé |
| Contexte policy faible | Le policy check décide sans actor/tenant/scopes | Passer le contexte complet : actor, tenant, resource, risk, budget |
| Qualité mémoire faible | L'agent personnalise la réponse sur des faits périmés ou faibles | Règles de qualité mémoire : relevance, freshness, source, sensitivity, TTL |
| Isolation tenant faible | Cache, mémoire ou credentials se mélangent entre clients | Namespace tenant-scoped, clés d'accès et budgets par tenant |
| Instabilité opérationnelle | Après le déploiement, le comportement change à cause d'une image mutable ou de dépendances non épinglées | Immutable images, pinned dependencies, health checks, canary et rollback rapide |
La plupart des problèmes de production ne viennent pas d'une seule "erreur du modèle", mais de frontières faibles entre les couches d'architecture.
Comment cela se combine avec d'autres patterns
Production Stack ne concurrence pas les autres patterns. Il les assemble en un système cohérent.
- Agent Runtime — gère la boucle de steps et les stop conditions.
- Tool Execution Layer — contrôle l'exécution des outils et les side effects (changements d'état).
- Memory Layer — lit et écrit uniquement la mémoire utile selon des critères de qualité.
- Policy Boundaries — définit allow/deny/require_approval pour les actions risquées.
- Orchestration Topologies — définit la route de la tâche entre agents.
- Hybrid Workflow Agent — sépare workflow déterministe et décisions d'agent bornées.
- Human-in-the-Loop Architecture — ajoute un contrôle humain aux points critiques.
- Containerizing Agents — fournit exécution reproductible, health checks et contrôle du rollout.
- Multi-Tenant — isole contexte, ressources et accès entre clients.
Autrement dit :
- Production Stack définit comment toutes ces couches fonctionnent ensemble comme un seul système
- Chaque pattern individuel couvre son propre type de risque spécifique
En bref
Production Stack:
- transforme un agent de démo en système de production gouverné
- sépare les responsabilités entre Runtime, policy, tools, memory et ops
- ajoute un contrôle du risque via budgets, gates d'approbation et audit
- rend le comportement de l'agent prévisible sous charge
FAQ
Q: Par quoi commencer s'il n'y a pas de ressources pour tout le stack d'un coup ?
A: Commencer par Runtime (limites + stop reasons), Tool Execution Layer (validation + timeout) et audit. Ajouter ensuite progressivement policy/HITL, qualité mémoire et isolation multi-tenant.
Q: Peut-on avoir un Production Stack avec un seul agent, sans topologie multi-agent ?
A: Oui. La topologie peut être simple, mais les autres couches restent nécessaires s'il y a des actions risquées ou de la charge production.
Q: Est-ce que Production Stack remplace observability ou les pratiques SRE ?
A: Non. Il les inclut dans l'architecture, mais exige toujours une discipline opérationnelle : monitoring, alertes, rollout et incident response.
Q: Qu'est-ce qui casse en premier quand le stack est incomplet ?
A: Le plus souvent, les frontières d'exécution cassent en premier : tool calls non contrôlés, mémoire bruyante ou trous de policy sans audit.
Et ensuite
Production Stack est la carte de tout le système. Vous pouvez maintenant approfondir les couches qui cassent le plus souvent en premier :
- Tool Execution Layer — contrôle des outils, des timeouts et des side effects (effets secondaires, c'est-à-dire changements d'état).
- Memory Layer — qualité mémoire, TTL et contrôle des données sensibles.
- Policy Boundaries — allow/deny/approval pour les actions à risque.
- Multi-Tenant — isolation du contexte, des ressources et des budgets entre clients.