File size: 5,301 Bytes
7e2d97f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# 🚀 Pistes d'amélioration — RAG Number_one

Objectif du hackathon : **JUSTE** (accuracy) · **PAS CHER** (tokens) · **SOBRE** (CO₂).
On avance **dans l'ordre**, une piste à la fois, en mesurant l'effet avant de passer à la suivante.

> État de base actuel : 152 mémoires, 84 840 chunks, `text-embedding-3-small`, LLM `gpt-5.1`,
> recherche cosinus top-3, `temperature=0.7`. Pipeline = `rag_query()` dans `app.py`.

---

## 1. ✍️ Améliorer le pré-prompt  `[ À FAIRE ]`

**Objectif :** de meilleures réponses (plus justes, moins d'hallucinations, format respecté) sans rien changer au code.

**Où :** `prompts/rag_prompt.txt` (chargé tel quel par `build_rag_prompt()` dans `app.py`).

**Comment :**
- Rendre les consignes plus strictes : répondre **uniquement** à partir du contexte, dire explicitement « information insuffisante » sinon (anti-hallucination).
- Soigner le format JSON exigé (`answer`, `explanation`) — un écart = parsing raté.
- Ajouter éventuellement : style concis, citer les sources, raisonner étape par étape avant de répondre.
- Spécialiser le ton « expert actuariat » (vocabulaire métier).

**Impact attendu :** ↗️ accuracy · coût/CO₂ ≈ neutres (prompt un peu plus long).
**Risque :** faible. **Effort :** très faible. → **Meilleur rapport gain/effort, on commence par là.**

---

## 2. 🎯 Réduire le `k` (top-3 → top-2 ?)  `[ À FAIRE ]`

**Objectif :** moins de tokens injectés dans le prompt → **moins cher + moins de CO₂**, si 2 passages suffisent à répondre.

**Où :** `app.py``TOP_K_RESULTS = 3` (≈ ligne 60). Aussi le défaut de `/query`.

**Comment :**
- Tester `k=2` et comparer l'accuracy vs `k=3` sur quelques questions types.
- Chaque chunk ≈ 130 tokens → passer de 3 à 2 économise ~1 chunk de contexte par requête, à chaque appel.

**Impact attendu :** ↘️ coût · ↘️ CO₂ · accuracy = à surveiller (risque de perdre le bon passage).
**Risque :** moyen (si le bon contexte était le 3ᵉ). **Effort :** très faible (1 ligne).
**Note :** à tester APRÈS le prompt, pour mesurer proprement.

---

## 3. 🌡️ Régler la température du LLM  `[ À FAIRE ]`

**Objectif :** réponses plus **déterministes et factuelles** (moins de variabilité/invention).

**Où :** `config.json``llm.temperature` (actuellement `0.7`), lu par `app.py`.

**Comment :**
- Pour du factuel/RAG, une température **basse** (ex. `0.0``0.3`) est généralement préférable.
- Tester `0.2` puis `0.0`, comparer la justesse et la stabilité des réponses.

**Impact attendu :** ↗️ accuracy (moins d'hallucinations) · coût/CO₂ ≈ neutres.
**Risque :** faible. **Effort :** très faible (1 valeur).

---

## 4. 🔁 Cross-encoder (reranker)  `[ À FAIRE ]`

**Objectif :** récupérer les **bons** passages → c'est *« la qualité du retrieval qui fait le score »*.

**Principe :**
```
question → recherche cosinus large (top-20)   ← rappel
        → cross-encoder reclasse les 20 (lit question+passage ENSEMBLE)
        → garde les top-2/3 meilleurs → LLM    ← précision
```

**Où :** `retrieve_relevant_context()` dans `app.py` (élargir le `n_results`, ajouter une étape de rerank avant de renvoyer).

**Comment :**
- Modèle type `BAAI/bge-reranker-v2-m3` via `sentence-transformers`, **en local sur le GPU**.
- Bien plus précis que le cosinus (qui compare 2 vecteurs figés).

**Impact attendu :** ↗️↗️ accuracy (souvent le plus gros levier) · coût ≈ neutre (rerank local, pas d'appel payant) · CO₂ : un peu de calcul GPU local.
**Risque :** moyen (latence + dépendance). **Effort :** moyen. **⚡ Le GPU sert enfin ici.**

---

## 5. 🧭 Routing petit/gros modèle via le cross-encoder  `[ À FAIRE ]`

**Objectif :** envoyer les questions **simples** sur **GPT-5-mini** (petit, pas cher, sobre) et garder **GPT-5.1** pour les **difficiles** → c'est l'*« arbitrage intelligent »* explicitement récompensé par le jury.

**Principe :**
```
question + passages → score de confiance (issu du cross-encoder / du retrieval)
   ├─ confiance haute (question simple, contexte net) → GPT-5-mini   (€/CO₂ ↓↓)
   └─ confiance basse (ambigu, technique)             → GPT-5.1
```

**Où :** dans `rag_query()` (`app.py`), choisir dynamiquement le modèle/endpoint avant l'appel LLM. Nécessite d'ajouter la config du **mini** dans `config.json` (2ᵉ endpoint/modèle).

**Comment :**
- Réutiliser le **score du reranker** (piste 4) comme signal de difficulté/confiance : score élevé sur le top-1 ⇒ question bien couverte ⇒ mini suffit.
- Seuil à calibrer sur des exemples.

**Impact attendu :** ↘️↘️ coût · ↘️↘️ CO₂ · accuracy ≈ maintenue si le seuil est bien réglé.
**Risque :** moyen-élevé (calibrer le seuil sans perdre en accuracy). **Effort :** moyen-élevé.
**Dépend de :** la piste 4 (le cross-encoder fournit le signal de confiance).

---

## Ordre de travail recommandé
1 → 2 → 3 (gains rapides, faible risque) puis 4 (gros levier accuracy) puis 5 (gros levier coût/CO₂, s'appuie sur 4).

⚠️ **À chaque changement** : tester quelques questions, vérifier que le **format JSON de `/query` reste intact** (sinon score = 0), puis re-déployer (push + restart Space).