Agent IA local : architecture FastAPI et RAG14 min de lecture2 844 mots

Agent IA local : architecture FastAPI et RAG

Construisez un agent IA local avec FastAPI, ChromaDB et LlamaIndex. Architecture, coûts réels, sécurité et étapes de mise en production : découvrez le guide.

agent IA localRAG localFastAPIChromaDBLlamaIndex
Agent IA local : architecture FastAPI et RAG
Agent IA local : architecture FastAPI et RAG

Construire un agent IA local sans dépendre d'API externes

Les API d'IA générative permettent de lancer un prototype en quelques heures. Mais dès que les requêtes s'accumulent, que les données deviennent sensibles ou que le service doit rester disponible, ça vaut le coup de remettre à plat le modèle économique et les dépendances techniques. Dans ce cas, la facture dépend du volume consommé, les données transitent par un fournisseur externe et une partie de la latence vous échappe.

Un agent exécuté localement peut aider à mieux tenir ces contraintes. En combinant un modèle open-weight avec FastAPI, ChromaDB et LlamaIndex, vous pouvez mettre en place une chaîne de recherche augmentée par génération (RAG) où les données restent dans votre infrastructure. En revanche, "local" ne veut pas dire "gratuit", ni automatiquement "conforme au RGPD", ni "prêt pour la production" dès le jour 1. Le matériel, l'exploitation, la sécurité et la qualité des réponses restent sous votre responsabilité.

Ce guide propose une architecture réaliste, un exemple d'implémentation et les arbitrages à faire avant de déployer. L'objectif n'est pas de remplacer à tout prix les services cloud, mais de vous aider à décider quand une approche locale a du sens - et comment la tester sans confondre démo technique et service réellement exploitable.

Pourquoi envisager un agent IA local ?

Un prototype branché à une API externe est souvent le moyen le plus rapide de valider une idée. Le problème, c'est la suite : quand vous passez au fonctionnement régulier, les sujets deviennent très concrets. En général, on se retrouve face à trois questions : le coût total, le traitement des données, et la maîtrise opérationnelle.

Le coût des API n'est qu'une partie de l'équation

Si le fournisseur facture au volume de jetons, la dépense monte avec le nombre de requêtes, la longueur du contexte et la complexité de l'agent. Un système qui enchaîne plusieurs appels (planifier, rechercher, rédiger) peut vite coûter bien plus qu'un simple échange "question-réponse".

L'inférence locale supprime la facture par jeton auprès d'un fournisseur externe. Mais elle ne supprime pas les coûts. Il faut compter les machines, les GPU (le cas échéant), l'électricité, le stockage, la maintenance et le temps passé par l'équipe. Une machine dédiée peu sollicitée peut finir par coûter plus cher qu'une API facturée à l'usage. À l'inverse, si votre service est régulièrement sollicité, l'investissement local peut se justifier.

Le bon comparatif, c'est le coût total par requête utile, pas seulement le prix d'un jeton. Pensez aussi au taux de réponses exploitables, aux reprises humaines et aux périodes de faible activité.

La confidentialité ne se résume pas à « tout reste chez nous »

Un modèle et une base hébergés dans votre infrastructure réduisent les transferts vers des tiers. C'est important pour certains documents internes, des données clients, ou des contextes réglementés. Mais l'hébergement local ne suffit pas à lui seul pour garantir la conformité au RGPD.

Il faut encore définir les finalités, limiter ce qui est collecté, gérer les droits d'accès et les suppressions, protéger les journaux et cadrer les durées de conservation. Les sauvegardes, la supervision et les accès d'administration peuvent aussi faire circuler des données. Si le sujet est sensible, impliquez le DPO et l'équipe sécurité dès le départ.

La latence et la disponibilité changent de camp

Une solution locale évite certains aléas liés à un service distant, mais elle ajoute d'autres points de panne : manque de mémoire, modèle qui ne démarre pas, disque plein, GPU saturé, ou mise à jour qui casse quelque chose. Vous contrôlez davantage la chaîne, mais vous devez aussi la faire tourner.

En pratique, le local est plus pertinent si vous devez maîtriser les flux de données, si la charge est suffisamment régulière, ou si la connectivité externe est limitée. Une API cloud reste souvent plus simple pour tester vite, encaisser des pics, ou utiliser des modèles difficiles à exécuter en interne. L'arbitrage dépend du volume, du niveau de confidentialité et de la capacité de votre équipe à assurer l'exploitation.

Architecture : FastAPI, ChromaDB, LlamaIndex et modèle local

Une architecture RAG locale découpe le travail en plusieurs responsabilités. Cette séparation aide à remplacer un composant sans tout réécrire, et surtout à repérer les problèmes au bon endroit.

Les rôles des composants

  • FastAPI expose une interface HTTP, valide les entrées (avec Pydantic) et organise l'accès au service. Elle ne doit pas porter toute la logique métier.
  • LlamaIndex orchestre l'indexation et la récupération des passages pertinents, puis transmet le contexte au modèle. Les abstractions sont pratiques, mais il faut comprendre comment le RAG fonctionne "dans le fond".
  • ChromaDB stocke les vecteurs et les métadonnées dans une collection. En mode persistant, les données restent sur disque. C'est pratique pour un prototype ou un service limité, mais il faut évaluer sauvegardes, concurrence et disponibilité avant d'en faire un socle général.
  • Ollama ou vLLM servent à exécuter un modèle local. Ollama facilite souvent le démarrage et l'expérimentation. vLLM est plutôt adapté aux contraintes de service et de débit, selon le matériel et le modèle.
  • Un modèle d'embeddings transforme documents et questions en vecteurs. Il doit être cohérent avec votre indexation et votre recherche.

Le chemin d'une requête est simple : le client envoie une question à FastAPI ; l'application récupère des passages dans ChromaDB ; LlamaIndex assemble le contexte ; le modèle local génère une réponse ; l'API renvoie le résultat. Et non : le RAG ne garantit ni la vérité, ni l'absence d'hallucinations. Il donne au modèle des éléments à exploiter, et la qualité dépend autant de l'index que de la requête.

L'ingestion est aussi importante que la génération

Une base vectorielle vide n'est pas une base de connaissances. Le cœur du travail, c'est une chaîne d'ingestion : documents autorisés, extraction du texte, découpage en segments, calcul des embeddings, puis enregistrement des métadonnées utiles (source, date, catégorie, niveau de confidentialité).

Le découpage doit coller à la structure des documents. Des segments trop courts perdent du contexte ; des segments trop longs rendent la recherche moins précise et augmentent la quantité de texte envoyée au modèle. Il n'y a pas de taille universelle : testez avec vos documents et vos questions réelles.

Pensez aussi à la mise à jour et à la suppression. Si un document change, votre index doit refléter ce changement. Une réindexation contrôlée vaut mieux que des ajustements manuels impossibles à reproduire.

Schéma de la chaîne

Client

│ HTTP

▼

FastAPI ── validation, authentification, limites d'usage

│

├── LlamaIndex ── orchestration de la recherche et du contexte

│ │

│ ├── ChromaDB ── vecteurs, métadonnées, passages retrouvés

│ └── Modèle d'embeddings local

│

└── Serveur d'inférence ── Ollama ou vLLM ── modèle open-weight

Cette architecture peut réduire certains coûts variables d'API, mais elle ne donne pas automatiquement une capacité de mise à l'échelle "propre". Plusieurs instances FastAPI partageant un stockage local ne suffisent pas, à elles seules, à faire un système distribué robuste. Si la charge augmente, il faudra regarder le service d'inférence, les files d'attente, le stockage partagé et les mécanismes de reprise.

Construire un premier service exploitable

Le code ci-dessous sert d'exemple pour une route, pas de plateforme complète. Il suppose que la collection a déjà été alimentée et que les versions des dépendances sont figées. Les interfaces LlamaIndex évoluent : vérifiez les méthodes correspondant à votre version, puis testez le démarrage dans votre environnement cible.

Installer et préparer le modèle

Installez les dépendances Python, puis lancez un modèle compatible via Ollama ou un serveur d'inférence équivalent. Le modèle doit être disponible avant l'appel à l'API. En contexte pro, épinglez les versions et les révisions : une mise à jour peut changer les performances ou le comportement.

Pour les embeddings, choisissez un modèle adapté à la langue et à vos documents. Si votre corpus est majoritairement en français, testez la qualité de recherche sur des questions en français, au lieu de réutiliser "par défaut" un modèle conçu pour un exemple anglophone.

Exemple de route FastAPI

from fastapi import FastAPI, HTTPException

from fastapi.concurrency import run_in_threadpool

from pydantic import BaseModel, Field

from llama_index.core import Settings, VectorStoreIndex

from llama_index.embeddings.huggingface import HuggingFaceEmbedding

from llama_index.llms.ollama import Ollama

from llama_index.vector_stores.chroma import ChromaVectorStore

import chromadb

app = FastAPI(title="Passerelle d'agent IA local")

Settings.llm = Ollama(model="llama3:8b", request_timeout=60.0)

Settings.embed_model = HuggingFaceEmbedding(

model_name="BAAI/bge-m3"

)

client = chromadb.PersistentClient(path="./chroma_storage")

collection = client.get_or_create_collection("base_metier")

vector_store = ChromaVectorStore(chroma_collection=collection)

index = VectorStoreIndex.from_vector_store(vector_store)

query_engine = index.as_query_engine(similarity_top_k=4)

class Requete(BaseModel):

question: str = Field(min_length=3, max_length=4000)

class Reponse(BaseModel):

reponse: str

statut: str

@app.post("/api/v1/question", response_model=Reponse)

async def poser_question(payload: Requete):

try:

resultat = await run_in_threadpool(

query_engine.query, payload.question

)

return Reponse(reponse=str(resultat), statut="ok")

except Exception as exc:

raise HTTPException(

status_code=502,

detail="Le service de recherche ou d'inférence est indisponible.",

) from exc

L'appel à run_in_threadpool évite de bloquer la boucle asynchrone de FastAPI avec une opération synchrone. Dans une version plus complète, privilégiez une intégration réellement asynchrone si c'est disponible et compatible avec vos composants. Et surtout : ne renvoyez pas au client les détails internes d'une exception. Ils peuvent révéler des chemins, des paramètres ou des infos sensibles.

Cet exemple omet volontairement l'authentification, la limitation de débit, l'ingestion et une journalisation structurée. Ne le mettez pas tel quel sur Internet. Ajoutez ces briques selon votre niveau de risque et le type d'utilisateurs.

Tester la qualité avant de parler de production

Avant d'ajuster les paramètres, préparez un jeu de questions représentatives. Pour chaque question, notez les documents attendus, les passages utiles et ce qui ferait une réponse acceptable. Mesurez séparément :

  • la pertinence des passages récupérés ;
  • la fidélité de la réponse aux sources ;
  • le temps de réponse, avec et sans charge ;
  • le taux d'erreurs et les réponses sans résultat exploitable ;
  • le comportement face à une question absente de la base.

Un similarity_top_k de trois ou quatre peut servir de point de départ, pas de règle. Plus de passages peuvent améliorer le rappel, mais aussi augmenter le bruit, la latence et la taille du contexte. Ajustez avec votre corpus et vos cas métier.

Sécurité, coûts et limites en production

"Sans coût d'API" décrit le mode de facturation, mais c'est une description incomplète du coût réel d'exploitation. Pour trancher, comparez les options sur une période cohérente (par exemple un mois ou un an) et incluez le coût des ressources sous-utilisées, ainsi que les pics de demande.

Une liste de contrôle de mise en production

Avant d'ouvrir le service à des utilisateurs, vérifiez :

  • Accès : authentification, autorisation par utilisateur ou équipe, et règles sur les documents consultables.
  • Protection : chiffrement des échanges, gestion des secrets, mises à jour et isolement du processus d'inférence.
  • Données : conservation, suppression, sauvegarde et restauration de la base vectorielle.
  • Résilience : timeouts, contrôle de concurrence, gestion des pannes du modèle et erreurs compréhensibles.
  • Observabilité : latence, mémoire, erreurs, disponibilité, sans stocker inutilement des prompts sensibles.
  • Évaluation : tests de non-régression après un changement de modèle, d'embeddings, de découpage ou de prompt.
  • Sécurité des entrées : tests d'injection de prompt et mécanismes pour empêcher un document retrouvé de court-circuiter les règles système.

Un document indexé peut contenir des instructions malveillantes ou trompeuses. Le modèle doit traiter le contenu retrouvé comme des données, pas comme une autorité capable de modifier les règles de l'application. Ça réduit le risque, sans l'annuler : les opérations sensibles doivent rester soumises à des contrôles explicites.

Choisir un modèle en fonction du cas d'usage

Un modèle open-weight plus petit peut suffire si vous faites surtout du classement, du résumé ou de la recherche sur un corpus maîtrisé. Il peut aussi être trop lent ou produire des réponses de mauvaise qualité sur des tâches plus difficiles. La quantification aide souvent à réduire les besoins en mémoire, au prix d'un compromis sur la qualité. Le point clé : mesurez sur votre matériel et vos scénarios, pas uniquement sur des benchmarks "génériques".

Pour un outil interne utilisé par quelques dizaines de personnes, une machine correctement dimensionnée peut suffire. Pour un produit exposé à des pics, l'inférence peut devenir le goulot d'étranglement principal. Dans ce cas, les GPU, la gestion des files et la supervision comptent vraiment.

Local, cloud ou hybride ?

Approche Intérêt principal Coût ou contrainte à surveiller
API cloud Démarrage rapide et modèles performants Facturation à l'usage, dépendance et transfert de données
Modèle local Maîtrise de l'environnement et coût par requête plus prévisible Matériel, exploitation et capacité limitée
Architecture hybride Choix du modèle selon la sensibilité ou la tâche Routage, gouvernance et complexité supplémentaires

Une stratégie hybride peut être pragmatique : traiter localement les documents sensibles ou les tâches simples, puis utiliser un service externe pour les demandes qui nécessitent ses capacités. Mais il ne faut pas en faire une boîte noire qui transfère des données "au hasard". Définissez les règles de routage, documentez-les et vérifiez les flux observés.

Faire de la documentation technique un outil de validation

Publier un tutoriel public peut attirer des développeurs, mais sa valeur ne tient pas à un titre "coûts nuls". Ce qui compte, c'est la reproductibilité : installation, compromis assumés, et résultats vérifiables. Mettez en ligne un dépôt avec des versions explicites, des commandes de lancement, des tests et des limites connues. Indiquez aussi le matériel et les mesures obtenues : sans contexte, un benchmark se lit mal.

Sur Dev.to ou ailleurs, une structure efficace consiste à décrire le problème, présenter le schéma d'architecture, détailler les étapes de reproduction et partager les résultats. Les tags aident à classer, mais ils ne remplacent pas une démonstration. Vous pouvez mentionner une offre commerciale à la fin si elle apporte vraiment du code, des tests ou un gain de temps clair. La confiance s'abîme vite quand un article technique ressemble à une pub déguisée.

Pour aller plus loin, consultez la documentation de FastAPI, le guide ChromaDB et la documentation LlamaIndex. Ces ressources sont plus fiables pour vérifier les API et les options de déploiement que des extraits copiés sans versions.

Conclusion : décider à partir d'un cas d'usage

Un agent IA local construit avec FastAPI, ChromaDB, LlamaIndex et un modèle open-weight est une option crédible quand la maîtrise des données, la prévisibilité des coûts ou l'autonomie opérationnelle comptent vraiment. Mais ce n'est pas juste "remplacer une clé d'API par un modèle téléchargé". Il faut aussi gérer l'ingestion, les performances, la sécurité, les mises à jour et la qualité des réponses.

Commencez par un périmètre limité, rassemblez des questions représentatives, puis comparez une approche locale et une API en regardant le coût complet, la latence et la qualité. Si le local tient la route avec une charge d'exploitation acceptable, élargissez progressivement. Sinon, gardez le cloud ou passez par une approche hybride.

La prochaine étape, concrètement : choisissez un corpus non critique, mesurez une première chaîne RAG de bout en bout, et documentez ses limites avant de brancher des données métier. C'est ce test, pas la promesse de "coûts nuls", qui dira si l'architecture mérite d'aller en production.

Questions frequentes

Non. Il peut supprimer la facturation par jeton d’un fournisseur externe, mais il faut financer les machines, l’électricité, le stockage, la maintenance et le temps d’exploitation. Comparez le coût total sur votre volume réel : une API peut rester plus économique pour un usage irrégulier ou limité.
Non. Le traitement local réduit certains transferts, mais la conformité dépend aussi des finalités, des accès, de la conservation, des sauvegardes et des journaux. Cartographiez les données et impliquez les responsables concernés avant le déploiement, notamment si le système traite des informations personnelles ou sensibles.
Il peut convenir à des services dont les besoins de volume, de concurrence et de disponibilité sont compatibles avec le mode de déploiement retenu. Il faut tester les sauvegardes, les restaurations et les accès concurrents. Pour des exigences plus fortes ou une architecture distribuée, comparez d’autres solutions et mesurez les contraintes opérationnelles.
Ollama facilite généralement l’exécution locale et les premiers essais. vLLM vise davantage le service de modèles et le débit dans des environnements adaptés. Le choix dépend du matériel, du nombre de requêtes simultanées, du modèle et de la capacité de l’équipe à exploiter l’infrastructure.

Articles similaires