Écho Rapport technique POC RAG · v1
Logo Écho
Projet 9 OpenClassrooms
POC RAG · Puls-Events
Python 3.12 LangChain Mistral AI FAISS FastAPI

Rapport technique

Écho — Assistant intelligent de recommandation d'événements culturels

Système RAG construit autour d'OpenAgenda pour proposer des événements culturels du Bassin d'Arcachon.

Rapport technique - Écho, assistant intelligent de recommandation d’événements culturels

1. Objectifs du projet

Contexte

Puls-Events souhaite proposer un assistant intelligent capable d’aider les utilisateurs à trouver des événements culturels pertinents autour du Bassin d’Arcachon, à partir de données issues d’OpenAgenda exposées via Opendatasoft.

Le projet consiste à concevoir un système RAG, c’est-à-dire un système qui combine :

L’application développée dans le cadre du POC s’appelle Écho.

Problématique

Les événements culturels sont souvent décrits dans des formats hétérogènes : descriptions longues ou courtes, champs parfois incomplets, dates multiples, lieux différents, liens externes, images et métadonnées diverses.

Un système RAG répond à ce besoin car il permet de :

L’objectif n’est donc pas seulement de poser une question à un modèle de langage, mais de lui fournir un contexte fiable issu des événements collectés.

Objectif du POC

Le POC doit démontrer la faisabilité technique d’un assistant culturel basé sur un système RAG.

Les objectifs principaux sont :

Périmètre

Le périmètre du POC est volontairement limité afin de rester simple et maîtrisable.

Le corpus utilisé est composé d’événements OpenAgenda autour du Bassin d’Arcachon. Les données sont préparées localement, puis sauvegardées dans le dépôt sous forme de fichiers générés non versionnés.

Le POC implémente et teste l’ensemble de la chaîne RAG : préparation des données, chunking, embeddings Mistral, index FAISS LangChain, recherche sémantique, génération Mistral, API FastAPI et évaluation automatique sur un jeu annoté.

2. Architecture du système

Diagramme UML de composants

Le diagramme regroupe les éléments du système Écho en quatre zones : l'application Écho (API, service RAG, retriever), le service externe de génération (Mistral LLM), l'index vectoriel (FAISS) et le pipeline de données (OpenAgenda → préparation → embeddings).

Diagramme UML de composants — Écho

Le diagramme se lit en deux flux :

Données entrantes

Les données entrantes proviennent d’OpenAgenda via l’API Opendatasoft. Le pipeline de collecte et de préparation est découpé en scripts courts, chacun responsable d’une étape précise.

Étape Script Rôle Sortie principale
Collecte 01_fetch_openagenda_events.py Récupérer les événements bruts depuis OpenAgenda. data/raw/openagenda_events_raw.json
Filtrage 02_filter_openagenda_events.py Conserver le périmètre géographique et temporel du POC. data/processed/events_filtered.json
Nettoyage 03_clean_openagenda_events.py Normaliser les textes, les dates et les métadonnées utiles. data/processed/events_clean.json
Documents RAG 04_build_event_documents.py Transformer les événements nettoyés en documents indexables. data/processed/events_documents.jsonl

Le fichier events_documents.jsonl est ensuite utilisé pour construire le vector store FAISS.

Les scripts sont situés dans le dossier scripts/.

Prétraitement, embeddings et base vectorielle

Les événements nettoyés sont transformés en documents Markdown. Ce format reste lisible par un humain tout en donnant au modèle un texte structuré à indexer.

Exemple court de document indexable :

# Initiation à l'astronomie à Lanton

Ville : Lanton
Date : 5 janvier 2026

Découverte du ciel et initiation à l'observation astronomique.

Ces documents sont ensuite découpés en chunks, puis vectorisés avec le modèle d’embedding Mistral.

Les vecteurs et leurs métadonnées sont stockés dans un vector store FAISS LangChain (langchain_community.vectorstores.FAISS), qui les sauvegarde localement sous forme de deux fichiers index.faiss + index.pkl.

Intégration LLM

L’intégration avec le modèle de langage est portée par la classe RagService, dans echo_app/rag/rag_service.py. Cette classe orchestre :

  1. la recherche sémantique via le retriever LangChain obtenu avec vectorstore.as_retriever(search_kwargs={"k": top_k}), appelé par retriever.invoke(question) ;
  2. la construction d’un contexte numéroté à partir des Document retrouvés : chaque chunk est préfixé par [1], [2], etc. pour distinguer les sources utilisées ;
  3. la construction d’un message utilisateur combinant ce contexte et la question ;
  4. l’appel à Mistral via client.chat.complete() ;
  5. l’extraction d’une liste de sources lisibles, dédoublonnée par event_id.

Exemple simplifié de contexte envoyé au modèle :

[1] Initiation à l'astronomie — Lanton
Découverte du ciel et observation des étoiles.

---
[2] Nuit des étoiles — Le Teich
Animation autour de l'observation astronomique.

Le message utilisateur final combine ensuite ce contexte avec la question :

Contexte :
[1] Initiation à l'astronomie — Lanton
...

Question :
Quels événements autour de l'astronomie sont proposés ?

Cette numérotation facilite la traçabilité entre les chunks retrouvés, la réponse générée et les sources affichées.

Le modèle de génération utilisé est mistral-small-latest, configurable via la variable d’environnement MISTRAL_MODEL. Le client Mistral est créé uniquement au moment de générer une réponse, ce qui permet d’instancier RagService sans clé API en environnement de test.

Exposition via API

L’API FastAPI est implémentée dans echo_app/api/. Elle expose les endpoints nécessaires au POC : vérification de santé, métadonnées techniques, question au chatbot et reconstruction locale de l’index.

La logique RAG reste isolée dans echo_app/rag/rag_service.py : l’API ne fait que valider les requêtes, appeler le service métier et formater les réponses. Les endpoints, les formats de requête/réponse et les choix de gestion d’erreur sont détaillés dans la section 6. API et endpoints exposés.

Attention

POST /rebuild est utile pour le POC local, mais il devrait être protégé ou remplacé par une tâche interne si l’API était exposée en production.

Technologies utilisées

Les principales technologies utilisées sont :

3. Préparation et vectorisation des données

Source de données

Les événements sont collectés depuis OpenAgenda. La collecte récupère des événements culturels, puis le pipeline applique un filtrage afin de conserver un périmètre cohérent avec le POC.

Note

Une date de référence fixe (2026-05-01) est utilisée pour rendre le POC reproductible et obtenir des résultats stables pendant le développement.

Exemple simplifié de donnée OpenAgenda avant préparation :

{
  "title": "Initiation à l'astronomie à Lanton",
  "location_city": "Lanton",
  "description": "<p>Découverte du ciel...</p>",
  "firstdate_begin": "2026-01-05T19:30:00+00:00"
}

Nettoyage des données

Les événements bruts contiennent des champs hétérogènes. Le nettoyage permet de produire des données plus régulières et plus faciles à indexer.

Les traitements réalisés incluent notamment :

Les URL ne sont pas intégrées dans le texte indexable. Elles sont conservées dans les métadonnées afin de pouvoir être affichées après la recherche.

Par exemple, un fragment HTML comme <p>Découverte du ciel...</p> est converti en texte simple : Découverte du ciel....

Construction des documents RAG

Chaque événement est transformé en document RAG.

Chaque document contient :

Exemple de métadonnées conservées avec le document :

{
  "event_id": "13708573",
  "title": "Initiation à l'astronomie à Lanton",
  "city": "Lanton",
  "start_date": "2026-01-05T19:30:00+00:00",
  "url": "https://openagenda.com/...",
  "latitude": 44.704,
  "longitude": -1.039
}

Cette séparation permet de garder un texte propre pour les embeddings, tout en conservant les informations utiles pour l’affichage des résultats.

Exemple court de document Markdown produit pour l’indexation :

# Initiation à l'astronomie à Lanton

Ville : Lanton
Date : 5 janvier 2026
Lieu : Lanton

Découverte du ciel et initiation à l'observation astronomique.

Chunking

Avant la vectorisation, les documents sont découpés en chunks.

L’objectif du chunking est d’éviter d’envoyer des textes trop longs au modèle d’embedding et d’améliorer la précision de la recherche. Un chunk représente un morceau de document qui peut être retrouvé indépendamment dans l’index FAISS.

La stratégie retenue est volontairement simple :

Les paramètres principaux sont :

CHUNK_SIZE = 1200
CHUNK_OVERLAP = 150
MIN_CHUNK_SIZE = 200
Note

Cette stratégie a été retenue car le corpus OpenAgenda utilisé contient majoritairement des documents courts. Un découpage plus complexe, par structure Markdown ou par phrases avec spaCy, a été exploré dans le notebook, mais il n’a pas été conservé dans le pipeline principal afin de garder une solution simple, robuste et facile à maintenir.

Génération des embeddings

Chaque chunk est transformé en vecteur numérique avec le modèle d’embedding Mistral.

Le modèle utilisé est mistral-embed, qui produit des vecteurs de dimension 1024.

La génération des embeddings est faite par batchs. Un batch est différent d’un chunk : le chunk correspond à une unité de contenu indexée, tandis que le batch est seulement un regroupement technique de plusieurs chunks envoyés ensemble à l’API Mistral.

Cette logique permet d’éviter de faire un appel API séparé pour chaque chunk.

Le pipeline vérifie également que les embeddings retournés ont bien la dimension attendue avant de les envoyer à FAISS. Cela évite de construire un index incohérent.

4. Choix du modèle NLP

Modèle d’embedding

Pour la vectorisation, le modèle retenu est : mistral-embed.

Utiliser Mistral pour les embeddings et la génération permet de garder une configuration homogène : une seule clé API, une seule bibliothèque Python et des modèles compatibles avec le reste de la chaîne RAG.

Les raisons principales sont :

Modèle de génération

Le modèle de génération est utilisé pour produire la réponse finale à partir des chunks retrouvés par la recherche sémantique.

Le modèle par défaut est : mistral-small-latest.

Il est configurable via la variable d’environnement MISTRAL_MODEL. L’appel est effectué via client.chat.complete() de la bibliothèque Python Mistral, dans la méthode _generate_answer() de RagService. Cette méthode est isolée pour faciliter les tests avec un faux client Mistral.

Important

Résilience face aux erreurs Mistral

Mistral peut renvoyer ponctuellement un HTTP 429 avec le message service_tier_capacity_exceeded lorsque le modèle est temporairement saturé côté serveur. Pour absorber ces pics, _generate_answer() retente l’appel une seule fois après 2 secondes lorsque l’erreur correspond à ce cas, et laisse remonter toute autre exception sans retry. Cette stratégie est volontairement simple (pas de backoff exponentiel ni de bibliothèque externe) et reste facile à expliquer.

Prompting

Les prompts sont versionnés dans echo_app/rag/prompts.py :

Cette séparation permet de faire évoluer le cadrage métier sans modifier directement le service RAG.

Le prompt envoyé à Mistral est composé de deux messages :

Message Rôle
system Définit la persona Écho et les règles de réponse.
user Contient les chunks retrouvés par FAISS, puis la question posée.

Les règles principales du message système sont volontairement simples : répondre en français, utiliser uniquement le contexte fourni, ne pas inventer d’événement, et signaler clairement quand le contexte ne permet pas de répondre.

Le message utilisateur contient un contexte numéroté ([1], [2], etc.) afin de faciliter la traçabilité entre les chunks retrouvés, la réponse générée et les sources affichées.

Dans cette partie, LangChain sert surtout à assembler les messages envoyés au modèle grâce à ChatPromptTemplate. Son rôle dans la recherche vectorielle est détaillé dans la section 5. Base vectorielle et recherche sémantique.

Les messages obtenus sont ensuite convertis en dictionnaires simples, compatibles avec client.chat.complete() de la bibliothèque Python Mistral.

Le paramètre temperature=0.2 est utilisé pour limiter la créativité du modèle et privilégier des réponses ancrées dans le contexte.

Note

Aucun historique conversationnel n’est utilisé : chaque question est traitée indépendamment. Ce choix garde le POC simple et limite les effets de bord.

Si la recherche FAISS ne retourne aucun résultat, le service n’appelle pas le modèle. Il renvoie directement une réponse explicite avec une liste de sources vide. Cela évite un appel API inutile et garantit un comportement déterministe.

Limites du modèle

La qualité des réponses dépendra de plusieurs facteurs :

L’utilisation d’un système RAG réduit le risque de réponse inventée, mais ne le supprime pas complètement. L’évaluation automatique repose sur un jeu annoté de 15 questions, qui peut être enrichi pour obtenir une mesure plus robuste.

5. Base vectorielle et recherche sémantique

Intégration avec LangChain

Le système utilise le vector store FAISS fourni par LangChain (langchain_community.vectorstores.FAISS). Les chunks OpenAgenda sont convertis en objets Document, indexés avec les embeddings Mistral, puis sauvegardés localement dans vector_store/.

LangChain apporte trois abstractions utiles dans le projet :

Élément Rôle dans Écho
Document Associer un texte de chunk à ses métadonnées.
FAISS Stocker les vecteurs et effectuer la recherche de similarité.
Retriever Interroger FAISS depuis RagService avec .as_retriever(search_kwargs={"k": 5}).

Au moment de répondre à une question, RagService charge l’index, récupère les documents pertinents avec le retriever, puis transmet leur contenu à la chaîne de génération.

Recherche vectorielle

Le vector store LangChain s’appuie sur un index FAISS IndexFlatL2. Ce choix est adapté au POC car le volume de données est faible, l’index est simple à construire et la recherche reste exacte.

IndexFlatL2 compare les vecteurs avec une distance L2 : plus la distance est faible, plus le chunk est proche de la question utilisateur.

Dans le corpus utilisé, le pipeline produit 138 documents OpenAgenda, découpés en 155 chunks. Chaque chunk reçoit un embedding, ce qui donne 155 vecteurs dans FAISS.

Note

Le nombre de vecteurs est supérieur au nombre de documents, car certains événements longs sont découpés en plusieurs chunks.

Persistance de l’index

Le vector store est sauvegardé localement dans le dossier vector_store/ avec le format LangChain :

Fichier Contenu
vector_store/index.faiss Vecteurs numériques utilisés par FAISS.
vector_store/index.pkl Docstore LangChain : texte des chunks et métadonnées associées.

Ces fichiers sont générés localement et ne sont pas versionnés dans Git. Le script de reconstruction nettoie aussi les fichiers résiduels éventuels afin de garder un dossier vector_store/ cohérent.

Métadonnées associées

Les métadonnées des événements sont conservées dans les Document LangChain associés aux chunks. Elles ont déjà été préparées lors de la construction des documents RAG, puis sont réutilisées après la recherche pour afficher les sources.

Après une recherche vectorielle, retriever.invoke(question) retourne une liste de Document : le texte du chunk est disponible dans page_content, et les informations utiles à l’affichage des sources restent disponibles dans metadata.

Reconstruction de l’index

L’index peut être reconstruit avec la commande suivante :

poetry run python scripts/rebuild_index.py

Cette commande régénère entièrement le vector store à partir des documents pré-processés :

  1. charger data/processed/events_documents.jsonl ;
  2. construire les chunks ;
  3. générer les embeddings Mistral ;
  4. convertir les chunks en Document LangChain ;
  5. construire le vector store FAISS ;
  6. sauvegarder index.faiss et index.pkl dans vector_store/.
Note

L’index est reconstruit entièrement plutôt que mis à jour partiellement.

6. API et endpoints exposés

Framework utilisé

L’API du projet est implémentée avec FastAPI, dans le dossier echo_app/api/.

FastAPI est utilisé car il permet de construire une API Python typée, documentée automatiquement via Swagger, et facile à tester avec TestClient.

Exécution locale avec Docker

L’API peut être lancée localement avec Docker Compose. Cette approche permet de tester le service dans un environnement reproductible, sans dépendre directement de l’environnement Python local.

docker compose up --build

Au démarrage, l’application affiche l’URL de la documentation Swagger afin de faciliter les tests manuels dans le navigateur : http://127.0.0.1:8000/docs.

Note

Le vector store FAISS doit être disponible localement dans vector_store/ pour que l’API puisse répondre aux questions. Il reste généré localement et n’est pas versionné dans Git.

Endpoints exposés

L’API expose quatre endpoints principaux :

Endpoint Rôle
GET /health Vérifie que l’API répond avec un statut minimal.
GET /metadata Expose des informations techniques non sensibles sur le système RAG : disponibilité du vector store, nombre de chunks, modèles utilisés, dernier rebuild.
POST /ask Reçoit une question utilisateur et retourne une réponse générée avec ses sources.
POST /rebuild Reconstruit localement l’index FAISS avec une confirmation explicite (confirm=true).

La documentation interactive Swagger est générée automatiquement par FastAPI et disponible sur /docs lorsque l’API est lancée localement.

Séparation API / logique métier

La couche API ne réimplémente pas la logique RAG. L’endpoint POST /ask appelle directement RagService.ask(question), qui orchestre le retriever FAISS LangChain, la construction du contexte, le prompt LangChain et l’appel Mistral.

La reconstruction de l’index est portée par echo_app.indexing.rebuild.rebuild_index(). Cette fonction est utilisée à la fois par le script CLI scripts/rebuild_index.py et par l’endpoint POST /rebuild, ce qui évite de dupliquer la logique.

Format des requêtes et réponses

Exemple de requête pour /ask :

{
  "question": "Quels événements autour de l’astronomie sont disponibles ?"
}

Exemple de réponse :

{
  "question": "Quels événements autour de l’astronomie sont disponibles ?",
  "answer": "...",
  "sources": [
    {
      "event_id": "13708573",
      "title": "Initiation à l'astronomie à Lanton",
      "city": "Lanton",
      "start_date": "2026-01-05T19:30:00+00:00",
      "url": "https://openagenda.com/..."
    }
  ]
}

GET /metadata n’expose pas de clé API ni de chemin local absolu. Les noms de modèles (mistral-embed, mistral-small-latest) sont des informations techniques non sensibles.

Tests et gestion des erreurs

Les tests API sont regroupés dans tests/test_api.py. Ils utilisent TestClient et des fakes pour éviter tout appel réel à Mistral ou tout chargement réel de FAISS pendant les tests unitaires.

Les principaux comportements testés sont :

Un script fonctionnel manuel scripts/api_test.py permet également de tester une API déjà lancée localement. Par défaut, il vérifie /health, /metadata, /ask et le refus de /rebuild sans confirmation. Le rebuild réel est optionnel afin d’éviter des appels Mistral coûteux pendant un test rapide.

7. Évaluation du système

L’évaluation automatique est implémentée via scripts/08_evaluate_rag.py. Elle rejoue 15 questions issues d’un jeu annoté et calcule deux familles de métriques :

Jeu de test annoté

Le jeu de questions/réponses annoté est stocké dans data/evaluation/qa_annotated.csv. Il contient 15 questions couvrant plusieurs intentions du chatbot Écho : astronomie, exposition, nature, vélo, famille, commune, spectacle, patrimoine, santé, retraite, emploi et mobilité.

Note

Le jeu contient aussi un cas hors sujet lié à une demande de restaurant, afin de vérifier que le système ne force pas une réponse quand le contexte ne le permet pas.

Chaque ligne du CSV contient cinq colonnes :

Exemples de lignes du jeu annoté :

Question Attendu Type de cas
Quels événements autour de l'astronomie sont disponibles ? Retrouver l’événement d’initiation à l’astronomie à Lanton. Requête thématique précise
Peux-tu me conseiller un restaurant à Arcachon ? Répondre prudemment que le contexte ne permet pas de recommander un restaurant. Cas hors sujet

Ce jeu sert de base à l’évaluation automatique : le script vérifie notamment les sources attendues et la présence de mots-clés dans la réponse générée.

Méthode d’évaluation

La méthode d’évaluation repose sur deux étapes :

  1. exécuter la chaîne RAG sur chaque question annotée pour récupérer la réponse, les sources et les chunks utilisés ;
  2. transmettre ces éléments à Ragas pour calculer les métriques d’évaluation.

Le LLM juge utilisé par Ragas est mistral-large-latest. Il est volontairement différent du modèle de génération d’Écho (mistral-small-latest) : il respecte mieux les schémas de sortie attendus par Ragas. Ce choix concerne uniquement l’évaluation et ne modifie pas la chaîne RAG utilisée pour répondre aux utilisateurs.

Note

L’évaluation peut déclencher plusieurs appels Mistral supplémentaires, car Ragas utilise un LLM juge et des embeddings pour calculer ses métriques.

Les métriques Ragas utilisées sont :

Métrique Ce qu’elle vérifie
faithfulness La réponse reste fidèle aux contextes récupérés.
answer_relevancy La réponse est pertinente par rapport à la question.
context_precision Les chunks pertinents sont bien placés dans les résultats.
context_recall Le retrieval couvre les informations attendues.
Attention

La métrique answer_relevancy est instanciée avec strictness=1 pour éviter un problème d’agrégation observé avec langchain-mistralai 1.1.4. Le score est donc un peu moins robuste que le réglage par défaut, mais l’évaluation reste reproductible.

Des métriques maison complètent Ragas pour faciliter la relecture manuelle :

Métrique Rôle
keyword_match_rate Vérifier la présence des mots-clés attendus dans la réponse.
event_recall Vérifier la présence des événements attendus dans les sources.
sources_count Contrôler le nombre de sources affichées.
status Résumer le résultat en ok, partial ou ko.

Les résultats sont versionnés dans data/evaluation/ :

Important

Cette évaluation ne remplace pas une revue humaine, mais elle donne une base reproductible pour repérer les régressions. La génération est stabilisée avec SEED=42 et temperature=0.2 côté chaîne RAG, temperature=0 côté juge Ragas.

Le notebook notebooks/04_rag_evaluation.ipynb permet de visualiser le jeu annoté, les résultats générés et les cas partial / ko. Il lit les fichiers CSV/JSON déjà produits et ne relance pas les appels Mistral à l’ouverture.

Analyse des erreurs

L’évaluation lancée sur les 15 questions annotées avec le pipeline final donne le résumé suivant :

Indicateur Valeur
Questions évaluées 15
ok 14
partial 1
ko 0
keyword_match_rate moyen 0.830
event_recall moyen 0.811
faithfulness moyen 0.927
answer_relevancy moyen 0.828
context_precision moyen 0.942
context_recall moyen 0.867

Les 4 métriques Ragas sont calculées pour les 15 questions, sans valeur manquante. Elles montrent une chaîne RAG globalement fiable :

Une seule question est classée partial :

Note

Aucun cas n’est classé ko.

Limites connues de l’évaluation :

Les améliorations réalistes seraient :

Validation technique

La recherche sémantique peut être vérifiée manuellement avec le script suivant :

poetry run python scripts/06_test_semantic_search.py

Exemples de requêtes utilisées :

Résultats observés

La requête astronomie retrouve bien les chunks associés à l’événement :

Initiation à l'astronomie à Lanton

Cela valide le fonctionnement de la chaîne : requête utilisateur → embedding Mistral via l’adaptateur LangChain → retriever FAISS LangChain → récupération des documents pertinents → contexte RAG + sources.

Certaines requêtes composées donnent des résultats moins précis. Par exemple, une requête combinant un type d’événement et une commune peut favoriser la commune plutôt que le type d’événement.

Cette limite vient du fonctionnement d’une recherche sémantique brute, sans filtre métier ni reranking.

8. Recommandations et perspectives

Ce qui fonctionne bien

Le POC valide plusieurs briques importantes :

Limites du POC

Le POC présente plusieurs limites :

Améliorations possibles

Les améliorations possibles sont :

9. Organisation du dépôt GitHub

L’organisation du dépôt est la suivante :

oc_project9_rag/
├── data/                  # Données brutes et transformées, non versionnées
├── docs/                  # Documentation projet et rapport technique
├── Dockerfile             # Image Docker de l’API
├── docker-compose.yml     # Lancement local de l’API avec Docker Compose
├── echo_app/              # Code de l’application Écho
│   ├── api/               # API FastAPI
│   ├── indexing/          # Embeddings, FAISS et recherche sémantique
│   └── rag/               # Chaîne RAG 
├── notebooks/             # Notebooks d’exploration et de validation
├── scripts/               # Scripts exécutables du pipeline
├── src/                   # Fonctions communes de collecte, nettoyage, documents et chunking
├── tests/                 # Tests automatisés
└── vector_store/          # Index FAISS généré localement, non versionné

Fichiers et dossiers clés

Les principaux fichiers et dossiers sont :

10. Annexes

Commandes utiles

Reconstruction de l’index :

poetry run python scripts/rebuild_index.py

Lancement de l’API locale avec Docker Compose :

docker compose up --build

Test fonctionnel de l’API locale déjà lancée :

poetry run python scripts/api_test.py

Test manuel de la chaîne RAG complète :

poetry run python scripts/07_test_rag_service.py

Tests automatisés :

poetry run pytest -v

Exemple de test API local

Après lancement avec Docker Compose, les endpoints peuvent être testés avec curl.

Vérification de l’état de l’API :

curl -X GET http://127.0.0.1:8000/health

Réponse obtenue :

{
  "status": "ok",
  "service": "echo-rag-api",
  "rag_service_ready": true
}

Consultation des métadonnées techniques :

curl -X GET http://127.0.0.1:8000/metadata

Réponse obtenue :

{
  "service": "echo-rag-api",
  "rag_service_ready": true,
  "vector_store_available": true,
  "chunks_count": 155,
  "top_k_default": 5,
  "last_rebuild_at": "2026-05-18T13:49:17Z",
  "embedding_model": "mistral-embed",
  "generation_model": "mistral-small-latest"
}

Exemple de question envoyée au chatbot :

curl -X POST http://127.0.0.1:8000/ask \
  -H "Content-Type: application/json" \
  -d '{"question": "Quels événements autour de l astronomie sont proposés ?"}'

Extrait de réponse obtenue :

{
  "question": "Quels événements autour de l astronomie sont proposés ?",
  "answer": "D'après le contexte fourni, un seul événement autour de l'astronomie est proposé : Initiation à l'astronomie à Lanton...",
  "sources": [
    {
      "event_id": "13708573",
      "title": "Initiation à l'astronomie à Lanton",
      "city": "Lanton",
      "start_date": "2026-01-05T19:30:00+00:00",
      "url": "https://openagenda.com/econature/events/initiation-a-lastronomie-a-lanton"
    }
  ]
}

Cet exemple montre que l’API est disponible, que le vector store est chargé, et que la chaîne RAG retourne une réponse structurée avec sources.