# Deduplicazione di segmenti di prove grafiche RAG in ***lucido.*RAG**

<datetime class="hidden">2026-01-17T14:00</datetime>

<!-- category -- C#, lucidRAG, Vector Search, Machine Learning, Knowledge Graphs -->
> **Nota:** Questo non è un normale articolo di blog. È un **specificazione tecnica** Scrisse per una caratteristica concreta. ***lucido.*RAG**.
> Iterativemente aggiungo questo documento a codificare-LLM focalizzati durante lo sviluppo per ragionare sul commercioM SK1offs,validare le supposizioniMSC3 e convergere su una implementazione razionaleMNK4

Questo documento descrive un sottosistema da ***lucido.*RAG**, un progetto IM SK1 sto sviluppando in modo attivo.

Un requisito fondamentale di ***lucido.*RAG** è la capacità di estrarre. **segmenti di prove.** - frasi , paragrafiM SK2 titoli, sottotitoliMNK4 frammentiMMK5 o blocchi strutturati SNK6 e assicurare che quegli segmenti siano **deduplicato** senza distruggere un segnale utile.

***lucido.*RAG** lavora analizzando e estrarendo *La migliore.* prova disponibile dai documenti, immaginiMSC1 audio, e dati strutturatiM SK3 Contrariamente alla maggior parte delle implementazioni RAG **Non.** Immagazzinare LLM-generare riassunti come artefatto primario. In molti casi , l'ingestione non richiede alcun LLM M SK3although one can be used when escalation is justifiedMSC4

Invece, ***lucido.*RAG** applica una vasta gamma di tecniche deterministiche e probabilistiche a:

* estrarre segmenti potenziali.
* valutare il loro valore informale.
* e rimangono solo i più forti rappresentanti.

**La deduplicazione è una parte fondamentale di questo processo.**

L'equità delle semplici stringhe non è sufficiente. Lo stesso concetto viene spesso espresso con formulazioni diverse, struttura , o modalitàM SK3 Trattare queste come distinte porta ad un almacenamiento ridondante e a un cattivo comportamento in avalitoMSC4

**Il problema si complica al tempo di recupero.**

Quando i risultati sono recuperati ( tramite SQLM SK1 inserzioni vettoriali, BMMSC3 o ibridiMSL4 alimentando un LLM con segmenti multipli che esprimeno tutti la stessa idea sottostante producono risposte dull'appendice , ripettiveMST6 Cinque viciniM ST7 frammenti identici da diversi documenti non aggiungono chiarezza MST8 lo diluisconoM st9

Per indirizzare questo, ***lucido.*RAG** Tratterà la deduplicazione come un **Il problema di compilazione della classe first-**, non una postaM SK1filtro automatico.

Il resto di questo documento descrive come è stata progettata quella strategia di duplicazione. Questa è parte del modo in cui lavoro con i Code LLMs, adattando il mio ['Agile Speccing'](https://www.mostlylucid.net/blog/writingfeaturespecs) adattato ai bisogni del codice LLMS.

Questo cristallizza i pensieri, diversi concetti e costringe il LLM a documentarlo's M SK2processi di pensiero '. Questa è la prima fase per assicurare al LLM *costruisce la cosa giusta.*.

[Vedete di più su ***lucido.*RAG** qui. ](https://www.lucidrag.com)

# Strategia di deduplicazione

***lucido.*RAG** usa una strategia di duplicazione in due fasi- per eliminare i contenuti ridondanti mentre si conservano segnali importanti. Questo è un **Il filtro conserva il segnale-**, non normalizzazione del contenuto.

## Apertura

```
┌─────────────────────────────────────────────────────────────────────────────┐
│                           INGESTION (Per Document)                          │
│                                                                             │
│  Document → Extract → Embed → DEDUPE (intra-doc) → Index to Vector Store   │
│                                   │                                         │
│                                   ├─ Near-duplicates: boost salience        │
│                                   └─ Exact duplicates: drop (no boost)      │
└─────────────────────────────────────────────────────────────────────────────┘
                                    │
                                    ▼
┌─────────────────────────────────────────────────────────────────────────────┐
│                          RETRIEVAL (Cross Document)                         │
│                                                                             │
│  Query → Search → Rank (RRF) → DEDUPE (cross-doc) → Top K → LLM Synthesis  │
│                                   │                                         │
│                                   └─ Keep segment with highest RRF score    │
└─────────────────────────────────────────────────────────────────────────────┘
```

---


## Garantie di progettazione

Queste invarianti sono mantenute dal sistema di deduplicazione:

| Garantia | Descrizione |
|-----------|-------------|
| **L'ordine conservato.** | La deduplicazione non cambia mai l'ordine semantico dopo la classifica RRF.
| **Nessuna perdita di concetto.** | La duplicazione non elimina mai tutti gli esempi di un concetto.
| **I confini del documento sono rispettati.** | La duplicazione non supera mai i confini del documento durante l'ingestione.
| **Contenuto immutabile** | La duplicazione non altera mai le inserzioni o il contenuto del testoM SK1 solo la selezione e i punteggi di salienza |
| **Determinista** | Given identical inputs and config, deduplication produce identical outputs |

---


## Non-Goali

Questo sistema lo fa esplicitamente. **Non.** provare a:

- **Detettare la contraddizione dei fatti.** - Due segmenti che dicono cose opposte non sono duplicati.
- **Canonizzare la verità** - Non scegliamo una versione "corrente" tra le varie fonti.
- **Collapse i parafrasi attraverso i documenti durante l'ingestione** - Ogni documento mantiene i suoi segmenti.
- **Normalizzare la terminologia** - "ML" e "apprendimento automaticoM SK4 sono conservati separatamente in diversi moduli.
- **Sostituire la risoluzione dell'entità** - Quello' il GraphRAGM SK2 il lavoroMSC3 che opera ad un altro livello

---


## Determinismo & Reproducibilità

La deduplicazione è completamente determinista:

- **Gli inserimenti sono immutabili.** una volta calcolata al momento dell'estrazione.
- **La classificazione è stabile.** - segmenti con uguale salienza mantengono l'ordine originale
- **Niente casualità.** - nessun campioneM SK1 nessuna approssimazione ANN, nessuna soglia probabilistica
- **Non c'è stato esterno.** Le decisioni di dedupzione - dipendeno solo dal segnale attuale.

**Perché questo conta:** I risultati di ricerca dei debuggeri degli utenti possono essere affidati al fatto che re-running con gli stessi input produce gli stessi output. ***lucido.*RAG**' la più ampia "l'incertezza limitataM SK2 la filosofia SSK3 l'incredibile corrispondenza con il comportamento deterministico.

---


## Perché due fasi?

### Fase 1: Duplicazione dell'ingestione

**Obiettivo:** Ridurre l'archiviazione e prevenire la redondanza intra-documento-

**Problema:** I documenti spesso contengono contenuti ripetuti:

- Il testo del boilerplate (headers,footerM SK2disclaimers )
- Copia-sezioni sparite
- Lo stesso concetto spiega in molti modi.

**Solution:** Duplicare dentro ogni documento prima dell'indexazione.

**Key Insight:** Quasi i duplicati- vengono trattati come *prova di importanza indipendente*Se un autore spiega un concetto in tre modi diversi, questo concetto è importante.

### Deduplicazione di rilevamento della fase 2:

**Obiettivo:** Prevenire che il LLM riceva informazioni ridondanti attraverso i documenti.

**Problema:** Quando si fanno ricerche su più documenti, paragrafi simili possono apparire in diverse fonti . Il LLM non dovrebbe' descrivere le stesse informazioni più volteM SK3

**Solution:** Dopo essere classificati da RRF ( che combina semantice somiglianza, corrispondenza tra le parole chiaveM SK2 salienza , e frescozzaMSC4 duplicare per tutti i documenti mantenendo il più alto SSK5 segmento di classificazioneMST6

**Perché dopo RRF?** Il punteggio RRF rappresenta la migliore misura globale della rilevanza. Duplicare prima di classifica perderebbe questo segnaleM SK1

### Perché la salienza aumenta solo durante l'ingestione

La separazione è intenzionale:

| Fase | Quello che cattura |
|-------|------------------|
| **Incremento dell'ingestione** | L'accento dell'autore - quanto il documente insiste su un concetto
| **Il punteggio di recupero** | Relevance della domanda - quanto bene il contenuto corrisponde all'intenzione dell'utente SSK2

Mischiarle alla ricerca renderebbe l'intenzione del documento in conflitto con quella dell'utente. Un concetto ripetuto 5 volte in un documento è importante. *a quel documento.*, ma può non essere rilevante *a questa domanda.*. Sostenendo il segnale dell'autore, senza pregiudicare i risultati della domanda, durante l'ingestione.

---


## Fase 1: Duplicazione dell'ingestione

### Localizzazione

`src/Mostlylucid.DocSummarizer.Core/Services/BertRagSummarizer.cs`

### Metoda

`DeduplicateSegments()`

### Algoritmo

```
1. Filter segments by minimum salience threshold (0.05)
2. Sort by salience score (highest first)
3. For each segment:
   a. If no embedding → keep (can't compare)
   b. Check cosine similarity against all selected segments
   c. If similarity >= 0.90:
      - If same ContentHash → exact duplicate, drop silently
      - If different ContentHash → near-duplicate, boost kept segment's salience
   d. If no match → add to selected list
4. Apply salience boosts: +15% per near-duplicate merged
5. Cap salience at 1.0 to prevent any single concept from dominating
```

### Parametri

| Parametere | Default SSK2 Description |
|-----------|---------|-------------|
| `similarityThreshold` |
| `salienceThreshold` | 0.05 ♫ ♫ | La salienza minima da considerare ♫(ruore dei filtri ♫
| `boostPerNearDuplicate` |

### Esempi.

**Esatto Duplicato (No Boost)**

```
Segment A: "Contact us at support@example.com" [hash: abc123]
Segment B: "Contact us at support@example.com" [hash: abc123]  ← same hash
Result: Keep A, drop B, no boost (likely boilerplate)
```

**Quasi-Duplicato (Boost AppliedM SK2**

```
Segment A: "Machine learning models require training data" [hash: abc123]
Segment B: "ML systems need data for training" [hash: def456]  ← different hash, 0.92 similarity
Segment C: "Training data is essential for ML" [hash: ghi789]  ← different hash, 0.91 similarity
Result: Keep A with +30% salience boost (concept emphasized 3 ways)
```

### Razionalità per i limiti

- **0.90 somiglianzaM SK1** Sulla base della ricerca (NVIDIA NeMo usa la standardizzazione industriale per il dedupo semantico 0.90-0.92,
- **0.05 salienza:** Filtra segmenti di valore molto bassi- mantenendo la maggior parte del contenuto.
- **15% incrementoM SK1** Signale significativo senza superamento-weighting ripetitivi concetti

---


## Deduplicazione di rilevamento della fase 2:

### Localizzazione

`src/LucidRAG.Core/Services/AgenticSearchService.cs`

### Metoda

`DeduplicateByEmbeddingPostRanking()`

### Algoritmo

```
1. Receive ranked results (already sorted by RRF or dense score)
2. For each segment (in score order):
   a. If no embedding → keep
   b. Check cosine similarity against all selected segments
   c. If similarity >= 0.90 → skip (higher-scored duplicate already selected)
   d. If no match → add to selected list
3. Return deduplicated list (maintains score ordering)
```

### Parametri

| Parametere | Default SSK2 Description |
|-----------|---------|-------------|
| `similarityThreshold` |

### Perché Post-RRF?

RRF (Reciprocal Rank Fusion) combina quattro segnaliM SK2

1. **punteggio denso:** Semantica somiglianza alla domanda
2. **BM25 punteggio:** Lexico/combinazione di parole
3. **Il punteggio di Salience:** Importanza del documento
4. **punteggio di frescozza:** Innalzamento della recenzione

Deduplicare AFTER RRF significa tenere il segmento che corrisponde meglio alla domanda in tutte le dimensioni, non solo la semintica somiglianza.

### Esempio

```
Query: "How do I configure authentication?"

Results before dedup:
1. [Doc A] "Authentication is configured via config.yaml..." (RRF: 0.052)
2. [Doc B] "Configure auth using the config.yaml file..." (RRF: 0.048, similarity to #1: 0.93)
3. [Doc A] "Set the API key in environment variables..." (RRF: 0.041)

Results after dedup:
1. [Doc A] "Authentication is configured via config.yaml..." (RRF: 0.052)
2. [Doc A] "Set the API key in environment variables..." (RRF: 0.041)

Doc B's similar paragraph dropped - Doc A's version had higher RRF score.
```

---


## Mode di fallimento & Commercio-Offs

### Limitazioni conosciute

| Mode di blocco | Descrizione | Mitizione S|
|--------------|-------------|------------|
| **Falso positivo (overM SK1dedup)** | Due concetti distinti, ma intimamente correlati, possono superare 0.90 la somiglianza
| **Falso negativo (in bassoM SK1in alto)** | Segmenti molto brevi possono essere inseriti maleM SK1 manca una semantice somiglianza | Hash- La rilevazione del duplicato accurata basata sul codice cattura un testo identico SSK4
| **L'inserzione del drift** | Cambiare i modelli di inserzione invalida le supposizioni di dedup | Richiede una ri-ingestione completaM SK2ingestioni; gli inserimenti sono immutabili dopo averli conservati ♫|
| **Sensibilità di ordine** | Selezione affamata significa primo altoM SK1 Segmento di successo vince | Mitigato dal sistema di classificazione stabile

### Commercio accettato-offs

- **Precision over recall:** Preferiamo tenere occasionalmente i duplicati vicino a - piuttosto che rimuovere accidentalmente diversi contenuti.
- **Conservazione oltre la precisione:** Stiamo conservando per documento - piuttosto che dedup globale per preservare l'attribuzione della fonte.
- **Semplicità sull'ottimizzazione:** O(nM SK1 è accettabile per tipiche dimensioni del documento; LSH aggiunge complessità

---


## Considerazioni multilinguali

Comportamento di deduplicazione con contenuti multilingui:

| Scenario | Comportamento | Razionalità S|
|----------|----------|-----------|
| **Lo stesso linguaggio.** | Si applica il dedupo normale | L'Embedding cattura la somiglianza semantica |
| **Parafrase di lingua Cross-** | Non deduplicato | Conserva la fonte-La diversità linguistica |
| **Documento in lingua mixed-** | Dedup all'interno dei cerchi di lingue | L'incorporazione della somiglianza separa naturalmente le lingue

**scelta di design:** Cross-Linguale dedup non è esplicitamente supportatoM SK1 Questo salva la capacità di recuperare lo stesso fatto nell'utente'la lingua preferita o di confrontare come le frasi delle diverse fonti siano diverseMSC3

Amplification futura: CrossM SK1Linguale dedup può essere stratificato attraverso la traduzione-Invariant embeddings se necessario .

---


## Sicurezza & Considerazioni avversarie

Il sistema di deduplicazione include protezioni implicite:

| Vettore d'attacco | Protezione |
|---------------|------------|
| **Inflazione saliva attraverso la ripetizione** | Boost capped at 1.0; exact duplicates don't boost |
| **Copy-paste spam attraverso i documenti** | Cross-doc dedup alla ricerca elimina risultati ridondanti |
| **Manipulazione del punteggio attraverso l'injezione duplicata** | Dedup si verifica dopo la classificazioneM SK1 prevenire l'inflazione dei punteggi |
| **Inondazioni di pannelli** | La rilevazione accurata di un'accoppiata si abbassa senza innalzamento |

**Nota:** La deduplicazione non è un confine di sicurezza. Il contenuto nocivo che passa i filtri d'ingestione sarà indexato. Il filtramento del contenuto dovrebbe avvenire in prima lineaM SK2

---


## Interazione con GraphRAG

Deduplicazione e GraphRAG sono intenzionalmente ortogonali:

| Il sistema | Opera su | Obiettivo
|--------|-------------|---------|
| **Deduplicazione** | Segmenti ( blocchi di testo) | Rimuovere risultati di ricerca ridondanti SSK4
| **GraphRAG** | Entità

**Perché separare:**

- Un segmento che menziona "Apple" e un altro che menzione "la compagniaM SK3 può deduppiare come un testo simile ma rappresenta la stessa entità |- che | ' | GraphRAG | L'opera da risolvere
- Dedup non ha ' bisogno di consapevolezza dell'entità; funziona puramente sulla semantice somiglianza.
- Entità-aware dedup potrebbe essere aggiunto più tardi come un miglioramento, non come un sostituto

---


## Observabilità & Metrica

### Logging attuale

Ingestione:

```
[dim]Deduplication: 150 → 98 segments[/]
```

Retrieval:

```
Post-ranking deduplication: 50 → 42 segments (removed 8 cross-doc duplicates)
```

### Metrica raccomandata

Per monitorare la produzione, consideriamo il tracciamento:

| Metrica | Description | Range salutare S|
|--------|-------------|---------------|
| `dedup_ratio_ingestion` | % segmenti rimucchiati durante l'ingestione
| `dedup_ratio_retrieval` | % Segmenti rimucchiati alla ricerca | | | 5-20% |
| `avg_salience_boost` | Riscaldamento medio applicato per ogni documento
| `max_salience_boost` | Incremento più alto in un documento | < | | 3 | 4 | l'altro concetto domina | 5 | 6
| `dedup_by_doc_type` | Tasso di deduzione segmentato per tipo di documento | Varie

### I consigli di debugging

- **Diminuzione di ingestione elevata (>50%):** Il documento può avere una boilerplate eccessiva o essere generato auto-.
- **Low ingestion dedup (<5%):** Il documento ha diversi contenuti (goodM SK1 o le inserzioni sono scarse (investigate)
- **High retrieval dedup (>30%):** La domanda può essere troppo ampia, o il corpus ha molti documenti simili.
- **Salienza che si avvicina 1.0:** Il concetto è stato fortemente sottolineato; verificarlo ' la sua legittimità, non spam.

---


## Configurazione

La deduplicazione è configurata tramite `DocSummarizerConfig.Deduplication` la sezione in `appsettings.json`:

```json
{
  "DocSummarizer": {
    "Deduplication": {
      "Ingestion": {
        "Enabled": true,
        "SimilarityThreshold": 0.90,
        "SalienceThreshold": 0.05,
        "EnableSalienceBoost": true,
        "BoostPerNearDuplicate": 0.15,
        "MaxSalienceBoost": 1.0,
        "BoostDecayMode": "Logarithmic",
        "LogBase": 2.0
      },
      "Retrieval": {
        "Enabled": true,
        "SimilarityThreshold": 0.90,
        "MinRelevanceScore": 0.25
      },
      "Analytics": {
        "EnableLogging": true,
        "EnableMetrics": true,
        "HighIngestionDedupThreshold": 0.50,
        "HighRetrievalDedupThreshold": 0.30,
        "HighSalienceBoostThreshold": 0.60
      }
    }
  }
}
```

### Configurazione dell'ingestione

| Parametere | Default SSK2 Description |
|-----------|---------|-------------|
| `Enabled` | `true` | Enable/disable ingestion deduplication |
| `SimilarityThreshold` | `0.90` | Soglia di somiglianza delle cossine per la rilevazione del duplicato |
| `SalienceThreshold` | `0.05` | La salienza minima da considerare (ruore dei filtriM SK2 SSK3
| `EnableSalienceBoost` | `true` | Aumento della salienza per quasi-duplicati |
| `BoostPerNearDuplicate` | `0.15` | Incremento di base per vicinoM SK1duplicato
| `MaxSalienceBoost` | `1.0` | Capa maximale di salienza |
| `BoostDecayMode` | `Logarithmic` | `Linear` o `Logarithmic` decadere |
| `LogBase` | `2.0` | Base per la decasione logaritmica |

### Configurazione di Ricerca

| Parametere | Default SSK2 Description |
|-----------|---------|-------------|
| `Enabled` | `true` | Enable/disable retrieval deduplication |
| `SimilarityThreshold` | `0.90` | Soglia di somiglianza delle cossine |
| `MinRelevanceScore` | `0.25` | Un punteggio RRF minimo per includere |

### Configurazione delle analisi

| Parametere | Default SSK2 Description |
|-----------|---------|-------------|
| `EnableLogging` | `true` | Operazioni di duplicazione dei log |
| `EnableMetrics` | `true` | Raccolgere parametri per monitorare |
| `HighIngestionDedupThreshold` | `0.50` | Avvertire se >50% è duplicato durante l'ingestione.
| `HighRetrievalDedupThreshold` | `0.30` | Ossia se >30% è duplicato alla ricerca |
| `HighSalienceBoostThreshold` | `0.60` | Avvertire se l'aumento supera 60% |

### Incoraggiare i modi di fallimento

**Il modo lineare** (simpleM SK1 prevedibile):

```
boost = boostPerNearDuplicate × count
```

Esempio: M SK1 vicino-dupes × ≥0.15 ≤= ±+45% aumento

**Mode logaritmici** (risultato diminutivo,defaultM SK2

```
boost = boostPerNearDuplicate × log₂(1 + count)
```

Esempio: M SK1 vicino-dupes → ≥0.15 ≤× log

Il modo logaritmico è raccomandato perché:

- I primi due duplicati hanno il segnale più forte (accento dell'autoreM SK1
- Molti duplicati possono indicare che la boilerplate, non è importante.
- Prevede l'inflazione di salienza in fuga.

---


## Considerazioni di performance

### La complessità

| Fase | complessità | dimensione tipica S| impatto M|
|-------|------------|--------------|--------|
| Ingestione | OM SK2n² | \50-500 Segmenti SSK6 |< | | 100ms | SSK9
| Retrieval | OM SK2m² | \20-100 segmenti SSK6 |< | | 10ms | SSK9

### Scalare il percorso

Per documenti molto grandi (10,000+ segmenti):

1. **LSH (Località-Hashing sensibileM SK2** O(nM SK1 dedupa approssimativa
2. **Paragonazione di lotti:** Procedere in blocchi per ridurre la memoria
3. **Filtrazione precoce:** Un limite di salienza più aggressivo.

La implementazione attuale è ottimizzata per tipiche dimensioni di documenti. LSH aggiunge complessità senza beneficio per la maggior parte dei casi di uso.

---


## Paragonazione con la ricerca

| Approco | Soglia SSK2 Source |
|----------|-----------|--------|
| lucidRAG
| NVIDIA NeMo Curator [Documenti SemDeDup](https://docs.nvidia.com/nemo/curator/latest/curate-text/process-data/deduplication/semdedup.html) |
| MinHash LSH [Google C4, GPT-3 carta](https://huggingface.co/blog/dedup) |
| SemHash [GitHub](https://github.com/MinishLab/semhash) |

Il nostro limite di 0.90 è in accordo con le migliori pratiche dell'industria per la deduplicazione semantica.

---


## Cosa non è duplicato?

| Tipo del contenuto | La ragione |
|--------------|--------|
| CrossM SK1documento all'ingestione | Conserva la risoluzione e l'attribuzione per la fonte -
| BassoM SK1Contenimento di somiglianza (<0.90)
| Diversi tipi di segmenti | La classifica e il paragrafo hanno ruoli strutturali diversi |
| Cross-parafrase linguistiche | Preserva la diversità linguistica |

---


## Status di Implementazione

| Carattolo | Livello | Livellatura S|
|---------|--------|----------|
| Porti di soglia configurabili `DeduplicationConfig` Classe |
| Riscrescimento della decasione ( scala di blocco ) S| \✅ Implementato SSK5 `BoostDecayMode.Logarithmic` |
| Analitica di deduppiamentoM SK1metria | ✅ Implementata SSK4 `DeduplicationResult<T>` record |
| Integrazione dei servizi DI | ✅ Implementata M| `IDeduplicationService` |

## futuri miglioramenti

1. **Dedup analytics dashboard:** Il tracciamento visivo dei tassi per ogni tipo di documento
2. **Cross-opzione linguistica:** Traduzione-invariante embeddings for multilingual dedup
3. **Entità- dedupo informato:** Utilizzate le entità GraphRAG come segnale aggiuntivo (non sostituzione)
4. **Prometheus/OpenTelemetry:** Exporte le misurazioni per il controllo dei pannelli.

---


## Summary

Questa strategia di duplicazione:

- **Conserva il segnale.** - QuasiM SK1 i duplicati aumentano l'importanza piuttosto che essere buttati via.
- **Respecta i confini.** - Documenti mantengono set di segmenti indipendenti
- **I ranghi poi filtrano.** - Usa il segnale RRF completo prima del dedupmento didoc
- **Funziona in modo sicuro** - Preferisce tenere il contenuto piuttosto che eliminare aggressivamente.
- **Rimangono deterministi.** - Gli stessi input producono sempre gli stessi output.