Skip to content

rag(05b): l'exercice recall@5 interroge le helper avec limit=K=10 — il mesure du recall@10 contre un top-5 non ordonnable #15670

Description

@myia-ai-01

Finding J02+J03 de la passe d'audit GenAI, re-verifie firsthand le 2026-09-12 sur origin/main = 162779ec06. Sous-partie (b) confirmee ; la sous-partie (a) du finding original est ecartee en fin de body (voir « Ecarte apres re-verification »).

Le defaut

L'exercice recall@5 demande de mesurer le rappel a 5 de search_qdrant(q, ef=8), mais le helper met le K global (10) dans limit : la requete rend un top-10, pas un top-5. Le K5 = 5 defini dans la cellule d'exercice n'est jamais consomme par le helper. En intersectant un top-10 avec un ground truth top-5, l'eleve mesure |GT5 ∩ top10| / 5, qui vaut 1.0 des que les 5 vrais voisins sont quelque part dans le top-10 — l'exercice peut donc valider un recall@5 de 1.0 quand le vrai recall@5 vaut 0.0.

Second defaut du meme exercice : le TODO demande un « ground truth top-5 ordonne » calcule par la « meme methode numpy que la cellule ground_truth » — or cette cellule reference stocke le ground truth comme un set (l'ordre est detruit) : la methode a recopier ne peut pas produire un top-5 ordonne.

Localisation

MyIA.AI.Notebooks/GenAI/RAG-et-Memoire-Semantique/05b-Stockage-Vectoriel-Serveur.ipynb

  • cellule 10 (ground truth) : ground_truth.append(set(int(i) for i in top_k_sorted)) — ordre perdu ; l'exemple affiche sorted(list(ground_truth[0]))[:5] (tri d'identifiants).
  • cellule 12 (helper) : def search_qdrant(query_vec, ef=None, ...) construit "limit": K avec K = 10 global.
  • cellule 19 (exercice) : K5 = 5 puis # TODO Etudiant : ... mesurer le recall@5 de search_qdrant(q, ef=8).

Sortie de re-verification (origin/main, 2026-09-12)

$ git show origin/main:...05b-Stockage-Vectoriel-Serveur.ipynb | grep -o 'indexing_threshold[^,]*'
indexing_threshold\": 0\n"

$ git show origin/main:...05b | python -c "..."   # extraits
cell 12:  payload = { "vector": query_vec.tolist(), "limit": K, ... }   # K = 10 (global)
cell 19:  K5 = 5
          # TODO Etudiant : (1) recalculer le ground truth top-5 ordonne ... (2) mesurer le
          # recall@5 de search_qdrant(q, ef=8) puis de search_qdrant(q, exact=True),
cell 10:  ground_truth.append(set(int(i) for i in top_k_sorted))

K5 apparait une seule fois (definition, jamais consommee) ; search_qdrant(q, ef=8) est bien l'appel demande ; le helper met K (10) dans limit.

Ce qu'un correctif devrait faire (sans l'ecrire)

  • Permettre a l'exercice d'interroger avec limit=5 (le helper prendrait la profondeur en parametre, ou l'exercice construirait son payload) — le recall@5 doit se mesurer contre un top-5 reellement rendu.
  • Faire produire a la methode de ground truth un top-5 qui conserve l'ordre (le set de la cellule 10 est l'idiome du recall@10 non ordonne, pas du top-5 ordonne demande).

Coordination

La PR #15656 (OPEN) retravaille exactement cette zone du notebook : elle ajoute « Exercice 1 — Casser la saturation » et renumerote l'exercice recall@5, mais ne modifie pas le helper (def search_qdrant absent du patch ; "limit": K persiste) — le defaut survit sur la branche de la PR. Le correctif devra atterrir en coordination avec elle, pas en aveugle.

Ecarte apres re-verification (pour eviter le re-dispatch)

La sous-partie (a) du finding — « indexing_threshold: 0 DESACTIVE l'indexation HNSW, or la prose dit "demander l'indexation sans seuil d'attente" » — est invertie : dans la semantique Qdrant de optimizers_config.indexing_threshold (nombre minimal de vecteurs d'un segment pour construire l'index HNSW), la valeur 0 force l'indexation de tous les segments immediatement ; c'est une valeur ELEVEE qui la desactiverait. La prose du notebook est donc correcte, et le benchmark peut legitimement s'interpreter en termes de HNSW/ef. Le recall@10 = 1.000 uniforme des sorties commitees (a tous les ef) s'explique par des requetes triviales (les vecteurs de requete sont des points du corpus eux-memes), pas par une indexation absente. Non-lieu documente.

Reassessed by audit-issue-opener: CONFIRMED pedagogy (mesure d'exercice biaisee : limit=10 pour un recall@5, ground truth non ordonnable)

Activity

  1. jsboige commented on Sep 12, 2026

    @jsboige
    Owner

    [CLAIMED] lane myia-po-2023:CoursIA — 2026-09-12 — fix(rag 05b) : helper search_qdrant paramètre de profondeur (limit=K5 consommé), ground truth top-5 ordonné conservé à côté du set recall@10, TODO de l'exercice réaligné sur les deux — re-exécution complète du notebook (Qdrant Docker local) -- paths: MyIA.AI.Notebooks/GenAI/RAG-et-Memoire-Semantique/05b-Stockage-Vectoriel-Serveur.ipynb

    Preflight : #15656 fermée orpheline, sa dissipation (Exercice 1 saturation) est déjà sur main et le défaut a survécu tel que prédit — mesure live refaite sur origin/main du jour (cellules 10/12/19).

    Grain: MED/notebook-python — prev: LIGHT/readme #15730

  2. jsboige commented on Sep 12, 2026

    @jsboige
    Owner

    [DELIVERED] lane myia-po-2023:CoursIA — PR #15731 (2 fichiers : le notebook + son PNG artefact régénéré).

    Acceptance 1 — le helper prend la profondeur en paramètre : search_qdrant(..., limit=None) → "limit": limit if limit is not None else K. Les 6 sites d'appel existants (benchmark ×2, persistance ×2, filtrage ×2) passent par le défaut K → comportement inchangé ; l'exercice interroge avec limit=K5 contre un vrai top-5 rendu.

    Acceptance 2 — la cellule ground truth conserve le classement : ground_truth_ranked (ordre par similarité décroissante) à côté du set (idiome du recall@10 d'ensemble). Le « top-5 ordonné » = la tranche [:5], plus de contradiction avec la méthode à recopier.

    Découverte en corrigeant (mesurée, seed 42) : l'ancienne ligne d'exemple sorted(list(ground_truth[0]))[:5] affichait les 5 plus petits ids du top-10 — [1519, 1720, 3065, 3128, 4136] où 3128 est le 7e voisin et remplace 4529 (4e) — et l'ancienne prose appelait cette liste « le top-5 exact ». Corrigé : le vrai top-5 classé [4136, 3065, 1519, 4529, 1720] s'affiche et se recroise avec la recherche serveur de la cellule persistance (même ordre, même requête).

    Coordination — #15656 (fermée orpheline) : sa dissipation (Exercice 1 saturation) est sur main, le défaut y a survécu comme l'issue le prévoyait ; ce correctif atterrit sur main sans collision.

    Preuves : exécution complète SUCCESS 44 s (Qdrant Docker local, conteneur provisionné par le notebook) ; séquence 1..13, 0 erreur, 0 fuite de chemin ; validate_pr_notebooks.py PASS 13 cells ; C.1 intact ; catalogue byte-identique ; gardes grain MED/notebook-python prev #15730 verts ; périmètre OK.

    Résiduel signalé hors scope : prose de la cellule d'interprétation persistance (« conteneur détecté qdrant-rag05 » vs sortie qdrant_rag05b, avant comme après ce run).

    🤖 Generated with Claude Code

  3. added a commit that references this issue on Sep 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    auditAutomated quality audit findings

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions