# DocSummarizer Part 4 - Pipeline di costruzione RAG

<!--category-- AI, LLM, RAG, C#, Embeddings, ONNX, Semantic Search -->
<datetime class="hidden">2025-12-30T17:00</datetime>

[![NuGet](https://img.shields.io/nuget/v/Mostlylucid.DocSummarizer?label=NuGet)](https://www.nuget.org/packages/Mostlylucid.DocSummarizer)
[![npm](https://img.shields.io/npm/v/@mostlylucid/docsummarizer?label=npm)](https://www.npmjs.com/package/@mostlylucid/docsummarizer)
[![.NET](https://img.shields.io/badge/.NET-8.0%20%7C%2010.0-512BD4)](https://dotnet.microsoft.com/)
[![Node.js](https://img.shields.io/badge/Node.js-18%2B-339933)](https://nodejs.org/)

Questo è **Parte 4** della serie DocSummarizer. Vedete [Parte 1](/blog/building-a-document-summarizer-with-rag) per l'architettura, [Parte 2](/blog/docsummarizer-tool) per l'outil CLI, o [Parte 3](/blog/docsummarizer-advanced-concepts) per l'in immersione profonda sulle imbarcazioni.

> **La parte dura del RAG è: ' non è il LLM, ., "M SK2" è tutto prima del LLM.**

Voi' probabilmente avete visto il modello: dividere i documenti in blocchiM SK2 generare degli inserimenti , immagazzinare in una base di dati vectoriM Sk4 recuperare i blocchi rilevantiM sk5 mandare a LLMMtk6 Semplice in teoriaMdk7 In praticaMk8 voiMkt9 scriveteMkk10

- Parsatori di documenti per ogni formato
- Logica di fusione che rispetta i confini semantici
- Tokenizzazione che corrisponde al vostro modello di inserzione.
- Batching per una produzione efficiente di inserzioni
- Salience scoring, quindi non tutti i pezzi sono trattati uguali.
- Tracciare le citazioni per sapere da dove provengono le risposte.

Quello' è un sacco di infrastrutture prima di scrivere una singola linea di codice di applicazione.

**DocSummarizer.Core gestisce tutto in un singolo pacchetto** - è disponibile sia per .NET che per NodeM SK2js.

DocSummarizer.Core è essenzialmente un **Layere dell'informazione dei documenti**: struttura deterministica prima, ricavo probabilistico secondoM SK2 Risolve l'informazioneMSC3problema di ingegneria così che si possa concentrare sul problema di ragionamento .

### Il tubo dell'ingestione

Ecco cosa fa DocSummarizer. *doesn't* Do:

```mermaid
flowchart TB
    subgraph INPUT["Input (Your Document)"]
        DOC[/"PDF / DOCX / Markdown / HTML / URL"/]
    end
    
    subgraph DOCSUMMARIZER["DocSummarizer.Core (Deterministic)"]
        direction TB
        PARSE["Parse & Structure"]
        SEGMENT["Segment by Semantics"]
        EMBED["Generate Embeddings<br/>(ONNX - Local)"]
        SCORE["Compute Salience"]
        CITE["Assign Citation IDs"]
        
        PARSE --> SEGMENT
        SEGMENT --> EMBED
        EMBED --> SCORE
        SCORE --> CITE
    end
    
    subgraph OUTPUT["Output (ExtractionResult)"]
        SEGMENTS[/"Segments[]<br/>• Original text (verbatim)<br/>• float[384] embedding<br/>• Salience score<br/>• StartChar / EndChar<br/>• Section context"/]
    end
    
    subgraph YOURS["Your Code"]
        STORE[("Vector Store<br/>(Qdrant / pgvector / etc)")]
    end
    
    subgraph QUERY["Query Time (Later)"]
        Q["User Question"]
        RETRIEVE["Retrieve Top-K"]
        LLM["LLM Synthesis"]
        ANS["Answer + Citations"]
        
        Q --> RETRIEVE
        RETRIEVE --> LLM
        LLM --> ANS
    end
    
    DOC --> PARSE
    CITE --> SEGMENTS
    SEGMENTS --> STORE
    STORE --> RETRIEVE
    
    style DOCSUMMARIZER stroke:#27ae60,stroke-width:3px
    style YOURS stroke:#3498db,stroke-width:2px
    style QUERY stroke:#9b59b6,stroke-width:2px
    style LLM stroke:#e74c3c,stroke-width:2px
```

**Cosa fa DocSummarizer (box verdeM SK1**

- Parsa i documenti conservando la struttura.
- Divide in segmenti semantici (non blocchi arbitrari)
- Genera inserzioni localmente con ONNX
- Computa i punteggi di salienza.
- Assigna ID di citazione con posizioni di carattere.

**Cosa fate (box blu):**

- Gestire segmenti nella vostra base di dati dei vettori.
- Costruire la logica della ricerca.

**Cosa succede al momento della domanda (catola viola):**

- Inserire la domanda (same model)
- Trovare segmenti simili.
- Inviate a LLM per la sintesi

**Percezione chiave:** Il LLM (bordo rossoM SK1 è coinvolto solo al momento della domanda. l'ingestione è completamente determinista - lo stesso documento produce sempre gli stessi segmentiMSC4 Questo è ciò che rende RAG riproducibile e debuggerabileMNK5

**Bono di riproduttività:** L'ingestione deterministica significa che si può ri-indexM SK1 diff, e debugare il pipeline RAG come qualsiasi altro artefatto di costruzioneMSC3 Nessuna variazione di prima azioneMSSK4 nessuna temperatura del modello MST5 solo puraMSS6 ingegneria dei dati testabileM SS7

### Perché nessun LLM per l'ingestione?

Per RAG, volete il *Le frasi concrete.* dai vostri documenti - non LLMM SK1parafrase generate. Quando un utente chiede " cosa dice il contratto sulla cessazione di contrattiMSC4 bisogna recuperare il testo reale del contrattoMST5 non un sommesso di quelloMSST6

Il LLM arriva più tardi, al momento della domanda, per sintetizzare una risposta dai frammenti recuperati . Ma i frammenti stessi dovrebbero essere materiale di origine verbatimoMSC3 QuestoM SK4 è ciò che rende le citazioni significativeMSL5

DocSummarizer's `ExtractSegmentsAsync` vi da esattamente questo: i segmenti originali di testo con inserzioni, pronti per essere recuperatiM SK2 Nessun LLM coinvolto nell'ingestioneMSC3

[TOC]

## La proposta di valore

Ecco cos'è che si ottiene con uno. `dotnet add package`:

```bash
dotnet add package Mostlylucid.DocSummarizer
```

- **Segmentazione intelligente** - Divisioni sulle sedi, rispetta i limiti semantici
- **Inserzioni ONNX** - Locale, non c'è API KeysMSC2 modelli autoM SK3download ~23MBMST5
- **Il punteggio della salinità** - Pre-importanza calcolata per ogni segmento
- **Il tracciamento delle citazioni** - Ogni segmento ha un'ID unica.
- **Numerosi formati** - Markdown
- **Opzioni di conservazione dei vettori** - InMemory

Niente Python. Niente API esterne. Niene configurazioni complesse . Funziona offline dopo il primo download del modelloM SK3

## Estrarre Segmenti: L'API Core

Il caso più semplice di uso - estratto segmenti con inserzioni pronti per il vostro vettore:

```csharp
using Microsoft.Extensions.DependencyInjection;
using Mostlylucid.DocSummarizer;

// Setup DI
var services = new ServiceCollection();
services.AddDocSummarizer();
var provider = services.BuildServiceProvider();

var summarizer = provider.GetRequiredService<IDocumentSummarizer>();

// Extract segments with embeddings
string markdown = File.ReadAllText("document.md");
var extraction = await summarizer.ExtractSegmentsAsync(markdown);

foreach (var segment in extraction.AllSegments)
{
    Console.WriteLine($"[{segment.Type}] {segment.SectionTitle}");
    Console.WriteLine($"  ID: {segment.Id}");
    Console.WriteLine($"  Salience: {segment.SalienceScore:F2}");
    Console.WriteLine($"  Embedding: float[{segment.Embedding?.Length}]");
    Console.WriteLine($"  Text: {segment.Text[..Math.Min(80, segment.Text.Length)]}...");
}
```

**Output:**

```
[Heading] Introduction
  ID: a1b2c3d4e5f6g7h8_h_0
  Salience: 0.85
  Embedding: float[384]
  Text: This document describes the architecture of our new microservices platform...

[Sentence] Introduction  
  ID: a1b2c3d4e5f6g7h8_s_1
  Salience: 0.72
  Embedding: float[384]
  Text: The system is designed to handle 10,000 requests per second with sub-100ms...
```

Quello'è questo. Niente orchestrazione , niente promptsM SK3 nessuna opinione MSC4 solo segmenti con inserzioni e provenienzaMST5 pronto per la vostra base di dati vectoriMSV6

### ID del documento

Ogni segmento's `Id` è costruito da un documento ID più tipo e indice: `{docId}_{type}_{index}`.

Potete fornire il vostro stesso ID di documento, o lasciare che DocSummarizer ne compita uno dal content hash:

```csharp
// Option 1: Provide your own ID (useful for tracking documents in your system)
var extraction = await summarizer.ExtractSegmentsAsync(markdown, documentId: "contract-2024-001");
// Segments get IDs like: contract_2024_001_s_0, contract_2024_001_h_1, ...

// Option 2: Auto-generated from content hash (default)
var extraction = await summarizer.ExtractSegmentsAsync(markdown);
// Segments get IDs like: a1b2c3d4e5f6g7h8_s_0, a1b2c3d4e5f6g7h8_h_1, ...
// Same document = same hash = same IDs (deterministic)
```

**Perché questo è importante per RAG:**

- I dati personalizzati vi permettono di correlare segmenti con il vostro sistema di gestione dei documenti.
- Content-hash IDs ensure re-indexing the same document produce identical segment IDs
- Entrambi approcci sostengono citazioni stabili - `[s42]` si risolve sempre allo stesso testo sorgente.

## Cosa c'è in un segmento?

Ogni segmento estratto contiene tutto quello di cui avete bisogno per RAG:

```csharp
public class Segment
{
    string Id;              // Unique ID: "mydoc_s_42" (for citations)
    string Text;            // The actual content
    SegmentType Type;       // Sentence, Heading, ListItem, CodeBlock, Quote, TableRow
    int Index;              // 0-based order in document
    
    // Source location tracking
    int StartChar;          // Character offset where segment starts
    int EndChar;            // Character offset where segment ends
    int? PageNumber;        // Page number (for PDFs)
    int? LineNumber;        // Line number (for text/markdown)
    
    // Section context
    string SectionTitle;    // "Introduction" - immediate heading
    string HeadingPath;     // "Chapter 1 > Introduction > Overview"
    int HeadingLevel;       // 1-6 (heading depth)
    
    // Computed during extraction
    float[] Embedding;      // 384-dim vector (default model)
    double SalienceScore;   // 0-1 importance score
    string ContentHash;     // Stable hash for citation tracking across re-indexing
    
    // For retrieval (set during query)
    double QuerySimilarity; // Similarity to the query
    double RetrievalScore;  // Combined score: similarity + salience
    
    string Citation { get; } // Auto-generated: "[s42]", "[h3]", etc.
}
```

L'informazione figura nella parte dispositiva. `Id` è la chiave per la tracciazione delle citazioni. Quando il vostro LLM produce `[s42]`, potete risolverlo fino alla posizione esatta della fonte usando `StartChar`/`EndChar`.

**Bonus:** L'informazione figura nella parte dispositiva. `ExtractionResult` Include metodi di aiuto per la risoluzione delle citazioni:

```csharp
var extraction = await summarizer.ExtractSegmentsAsync(markdown);

// Fast O(1) lookups
var segment = extraction.GetSegment("mydoc_s_42");
var segmentByIdx = extraction.GetSegmentByIndex(42);

// Find segment at a character position
var segmentAtPos = extraction.GetSegmentAtPosition(5432);

// Get all segments on page 5 (for PDFs)
var pageSegments = extraction.GetSegmentsOnPage(5);

// Get source location for highlighting
var location = extraction.GetSourceLocation("mydoc_s_42");
// Returns: StartChar, EndChar, LineNumber, PageNumber, SectionTitle, HeadingPath

// Extract highlighted text with context
var highlight = extraction.GetHighlightedText(originalMarkdown, "mydoc_s_42", contextChars: 50);
Console.WriteLine(highlight.ToHtml());  // <span class="highlight">...</span>
Console.WriteLine(highlight.ToMarkdown()); // **...**
```

## Lavorare nei negozi di vettori

DocSummarizer vi dà gli inserimenti. Usate qualsiasi database di vectori che vi piaccia.

### Qdrant

```csharp
var points = extraction.AllSegments.Select((s, i) => new PointStruct
{
    Id = (ulong)i,
    Vectors = s.Embedding,
    Payload = 
    {
        ["text"] = s.Text,
        ["section"] = s.SectionTitle,
        ["salience"] = s.SalienceScore,
        ["segment_id"] = s.Id,
        ["start_char"] = s.StartChar,
        ["end_char"] = s.EndChar
    }
}).ToList();

await qdrantClient.UpsertAsync("documents", points);
```

### PostgreSQL + pgvector

```csharp
foreach (var segment in extraction.Segments)
{
    await connection.ExecuteAsync(
        @"INSERT INTO documents (segment_id, text, heading, salience, embedding) 
          VALUES (@id, @text, @heading, @salience, @embedding::vector)",
        new { 
            id = segment.Id,
            text = segment.Text, 
            heading = segment.SectionTitle,
            salience = segment.SalienceScore,
            // NOTE: String interpolation is for demo simplicity only.
            // For production, use NpgsqlParameter with Vector type for better
            // performance and to avoid culture-dependent decimal separators.
            embedding = $"[{string.Join(",", segment.Embedding)}]"
        });
}
```

### O usare i negozi - costruiti

Don'non vuole gestire una base di dati separataM SK1 DocSummarizer ha tre backends:

```csharp
services.AddDocSummarizer(options =>
{
    // In-memory (fastest, no persistence)
    options.BertRag.VectorStore = VectorStoreBackend.InMemory;
    
    // DuckDB (embedded file-based, default)
    options.BertRag.VectorStore = VectorStoreBackend.DuckDB;
    
    // Qdrant (external server)
    options.BertRag.VectorStore = VectorStoreBackend.Qdrant;
    options.Qdrant.Host = "localhost";
    options.Qdrant.Port = 6334;
});
```

## Perché la salinzia conta

La maggior parte dei sistemi RAG falliscono non perché gli inserimenti sono cattivi, ma perché tutti i frammenti sono trattati come ugualmente importanti.

```mermaid
flowchart LR
    subgraph DOC["Document"]
        H1["# Title"]
        P1["First paragraph<br/>(intro)"]
        H2["## Methods"]
        P2["Technical details..."]
        P3["More details..."]
        H3["## Results"]
        P4["Key findings here"]
        H4["## Appendix"]
        P5["Reference data..."]
    end
    
    subgraph SCORES["Salience Scores"]
        S1["0.95"]
        S2["0.85"]
        S3["0.70"]
        S4["0.65"]
        S5["0.60"]
        S6["0.80"]
        S7["0.30"]
    end
    
    H1 --> S1
    P1 --> S2
    H2 --> S3
    P2 --> S4
    P3 --> S5
    P4 --> S6
    P5 --> S7
    
    style S1 stroke:#27ae60,stroke-width:3px
    style S2 stroke:#27ae60,stroke-width:2px
    style S6 stroke:#27ae60,stroke-width:2px
    style S7 stroke:#e74c3c,stroke-width:2px
```

Una frase in abstrato è più importante di quella dell'appendice. DocSummarizer pre-computa questoM SK2

```csharp
// Get the top 20% most salient segments
var topSegments = extraction.Segments
    .OrderByDescending(s => s.SalienceScore)
    .Take((int)(extraction.Segments.Count * 0.2));
```

**I fattori di salivazione:**

| fattore | effetto |
|--------|--------|
| Posto | IntroduzioneM SK2 punteggi più alti per le frasi di conclusione SSK3
| Proximità delle sezioni | Le prime frasi dopo le sezioni sono frasi su cui si tratta SSK2
| Lunghezza | Segmenti molto brevi (< S80 i carri M) sono penalizzati R|
| Tipo di sezione | AstrattoM SK2Introduction boosted, ReferencesMSC4Appendix reduced SSK5
| Tipo del contenuto | Blocchi di codici, citazioniM SK3 liste pesante diversamente |

Questo significa che la tua ricerca può avere un peso di `(similarity * salience)` Invece di una semplice somiglianza.

## Classificazione del documento

DocSummarizer auto- rileva il tipo di documento usando l'euristica sul contenuto:

```csharp
var extraction = await summarizer.ExtractSegmentsAsync(markdown);

// Document type detected from content
Console.WriteLine($"Type: {extraction.DocumentType}");     // Technical, Narrative, Legal, etc.
Console.WriteLine($"Confidence: {extraction.Confidence}"); // High, Medium, Low
```

**La classificazione influisce sulla ricerca.**: Scale di profondità di ricerca con entropia del documento, non hardcoded TopKM SK2 Documenti narrativi ( fantascienzaMska4 storieMske5 ottengono un 1.5x boost al conteggio di ricerca perché hanno bisogno di più contestoMsek7 Documentamenti tecnici con una struttura chiara hanno bisogno meno di materiale

L'euristica guarda a:

- Frequenza del blocco di codici (technico)
- Structure di testa (academica,tecnicaM SK2
- Patterni di dialogo (narrative)
- Terminologia legale (contratti)
- Densità della lista (documentazione)

Se l'euristica è incerta, DocSummarizer può optionalmente tornare a una classificazione veloce LLM usando un modello M SK1sentinel" . Questo richiede che Ollama funzioni localmente con un piccolo modello come `tinyllama`. Lo accendere tramite la configurazione:

```csharp
services.AddDocSummarizer(options =>
{
    options.Ollama.BaseUrl = "http://localhost:11434";
    options.Ollama.Model = "tinyllama";
});

// Then use with LLM fallback enabled
var extraction = await summarizer.ExtractSegmentsAsync(markdown, useLlmFallback: true);
```

Per la maggior parte dei documenti, solo l'euristica è abbastanza precisa - il fallback LLM esiste per i casi di bordoM SK2

## Esempio del Pipeline del Full RAG

Ecco qui un indice completo: - e -, il tubo di domanda ., noi ' lo costruiamo in tre fasi.

```mermaid
sequenceDiagram
    participant User
    participant App as Your App
    participant DS as DocSummarizer
    participant VS as Vector Store
    participant LLM
    
    Note over DS: INGESTION (No LLM)
    App->>DS: ExtractSegmentsAsync(markdown)
    DS->>DS: Parse structure
    DS->>DS: Split into segments
    DS->>DS: Generate embeddings (ONNX)
    DS->>DS: Compute salience
    DS-->>App: ExtractionResult
    App->>VS: Store segments + vectors
    
    Note over LLM: QUERY TIME (LLM involved)
    User->>App: "What about X?"
    App->>DS: EmbedAsync(question)
    DS-->>App: float[384]
    App->>VS: Search(vector, topK=5)
    VS-->>App: Top segments
    App->>LLM: Question + Context
    LLM-->>App: Answer with [citations]
    App-->>User: Answer
```

### Step 1: Structure dei dati

```csharp
public class SimpleRagService
{
    private readonly IDocumentSummarizer _summarizer;
    
    // In-memory segment store - maps "docId:segmentId" to the full segment
    private readonly Dictionary<string, ExtractedSegment> _segments = new();
    
    // In-memory vector index - pairs of (id, embedding vector)
    private readonly List<(string Id, float[] Vector)> _index = new();
```

In produzione voi usate una vera base di dati dei vettori (QdrantM SK2 pgvector, ecc.

### Step 2: Documenti per l'indexazione

```csharp
    public async Task IndexAsync(string markdown, string docId)
    {
        // Extract segments with embeddings - this is where DocSummarizer does the work
        var extraction = await _summarizer.ExtractSegmentsAsync(markdown);
        
        // Store each segment and its vector
        foreach (var segment in extraction.Segments)
        {
            // Composite key: document + segment for citation tracking
            var id = $"{docId}:{segment.SegmentId}";
            
            // Keep the full segment for retrieval
            _segments[id] = segment;
            
            // Add to vector index for similarity search
            _index.Add((id, segment.Embedding));
        }
    }
```

Nota: non c'è un LLM coinvolto. NoiM SK2 sto conservando il *attuale* Texte del documento, non sommità.

### Step 3: Query

```csharp
    public async Task<string> QueryAsync(string question, int topK = 5)
    {
        // Embed the question using the same model as documents
        // This ensures vectors are in the same space
        var embedding = await _summarizer.EmbedAsync(question);
        
        // Find top-K most similar segments
        var results = _index
            .Select(x => (x.Id, Similarity: CosineSimilarity(embedding, x.Vector)))
            .OrderByDescending(x => x.Similarity)
            .Take(topK)
            .Select(x => _segments[x.Id])
            .ToList();
        
        // Build context with citation markers
        // The LLM can reference [chunk-3] and we can trace it back
        var context = string.Join("\n\n", results.Select(s => 
            $"[{s.SegmentId}] {s.Text}"));
        
        return context; // Send this + the question to your LLM
    }
```

Il contesto restituito contiene: *Reale* Il testo del documento con ID di segmenti. Il vostro prompt LLM potrebbe assomigliare a:

```
Answer the question based on the following context.
Cite sources using the [chunk-N] markers.

Context:
{context}

Question: {question}
```

### La matematica (Standard Cosine Similarity)

```csharp
    private static float CosineSimilarity(float[] a, float[] b)
    {
        float dot = 0, normA = 0, normB = 0;
        for (int i = 0; i < a.Length; i++)
        {
            dot += a[i] * b[i];
            normA += a[i] * a[i];
            normB += b[i] * b[i];
        }
        return dot / (MathF.Sqrt(normA) * MathF.Sqrt(normB));
    }
}
```

DocSummarizer include `VectorMath.CosineSimilarity()` Se non lo volete'non volete scrivere da voi stessi.

Il DocSummarizer espone anche `IEmbeddingService` direttamente se dovete inserire le domande separatamente dal flusso di sommificazione completo.

## Moduli di inserzione

Default is `AllMiniLmL6V2` - veloce , piccolo, buona qualitàM SK3 scegliere a seconda dei vostri bisogniMSC4

```csharp
services.AddDocSummarizer(options =>
{
    options.Onnx.EmbeddingModel = OnnxEmbeddingModel.BgeBaseEnV15;
});
```

| Modello | | | Dims || | Max Tokens |
|-------|------|------------|------|-------|
| `AllMiniLmL6V2` |
| `BgeSmallEnV15` |
| `BgeBaseEnV15` |
| `JinaEmbeddingsV2BaseEn` |

Models auto-download from HuggingFace on first use. Subsequent runs load from diskM SK2

## OpenTelemetry

Monitorare la vostra pipeline RAG nella produzione:

```csharp
services.AddOpenTelemetry()
    .WithTracing(tracing => tracing
        .AddSource("Mostlylucid.DocSummarizer")
        .AddSource("Mostlylucid.DocSummarizer.Ollama")
        .AddSource("Mostlylucid.DocSummarizer.WebFetcher")
        .AddOtlpExporter())
    .WithMetrics(metrics => metrics
        .AddMeter("Mostlylucid.DocSummarizer")
        .AddMeter("Mostlylucid.DocSummarizer.Ollama")
        .AddMeter("Mostlylucid.DocSummarizer.WebFetcher")
        .AddPrometheusExporter());
```

**Metrica chiave:**

- `docsummarizer.summarizations` - Conta le richieste
- `docsummarizer.summarization.duration` - Tempo di processo in ms
- `docsummarizer.document.size` - dimensioni del documento
- `docsummarizer.ollama.embed.requests` - Integrare le chiamate API

## Support per formati

DocSummarizer gestisce diversi formati di documento con rilevamento e processo intelligente.

### Traduzione diretta (Niente dipendenze esterne)

Questi formati sono processati in modo nativo - nessun Docling o altri servizi necessari:

| Formato | Espansione | Trattura S|
|--------|-----------|------------|
| Markdown  | `.md`, `.markdown` | Parsa con Markdig, struttura conservata |
| Plain Text | `.txt`, `.text` | Split per paragrafi (double newlines) |
| HTML  | `.html`, `.htm` | SanitizzatoM SK1 convertito in Markdown |
Archivi ZIP | `.zip` | Extrae file di testoM SK1 auto- rileva il formato Gutenberg |

**Il testo semplice riceve un trattamento intelligente.**: Quando non ci sono le sedi di marcamento, il blocco si sposta al paragrafoM SK2 la divisione basata sulla divisione . Detetisce la struttura del documento heuristicamente - se il vostro testo ha frazioni di paragrafi chiariMSC5 queste diventano i confini del bloccoMNK6

```csharp
// Plain text works the same way
var plainText = File.ReadAllText("notes.txt");
var extraction = await summarizer.ExtractSegmentsAsync(plainText);
// Chunks split by paragraphs, embeddings generated
```

### Documenti ricchi con Docling

Per PDF, DOCXM SK1 PPTX, XLSXMSC3 e le immagini (OCRMska5 Mske6 aggiungere DoclingMsko7

```bash
docker run -d -p 5001:5001 quay.io/docling-project/docling-serve
```

```csharp
services.AddDocSummarizer(options =>
{
    options.Docling.BaseUrl = "http://localhost:5001";
});

// PDF, DOCX, PPTX, images all work
var pdfBytes = await File.ReadAllBytesAsync("document.pdf");
var extraction = await summarizer.ExtractSegmentsAsync(pdfBytes, "document.pdf");
```

La compilazione preserva la struttura del documento - i titoli, le tabelle , le liste passano attraverso come un Markdown appropriatoM SK3 Questo significa un blocco migliore dell'estrazione di testo grezzoMSC4

| Formato | Estensione | Note SSK3
|--------|-----------|-------|
| PDF  | `.pdf` | testo + layout conservato, tabulche convertite |
| Voce  | `.docx` | Formatazione completaM SK1 titoli, liste |
| PowerPoint  | `.pptx` | Le diapositive diventano sezioni |
| Excel  | `.xlsx` | Diagrammi estratto |
| Immagini  | `.png`, `.jpg`, `.tiff` | OCR via Docling |

Vedete. [Parte 1](/blog/building-a-document-summarizer-with-rag) per saperne di più su Docling integration, o [Conversione del documento multi-Format](/blog/building-a-lawyer-gpt-for-your-blog-part9) per una immersione profonda.

## Le parti difficili da saltare

| Problema | DocSummarizer Solution |
|---------|----------------------|
| Istruire a confini semantici | Le divisioni sulle sediM SK2 Contenuto associato ai gruppi SSK3
| Tokenizzazione per modello | Usa il tokenizzatore corretto per ogni modello ONNX
| Integrazione di lotti | Tasso di lotto configurabileM SK2 memoria-efficienza SSK4
| Tracciamento delle citazioni | Ogni segmento diventa unico `SegmentId` |
| Conversione di formato | Markdown, HTMLM SK3 PDFMSC4 DOCX tramite un unico API |
| Descensione del modelloM SK1caching | Auto-downloadsMSC4 cache in `~/.docsummarizer` |

## Summary

Le tubature RAG hanno bisogno di infrastrutture prima della parte interessante. DocSummarizer.Core ti dàM SK2

1. **Segmenti con inserzioni** - pronto per qualsiasi negozio di vettori
2. **punteggi di Salience** - Non tutti i pezzi sono uguali.
3. **Il tracciamento delle citazioni** - Sapete da dove provengono le risposte
4. **Locale-prima** - No API keys, funziona offline
5. **Telemetria di produzione** - OpenTelemetry incorporata

```bash
dotnet add package Mostlylucid.DocSummarizer
```

Le tubature sono finite. Costruire la vostra app RAG.

## Article connessi

### DocSummarizer Series

- [Parte 1 - Architettura & Patterns](/blog/building-a-document-summarizer-with-rag) - Perché l'approccio del pipeline funziona
- [Parte 2 - Utilizzando l'outil](/blog/docsummarizer-tool) - Installation del CLI, ModesM SK2 Template
- [Parte 3 - Concepti avanzati](/blog/docsummarizer-advanced-concepts) - inserzioni BERT, ONNXM SK2 ricerca ibrida
- [Parte 5 - DoomSummarizer: Ricerca approfondita](/blog/doomsummarizer-deep-research) - MultiM SK1 Ricerca di sorgenti, Profili delle entità , scoperta del grafico semanticoMSC4 e sintesi della forma parallela longitudinale

### Le immersioni profonde di RAG

- [Primero RAG](/blog/rag-primer) - Concepti fondamentali per la ripresa-generazione aumentata
- [L'architettura RAG](/blog/rag-architecture) - Palette di progettazione del sistema per RAG
- [La ricerca e l'indexazione ibride](/blog/rag-hybrid-search-and-indexing) - Combinare la ricerca densa e sparsa
- [Applicazioni pratiche della RAG](/blog/rag-practical-applications) - Usazioni reali-world

### GraphRAG

- [GraphRAG: Graffi di conoscenza per RAG](/blog/graphrag-knowledge-graphs-for-rag) - Quando la ricerca dei vettori non è sufficiente
- [GraphRAG Minimum Viable Implementation](/blog/graphrag-minimum-viable-implementation) - Costruire un sistema GraphRAG funzionante

### Gli strumenti connessi

- [La ricerca semantica con ONNX e Qdrant](/blog/semantic-search-with-onnx-and-qdrant) - Gli elementi di costruzione
- [Self-Database di Vector Hosted: Qdrant](/blog/self-hosted-vector-databases-qdrant) - Running Qdrant locally
- [Analizzare grandi file CSV con LLM locali](/blog/analysing-large-csv-files-with-local-llms) - Same pattern, different domain
- [Portare e analizzare il contenuto web con i LLM](/blog/fetching-and-analysing-web-content-with-llms) - Scrapping web per RAG
- [Multi-Format Document Conversion Service](/blog/multi-format-document-conversion-service) - La immersione profonda di Docling

## Link

- [NuGet Package](https://www.nuget.org/packages/Mostlylucid.DocSummarizer)
- [GitHub - Core Library](https://github.com/scottgal/mostlylucidweb/tree/main/Mostlylucid.DocSummarizer.Core)
- [GitHub - CLI Tool](https://github.com/scottgal/mostlylucidweb/tree/main/Mostlylucid.DocSummarizer)