Votre requête d'agent traverse douze conteneurs. Un seul exécute un modèle.
SOIT Team

La réaction la plus fréquente devant notre quickstart, c'est que douze conteneurs font beaucoup pour une démo. La remarque est légitime, et la réponse honnête n'est pas de défendre le chiffre mais de parcourir une exécution d'agent service par service, en disant de quoi chaque conteneur répond réellement et quelle garantie disparaît si on le supprime. Un article précédent répondait à la question du minimum atteignable. Celui-ci répond à la question de savoir pourquoi les autres sont là.
Corrigeons d'abord le chiffre, car deux comptes différents circulent. La commande du quickstart nomme douze services, le fichier compose en définit quatorze. Treize démarrent réellement : minio-init n'est pas dans la commande, mais api dépend de sa bonne exécution, il est donc lancé, crée le bucket, coupe l'accès anonyme et se termine. Le quatorzième est scheduler, dont aucun service ne dépend et que le quickstart ne démarre donc jamais. Le nombre de services définis et le nombre réellement exécutés sont deux nombres distincts.
Trois conteneurs sont des tâches uniques qui se terminent avant votre première requête : migrate crée les tables, bootstrap crée l'administrateur et le tenant, minio-init prépare le bucket objet. Ils coûtent du temps de démarrage, pas de l'empreinte permanente. Deux autres sont simplement l'objet de la démonstration : api et web. Tout le reste est le registre d'exécution et les frontières qui l'entourent.
Postgres est ce registre. Une exécution est consignée dans cinq tables couvrant l'exécution elle-même, ses étapes, ses appels d'outils, ses artefacts et son coût. C'est la base physique des deux promesses faites sur chaque exécution : elle est observable et elle est rejouable. MinIO en est l'autre moitié et conserve les gros objets produits, la base ne gardant qu'une clé de stockage et un SHA-256. Ce sont aussi les deux seules barrières dures de readiness : si l'une tombe, la plateforme se déclare non prête plutôt que d'accepter des requêtes qu'elle ne saurait pas consigner.
Chacun des conteneurs restants n'achète qu'une frontière. Vault conserve les identifiants dans un magasin KV v2, pour qu'ils n'atterrissent ni dans un processus ni dans un fichier dotenv. Redis met en cache les décisions de permission avec un TTL de cinq minutes, soutient le limiteur de débit et porte le bus d'événements entre instances. Milvus fournit la recherche vectorielle, et etcd mérite d'être nommé précisément parce qu'il est une source fréquente de confusion : c'est le magasin de métadonnées de Milvus lui-même, pas une dépendance de la plateforme. Autre asymétrie voulue : une panne de Milvus fait échouer la recherche documentaire sans faire baisser le readiness.
Un conteneur ne devient intéressant qu'après le retour de la réponse. Les événements produits pendant une exécution sont écrits en base dans la même transaction que le travail ; c'est l'outbox dispatcher qui les délivre ensuite, avec une idempotence par checkpoint. Retirez-le et rien ne semble cassé pendant la requête, puisque la requête a déjà réussi : les événements restent simplement en attente pour toujours et aucun consommateur en aval ne reçoit quoi que ce soit. À savoir également : ce processus et le worker d'ingestion de connaissances sont le même code qu'api avec un autre point d'entrée.
Regroupé selon ce qu'il garantit plutôt que selon son nom, l'ensemble permanent est petit : deux conteneurs sont le produit, deux portent physiquement le registre et ses artefacts, deux et demi constituent une seule capacité, la recherche vectorielle, un assure l'isolation des secrets, un la diffusion entre réplicas et le cache, et deux sont des processus d'arrière-plan issus du même code. Un seul processus de toute la topologie exécute un modèle. Le reste du poids achète une chose : qu'après l'exécution il reste une preuve de ce qui s'est passé, et qu'un plantage à mi-course ne laisse pas un demi-état.
Le compromis en vaut-il la peine ? Cela dépend de votre usage. Pour vérifier qu'un agent mène une tâche à terme, cette pile est trop lourde, et l'article précédent montre comment la réduire à quatre conteneurs permanents. Si l'agent entre dans un processus que quelqu'un devra rapprocher ensuite, ces conteneurs sont ce que vous finiriez par écrire vous-même. Une réserve : ce parcours est une lecture statique du code et du compose, pas une nouvelle exécution de bout en bout. Le dépôt est sur github.com/soit-ai/soit et la topologie complète dans docker/docker-compose.yml.