# DoomSummarizer: DocSum marizer 's YoungerM SK2 Smarter Brother

<!--category-- AI, LLM, RAG, C#, Deep Research, Lucene, Knowledge Graph, Time Boxed Tool -->
<datetime class="hidden">2026-01-29T10:00</datetime>

Recherche approfondie sans poches profondes.

Lorsque "Deep Research" a débarqué dans les outils d’AI de qualité supérieure , J’ai été curieuxM SK3 ce qu’est-ce que c’est?

### DoomSummarizer exploite un flux de travail similaire,, mais sa conception optimise le "read + réduisantM SK3 le processus pour être principalement déterministe et localiséMSC4 avec le Modèle langage large (LLMMST6 employé principalement à la synthèseMSL7

Dans cette approche, la force de l’étape de réduction élimine le besoin d’un modèle gros et coûteux pour produire des résultats satisfaisants.

En particulier, J’avais déjà plusieurs éléments de base essentiels, y compris des graphiques de connaissances multiples - la récupération de sources M SK3 l’extraction d’entités , les graphes de savoir MSC5 et le classement fondé sur - qui sont partagés avec lucidRAG et la série DocSummarizer

La composante manquante n’était pas un manque de capacités, mais plutôt une compréhension de la façon d’appliquer efficacement ces éléments existants.

Dans les outils commerciaux, le terme « recherche approfondie » signifie habituellement un processus de travail qui prévoit une approche de recherche.

Une grande partie de la valeur est attribuable à l’amélioration des sources d’entrées :

Exemples: [Recherche approfondie OpenAI](https://openai.com/index/introducing-deep-research/), [Recherche approfondie sur les gémins](https://blog.google/products/gemini/new-gemini-app-features-march-2025/), et [Recherche approfondie sur la perplexité](https://www.perplexity.ai/hub/blog/introducing-perplexity-deep-research) (appelé aussi “Mode de recherche” dans leur interface

DoomSummarizer suit le même processus de travail, mais ilM SK1 est conçu de telle sorte que la plupart des “ lectures + réductionsMSC4 travaux sont déterministes et locauxMST5 et le LLM est utilisé principalement pour la synthèseMSL6

Si l’étape de réduction est forte, vous n’avez pas besoin d’un modèle gros et coûteux pour obtenir un bon résultat.

Entre [lucidRAG](https://github.com/scottgal/lucidrag) et la série DocSummarizer, J'ai déjà eu la plupart des éléments de base: multiM SK2 recherche de sourcesMSC3 extraction d'entitésMST4 graphiques de connaissancesMSV5 emplacementMSS6 classement fondé sur le MSV7

La pièce manquante était't capacité. Elle était *orchestration*. Comment prendre tous ces signaux et les fusionner en quelque chose cohérent avec un petit modèle?

Que's DoomSummarizer . Nomné après le scrolling du doom, parce qu’il tourne de la sorte que vous n’avez pas à le faire.

Mais cet article ne traite pas de l’outil, mais des idées qui le font fonctionner.

[![Mise à jour de GitHub](https://img.shields.io/github/v/release/scottgal/lucidrag?filter=doomsummarizer*&label=doomsummarizer)](https://github.com/scottgal/lucidrag/releases?q=doomsummarizer)

Il s'agit de **Partie 5** de la série DocSummarizer.

Si vous voulez les travaux de fond d’abord:

- [Partie 1: Architecture](/blog/building-a-document-summarizer-with-rag)
- [Partie 2: Utilisation de l'outil](/blog/docsummarizer-tool)
- [Partie 3: Concepts avancés](/blog/docsummarizer-advanced-concepts)
- [Partie 4: Établissement de pipelines RAG](/blog/docsummarizer-rag-pipeline)

Il s’agit également d’un [Outil encadré du temps](/blog/timeboxedtool-consoleimage).

---


[toc]

## L’idée de base: RAG réduit

Le RAG standard fait déjà la récupération sémantique des documents de tronçons.

La douleur est le dernier pas.

Qu'arrive-t-il si vous faites plus de travail? *précédemment* Le LLM voit quelque chose.

Il s’agit de l’exemple suivant : **Réduire avant de produire**. Prendre les documents bruts et les réduire de façon déterministe à leurs signaux essentielsM SK1 embeddings , ranks

```mermaid
flowchart TD
    subgraph REDUCE["REDUCE: Distil to Signals"]
        Q[Query] --> Decompose[Composite Decomposition]
        Decompose --> S1[Subquery 1]
        Decompose --> S2[Subquery 2]
        S1 & S2 --> Fetch[Multi-Source Fetch]
        Fetch --> Embed[ONNX Embed Each Item]
        Embed --> Rank[6-Signal RRF Fusion]
        Rank --> TextRank[TextRank Extraction]
        TextRank --> NER[Entity Extraction]
        NER --> Profile[Entity Profile Vectors]
        Profile --> Segments[Salient Segment Extraction]
    end

    subgraph SYNTH["SYNTHESIZE"]
        Segments --> Standard["Standard Path - 1 LLM Call"]
        Segments --> LongForm["Long-Form Path - N+3 LLM Calls"]
    end

    style REDUCE fill:#1a1a2e,color:#e0e0e0
    style SYNTH fill:#162447,color:#e0e0e0
```

La phase de réduction est déterministe: embeddings , ranking, extraction d’entitésMSC3 TextRankM SK4 cotation des segmentsMST5 Aucun appel LLMMSL6

La synthèse est la seule étape du LLM. Pour une demande standard, les signaux réduits sont suffisamment propres pour **Un seul appel** Doit le travail. Pour les documents longsM SK1form document, un sentinel planifie la structure et le modèle principal génère des sections parallèles**N+3** appels pour les sections N).

Pour plus de détails sur ce modèle, voir [RAG réduit](/blog/reduced-rag).

## Phase de la carte: De la demande à des sources

Avant que rien ne soit réduit, la demande doit devenir des actions de recherche.

Un petit modèle sentinel local (0.6B dans mon casM SK1 mode JSON, température 0.1) interprète la demande brute en une intention structurée.

```mermaid
flowchart TD
    Q["User Query"] --> Sentinel["Sentinel: JSON Interpretation - categories, intent, entities, - temporal hints, tone"]
    Sentinel --> Router["Source Router - YAML category → source mapping"]
    Router --> S1["gnews:AI safety"]
    Router --> S2["search:AI regulation"]
    Router --> S3["bbc:technology"]
    Router --> S4["reddit • hn"]
    S1 & S2 & S3 & S4 --> Fetch["Parallel Fetch - circuit breaking + rate limiting"]
    Fetch --> Merge["Merge + Deduplicate - → reduce phase"]

    style Sentinel fill:#1e3a5f,color:#e0e0e0
    style Router fill:#0d3b2e,color:#e0e0e0
```

Le sentinel extrait des champs structurés:

- Catégories thématiques (avec pondérations de confianceM SK1
- Tendance de la demande (nouvelles, QCM SK2 rechercheMST3 comparaisonMSS4 commentMSSS5
- Sensibilité temporelle (breaking / aujourd’hui / semaineMSC3
- Entités désignées
- Pour les questions composées: sous-questions décomposées M SK1avec pronons résolus )

**Choix de la source** se produit en six phases:

1. **Sources explicites**: l'utilisateur a dit `"from HackerNews"` → `hn` va directement dans
2. **Demandes de recherche**: le sentinel ' les termes de recherche optimisés deviennent vibes- les appels API admissiblesM SK3DuckDuckGoMSC4 BraveMST5 Google News RSSMst6
3. **Répartition des catégories**: les pondérations thématiques des flux RSS par l'entremise de la configuration YAML . Une demande concernant " la réglementation AI " les voies vers les flux techniques *et* Programmes d'information sur les politiques
4. **Enrichissement de la recherche**: `research` ou `deep_dive` intentions ajouter archive
5. **Enrichissement de l'entité**: les entités désignées de l'NER obtiennent leurs propres demandes gnews | `gnews:OpenAI`)
6. **Étage de la diversité**: si les sources choisies sont inférieures à 3 les défauts de remplir

Les identifiants de source sont obtenus parallèlement à la rupture du circuit de source.

Vibes modifient les termes de recherche avant qu’ils ne soient saisis par une API. Par exemple, `--vibe doom` Questions de préfixes avec *"concernant les problèmes risque d’entraîner des problèmes dans le*, remanier ce qui revient avant tout classement

Si vous voulez l'arrière-plan des bits de résilience, voir [Utilisation de Polly pour les retraités](/blog/usingpollyforretries) (blocateurs de circuits ) et [Pression arrière dans les systèmes d'attente](/blog/backpressure-queueing-systems) (limitation du taux et pression de reculM SK1

## Déconstruire la demande

La plupart des systèmes de recherche traitent : "Qu'est-ce qui est nouveau dans le domaine de la sécurité de l'AI et quelles sont les dernières réglementations?

Le sentinel décompose les demandes combinées:

```json
{
  "is_composite": true,
  "subqueries": [
    "What's new in AI safety?",
    "What are the latest AI regulations?"
  ]
}
```

L’option intéressante est ce qui se passe ensuite. Chaque sous-question reçoit son propre emplacement ONNX (voir [ONNX: Modèles ML exploités localement](/blog/docsummarizer-advanced-concepts#onnx-running-ml-models-locally)). Lorsque j’obtient des points pour les articles **la similitude maximale des cosine** sur toutes les embeddings de sous-question, non la moyenneM SK1

Pourquoi le maximum? Un article qui répond parfaitement M SK1 Sécurité de l’AI " ne devrait pas être pénalisé' pour n’avoir rien dit au sujet des règlementsMST4 MST5 L’évaluation l’enfouierait sous un match partiel moyenMSS6 La similitude maximale signifieMSSS7 si un article souffre *Toute* part of your question, it rises. The alternativeM SK2 averagingMSC3 rewards bland articles that vaguely touch everything .

## Écoulement de signaux hétérogènes

J’ai six signaux de classement. Ils ont des échelles complètement différentesM SK1

```mermaid
flowchart LR
    subgraph Signals
        BM25[BM25 - Keyword Match]
        Fresh[Freshness - 48h Half-Life]
        Auth[Authority - HN/Reddit Score]
        QSim[Query Similarity - Cosine]
        Vibe[Vibe Alignment - Cosine]
        Qual[Quality - Clickbait Detector]
    end

    subgraph RRF[RRF Fusion]
        direction TB
        R[Rank Each Signal - Independently]
        F["score = Σ weight × 1/(60 + rank)"]
    end

    BM25 & Fresh & Auth & QSim & Vibe & Qual --> R --> F

    style RRF fill:#1e3a5f,color:#e0e0e0
```

HN points vont jusqu'à des milliers. La similitude cosine est M SK1 à 1. La fraîcheur décline exponentiellement. Vous pouvezMSC4 ne pas les ajouter de façon sécuritaireMska5 Les échelles sont incompatiblesM Ska6

Le signal clé ici est BM25 à travers plusieurs champs (BMM SK2F). Si vous voulez l'arrière-plan sur BMCSK4 voir [DocSummarizer Part 3](/blog/docsummarizer-advanced-concepts#bm25-the-sparse-retrieval-workhorse).

**[Fusion de rang réciproque](/blog/docsummarizer-advanced-concepts#hybrid-search-with-rrf)** (Cormack et coll. *Ã‰tablissement d'un programme de rÃ©seau communautaire*: `score = Σ weight × 1/(k + rank)` (avec `k=60`).

Si vous voulez l'arrière-plan complet sur RRF, Partie 3 le couvre. C'est là que le tournement est **Les poids s'adaptent au type de demande**. Le sentinel détecte l’intention , et le scoreur se transforme en lui-même

- Enquêtes en ligne de temps ("Qu'est-ce qui s'est passé aujourd'hui?
- Questions des explicateurs ("Comment fonctionne l'informatique quantique?
- Roundups et comparaisons ont leurs propres profils réglés.

## Vibes en tant que dimension de récupération

Ce qui a commencé comme une joke. Maintenant, c’est la fonction préférée de ' .

A "vibeM SK1 n’est pas't mot de recommandation prompte . Il **signal de classement premier-** embedded into the retrieval pipeline:

```mermaid
flowchart LR
    V["--vibe doom"] --> Expand["Query Expansion - 'concerning risks issues in...'"]
    V --> Embed["Vibe Embedding - 'vulnerability breach layoffs - recession crisis warning...'"]
    Embed --> Score["Cosine Similarity - per article"]
    Score --> RRF["RRF Signal - weight: 0.4"]

    style V fill:#8b0000,color:#e0e0e0
```

Trois things happen when you set a vibe:

1. **Expansion de la demande** - la recherche est précédée d'un moodM SK1qualifications appropriées
2. **Emplacement de la vibration** Le texte représentatif - est incorporé comme cible 384-dim
3. **Signale de classement** - articles codés par la similitude des cosines avec l'incorporation de la vibe

Les vibes personnalisées fonctionnent identiquement. `--vibe "contemplative philosophical"`- Votre texte devient à la fois le préfixe de la demande et l’objectif de classement . Le système n’obtient pas de distinction entre les données prédéfinies et les données personnalisées . Il intègre tout ce que vous lui donnez.

## Profils d’entités, Nombre des entités

Voici une erreur que j’ai faite d’abord.

Deux articles mentionnent à la fois "CalifornieM SK1

1. *Le bureau de la Californie annonce l’équipe de sécurité*
2. *"Les agriculteurs de noix de Californie sont confrontés à la sécheresse "*

Cote des entités partagées: M SK1 Par conséquent liées! Obviellement erronée .

La solution consistait à considérer les entités comme des vecteurs, et non comme des chaînes.

Il s’agit de [Le modèle de fuzziness restreint](/blog/constrained-fuzziness-pattern)Le modèle NER propose des entités, mais la pondération déterministe décide de ce qui importe.

Chaque document reçoit un **Profil de l'entité pondérée** Encodage du vecteur (a 384-dim *qui* les entités apparaissent et leur caractère distinctif):

```
weight = TF × IDF × confidence × type_weight
profile = L2_normalize(Σ entity_embedding × weight)
```

```mermaid
flowchart TD
    subgraph Doc1["Article: OpenAI Safety Team"]
        E1["OpenAI (ORG) - IDF: high - weight: 2.1"]
        E2["California (LOC) - IDF: low - weight: 0.3"]
        E3["Safety Team (MISC) - IDF: high - weight: 1.8"]
    end

    subgraph Doc2["Article: Almond Farming"]
        E4["California (LOC) - IDF: low - weight: 0.3"]
        E5["Almond Farmers (MISC) - IDF: high - weight: 1.9"]
        E6["Drought (MISC) - IDF: medium - weight: 1.2"]
    end

    Doc1 --> P1["Profile Vector - Dominated by OpenAI + Safety"]
    Doc2 --> P2["Profile Vector - Dominated by Farming + Drought"]
    P1 -. "low similarity" .- P2

    style Doc1 fill:#1a1a2e,color:#e0e0e0
    style Doc2 fill:#2d1a2e,color:#e0e0e0
```

IDF est la clé. M SK1Californie" apparaît en tonnes d’articles - faible IDFMST4 signal faibleMSSK5 ♫"OpenAIMSC7 est distinctifMSL8 haute IDF~, domine le profilMSR10 Maintenant les recherches de similitude fonctionnent~MSR11~ OpenAI regroupe des articles ensemble~M SR12~ Les articles agricoles regroupent séparément~MSL13~ Le partage MSR14~ClifornieM SR15~ devient bruit~M RS16~

La partie intelligente: **TF saturant**. Au lieu de compter le nombre de mentions brutes `1 + log(mentions)`. Une entité mentionnée 50 fois dans un long article ne reçoit pas

## La découverte de graphiques sémantiques

Les profils d’entités ne servent pas uniquement à comprendre les documents. **dimension de récupération**. Chaque documen 🥱tM SK2 son profil d'entité est indexé dans un graphe de l'HNSW.

Si vous voulez plus de détails sur HNSW et DuckDB VSS, voir [GraphRAG Partie 2: Minimum viable](/blog/graphrag-minimum-viable-implementation).

```mermaid
flowchart TD
    subgraph Retrieval["Three-Layer Retrieval (UNION)"]
        L1["Lucene FTS - keyword matches"]
        L2["Embedding HNSW - semantic similarity"]
        L3["Entity Profile HNSW - entity fingerprint match"]
        L1 & L2 & L3 --> Union["Union of all candidates"]
    end

    subgraph Enrich["Post-RRF Enrichment"]
        Top["Top 5 Ranked Items"] --> Agg["Aggregate Profile - mean of entity profiles"]
        Agg --> Graph["HNSW Search - min similarity: 0.30"]
        Graph --> Related["+3 Related Articles - scored below existing items"]
    end

    Union --> RRF["RRF Fusion"] --> Enrich

    style Retrieval fill:#1a1a2e,color:#e0e0e0
    style Enrich fill:#0d3b2e,color:#e0e0e0
```

Cela fonctionne en deux étapes:

**Au cours de la recherche**: lorsque le sentinel extrait des entités de la demande 2+, un profil d'entité de demande est calculé à l'aide de la même formule TFM SK3IDF. Ce dernier recherche dans l'indice HNSW les articles comportant des empreintes digitales similaires de l'entityMSC5 avec une similitude minimale de \0.25. Un article sur les préoccupations liées à la sécurité de |"OpenAI " surfaces même s'il n'y a jamais mention des termes exacts de la questionMSSK9 parce que son profil d’entités ( dominée par un niveau élevé

**Après le classement**: les articles classés au premier rang 5 ont leurs profils d'entité en moyenne dans un vecteur agrégéM SK2 Ce vecteur àgrégé recherche des articles connexes que le mot clé et les couches d'implantation ont complètement manquées. Les articles trouvés reçoivent une note juste inférieure à l'article classé le moins bas (×0.9) et sont marqués comme découverts *"par l’entremise d’entitésM SK1*. Cela attire les sources primaires auxquelles les articles de presse font référence, mais ne citent pas verbatimment

Trois couches de récupération se fusionnent par l'entremise d'une union: Les mots clés Lucene correspondent ∪ L'intégration correspond à l'HNSW ∪ Le profil de l'entité correspond à HNSWM SK3 La union est délibérément plus large que l'intersectionMSC4 Elle saisit les éléments sur lesquels apparaîtrait un signal unique quelconque.

Le chemin de chute (pour corpora sans profils d'entités encore ) utilise l'entité SQL coM SK2contrôle des occurrences`HAVING shared_count >= 2`). Il fonctionneM SK1 mais il 's O(NMSC4 au lieu d’OMska5log NM Ska6 Le `--backfill-entity-profiles` commande migre les corpora existants vers le chemin HNSW.

## Synthèse standard: Un appel LLM

C'est le chemin normal. `scroll "AI safety and regulation"` affiche ce message. Après la phase de réduction distille vos sources en segments classésM SK1 en doubles , entités- segments profiléesMSC4 la synthèse est un appel uniqueMNK5

```mermaid
flowchart TD
    subgraph REDUCE["Reduce Phase (ALL DETERMINISTIC)"]
        Items[Fetched Items] --> Embed[ONNX Embed All Items]
        Embed --> RRF[6-Signal RRF Fusion]
        RRF --> TR[TextRank Compression]
        TR --> Seg[Segment Extraction + Salience Scoring]
        Seg --> Dedup[Deduplication + Relevance Floor]
    end

    subgraph SYNTH["Synthesis (1 LLM CALL)"]
        Dedup --> Rerank["Semantic Re-Rank - by query similarity"]
        Rerank --> Budget["Smart Evidence Budgeting - redistribute unused chars"]
        Budget --> Gen["Single LLM Call - with curated evidence"]
        Gen --> Output[Final Summary]
    end

    style REDUCE fill:#0d3b2e,color:#e0e0e0
    style SYNTH fill:#1e3a5f,color:#e0e0e0
```

La phase de réduction fait le travail ardu. Au moment où le LLM voit quelque choseM SK1 il reçoit:

- **Seulement les articles de haut niveau**: rang de pertinence à 30% du meilleur article's cote
- **Diversité des sources**: est limité à 3 des articles par domaine pour les demandes de redressement
- **Semantic re-ranking**: items re-ordered by cosine similarity to the query embedding
- **Budgetage des preuves intelligentes**: les articles courts donnent un budget de caractère inutilisé aux articles longs , ainsi que l’espace de preuve n’est pas gaspillé
- **Blocs de preuve structurés**: `[E1] Title | topic | relevance` avec le contenu réduit au budget

Une LLM appelle ., ce qui correspond à la rémunération de [Réduction du RAG](/blog/reduced-rag): sélection , classement, dédoublementM SK3 et budgétisation tout se produit avant que le LLM ne constate quelque chose

## Production parallèle restreinte de longs pipelines

Long-form M SK1`--template blog-article`) est une bête différente . Vous'génerez un document de sections multiplesM SK3 à partir de douzaines de sourcesMSC4 et vous avez besoin d’une cohérence entre les sections sans appels coûteux de compression LLM

La réponse est la suivante : **[dragge de contexte fuzzy restreint](/blog/constrained-fuzzy-context-dragging)**. Il s'agit de mécanismes déterministes qui conservent la cohérence des sections croisées - tout en permettant une génération parallèle

```mermaid
flowchart TD
    subgraph Phase1["Phase 1: Evidence Preparation (DETERMINISTIC)"]
        Articles[Top 20 Articles] --> Segments[Chunk into Segments]
        Segments --> Salience[Score Salience per Segment]
        Salience --> EmbedSeg[Embed Each Segment]
    end

    subgraph Phase2["Phase 2: Document Planning (1 SENTINEL CALL)"]
        EmbedSeg --> Summary[Build Evidence Summary]
        Summary --> Sentinel["Sentinel: Generate Outline - with theme keywords per section"]
        Sentinel --> EmbedThemes[Embed Section Themes]
    end

    subgraph Phase3["Phase 3: Evidence Assignment (DETERMINISTIC)"]
        EmbedThemes --> Assign["Score: 60% theme similarity - + 25% salience + 15% relevance"]
        Assign --> Dedup[Cross-Section Deduplication]
        Dedup --> Gate["Quality Gates - • Min salience 0.35 - • Min theme sim 0.45 - • Max 2 per source per section"]
    end

    subgraph Phase4["Phase 4: Section Generation (N+2 LLM CALLS)"]
        Gate --> Intro["Intro (sequential)"]
        Intro --> Body["N Body Sections (parallel) - max 3 concurrent"]
        Body --> Conclusion["Conclusion (sequential)"]
    end

    subgraph Phase5["Phase 5: Validation (DETERMINISTIC)"]
        Conclusion --> Validate[Citation Validation - URL + Entity Grounding]
    end

    subgraph Phase6["Phase 6: Assembly (DETERMINISTIC)"]
        Validate --> Assemble[Final Document Assembly]
    end

    style Phase1 fill:#0d3b2e,color:#e0e0e0
    style Phase2 fill:#1e3a5f,color:#e0e0e0
    style Phase3 fill:#0d3b2e,color:#e0e0e0
    style Phase4 fill:#1e3a5f,color:#e0e0e0
    style Phase5 fill:#0d3b2e,color:#e0e0e0
    style Phase6 fill:#0d3b2e,color:#e0e0e0
```

Comptez les appels LLM: **1** (plan d’ensemble sentinelM SK1 + **1** (introduction **N** (sections du corpsM SK1 + **1** (conclusionM SK1  = **N+3**. Quatre des six phases sont déterministes.

### Traçage de contexte fuzzy restreint

Le problème avec la génération de sections parallèles est la cohérence. Si les sections ne savent pas ce que d’autres sections ont ditM SK2 vous obtiendrez une répétition et un débordement . La solution habituelle consiste à produire une génération séquentielle avec le contexte complet. Celle-ci

En revanche, chaque section **Contexte restreint** qu’elle a été construite de façon déterministe

```mermaid
flowchart LR
    subgraph Context["Per-Section Context (ALL DETERMINISTIC)"]
        RS["Running Summary - 1400 char budget - recent 2 sections: full - older: heading only"]
        NP["Negative Prompts - 'Do NOT discuss: X, Y, Z' - from covered concepts"]
        EC["Entity Continuity - re-introduce entities - last seen 2+ sections ago"]
        Props["Propositions - ~15 atomic facts - per section"]
        Evidence["Curated Evidence - max 12 segments - quality-gated"]
    end

    Context --> LLM["LLM generates - with full awareness - of document state"]

    style Context fill:#1a1a2e,color:#e0e0e0
```

- **Résumé en cours**: après chaque section , la partie supérieure M SK2 le segment des preuves de culpabilité (200 les chars MSC4 est enregistrée МSK5 Les sections récentes MST6 sont pleinement digestées M ST7 les sections plus anciennes sont placées sous la rubrique
- **Invitations négatives**: les concepts couverts sont extraits ( les noms de famille appropriés M SK2 les termes techniques , les mots clés de la positionnement *"Ne discutez pas de ces sujets (a déjà été examiné): XM SK3 YMST4 ZMst5*
- **La continuité de l'entité**Les entités qui ne sont pas mentionnées dans les sections 2+ reçoivent une balise pour la réintroduction - introduction *"ReM SK1introduire, s’il y a lieu:EntitéMNK3 (la dernière mentionnéeMRK5section SNK6*
- **Détection de la dérive**: après que chaque section a été généréeM SK1 ses premiers caractères 1000 sont incorporés et comparés par rapport au plan' l'incorporation du thème de la section

Dans le mode parallèle, l'intro génère la première M SK1setting the baseline), les sections du corps se déroulent simultanément (up to 3 via `SemaphoreSlim` pour capter la cohérence, chacun excluant les sujets d’intro, mais non l’un de l’autreM SK1 et la conclusion se termine (excluant tout ).

Le mode séquentiel donne une cohérence plus étroite (chacune des sections exclut tous les concepts antérieurs cumulativement ), mais la parallèle est MSC2x plus rapide pour les grands documents MSC3

### Assignation de la preuve: Le coeur du RAG réduit

Chaque section a besoin de preuves, mais pas *Toute* preuves. Chaque segment obtient une note compositeM SK1 **60% similitude thématique** (distance de cosine à la section'incorporation du thème de ), **25% salience** (de quelle façon le segment est-il informatif? **15% pertinence de l'article** (à quel point l’article de source est pertinent dans son ensemble ). Cette notation est entièrement déterministe M SK2 Aucune LLM ne décide ce qui est pertinent '

Puis les portes:

- **Sous-sol de Salience** Les segments de qualité (0.35): faiblesM SK1 ne parviennent jamais à la LLM
- **Soutien à la similitude des thèmes** (0.45): hors
- **Déduction de section croisée-** (0.80 cosine ): le même fait n’apparaît pas deux fois
- **Per-cap de source** (2 segments par article par section
- **Connaissance du rôle de la Section**: les sections d’intro imposent des pénalités au détail technique (-0.3); les dernières sections le récompensent
- **Porte de cohésion de la demande** (0.30): les éléments de preuve doivent être liés à la demande initiale , et non seulement au thème de la section

Le nombre de mots visés par le LLM est ajusté en fonction de la qualité des données probantes. Données solides ( Satisfaction ≥ | | 3 | 4 | Sources | , | 5 | 6 | Segments |) | 8 | Nombre total de mots | SMC9 | Données faibles ◦ ( | Satisfiance | 11 | 12 | Épaisse | 13 | 14 | 15 | de l'objectif | 16 | Cela évite les hallucinations lorsque les données sont minces | 17

### Extraction de la proposition: DenseM SK1X dans la pratique

Avant que les éléments de preuve ne parviennent au LLM,, il ' est atomisé en propositions ( inspirées par le [Papier de recherche dense-X](https://arxiv.org/abs/2312.06648)). Chaque segment est divisé en six types de faits atomiques **Les demandes d'indemnisation doivent être présentées dans les délais prescrits.** (affirmations générales fondées sur des faits **Les quotes-parts** (direct de la source), **Statistiques** (nombre et métriques ), **définitions** ("X est YM SK1 **Processus** (stageM SK1par -step), et **les faits de l'entité désignée** (concentré sur une entité particulièreM SK1

Chaque section reçoit des propositions ~15 de , reproduites à travers les sections au moyen d'une similitude sémantique.

Au moment où le LLM écrit une section,, la phase de réduction l’a donnée:

- Un titre et un thème clairs
- Segments de preuve curatés (qualité-gatedM SK2deduplicated )
- ~15 propositions atomiques
- Sommaire des sections précédentes déjà couvertes
- Les incitatifs négatifs pour ce qui *non pas* à répéter
- Orientation de la continuité des entités

Un petit modèle peut faire un excellent travail avec ce type de préprocessage.

## TextRank: Sommaire déterministe

Lorsque les articles sont trop longs pour le pipeline de la preuve, il faut les comprimer. Mais je ne veux pas consacrer un appel LLM à une résumation.

TextRank (Mihalcea & TarauM SK2 2004) le fait de façon déterministe:

```mermaid
flowchart LR
    Text[Article Text] --> Split[Split into Sentences]
    Split --> EmbedS[Embed Each Sentence]
    EmbedS --> Graph["Build Similarity Graph - (cosine > 0.15 = edge)"]
    Graph --> PR["PageRank - (20 iterations, d=0.85)"]
    PR --> Select["Select Top-K - in Original Order"]

    style Graph fill:#1e3a5f,color:#e0e0e0
```

Chaque phrase obtient une embedding. Les similitudes par pairs au-dessus de M SK1 deviennent des bordures de graphe . PageRank trouve le plus *Centre* sentences, celles qui sont les plus reliées à tout le reste de la documentation. Celles-ci représentent le document le mieux

Le détail clé: les phrases sélectionnées sont retournées **dans l'ordre du document original**. Cela préserve le flux narratif. Vous obtiendrez un résumé cohérent , pas une paire aléatoire de phrases importantesM SK3

Aucun appel LLM. Exécute en millisecondesM SK1 La similitude des cosine est SIMD-accélérée par `TensorPrimitives` (`System.Numerics.Tensors`) (AVX2, AVX≥-512, ou ARM NEONM SK4 choisi au moment du démarrage

## Un-Hop Lien suivant

Les articles renvoient à d’autres articles. Ces références contiennent souvent les meilleurs éléments de preuve - la source principale que récapitule un article de presse .

DoomSummarizer suit les liens, mais sélectivementM SK1 Chaque lien candidat reçoit une note:

```
link_score = 0.7 × query_relevance(anchor_context) + 0.3 × segment_salience
```

Lorsque la salience des segments est combinée

- **Position** (60%) - pyramide inverséeM SK2 les paragraphes précédents sont plus importants
- **Substances** Longueur du paragraphe et densité de l'information

Liens en bas d’un plancher de pertinence (0.15) sont passés à l’écart. Le système suit la pyramide héuristice journalistique inversée : les liens importants ont tendance à apparaître tôt dans le bon tempsMSC3 les articles écritsM SK4

Les résultats sont cachés avec les haches de contenu et ETags. Les secondes exécutions sont rapides . Voir [Cache des réponses, ETags , et Demandes conditionnelles](/blog/ASPNET-STATE-BETWEEN-REQUESTS).

## Mode Crawl: Établir une base de connaissances locale

Tout ce qui a été décrit jusqu'à présent suppose le téléchargement du Web. Mais vous pouvez faire passer complètement le web.

`crawl` intégre un site Web dans une base de connaissances locale. Il fait une largeur-premier crawl MSC2BFSM SK3 à partir d’une URL de semencesMska4 en ce qui concerne la profondeur et les limites des pagesM Ska5 avec une limite de vitesse adaptative qui mesure le retard fondé sur les temps de réponse du serveurMka6

```bash
doomsummarizer crawl https://docs.example.com --name example-docs --depth 3 --max-pages 200
```

Everything gets persisted: full content, ONNX embeddingsMSC2 entity profiles , SQLite FTSM SK4 keyword indexes Mska5fullMSKA6text searchMske7 sentiment and topic scores (computed via embeding anchorsSMA9 no LLMSMAP10 Incremental reMSA11crawls send `If-None-Match` / `If-Modified-Since` headers. pages non modifiées retournent HTTP 304 et skip reprocessing. Pour les serveurs sans support ETagM SK3 SHAMNK4 content hashes catch duplicatesMSC5

Une fois crawlé, la demande est entièrement hors ligne:

```bash
doomsummarizer scroll "how does authentication work?" --name example-docs
```

L'article 5 de la Loi sur l'immigration et le statut des réfugiés `--name` routes d'affichage vers le KB local au lieu de sources Web. Les mêmes trois Ã©chantillonsM SK1 feux de rÃ©cupÃ©ration des stratÃ ̈res : FTS5 complets M SK4 prÃ©texte préliminaire M Sk5 filtre M sk6 intÃ©glementation de la recherche HNSW , profil de l'entitÃ© Recherche HNSD Mtk8 Il s'agit d'une unionM Sk9 fondée et rangÃ©eM sk10 RÃ©duction du pipeline identique M sc11 synthèse identique~ M sc12 Aucun réseau n'est exigéM sc13

L'entreposage est léger: SQLite pour les métadonnées et FTS5 indices , DuckDB avec l'extension VSS pour les index vecteurs HNSWM SK3 Aucun service externeMSC4 aucun DockerMST5 aucune clé APIMSP6 Une base de connaissances crawlée de centaines de pages se trouve dans quelques mégabytes et des demandes en millisecondesMSV7

## Mettre les choses ensemble

```bash
doomsummarizer scroll "AI safety and regulation" --vibe doom --debug

Composite query detected: 2 subqueries
  • What's new in AI safety?
  • What are the latest AI regulations?

Searching...
├─ Lucene: 18 keyword matches (regulation^3, safety^2)
├─ Embedding: 12 semantic matches (max-sim across 2 subqueries)
├─ RRF fusion: 22 candidates, 6 signals
├─ Entity HNSW: +3 related via entity profiles
├─ TextRank: compressed 4 long articles
└─ Final: 12 items

Long-form: Phase 1 - 187 segments from 12 articles
Long-form: Phase 2 - "AI Safety Landscape" - 5 sections
Long-form: Phase 3 - Evidence assigned (cross-section dedup: 8 removed)
Long-form: Phase 4 - Generating sections...
```

## Les idées qui l'ont fait fonctionner

Il s’agit des points de vue suivants :

1. **Réduire avant de produire**: le chemin standard n’a besoin que d’un appel LLM 1 parce que la conduite fait tous les travaux de levage lourd de façon déterministe [RAG réduit](/blog/reduced-rag) est le modèle, les embeddings, la PageRank, l’héuristique et les portes de qualité produisent des intrants aussi propres que les petits modèles peuvent les synthétiser.
2. **Sentinel-route de source dirigée**: un petit modèle interprète les demandes dans l’intention structurée , puis YAMLM SK2 le routage dirigé sélectionne et vibe la route- qualifie les sourcesMSC4 The sentinel is cheap enough to call on every query
3. **Maximum de similitude pour les demandes combinées**: donM SK1t scores moyens de la sous-question, prendre le meilleur match . Un article portant sur une partie de votre question est mieux qu'une moitiéMSC4matcher toutMST5
4. **Combinez les rangs, sans cotes**: Le RRF vous permet de fusionner des signaux avec des échelles incompatibles . Autorité, fraîcheurM SK3 similitude d'incorporationMNK4 alinéa vibeMMK5 simple rang et fusionnageMRK6
5. **Vibes comme embeddings**: tout texte peut être une dimension de récupération . l’incorporer , la coter contre elle M SK3 le pondérer dans la RRF
6. **Profils d'entités en tant que vecteurs**: IDF - Emplacements d'entités pondéréesM SK2 non comptage des chaînes d'entité. Les entités rares dominent le profilMSC4 les entités communes deviennent bruiteusesMNK5 et la recherche HNSW détecte des articles connexes dans O
7. **Traçage de contexte fuzzy restreint**: [Gestion du contexte déterministe](/blog/constrained-fuzzy-context-dragging) permet la production de sections parallèles. Sommaires en coursM SK1 prompts négatifs, continuité d'entités , et détection de dérive maintenir la cohérence sans appels de compression LLMMSC4
8. **Déterministe lorsque possible**: des six phases de forme longues -, quatre sont déterministesM SK3 Le tableau TextRank remplace la sommation du LLMMSC4 L'attribution des preuves remplace le choix du LLSMSL5

## Ressources

- **[Remises de DoomSummarizer](https://github.com/scottgal/lucidrag/releases?q=doomsummarizer)**: binaire unique, aucun temps de démarrage nécessaire
- **[Répositoire lucidRAG](https://github.com/scottgal/lucidrag)**: le projet parent
- **[Code de source](https://github.com/scottgal/lucidrag/tree/main/src/DoomSummarizer)**

### Articles connexes

- [RAG réduit](/blog/reduced-rag): la diminution-avantM SK2générer le modèle en profondeur
- [Traçage de contexte fuzzy restreint](/blog/constrained-fuzzy-context-dragging): comment la génération de sections parallèles maintient la cohérence
- [Modèle de fuzziness restreint](/blog/constrained-fuzziness-pattern): le modèle plus large derrière le contrôle déterministe + les propositions probabilistes

### En outre

- [ConsoleImage (Outil encadré de temps)](/blog/timeboxedtool-consoleimage)