# Reduced RAG: Stop Stuffing Context Windows and Start Extracting Signals

<datetime class="hidden">2026-01-08T19:00</datetime>

<!-- category -- AI, RAG, LLM, Architecture, Semantic Search -->
Si vous êtes tout nouveau à RAG,, commencez par [RAG Expliqué](/blog/rag-primer) et [Architecture du RAG](/blog/rag-architecture). Ce poste est destiné au point où vous ' avez construit une pipeline RAG *en grande partie* … et maintenant vous payez pour cela en coûts , fragilité M SK3 et " pourquoi a-t-il répondu que les sessions de débugging

**Qu’est-ce que cela couvre:** Le modèle architectural qui sous-tend la production RAG. Pour les mainsM SK1 sur la mise en œuvre, voir [Établissement d'un sommaire de documents avec RAG](/blog/building-a-document-summarizer-with-rag).

**De quelle provenance il provient:** J'ai construit [DocSummarizer](/blog/building-a-document-summarizer-with-rag) (Motor RAG du document), [Système de gestion des données](/blog/datasummarizer-how-it-works) (Engine RAG de données), [ImageSummarizer](/blog/constrained-fuzzy-image-intelligence) (Engine RAG d'images), [AudioSummarizer](/blog/audiosummarizer-forensic-audio-characterization) (Engine audio RAG ), et [lucidRAG](/blog/lucidrag-multi-document-rag-web-app) (multiM SK1document Q &A). Le même schéma continue d’émerger dans les documentsMST4donnéesM ST5imagesM st6 et audioMst7

> REMARQUE: Vous avez peut-être remarqué à juste titre que la recherche sémantique sur ce site est défectueuse ...et oui, c’est une question de configuration je n’ai pas encore corrigée

## Rafraîchisseur de terminologie RAG rapide

| Mandat | Qu'est-ce que cela signifie MSC2 Exemple MSC3
|------|---------------|---------|
| **RAG** | Récupération- génération accrue | Envoyant un LLM à votre entreprise avant de répondre
| **Amélioration de la qualité des services** | Partitionner les documents en petits morceaux | Diviser un PDF en paragraphes |
| **Top-k** | Obtenez les résultats de la recherche suivants :
| **Recherche par vecteur** | Trouver un texte similaire à l'aide d'embeddings | CMS2Trouver des documents semblables à ce message d'erreur
| **TÉU, TPAC, TPMD, TPG** | Recherche par mots clés | MSC2Trouver des documents contenant SMC3démarrage de tempsS MC4 ET ESMC5base de donnéesSCM6 | |
| **Contexte** | Combien de texte vous pouvez inclure dans un message d'essai | Fin et coûteux
| **Signales** | Faits extraits sans A.I.

Retrieval-Augmented Generation M SK1RAG) est devenu l’une des phrases qui signifie *tout et rien*.

Pour beaucoup d’équipes, le RAG est maintenant

1. Documents en vrac
2. Inservez-les
3. Retour en haut-k
4. Insérer tout dans le prompt
5. Demandez au modèle de “configurer ce dernier”

Il fonctionne.
Jusqu’à ce qu’il ne soit pas

Il est difficile de reasoner sur ’, il est coûteux, , et ’ et il donne quietement la responsabilité au modèle. :, il étudie la structure, ,, il applique les filtres, M SK6, il décide ce qui importe, MNK7, il réconcilie les contradictions, MZK8 et il y a confiance.

Lorsque les gens disent : “RAG hallucinate ” ou “RAg ne filtrait pas bienM SK3”, ils plaident habituellement pour la mauvaise composanteMSC6

Le problème est’t RAG.
Le problème est que **RAG lazi**.

Ce post décrit un autre défaut: **RAG réduit** - utiliser des LLM *moins*En extrayant les signaux déterministes à l'avant et en traitant les modèles comme *moteurs de synthèse*, non *Commerce de données*.

[TOC]

## L’erreur fondamentale: de traiter les fenêtres contextuelles comme un stockage

Une fenêtre contextuelle est:

- Ã©tape transitoire
- non-typed
- coûteux
- Remboursement sur chaque demande

Il n'est pas un stockage de données.

Lorsque vous “lisez simplement plus dans l’énoncé de commandes, vous demandez au modèle :

- re-parse structure chaque fois
- infer les filtres au lieu de les faire exécuter
- Résumer les détails dont vous aurez besoin plus tard
- sound confident even when it’s wrong

C’est pourquoi les démonstrations RAG semblent excellentes et que les systèmes de production RAG se détruisent silencieusement.

## Qu'est-ce que “Reduced RAG”

RAG réduit tourne le défaut.

Au lieu de:

> Retourner le texte et laisser le modèle décider ce qui importe.

Vous le faites ?

> Décidez ce qui importe une fois qu’il est stocké, , et n’impliquez le modèle que lorsque vous avez besoin de synthèse.

Dans la pratique, cela signifie: **Ingestion déterministe, récupération peu coûteuseM SK1 génération limitée**.

Si cela vous paraît familier,, c’est la même forme de système que [Fuzziness restreinte](/blog/constrained-fuzziness-pattern): laisser les composantes probabilistes *proposer*; laisser les systèmes déterministes *Décision*.

## RAG traditionnel contre RAG réduit

Premièrement, laissez-moi voir ce que la plupart des équipes font et pourquoi cela est coûteux

```mermaid
flowchart LR
    subgraph Traditional["❌ Traditional RAG: Everything Through the LLM"]
        T1[Documents] --> T2[Chunk Everything]
        T2 --> T3["Embed All Chunks<br/>(once)"]
        T3 --> T4[Vector Search]
        T4 --> T5["Paste Top-K<br/>(per query)"]
        T5 --> T6["LLM Decides<br/>(per query)"]
        T6 --> T7[Answer]
    end

    style Traditional stroke:#ef4444,stroke-width:3px
    style T6 stroke:#ef4444,stroke-width:3px
    style T5 stroke:#ef4444,stroke-width:2px
```

**Problèmes:**

- LLM re-parse la structure de chaque demande
- Peut-on 'forcer les filtres (seulement
- Échelle des coûts de cote avec les demandes (↑ par demandeM SK1
- Hallucinations lorsque le modèle invente des filtres

Voici maintenant l’approche de RAG réduite, '

```mermaid
flowchart TB
    subgraph Ingestion["✅ Ingestion (Once - Pay Upfront)"]
        I1[Source Docs] --> I2[Parse Structure]
        I2 --> I3["Extract Signals<br/>(deterministic)"]
        I3 --> I4[(Structured Fields)]
        I2 --> I5[Semantic Units]
        I5 --> I6[(Vector Store)]
        I2 --> I7[(Evidence Store)]
    end

    subgraph Query["Query Time (Cheap Per Query)"]
        Q1[User Question] --> Q2{Extract Filters}
        Q2 --> Q3["Filter Database<br/>(no LLM)"]
        Q2 --> Q4["BM25 Search<br/>(no LLM)"]
        Q2 --> Q5["Vector Search<br/>(no LLM)"]

        Q3 --> R[Candidate Set]
        Q4 --> R
        Q5 --> R

        R --> S["Small Evidence Pack<br/>(5 sources not 50)"]
    end

    subgraph Generation["LLM (Bounded Synthesis Per Query)"]
        S --> L[Synthesize Answer]
        L --> A[Answer + Citations]
    end

    style Ingestion stroke:#22c55e,stroke-width:3px
    style Query stroke:#3b82f6,stroke-width:3px
    style Generation stroke:#f59e0b,stroke-width:2px
    style I3 stroke:#22c55e,stroke-width:3px
    style Q3 stroke:#3b82f6,stroke-width:3px
    style L stroke:#f59e0b,stroke-width:3px
```

**Principales différences:**

| Phase | RAG traditionnel | RAg réduit S|
|-------|----------------|-------------|
| **Ingestion** | Just chunk and embed
| **Filtration** | Demandez à LLM de filtrer dans l'énoncé préliminaire | Base de données Où se trouvent les clauses |
| **Rechercher** | Vector seulement | BMM SK2 + Vektor SSK4 Filtres structurés S|
| **Rôle de LLM** | ParsezM SK1 filtre, ET répondez | Synthèsez simplement la réponse |
| **Coût** | Chacune des demandes est payée pour le contexte complet | Ingestion une fois

## Étape 1: Ingestion déterministe (le bit borne qui importeM SK2

À l’heure de l’ingestion, étudier ce que vous pouvez *sans* une LLM.

**Exemple: Système de soutien des billets**

Plutôt que de fragmenter les billets en texte:

```
Traditional: "Ticket #1234: Customer complained about slow loading..."
→ Embed entire text
→ Hope the LLM figures out it's about performance
```

Extraire les signaux en avant:

```csharp
// Parse once during ingestion
var ticket = new SupportTicket
{
    Id = "1234",
    CreatedDate = DateTime.Parse("2025-01-15"),
    Category = "Performance",              // ← Deterministic field
    Product = "WebApp",                     // ← Filterable
    Priority = "High",                      // ← Sortable
    Customer = "Enterprise",                // ← Segment filter
    SentimentScore = -0.3,                  // ← Computed once
    Tags = ["slow-loading", "timeout"],     // ← Searchable
    Text = "Customer complained about..."   // ← Still keep for RAG
};
```

**Ce que vous pouvez extraire de façon déterministe:**

| Type de signale | Exemples MSC2 Pourquoi cela importe MSC3
|-------------|----------|----------------|
| **Taux temporaire** | Date de créationM SK1 date de mise à jour, date d'expiration | "Pour montrer seulement la semaine dernièreMSC5s erreursMST6
| **Catégorique** | ÉtablissementM SK1 priorité, ministèreMNK3 produit | "Filter aux billets d'équipe mobileMSC6 |
| **Nombreux** | Prix, quantitéM SK2 coteMSC3 confiance | "Sort par gravitéMST6 |
| **Identité** | AuteurM SK1 ID du client, Article d'immatriculationMSC3 facture # | ≥"Tous les billets de la clientèle X
| **Qualité** | Confiance en OCRM SK1 auto-ligne générée |
| **Provenance** | Système de sourceM SK1 chemin de fichiers, URL |

Doit-on le faire une fois. Gardez l’outil de sortie. Que ' est le substrat sur lequel votre système peut s’appuyer

**La partie dure du RAG n’est pas le modèle ', mais le modèle -, c’est tout ce qui précède le modèle** Pour des mises en œuvre concrètes, voir [Établissement d'un sommaire de documents avec RAG](/blog/building-a-document-summarizer-with-rag) et [DocSummarizer: Établissement de pipelines RAG](/blog/docsummarizer-rag-pipeline).

## Étape 2: Entretenir les signaux (et conserver des preuvesM SK2

Plutôt que de traiter "chunksM SK1 comme l'unité de la vérité , entreposer des champs structurés

Le texte fait encore partie du système -, mais il devient **preuves**, non "qu'il nous soit arrivé d'insérer dans le prompt".

Il s’agit de la différence entre les réponses "RAG sont vibesM SK1 et "RAg sont inspectables".

### " Mais comment puis-je savoir quels sont les signaux à extraire?

Vous ne le faites pas.

Il s’agit là du point central de l’entreposage. **signales bruts** instead of LLM-summaries traitées.

**RAG traditionnel (coût de changementM SK1**

```csharp
// ❌ You asked the LLM to "summarize the key points"
var summary = await llm.Summarize(ticket.Text); // Expensive
await db.SaveAsync(summary); // Threw away the original structure

// Later: "Actually, we need sentiment scores too"
// 😱 Have to re-process 10,000 tickets through LLM again!
```

**RAG réduit (cheap to changeM SK1**

```csharp
// ✅ Store raw signals extracted deterministically
var signals = new TicketSignals
{
    Text = ticket.Text,                    // ← Keep original
    WordCount = ticket.Text.Split().Length, // ← Cheap to compute
    ContainsErrorCode = Regex.IsMatch(ticket.Text, @"ERR-\d+"),
    MentionedProducts = ExtractProducts(ticket.Text), // ← Heuristic
    SentimentWords = CountSentimentWords(ticket.Text), // ← Word lists
    CreatedHour = ticket.Created.Hour      // ← Maybe useful later?
};

// Later: "We need to prioritize by sentiment"
// ✅ Just add a computed column - no LLM re-run needed!
await db.ExecuteSqlAsync(@"
    ALTER TABLE Tickets ADD COLUMN SentimentScore AS
    (SentimentWords->>'positive' - SentimentWords->>'negative')
");
```

**Ce qui vient d’arriver:**

- Vous avez stocké **plus de signaux que vous n'avez besoin** (cheapM SK1
- Lorsque les exigences ont changé, vous **Recommandations de l’Agence canadienne d’évaluation environnementale** (freeM SK1
- Vous n’avez pas corrigé 't re-run LLM inference on 10,000 documents

Il s’agit du même modèle que:

- **[DiSE (Evolution synthétique dirigée)](/blog/dise-architecture-overview)** - stocke les résultats des essaisM SK1 historique de mutations , métriques de qualité. Quand vous modifiez la fonction de cotationMSC4 vous n’effectuez pas de recommandation de coter les candidats existants à partir des signaux conservés.
- **[Détection des bottes](/blog/learning-lrus-when-capacity-makes-systems-better)** - stocke les patrons de requêteM SK1 signales d'horaire , héuristique du comportement. Lorsque vous réglagez le seuil SSK4 → ♫0.4, vous ne traitez pas de nouveau le traficMSC7 vous réévaluez les signaux entreposésMNK10

**La règle:** Rappelez-vous *précédemment* la LLM. Mise à jour de votre "mémoireM SK2 ( logique de récupérationMST4 gratuitementMSS5

**Avantage architectural clé: Évacuabilité.**
Étant donné que vous entreposez des signaux déterministes à côté des embeddings, ( non plutôt qu'à leur place ), chaque partie du système peut changer indépendammentM SK2 Swap embeding models? ReMSC4 embed without touching signalsMST5 Add a new signalMSP6 Compute it from stored text without reMSV7embeddingMSS8 Tune rankingMSR9 Adjust signal weights and scoring logic without reindexingMSL10

Avec les magasins multi-vector (comme QdrantM SK2, vous pouvez même ajouter **multiples embeddings par document**. Voulez essayer un nouveau modèle d'implantation ? Ajouter le modèle existant et passer progressivement à l'autre M SK2 Tester les deux dans la production , comparer la qualité

Chaque composant peut évoluer sans forcer la reconstruction d’un pipeline complet - et sans dégrader les autres .

### Quels signaux devriez-vous stocker?

Entreposer tout ce que vous pouvez calculer **de façon peu coûteuse et déterministe**.

**Important:** Les signaux sont simplement **chaînes de texte courtes, nombres, et booleans**—pas de structures de données gigantesquesM SK1Vous 'en stockez "Performance" (8 charsMSC6 pas S"Le client s'est plaint des temps de chargement lentes..." | | (50+ motsMSC10

```csharp
public class DocumentSignals
{
    // Always extract (almost free)
    public int CharCount { get; set; }              // Example: 1247
    public int WordCount { get; set; }              // Example: 203
    public int ParagraphCount { get; set; }         // Example: 5
    public string[] UniqueWords { get; set; }       // Example: ["timeout", "error", "api"]

    // Structural (parse once)
    public bool HasCodeBlocks { get; set; }         // true/false
    public bool HasLinks { get; set; }              // true/false
    public int HeadingCount { get; set; }           // Example: 3

    // Heuristic (simple patterns)
    public string[] MentionedProducts { get; set; }       // Example: ["WebApp", "API"]
    public string[] ErrorCodes { get; set; }              // Example: ["ERR-404", "ERR-500"]
    public Dictionary<string, int> SentimentWords { get; set; } // { "positive": 3, "negative": 7 }

    // Metadata (already available)
    public DateTime Created { get; set; }           // Example: 2025-01-15T14:23:00
    public string Author { get; set; }              // Example: "user@example.com"
    public string Category { get; set; }            // Example: "Performance" (not essay-length)

    // Computed (cheap math)
    public double ReadingTimeMinutes { get; set; }  // Example: 4.2
    public double KeywordDensity { get; set; }      // Example: 0.034
}
```

**Comparaison des coûts de stockage:**

| Ce que vous consacrez à l'entreposage | Taille par document
|----------------|------------------|---------------|
| **Texte complet** |  ~5 Kb
| **Tous ces signaux** | ~500 octets ≥| ≤5 Mo |
| **Résumé produit par LLM-** |  ~2 Kb

Les signaux sont **10x plus petit** par rapport au texte, **4x plus petit** par rapport aux sommaires de LLM, et **infiniment moins cher** pour recomputer ( car vous n’avez pas besoin d’un LLM

**Lorsque vous vous rendz compte que vous avez besoin d’un signal différent:** Il suffit de le calculer à partir des données brutes stockées.

C’est la raison pour laquelle "overM SK1extraction" est sécuritaire : vous payez une fois dans l’entreposage MSC4negligibleMSC5 ne pas répétitivement en inférence MSC6substantielMST7

## Étape 3: Recherche sans un LLM ( la plupart des demandes ne font pas l’objet d’une recherche

La plupart des "RAG queries" sont en fait simplement des recherches avec des contraintes

- "seulement les derniers dossiersM SK1
- "pour les clients du Royaume-Uni seulementM SK1
- "seulement le régime payéM SK1
- "seulement les erreurs de la semaine dernièreM SK1

**RAG traditionnelle** (prixM SK1indépendable):

```csharp
// ❌ Paste everything into prompt and hope
var chunks = await vectorSearch.SearchAsync(query, k: 50); // 50 chunks!
var prompt = $@"
Given these 50 chunks of text, answer the question but ONLY use
docs from last week and ONLY for UK customers.

Chunks: {string.Join("\n", chunks)}

Question: {userQuestion}
";
var answer = await llm.GenerateAsync(prompt); // Expensive + unreliable
```

**RAG réduit** (cheap,déterministeM SK2

```csharp
// ✅ Filter first, retrieve less, synthesize last
var candidates = await db.Tickets
    .Where(t => t.CreatedDate > DateTime.Now.AddDays(-7))  // ← Database does this
    .Where(t => t.Region == "UK")                          // ← Not the LLM!
    .ToListAsync();

// Hybrid search on the filtered set
// (In production: push BM25 to database/index, not in-memory LINQ)
var bm25Results = candidates.Where(c => c.Text.Contains(keyword));
var vectorResults = await vectorSearch.SearchAsync(query, k: 5, filter: candidates);

// Small evidence pack
var evidence = RRF.Merge(bm25Results, vectorResults).Take(5);

// LLM only synthesizes
var answer = await llm.GenerateAsync($@"
Synthesize an answer using ONLY these 5 sources:
{FormatEvidence(evidence)}

Question: {userQuestion}
");
```

**Ce qui vient d’arriver:**

- Base de données filtrée de façon déterministe (non le LLM)
- LLM voit des sources 5 au lieu de 50
- Les filtres sont garantis, non M SK1suggested"

C’est pourquoi la recherche hybride est importante dans la production. [Recherche hybride & Auto-Indexage](/blog/rag-hybrid-search-and-indexing) est la pièce la plus pratique de toute la série RAG.

### Optionnel: Utilisation d’un LLM pour extraire l’intention

Si une demande est vraiment bloquée, vous *utilisation* Utiliser un petit modèle pour extraire l’intention/filtres M SK1comparer vs expliquer vs corriger les problèmes"):

```csharp
// Use small model to propose filters (ephemeral - discarded after use)
var intent = await smallModel.ExtractIntent(userQuestion);
// Returns: { intent: "troubleshoot", filters: { priority: "high", product: "api" } }

// Validate the proposal against known fields (deterministic)
var validatedFilters = ValidateAgainstSchema(intent.filters);

// Use validated filters for retrieval
var results = await db.Tickets.Where(validatedFilters).ToListAsync();
```

**Principe fondamental: Le LLM propose , la validation de la couche déterministe.**

C'est le fondement de la [Fuzziness restreinte](/blog/constrained-fuzziness-pattern) pattern.

Pour en apprendre davantage sur les modèles d’exécution éphémères où vous utilisez temporairement des LLM sans que leurs résultats persistent, voir [Fire and Don't Quite Forget](/blog/fire-and-dont-quite-forget-ephemeral-execution).

## Étape 4: Les LLM en tant que moteurs de synthèse

Il n’est qu’après la récupération que vous appelez le LLM. Vous lui donnez un petit ensemble explicite de faits avec des indicateurs de preuve et des instructions claires sur l’incertitude.

Le modèle' son emploi: **synthétiser, expliquerM SK1 comparer**. NonM SK1 **exécuter les contraintes, décider la véritéM SK1 inventer la structure**.

Si vous vous préoccupez de “LLMs traînant l'ensemble du contexte dans la réponse ”, vousM SK2 avez déjà vu le mode d'échec . J'ai appelé explicitement en [Traçage de contexte fuzzy restreint](/blog/constrained-fuzzy-context-dragging): c'est ce que vous lui avez demandé de faire, ’ n'est pas malveillant.

## Pourquoi est-ce plus sûr? *et* avantageux

### Comparaison des coûts (exemple illustratifM SK1

Commande-deM SK1comparaison de la grandeur pour un système RAG typique d'appui aux clients:

**Scénario:** 10,000 billets de soutienM SK1 1,000 demandes par jour

| Approche | Coût de l’ingestion MSC2 Par SMC3Coût de la demande ESC4 Co coût quotidien ESC5
|----------|----------------|----------------|------------|
| **RAG traditionnelle** | Insérer 10k billets | M50 tronçons**$75/jour** |
| **RAG réduit** | Insérer + extraire les signaux**$7.50/jour** |

**Ordre de grandeur:** ~10x réduction des coûts par jour

**Même mieux:** Avec de bonnes preuves et un filtrage déterministe, il est probable que vous n’avez pas besoin d’un modèle frontal à tout le moinsM SK2 Un modèle local Ollama (free) avec une petite trousse de preuves excède souvent les performances du GPT

Plus: réduction du temps de débugging , moins d’escalades de soutien, et flexibilité des modèles M SK3swap models without architectural changesMSC4

### La fiabilité

**RAG traditionnelle** (espéranceM SK1filtration fondée sur le ):

```csharp
// ❌ Prompt says "only UK customers" but model can ignore it
var answer = await llm.Generate(prompt); // No guarantee
```

**RAG réduit** (filtration forcéeM SK1

```csharp
// ✅ Database physically prevents non-UK results
var results = db.Tickets.Where(t => t.Region == "UK"); // Guaranteed
```

**Pourquoi la sécurité est-elle plus élevée?** Les filtres sont exécutés avant la génération.

### Expliquement

**RAG traditionnelle:** "Le modèle dit ce qui suit , mais je ne suis pas certain de savoir pourquoi ou quel tronc il provient du ."

**RAG réduit:**

```csharp
// You know exactly why each result matched
var result = new SearchResult
{
    Text = "Server timeout error",
    MatchedBecause = new[]
    {
        "Region = UK (database filter)",
        "Created in last 7 days (date filter)",
        "BM25 score: 4.2 (keyword 'timeout')",
        "Vector similarity: 0.89 (semantic match)"
    },
    SourceChunks = [chunk1, chunk2], // ← Audit trail
    ConfidenceScore = 0.89
};
```

Vous pouvez vérifier les raisons pour lesquelles chaque résultat est identique, montrer des preuves lorsque la confiance est faibleM SK1 et débuger les problèmes de production en examinant le candidat établi avant la synthèse LLM.

## Getting started: Refactoring traditional → reduced RAG

Si vous avez déjà un système RAG opérationnel, ici 's comment migrer:

### Étape 1: Ajouter des champs structurés à votre ingestion

**Avant:**

```csharp
public class Document
{
    public string Id { get; set; }
    public string Text { get; set; }           // ← Only unstructured text
    public float[] Embedding { get; set; }
}
```

**Après:**

```csharp
public class Document
{
    public string Id { get; set; }
    public string Text { get; set; }           // ← Keep for evidence
    public float[] Embedding { get; set; }

    // Add deterministic signals (extract once during ingestion)
    public DateTime CreatedDate { get; set; }  // ← Parse from metadata
    public string Category { get; set; }       // ← Extract from filename/tags
    public string Author { get; set; }         // ← From file properties
    public string[] Tags { get; set; }         // ← Parse from content/metadata
    public double QualityScore { get; set; }   // ← Compute heuristics
}
```

### Étape 2: Déplacer les filtres hors des prompts, dans les demandes

**Avant:**

```csharp
var prompt = "Only use docs from last month for product 'API'. Query: " + userQuery;
var chunks = await vectorStore.Search(userQuery, k: 50);
var answer = await llm.Generate(prompt + chunks); // ❌ LLM might ignore filters
```

**Après:**

```csharp
// ✅ Database enforces filters
var candidates = await db.Documents
    .Where(d => d.CreatedDate > DateTime.Now.AddMonths(-1))
    .Where(d => d.Category == "API")
    .ToListAsync();

// Search only the filtered candidates
var results = await vectorStore.Search(userQuery, k: 5, filter: candidates.Select(c => c.Id));
var answer = await llm.Generate(FormatEvidence(results)); // Much smaller context
```

### Étape 3: Ajouter la recherche hybride (BMM SK2 + Vector)

```csharp
// Combine keyword and semantic search
var keywordResults = await db.Documents
    .Where(d => EF.Functions.ToTsVector("english", d.Text)
        .Matches(EF.Functions.ToTsQuery("english", keywords)))
    .ToListAsync();

var vectorResults = await vectorStore.Search(userQuery, k: 20);

// Merge using Reciprocal Rank Fusion (RRF)
var merged = RRF.Merge(keywordResults, vectorResults, k: 5);
```

Voir [Recherche hybride & Auto-Indexage](/blog/rag-hybrid-search-and-indexing) pour une mise en œuvre complète.

### Étape 4: Mesure de la différence

Suivre ces mesures avant et après:

```csharp
public class RAGMetrics
{
    public int PromptTokens { get; set; }           // Should drop by 80-90%
    public int CandidatesRetrieved { get; set; }    // Should drop from 50+ to 5-10
    public TimeSpan QueryLatency { get; set; }      // Should improve
    public bool FiltersEnforced { get; set; }       // Should be true
    public List<string> EvidenceSources { get; set; } // Should be traceable
}
```

## Règle de la poignée

Si votre système dépend d’une fenêtre contextuelle plus grande pour demeurer exacte, vous n’avez pas de problème de récupération.

## Carte à motifs

| | |
|---|---|
| **Intention** | Rendre le RAG prévisible, bon marchéM SK2 et débugable |
| **Forces** | Coûts élevés des cotes de monnaieM SK1 filtration insuffisante , hallucinations silencieuses
| **Solution** | Extraire les signaux une fois → exécuter des contraintes de façon déterministe
| **Conséquences** | Plus d’ingénierie à l’avant

---


## Résumé: Le modèle mental RAG réduit

La RAG réduite n’est pas anti-', mais anti‐-, anti‐LLM, anti–. et anti­'.

Pensez-en ainsi:

```
Traditional RAG = "LLM, here's 50 chunks. Figure out what matters and answer."
Reduced RAG    = "Database, filter to 100. BM25, find keywords. Vector, find similar.
                  Now LLM, here are the 5 most relevant sources. Synthesize an answer."
```

**Le changement:**

- **De:** LLM comme oracle (fait tout)
- **À:** LLM en tant que moteur de synthèse (fait une chose bien)

**Les primitives:**

1. **Signales** (déterministeM SK1 - datesMSC3 catégoriesMSc4 cotes, filtres
2. **Evidence** (texteM SK1 - ce que vous montrez au LLM
3. **Constraints** (limitesM SK1 - budgets de tokens, validation des filtresMSC4 exigences relatives aux citations

**Le modèle:**

- Extraire les signaux une fois (ingestion)
- Filtrer de façon déterministe (les bases de données sont bonnes à ce point
- Recherche hybride vecteurs (BMM SK1 +
- Synthèse limitée (small evidence pack → LLM)

Il s’agit de ce qui se passe lorsque vous appliquez une discipline normale d’ingénierie logicielle à des systèmes qui incluent des modèles linguistiques.

## Prochaines étapes

Si vous'êtes prêts à construire ce

1. **Démarrer simple:** Ajouter un champ structuré (CreatedDateM SK1 et un filtre de base de données
2. **Mesure de premier rang:** Cote du token de la piste avant/après
3. **Ajouter la recherche hybride:** Mettre en œuvre un vecteur BM25 M SK1 avec RRF ([guide ici](/blog/rag-hybrid-search-and-indexing))
4. **Établir progressivement:** Don' ne réfactorez pas tout à la fois

**Applications de référence:**

- [DoomSummarizer: Recherche approfondie](/blog/doomsummarizer-deep-research) - Réduction du RAG dans la pratiqueM SK1 6- fusion RRF des signaux, profils d'entitésMSC4 découverte de graphes sémantiquesMNK5 et longs parallèlesMMK6 synthèse formelleMRK7 tous à partir d'un seul binaire
- [Établissement d'un sommaire de documents avec RAG](/blog/building-a-document-summarizer-with-rag) - Procédure de mise en œuvre pratique
- [DocSummarizer RAG Pipeline](/blog/docsummarizer-rag-pipeline) - Pipeline d'ingestion complète
- [AudioSummarizer](/blog/audiosummarizer-forensic-audio-characterization) - Caractérisation légale audio avec diarisation de l'émetteur
- [lucidRAG](/blog/lucidrag-multi-document-rag-web-app) - App Web complète avec recherche hybride
- [StyloFlow:Signal-Flois de travail dirigés](/blog/styloflow-signal-driven-workflows) - moteur d'orchestre pour plusieurs pipelines RAG de stages - avec exécution conditionnelle et escalation
- [Fuzziness restreinte](/blog/constrained-fuzziness-pattern) - Le modèle sous-jacent

**Application connexe:** [Utilisation de Nimble du C#](/blog/stylomail-using-nimble-from-csharp), de la partie du [La série StyloMail](/blog/stylomail-behavioural-inference-with-jev), explore la fourniture du contexte postal limité à un modèle de décision locale. Il couvre l’appel CM SK2 , le commerce de déploiementMSC4 les dérogations et le rôle prévu d’interprétation stratifiéeMST5

L’infrastructure est déjà là. Vous devez simplement cesser de traiter la fenêtre contextuelle comme une base de données