Back to "DocSummarizer Teil 3- > Fortgeschrittene Konzepte :- > Die "- > Ich war zu weit entfernt von Deep Dive"

This is a viewer only at the moment see the article on how this works.

To update the preview hit Ctrl-Alt-R (or ⌘-Alt-R on Mac) or Enter to refresh. The Save icon lets you save the markdown file to disk

This is a preview from the server running through my markdig pipeline

.NET AI BERT C# Embeddings LLM ONNX RAG

DocSummarizer Teil 3- > Fortgeschrittene Konzepte :- > Die "- > Ich war zu weit entfernt von Deep Dive

Sunday, 21 December 2025

Einleitung

Das ist Teil von der DocSummarizer-Serie

  1. Teil .1: . Aufbau eines Dokument-Zusammenfassung mit RAG Die Architektur und warum der Pipeline-Ansatz naive LLM-Aufrufe schlägt
  2. Teil mit dem Werkzeug Kurzanleitung für den CLI
  3. Teil - Fortgeschrittene Konzepte Dieser Artikel ist zu weit gegangen, der technische Tieftauchgang
  4. Teil Gebäude RAG Pipelines Verwenden Sie die NuGet-Bibliothek, um Ihre eigenen RAG-Apps zu erstellen

Dies ist ein Teil meiner Zeit-- ,Boxed Tools ," , approach .: , geben mir ein festes Fenster zu bauen etwas funktionale , . , Es zwingt Entscheidungen und produziert Arbeitscode statt theoretische Designs .

DocSummarizer begann als Demonstration, wie Sie sollte Build Dokument-Zusammenfassungen mit LLMs Die meisten Tutorials zeigen Ihnen, wie man Text in eine LLM schiebt und Hoffnung auf die beste . Ich wollte die richtige Architektur zeigen

Aber wie ich immer tue, habe ich mich für den Problemraum interessiert.. Vier Tage später...,... IM']d gegraben in die Forschung.MSC4. Wie funktioniert die Produktion?-?grade-Systeme tatsächlich mit Zusammenfassungen umgehen?MSC6. Was Retrieval gut macht??. Warum machen einige Einbettungen andere besser als ??

Ich implementierte Versionen dieser Ansätze.. , Was begann als " , hier , ' , das richtige Muster wurde ONNX Embeddings laufen lokal , , , Hybrid-Suche kombiniert BM...25 , mit dichtem Retrieval ,, , Maximal Marginal Relevanz für Diversity , und Reziprokaler Rang Fusion für die Kombination von Signalen , . ,

Faire WarnungDies ist die -", die ich zu weit ging - ", Tieftauchgang -., Wenn Sie nur das Tool verwenden möchten - ,, lesen Sie Teil -MCK5, wenn Sie verstehen wollen warum es funktioniert und Wie die Stücke passen zusammen ,, , halten lesen , . ,

Dieser Artikel umfasst:

  • SatzeinbettungenWie Transformator-Modelle ( – MiniLM2 – / – GTE-) – Text in Vektoren verwandeln
  • ONNX LaufzeitAusführen von ML-Modellen lokal ohne Python oder Cloud-APIs
  • **RAG-Erzeugung )**Erdung LLM-Ausgang im Ausgangsmaterial
  • Hybride SucheKombination semantischer und lexikalischer Retrieval mit RRF

Die Architektur auf einen Blick

Vor dem Eintauchen in Spezifika,, hier', wie die Stücke zusammenpassen

flowchart TB
    subgraph Input["Document Input"]
        DOC[/"Document<br/>(PDF, MD, URL)"/]
    end

    subgraph Parse["Parsing Layer"]
        DOCLING["Docling<br/>(PDF/DOCX)"]
        MARKDIG["Markdig<br/>(Markdown)"]
    end

    subgraph Extract["Extraction Layer"]
        CHUNK["Document Chunker"]
        SEGMENT["Segment Extractor"]
    end

    subgraph Embed["Embedding Layer"]
        ONNX["ONNX Runtime<br/>(Sentence Transformers)"]
        OLLAMA_EMB["Ollama<br/>(Optional)"]
    end

    subgraph Store["Vector Storage"]
        QDRANT["Qdrant<br/>(Vector DB)"]
        MEMORY["In-Memory<br/>(Small Docs)"]
    end

    subgraph Retrieve["Retrieval Layer"]
        DENSE["Dense Search<br/>(Semantic)"]
        BM25["BM25<br/>(Lexical)"]
        RRF["RRF Fusion"]
    end

    subgraph Synthesize["Synthesis Layer"]
        OLLAMA["Ollama LLM<br/>(Local)"]
        TEMPLATES["Summary Templates"]
    end

    subgraph Output["Output"]
        SUMMARY[/"Summary with<br/>Citations [chunk-N]"/]
    end

    DOC --> DOCLING & MARKDIG
    DOCLING & MARKDIG --> CHUNK & SEGMENT
    CHUNK --> ONNX & OLLAMA_EMB
    SEGMENT --> ONNX
    ONNX & OLLAMA_EMB --> QDRANT & MEMORY
    QDRANT & MEMORY --> DENSE
    CHUNK --> BM25
    DENSE & BM25 --> RRF
    RRF --> OLLAMA
    OLLAMA --> TEMPLATES
    TEMPLATES --> SUMMARY

Einbettungen verstehen

Das Problem: Wie finden Sie Relevante Inhalte ohne Schlüsselwörter?

Beim Zusammenfassen eines Handbuchs der 500--Seite müssen Sie relevante Abschnitte finden.

  • Benutzer fragt, wie ich das Gerät zurücksetze
  • Manual sagt, dass die Werkseinstellungen wiederhergestellt werden sollen.
  • Stichwortsuche verfehlt es (-Keine geteilten Wörter)-

Du brauchst semantische Suche Nicht nur Wörter, sondern auch Wörter, die mit der Bedeutung , übereinstimmen

Was sind Einbettungen?

Embeddings lösen dies, indem sie Text in dichte Vektoren verwandeln.(-Arrays von Zahlen.MSC1., die semantische Bedeutung erfassen. .. Ähnliche Bedeutungen.

Hier stellt sich die Intuition – : – einen Raum vor, in dem jedes Stück Text eine Position hat.

graph LR
    subgraph "Embedding Space (simplified to 2D)"
        A["🚗 car"]
        B["🚙 automobile"]
        C["🏎️ vehicle"]
        D["🍎 apple"]
        E["🍊 orange"]
        F["🍌 fruit"]
    end
    
    A -.->|"close"| B
    B -.->|"close"| C
    A -.->|"close"| C
    
    D -.->|"close"| E
    E -.->|"close"| F
    D -.->|"close"| F
    
    A -.-|"far"| D

Warum Sentence Transformer Nicht Raw BERTR.)?

ProblemstellungIch brauchte Einbettungen, die für semantische Ähnlichkeiten arbeiten.......... und Raw BERT wurde für Klassifizierungsaufgaben entwickelt.

LösungVerwendung Satztransformatoren Modelle, die speziell auf Ähnlichkeitsaufgaben mit kontrastiven Lernprozessen trainiert wurden, auf der Grundlage des BERT-Architektur aber fein, fein, anders abgestimmt

Modelle wie all-MiniLM-L6-v2 und bge-small-en-v1.5 wurden auf Milliarden von Textpaaren wie trainiert

  • Wie das Gerät zurückgesetzt wird" Wie das System zurückgesetzt werden kann↔ Wie die Werkseinstellungen wiederhergestellt werden können" Wie die ) ähnlich
  • Wie das Gerät zurückgesetzt werden kann" Wie das System zurückgesetzt wird↔ Wie das Produkt Spezifikationen

Das Training lehrt sie, ähnliche Bedeutungen, nahe Vektoren, hohe Kosinus-Ähnlichkeit

VerbundenWenn Sie verstehen wollen, wie Transformatorenmodelle auf einer tieferen Ebene funktionieren, und warum Embeddings arbeiten, sehen Sie meinen Artikel über Wie neurale maschinelle Übersetzung funktioniertEs deckt die gleichen Trafokonzepte aus einer Übersetzungsperspektive ab.

DurchführungWir nehmen die Ausgabeschicht des Modells, und verwenden durchschnittliche Bündelung Die Einbettungen aller Token durchschnittlich, um einen einzelnen Vektor für den gesamten Text zu erhalten.

flowchart LR
    subgraph Input
        TEXT["The quick brown fox"]
    end
    
    subgraph Tokenization
        CLS["[CLS]"]
        T1["the"]
        T2["quick"]
        T3["brown"]
        T4["fox"]
        SEP["[SEP]"]
    end
    
    subgraph "BERT Encoder"
        direction TB
        L1["Layer 1: Self-Attention"]
        L2["Layer 2: Self-Attention"]
        L3["..."]
        L6["Layer 6: Self-Attention"]
    end
    
    subgraph Output
        E1["E[CLS]"]
        E2["E[the]"]
        E3["E[quick]"]
        E4["E[brown]"]
        E5["E[fox]"]
        E6["E[SEP]"]
    end
    
    subgraph Pooling
        MEAN["Mean Pool<br/>(with attention mask)"]
        VEC["384-dim Vector"]
    end
    
    TEXT --> CLS & T1 & T2 & T3 & T4 & SEP
    CLS & T1 & T2 & T3 & T4 & SEP --> L1
    L1 --> L2 --> L3 --> L6
    L6 --> E1 & E2 & E3 & E4 & E5 & E6
    E1 & E2 & E3 & E4 & E5 & E6 --> MEAN
    MEAN --> VEC

ONNX-:-Laufen von ML Modellen vor Ort

Das Problem der Python-Abhängigkeit Hölle

Ich wollte Einbettungen, um einfach zu arbeiten, wenn jemand das Tool ausführt.

  1. Installieren Sie Python-Transformatoren
  2. Modelle manuell herunterladen
  3. Hope Versionskonflikte brechen nicht alles

Das saugt die Benutzer wollen docsummarizer -f doc.pdfNicht eine Anleitung für die Einstellung des Schrittes

Warum ONNX-??

ONNX - Open Neuronal Network Exchange - Open Neural Network Exchange – ist ein offenes Format für ML-Modelle. Laufzeitableitung ohne Python.

Was ich mit ONNX Runtime erhalte

  1. Null externe Abhängigkeiten Keine Python- oder PyTorch-Treiber
  2. Auto-Modelle herunterladen Erste Downloads von HuggingFace ausführen
  3. Reines .-NET Funktioniert überall, wo . NET läuft.( Windows, , Linux, MacOS,, ARM-64)
  4. CPU-Schlussfolgerung Keine GPU erforderlich , läuft auf billige Hardware

Handelt leicht langsamer als GPU PyTorch, aber viel schneller, als Benutzer zu bitten, Python, . zu installieren

Das Musterregister

DocSummarizer enthält mehrere Einbettungsmodelle, jeweils mit unterschiedlichem Trade

-Modell Abmessungen -Max-Token Größe (-Quantisiert )- -Anwendungsfall -Benötigt Anleitung -
AllMiniLmL6V2 -M384- -MNSK3-MUSK4-MKSK5-MB-MWSK6-Standard-Schnell-,-Gute Qualität
BgeSmallEnV15 Besser für technische docs
GteSmall -M384- -MNSK3-MUSK4-MKSK5-MB-MWSK6-Allgemeines Verwendungszweck
MultiQaMiniLm -M384- -MNSK3-MUSK4-MKSK5-MB-MWSK6-Optimiert für Q-&-A-MASSK8-Nr.

AnmerkungAlle Registrierungseinträge zeigen auf WordPiece.-.compatible ONNX-Exporte. vocab.txtBPE-/-Unigrammmodelle werden noch nicht unterstützt

BGE-AnleitungsformatEinige Modelle, wie z.B. BGE, erfordern Präfixe für eine optimale Performance. Das genaue Format hängt vom Modell ab.

// Query embedding (what the user asks)
var queryText = "Represent this sentence for searching relevant passages: " + userQuery;
var queryEmbedding = await EmbedAsync(queryText);

// Passage embedding (document chunks)
// Some BGE variants prefix passages, others don't - check model documentation
var passageEmbedding = await EmbedAsync(chunkText);

Die Registry-Tracks, die Modelle benötigen Anweisungen über RequiresInstruction und QueryInstruction fields-. , immer Benchmark Retrieval Qualität bei der Arbeit mit instruction-.- , basierenden Modellen ,. ,

Hier ist die Art und Weise, wie das Modell-Register arbeitet.

public static class OnnxModelRegistry
{
    public static EmbeddingModelInfo GetEmbeddingModel(OnnxEmbeddingModel model, bool quantized = true)
    {
        return model switch
        {
            OnnxEmbeddingModel.AllMiniLmL6V2 => new EmbeddingModelInfo
            {
                Name = "all-MiniLM-L6-v2",
                HuggingFaceRepo = "Xenova/all-MiniLM-L6-v2",
                ModelFile = quantized ? "onnx/model_quantized.onnx" : "onnx/model.onnx",
                VocabFile = "vocab.txt",
                EmbeddingDimension = 384,
                MaxSequenceLength = 256,
                SizeBytes = quantized ? 23_000_000 : 90_000_000,
                RequiresInstruction = false
            },
            // ... other models
        };
    }
}

Tokenization-:- WordPiece vs BPE

Verschiedene Modelle verwenden verschiedene Tokenizers all-MiniLM-L6-v2 Modell verwendet WordPiece-Tokenisierung, die unbekannte Wörter in Subwort Tokens aufteilt Andere Modelle können BPE verwenden ( Byte .- .Pair Encoding, ) oder Unigram tokenizers .

WichtigUnsere Registrierungsspuren, die Tokenizer jedes Modell erfordert Derzeit implementierte WordPiece ("via vocab.txtUnterstützung des BPE-/-Unigramms über tokenizer.json ist geplant, aber noch nicht implementiert.Verhalten Sie sich an die WordPiece-Modelle in der Registry für jetzt.

public class BertTokenizer
{
    private readonly Dictionary<string, int> _vocab;
    private const int ClsTokenId = 101;  // [CLS] - start of sequence
    private const int SepTokenId = 102;  // [SEP] - end of sequence
    private const int PadTokenId = 0;    // [PAD] - padding
    private const int UnkTokenId = 100;  // [UNK] - unknown token

    public BertTokenizer(string vocabPath)
    {
        // Load vocabulary: word -> token ID
        _vocab = File.ReadAllLines(vocabPath)
            .Select((word, index) => (word, index))
            .ToDictionary(x => x.word, x => x.index);
    }

    public (long[] InputIds, long[] AttentionMask, long[] TokenTypeIds) 
        Encode(string text, int maxLength)
    {
        // Split text into words, then apply WordPiece to each word
        var words = text.ToLowerInvariant()
            .Split(new[] { ' ', '\t', '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
        var tokens = words.SelectMany(WordPieceTokenize).ToList();
        
        // Truncate to fit [CLS] and [SEP] tokens
        if (tokens.Count > maxLength - 2)
            tokens = tokens.Take(maxLength - 2).ToList();

        // Build input: [CLS] + tokens + [SEP] + [PAD]...
        var inputIds = new List<long> { ClsTokenId };
        inputIds.AddRange(tokens.Select(t => (long)GetTokenId(t)));
        inputIds.Add(SepTokenId);

        // Pad to maxLength
        var padCount = maxLength - inputIds.Count;
        inputIds.AddRange(Enumerable.Repeat((long)PadTokenId, padCount));

        // Attention mask: 1 for real tokens, 0 for padding
        var attentionMask = inputIds.Select(id => id != PadTokenId ? 1L : 0L).ToArray();
        
        // Token type IDs: all zeros for single sentence
        var tokenTypeIds = new long[maxLength];

        return (inputIds.ToArray(), attentionMask, tokenTypeIds);
    }

    private IEnumerable<string> WordPieceTokenize(string word)
    {
        // If the whole word is in vocabulary, return it
        if (_vocab.ContainsKey(word))
        {
            yield return word;
            yield break;
        }

        // Otherwise, split into subwords with "##" prefix
        int start = 0;
        while (start < word.Length)
        {
            int end = word.Length;
            string? curSubstr = null;

            while (start < end)
            {
                var substr = word[start..end];
                if (start > 0) substr = "##" + substr;  // Continuation marker

                if (_vocab.ContainsKey(substr))
                {
                    curSubstr = substr;
                    break;
                }
                end--;
            }

            if (curSubstr == null)
            {
                yield return "[UNK]";
                yield break;
            }

            yield return curSubstr;
            start = end;
        }
    }
}

Beispiel für Tokenisierung

Eingabe-Marken |-------|--------| | "embedding" | ["em", "##bed", "##ding"] | | "DocSummarizer" | ["doc", "##su", "##mm", "##ari", "##zer"] | | "the quick brown" | ["the", "quick", "brown"] |

Mean Pooling mit Aufmerksamkeit Maske

Nachdem BERT die Tokens verarbeitet, erhalten wir einen versteckten Zustand für jeden Token, ., Mean Pooling Durchschnitte diese, MSC2 aber nur über echte Token.

private static float[] MeanPool(Tensor<float> hiddenStates, long[] attentionMask, int hiddenSize)
{
    // Assumes last_hidden_state shape: [batch=1, seq_len, hidden_size]
    // Note: Many sentence-transformer models export a pooled output directly,
    // but we use mean pooling for consistency across all ONNX exports.
    var result = new float[hiddenSize];
    var dims = hiddenStates.Dimensions.ToArray();
    var seqLen = (int)dims[1];
    
    // Count real tokens (not padding)
    float maskSum = attentionMask.Count(x => x == 1);
    if (maskSum == 0) maskSum = 1; // Avoid division by zero

    // Average each dimension, weighted by attention mask
    for (int h = 0; h < hiddenSize; h++)
    {
        float sum = 0;
        for (int s = 0; s < seqLen; s++)
        {
            if (attentionMask[s] == 1)
                sum += hiddenStates[0, s, h];
        }
        result[h] = sum / maskSum;
    }

    // L2 normalize for cosine similarity
    float norm = MathF.Sqrt(result.Sum(x => x * x));
    if (norm > 0)
    {
        for (int i = 0; i < result.Length; i++)
            result[i] /= norm;
    }

    return result;
}

Die komplette Einbettungspipeline

Hier ist der volle Fluss vom Text zum Einbetten.

public class OnnxEmbeddingService : IEmbeddingService, IDisposable
{
    private InferenceSession? _session;
    private BertTokenizer? _tokenizer;

    public async Task<float[]> EmbedAsync(string text, CancellationToken ct = default)
    {
        await InitializeAsync(ct);  // Downloads model if needed
        
        // Prepend instruction for models that need it (like BGE)
        if (_modelInfo.RequiresInstruction)
            text = _modelInfo.QueryInstruction + text;

        // Tokenize
        var (inputIds, attentionMask, tokenTypeIds) = 
            _tokenizer.Encode(text, _maxSequenceLength);

        // Create ONNX tensors
        var inputIdsTensor = new DenseTensor<long>(inputIds, new[] { 1, inputIds.Length });
        var attentionMaskTensor = new DenseTensor<long>(attentionMask, new[] { 1, attentionMask.Length });
        var tokenTypeIdsTensor = new DenseTensor<long>(tokenTypeIds, new[] { 1, tokenTypeIds.Length });

        var inputs = new List<NamedOnnxValue>
        {
            NamedOnnxValue.CreateFromTensor("input_ids", inputIdsTensor),
            NamedOnnxValue.CreateFromTensor("attention_mask", attentionMaskTensor),
            NamedOnnxValue.CreateFromTensor("token_type_ids", tokenTypeIdsTensor)
        };

        // Run inference
        using var results = _session.Run(inputs);
        
        // Get hidden states output
        var output = results.First(r => r.Name == "last_hidden_state");
        var outputTensor = output.AsTensor<float>();

        // Mean pooling with attention mask
        return MeanPool(outputTensor, attentionMask, _modelInfo.EmbeddingDimension);
    }
}

Erhöhte Erzeugung

Das Problem: Die LLMs können Dokumente lesen

Der naive Ansatz fehlschlägt.

var text = File.ReadAllText("500-page-manual.txt"); // 2MB of text
var summary = await llm.GenerateAsync($"Summarize: {text}"); // ❌ Doesn't fit in context

Selbst mit Kontextfenstern von 128-K können Sie riesige Dokumente in :-Cocktails deponieren

  • SpannungNur die ersten Seiten passen zu ,e Rest ignoriert
  • HalluzinationLLM erfindet Facts, um Lücken zu füllen
  • KostenVerarbeitung von Textkosten 2MB pro Abfrage
  • QualitätLLMs werden mit massivem Kontext verwechselt.

Die Lösung: :-RAG Retrieval---Augmentierte Generation: )-

Anstatt alles zu senden, schicken Sie nur das, was relevant ist.

  1. ZuckenUnterteilen Sie das Dokument in Segmente
  2. EinbettenSegmente nach Vektoren umrechnen
  3. WiedereinsetzungSuchen Sie die relevantesten Segmente für die Abfrage
  4. SyntheseLLM fasst nur jene Segmente zusammen

Warum das funktioniert Die LLM sieht -10-KB von hoch relevanten Inhalten anstelle von -2-MB von meist irrelevantem Text.

flowchart LR
    subgraph "Without RAG"
        DOC1[/"500-page PDF"/]
        LLM1["LLM<br/>(32K context)"]
        OUT1["❌ Truncated or<br/>Hallucinated"]
    end
    
    subgraph "With RAG"
        DOC2[/"500-page PDF"/]
        CHUNKS["100 Chunks"]
        VDB["Vector DB"]
        QUERY["Query"]
        TOP["Top 10 Chunks"]
        LLM2["LLM"]
        OUT2["✅ Grounded<br/>Summary"]
    end
    
    DOC1 --> LLM1 --> OUT1
    
    DOC2 --> CHUNKS --> VDB
    QUERY --> VDB --> TOP --> LLM2 --> OUT2

Dokument Chunking-Strategien

DocSummarizer unterstützt mehrere Chunking-Strategien basierend auf der Dokumentenstruktur.

public class DocumentChunker
{
    public List<DocumentChunk> ChunkByHeadings(string markdown, int maxHeadingLevel = 2)
    {
        var chunks = new List<DocumentChunk>();
        var lines = markdown.Split('\n');
        var currentChunk = new StringBuilder();
        var currentHeading = "";
        var headingLevel = 0;
        var order = 0;

        foreach (var line in lines)
        {
            // Detect heading (# to ######)
            var headingMatch = Regex.Match(line, @"^(#{1,6})\s+(.+)$");
            
            if (headingMatch.Success && 
                headingMatch.Groups[1].Length <= maxHeadingLevel)
            {
                // Flush current chunk
                if (currentChunk.Length > 0)
                {
                    chunks.Add(new DocumentChunk(
                        Order: order++,
                        Heading: currentHeading,
                        HeadingLevel: headingLevel,
                        Content: currentChunk.ToString().Trim(),
                        Hash: ComputeHash(currentChunk.ToString())
                    ));
                }
                
                // Start new chunk
                currentHeading = headingMatch.Groups[2].Value;
                headingLevel = headingMatch.Groups[1].Length;
                currentChunk.Clear();
            }
            else
            {
                currentChunk.AppendLine(line);
            }
        }
        
        // Don't forget the last chunk
        if (currentChunk.Length > 0)
        {
            chunks.Add(new DocumentChunk(
                Order: order,
                Heading: currentHeading,
                HeadingLevel: headingLevel,
                Content: currentChunk.ToString().Trim(),
                Hash: ComputeHash(currentChunk.ToString())
            ));
        }
        
        return chunks;
    }
}

Segmentextraktion für Feinst---Grained Retrieval

Für längere Dokumente: DocSummarizer extrahiert einzelne Segmente: (.Sentences:,.List items: ,.Codeblöcke: ).

public class SegmentExtractor
{
    public async Task<ExtractionResult> ExtractAsync(string docId, string markdown)
    {
        // 1. Parse into typed segments
        var segments = ParseToSegments(docId, markdown);
        
        // 2. Generate embeddings
        await GenerateEmbeddingsAsync(segments);
        
        // 3. Calculate document centroid (average embedding)
        var centroid = CalculateCentroid(segments);
        
        // 4. Score by salience using MMR (Maximal Marginal Relevance)
        ComputeSalienceScores(segments, centroid);
        
        return new ExtractionResult
        {
            AllSegments = segments,
            TopBySalience = segments.OrderByDescending(s => s.SalienceScore).Take(50).ToList(),
            Centroid = centroid
        };
    }
}

Das Problem: Semantische Suche gibt doppelte Rückgaben zurück

Ohne MMRWie funktioniert das Caching?

  1. Übersicht über das Einstecken von Daten"Ausblenden von Daten
  2. Einführung in das Caching", Ähnlichkeit mit (0.94,
  3. Was ist Caching??"?
  4. Details zur Implementierung des Caches". Ähnlichkeit von (0.85.

Die oberen Ergebnisse sagen alle dasselbe:

Die Lösung: Maximale Marginal-Relevanz:

MMR-Salden Relevanz Ähnlichkeit zu Abfragen mit Vielfalt Unähnlichkeit zu bereits ausgewählten Gegenständen

Formel ,:- $$-MMR-=--lambda--cdot S-Text-MSC5-sim}(-Simm,-Abfrage)-MSSK9-MS K10-M---Lambda-)-MSD14-Cdot-MSZ15-max_Ausgewählte }Ausgewählte\Ausgewählter {Ausgewählter }(Ausgekürzter S,Ausgelesener SMS-Text

Was es tut Straft Kandidaten ähnlich wie bereits gewählte Segmente.. Dies verhindert, dass die Zusammenfassung der Version des gleichen Absatzes ..

flowchart TB
    subgraph "MMR Selection"
        S1["Segment 1<br/>Score: 0.95"]
        S2["Segment 2<br/>Score: 0.90"]
        S3["Segment 3<br/>Score: 0.88"]
        S4["Segment 4<br/>Score: 0.85"]
    end
    
    subgraph "Selected"
        SEL1["✓ Seg 1<br/>(highest)"]
        SEL2["✓ Seg 3<br/>(most diverse)"]
        SEL3["✓ Seg 4"]
    end
    
    S1 -->|"Select"| SEL1
    S2 -->|"Skip - too similar to Seg 1"| X["❌"]
    S3 -->|"Select"| SEL2
    S4 -->|"Select"| SEL3

Die Formel „:"

]\(-MMR ®=-\-lambda ® \-cdot sim T(-s,-centroid ® )--MSC7-(1------\-lambenda ?)-MSSK12-cdot Â\-max_Ausgewählte }Ausgewählte(Ausgewählter ,Ausgewählter ')\)

private List<Segment> SelectSentencesMMR(
    List<Segment> segments,
    float[] centroid,
    int targetCount)
{
    var selected = new List<Segment>();
    var candidates = new HashSet<Segment>(segments.Where(s => s.Embedding != null));
    
    // Pre-calculate centroid similarities
    foreach (var segment in candidates)
    {
        segment.Score = CosineSimilarity(segment.Embedding!, centroid) 
                      * segment.PositionWeight;
    }
    
    while (selected.Count < targetCount && candidates.Count > 0)
    {
        Segment? best = null;
        double bestScore = double.MinValue;
        
        foreach (var candidate in candidates)
        {
            // Relevance: similarity to centroid
            var relevance = candidate.Score;
            
            // Diversity: max similarity to already selected
            double maxSimToSelected = 0;
            foreach (var sel in selected)
            {
                var sim = CosineSimilarity(candidate.Embedding!, sel.Embedding!);
                maxSimToSelected = Math.Max(maxSimToSelected, sim);
            }
            
            // MMR score: balance relevance and diversity
            var mmrScore = _config.Lambda * relevance 
                         - (1 - _config.Lambda) * maxSimToSelected;
            
            if (mmrScore > bestScore)
            {
                bestScore = mmrScore;
                best = candidate;
            }
        }
        
        if (best != null)
        {
            selected.Add(best);
            candidates.Remove(best);
        }
    }
    
    return selected;
}

Hybride Suche mit RRF

Das Problem: Semantische Suche vermisst exakte Übereinstimmungen

Ich rannte in diese beim Testen

AbfrageDer API-Endpunkt für die Authentifizierung von ?"

Semantische Suche zurückgegeben

  1. Benutzer-Login-Flussübersicht" hohe Ähnlichkeit)
  2. Sicherheits-bewährte Verfahren
  3. "-Sessionsmanagement"-Segment mit hoher Ähnlichkeit)-Signität

Was es verpasst hatDer tatsächliche API-Endpunkt, der in Codebeispielen vergraben ist POST /api/v1/auth/login

**Warum?**Embedding-Modelle werden auf natürliche Sprache trainiert......... nicht code.. ../ .URLs... POST /api/v1/auth/login doesns.' match semantisch mit dem Endpunkt der Aushöhlung von " ," , - , es ist eine buchstäbliche technische Referenz

Die Lösung: Hybride Suche: Semantisch Lexisch )

Kombinieren Sie zwei Retrieval-Methoden mit komplementären Stärken

Suchtyp Stärke Stärke Schwäche |-------------|-----------|------------| | Dichte (-Einbettung )- Memanisches Verständnis Memantische Synonyme Memanisches Verstehen Memanischer Verstand Kann exakte Übereinstimmungen verfehlen | Sparse (-BM-25)- Genaues Schlüsselwort passend zu den seltenen Begriffen von ,. Kein semantisches Verständnis

Hybride Suche kombiniert beides mit reziproker Rank Fusion

flowchart TB
    QUERY["Query: 'authentication security'"]
    
    subgraph Dense["Dense Search (Semantic)"]
        D1["1. OAuth 2.0 implementation"]
        D2["2. User login flow"]
        D3["3. Password hashing"]
    end
    
    subgraph Sparse["BM25 Search (Lexical)"]
        S1["1. Authentication middleware"]
        S2["2. Security headers"]
        S3["3. OAuth 2.0 implementation"]
    end
    
    subgraph RRF["RRF Fusion (Illustrative)"]
        R1["OAuth 2.0 implementation<br/>RRF = 1/(60+1) + 1/(60+3) ≈ 0.032"]
        R2["Authentication middleware<br/>RRF = (not in dense) + 1/(60+1) ≈ 0.016"]
        R3["User login flow<br/>RRF = 1/(60+2) + (not in BM25) ≈ 0.016"]
    end
    
    QUERY --> Dense & Sparse
    Dense --> RRF
    Sparse --> RRF

AnmerkungDie angezeigten RRF-Scores sind illustrativ......... die Konstante k.=60... ist standard.... die aktuelle Rangfolge hängt vom vollständigen Kandidatensatz ab.

RRF-Umsetzung

public static class HybridRRF
{
    /// <summary>
    /// Reciprocal Rank Fusion: combine multiple rankings into one.
    /// 
    /// Formula: RRF(d) = Σ 1/(k + rank_i(d))
    /// 
    /// Where k = 60 (standard constant to prevent division by small numbers)
    /// </summary>

    public static List<Segment> Fuse(
        List<Segment> segments,
        string query,
        BM25Scorer bm25,
        int k = 60,
        int topK = 20)
    {
        // Rank by dense similarity
        var byDense = segments
            .Where(s => s.Embedding != null)
            .OrderByDescending(s => s.QuerySimilarity)
            .ToList();
        
        // Rank by BM25 (scorer is built over the same ordered segment list)
        var bm25Scores = segments
            .Select((s, i) => (segment: s, score: bm25.Score(i, query)))
            .OrderByDescending(x => x.score)
            .Select(x => x.segment)
            .ToList();
        
        // Rank by salience (pre-computed importance)
        var bySalience = segments
            .OrderByDescending(s => s.SalienceScore)
            .ToList();
        
        // Compute RRF scores
        var rrfScores = new Dictionary<Segment, double>();
        
        void AddRRFScore(List<Segment> ranking)
        {
            for (int i = 0; i < ranking.Count; i++)
            {
                var segment = ranking[i];
                var rrfContribution = 1.0 / (k + i + 1);  // 1-based rank
                
                if (!rrfScores.TryAdd(segment, rrfContribution))
                    rrfScores[segment] += rrfContribution;
            }
        }
        
        AddRRFScore(byDense);
        AddRRFScore(bm25Scores);
        AddRRFScore(bySalience);
        
        // Return top-K by fused score
        return rrfScores
            .OrderByDescending(kv => kv.Value)
            .Take(topK)
            .Select(kv => kv.Key)
            .ToList();
    }
}

Das Sparse Retrieval Workhorse

BM-25 M(Best MatchingTM25)- ist der klassische Informationswiederholalgorithmus, der den Begriff Frequenz kombiniert., inverse Dokumentfrequenz und Dokumentenlängennormalisierung.

public class BM25Scorer
{
    private const double K1 = 1.5;  // Term frequency saturation
    private const double B = 0.75;  // Length normalization factor
    
    public double Score(int docIndex, string query)
    {
        var queryTerms = Tokenize(query);
        var docTermFreq = _docTermFreqs[docIndex];
        var docLength = _docLengths[docIndex];
        
        double score = 0;
        
        foreach (var term in queryTerms.Distinct())
        {
            if (!docTermFreq.TryGetValue(term, out var tf)) continue;
            if (!_docFreqs.TryGetValue(term, out var df)) continue;
            
            // IDF with smoothing
            var idf = Math.Log((_corpusSize - df + 0.5) / (df + 0.5) + 1);
            
            // BM25 TF component with length normalization
            var tfNorm = (tf * (K1 + 1)) / 
                (tf + K1 * (1 - B + B * docLength / _avgDocLength));
            
            score += idf * tfNorm;
        }
        
        return score;
    }
}

TF.-.IDF für die inhaltliche Zentralität

Das Problem: Wie unterscheiden Sie Kerninhalte von Trivia?

Als ich einen Roman zusammenfasste, bekam ich Ergebnisse wie:

Der Protagonist trug einen blauen Mantel... Watson bemerkte, dass das Wetter mild war.

Dies sind genaue Extraktionen, aber sie Farbe Details zum Einstellen von Informationen nicht Kernpunkte der Handlung.

HerausforderungWie erklären Sie den Unterschied zwischen

  • KerninhaltIm gesamten Dokument erscheinen die Namen der Zeichen, Hauptthemen und Schlüsselereignisse.
  • Unterstützende DetailsIn einigen Abschnitten erscheinen Erläuterungen zu )
  • FarbeDetails zu den Möbeln, die jemand trug ,

Die Lösung für die Klassifizierung der Zentralität

TF.-.IDF.Term Frequency - Inverse Dokumenthäufigkeit - Schätzungen wie zentral ein Begriff für das Dokument istNicht sein Wahrheitswert.

Logik ,: ,

  • Hohes DF (MSK) von Stücken:-Sherlock",-SharlockM"-Watson",-Surking"-Serlock→-Kerngehalt
  • Mittlerer DF-WertWeitere Informationen sind abrufbar unter: http:europa.eu.int
  • Niedriger DF-Wert"Blauer Mantel ",Black Möbel "Black

Dies ist nicht über Wahrheit, die wiederholte Behauptung kann falsch sein, ,. Eine seltene Tatsache kann wahr sein,).. Zentralität des Dokuments.

flowchart LR
    subgraph "TF-IDF Classification"
        CLAIM["Claim text"]
        TERMS["Extract terms"]
        TFIDF["Compute TF-IDF"]
        CLASS["Classify"]
    end
    
    subgraph "Term Types"
        COMMON["High DF (>50%)<br/>→ Core content"]
        MODERATE["Medium DF (20-50%)<br/>→ Supporting detail"]
        RARE["Low DF (<20%)<br/>→ Incidental colour"]
    end
    
    CLAIM --> TERMS --> TFIDF --> CLASS
    CLASS --> COMMON & MODERATE & RARE
public class TextAnalysisService
{
    private readonly Dictionary<string, int> _documentFrequency = new();
    private int _totalDocuments;

    public void BuildTfIdfIndex(IEnumerable<string> documents)
    {
        _documentFrequency.Clear();
        _totalDocuments = 0;
        
        foreach (var doc in documents)
        {
            _totalDocuments++;
            var terms = Tokenize(doc).Distinct();
            
            foreach (var term in terms)
            {
                _documentFrequency.TryGetValue(term, out var count);
                _documentFrequency[term] = count + 1;
            }
        }
    }

    /// <summary>
    /// Classify term centrality (not epistemic truth):
    /// - High DF (>50%): appears across most chunks = core content
    /// - Medium DF (20-50%): supporting detail
    /// - Low DF (<20%): rare = likely incidental ("colour")
    /// 
    /// Note: This estimates centrality, not factuality. A repeated 
    /// claim can be false; a rare fact can be true.
    /// </summary>

    public ClaimType ClassifyTermImportance(string term)
    {
        var df = _documentFrequency.GetValueOrDefault(term.ToLowerInvariant(), 0);
        
        if (_totalDocuments == 0 || df == 0)
            return ClaimType.Colour;
        
        var documentRatio = (double)df / _totalDocuments;
        
        // High centrality = appears widely
        if (documentRatio > 0.5)
            return ClaimType.Core;
        
        // Medium centrality = supporting themes
        if (documentRatio > 0.2)
            return ClaimType.Supporting;
        
        // Low centrality = incidental detail
        return ClaimType.Colour;
    }
}

Die komplette BertRag Pipeline

DocSummarizer, Produktionspipeline von 'BertRagSummarizerAlle diese Konzepte werden zusammengeführt.

public class BertRagSummarizer
{
    /// <summary>
    /// Full pipeline: Extract → Retrieve → Synthesize
    /// 
    /// Key properties:
    /// - LLM only at synthesis (no LLM-in-the-loop evaluation)
    /// - Deterministic extraction (reproducible, debuggable)
    /// - Validated citations (every claim traceable to source segment)
    /// - Scales to any document size
    /// - Cost-optimal (cheap CPU work first, expensive LLM last)
    /// </summary>

    public async Task<DocumentSummary> SummarizeAsync(
        string docId,
        string markdown,
        string? focusQuery = null)
    {
        // === Phase 1: Extract ===
        // Parse document → segments with embeddings + salience scores
        var extraction = await _extractor.ExtractAsync(docId, markdown);
        
        // === Phase 2: Retrieve ===
        // Hybrid search: Dense + BM25 + Salience via RRF
        var retrieved = await RetrieveAsync(extraction, focusQuery);
        
        // === Phase 3: Synthesize ===
        // LLM generates fluent summary from retrieved segments
        var summary = await SynthesizeAsync(docId, retrieved, extraction, focusQuery);
        
        return summary;
    }
}

Häufige Störungsmodi

Beim Bauen und Verwenden von DocSummarizer-,-I'-ve traf diese Probleme (- und Sie werden auch

  1. Tokenizer-Mismatch Unsinn EinbettungenDas Laden eines WordPiece Vokabelns für ein BPE-Modell erzeugt gültige, aber semantisch bedeutungslose Vektoren.Verifizieren Sie immer den Tokenizer, der dem Trainingsregime des Modells entspricht.

  2. Dominant---topische Voreingenommenheit bei der Einzelbetrachtung von --CentroidenDie Verwendung eines Dokuments zentroid systematisch down--rankt Minderheitenthemen (...Beschränkungen,.Ausnahmen,. Randfälle).. Multi--.Anchor Retrieval behebt dies, fügt aber Komplexität hinzu.

  3. BM.25. Beats dichte Suche auf seltenen BegriffenWenn Ihre Abfrage technisches Jargon oder richtige Substantive enthält, die nicht gut sind, wird das Embedding-Modell die semantische Suche übertreffen.

  4. OCR-Müll in gescannten PDFsDocling ist gut , aber OCR-Fehler Verbindung , wenn Sie Unfug in Zusammenfassungen sehen , überprüfen Sie die Markdown-Ausgabe von Docling erste , - , der Resumpler can , ' , fixieren Müll Eingang ,. .

  5. Niedrige --Erfassungszusammenfassungen müssen die Sprache absichernWenn du nur 3% siehst, sind die Phrasen eines Dokuments ,e wie "eultimately"e oder "in schlussfolgern"e unehrlich.e Das System muss sagen, in den abgetasteten Abschnitten "e und vermeiden definitive Endungen .e

  6. ZitierhalluzinationWir validieren, indem wir die Ausgabe für [chunk-N]Das Verifizieren von N existiert in den Quellstücken., und die Kennzeichnung oder Reparatur von Ansprüchen, die fehlende Stücke zitieren. [chunk-999] für ein Dokument mit dem Befehl 10--Cunk,-D Ihr LLM kämpft mit der Aufgabe.

Dies sind die inhärenten Spannungen im Designraum von -. Gute Produktionssysteme erkennen und mildern sie.

Praktische Überlegungen

Abdeckung und Probenahme Ehrlichkeit

Bei der Verarbeitung von sehr großen Dokumenten versucht DocSummarizer nicht, alles einzubetten. Es verwendet semantisches Pre-Molekül zur Auswahl repräsentativer Segmente. Dies bedeutet, dass die Zusammenfassung auf einer Probe basiert, nicht auf dem vollständigen Dokument.

Das System handhabt diese transparent

// If coverage is low (<5%), prepend disclaimer and use cautious language
if (coverage < 0.05)
{
    var disclaimer = $"WARNING: Summary (sampled ~{coverage:P1} of document)";
    summary = $"{disclaimer}\n\n{CleanAndHedge(summary)}";
}

// Append coverage footer to every summary
var footer = $"\n\n---\nCoverage: {coverage:P1} ({scope})\nConfidence: {confidence}";

WichtigDies ist ein Zusammenfassung der abgerufenen BeweiseNicht eine Garantie von der vollen Abdeckung von -, wenn wir sagen, dass "ampled 3%",, das genau, was passiert ist -, das System sah 3%, von dem Dokument und fasste, dass -.,

Die Probenahme ist zufällig ,-, es , ', es semantischWir verwenden Multi--Anchor-Clustering, um sicherzustellen, dass Minderheitenthemen ausgeschlossen sind'T .Ein zufälliges 3%I könnte alle Einschränkungen und Randfälle verpassen ..A semantic .3%C versucht, ein repräsentatives Segment aus jedem Hauptthema zu erfassen ,.Es ist immer noch partielle Abdeckung,Aber es ist bewusst verschiedene Teilabdeckung.

Adaptive Probenahme mit mehreren Themenankern- Filter verwendet mehrere Anker - Mittel - Stil-Clustering eines geschichteten Samples , um sicherzustellen, dass Minderheitenthemen systematisch ausgeschlossen werden . Dies verhindert die Dominante Thema Bias", wo ein einzelnes Zentrioid nach unten - ist wichtig - aber nicht - Seltene Inhalte wie Einschränkungen , Ausnahmen , oder Schlussfolgerungen .

Von SegmentExtractor.cs:

// Multi-anchor approach prevents single-centroid bias
var topicAnchors = ComputeTopicAnchors(embeddedSample, k: 5);

// Score by max similarity to ANY anchor (catches minority topics)
var score = topicAnchors.Max(anchor => CosineSimilarity(segment.Embedding, anchor));

Dies ist die Forschung.-.informiert.(.vermeiden einzelne...-.query Rückruf Kollaps, aber praktisch. -. es läuft in Sekunden auf CPU.

Warum nicht einfach alles einbetten?

Für ein Dokument auf der Seite von (2,000+, Segmenten, das alles einbettet, aber optimal ist :,

  • KostenDie Embeddings dominieren die Laufzeit.
  • QualitätAlles einbetten erhöht das Rauschen im Retrieval-Pool.Sie brauchen noch Ranking, also warum Embed Segmente, die nie hoch rangieren.
  • ZweckmäßigkeitSpeicher- und Latenzzwänge für die Verarbeitung von Daten über Speicher und Datenverarbeitung Die Kosinusgleichheiten pro Abfrage sind verschwenderisch, wenn Sie nur das Top benötigen.

Das Multi---Anchor-Sampling gibt Ihnen das Beste aus beiden, die breite Themenabdeckung mit traktierbaren Computing-.

Kontext Dragging - Warum Retrieval ist gerade Suche

Was oben beschriebene I''ve ist nur ein spezielles Muster, das ich nenne. Beschränkte Fuzzy Kontext Drackging (CFCDDie Einsicht

Die meisten Resumblierer halten Kontext hinzufügen zieht nach vorn nur das, was überlebt deterministische Auswahl... dann lässt das Modell fließend in jene Grenzen schreiben...

Hier geht es darum, wie die DocSummarizer-Pipeline zu CFCD.:

Anwendung von DocSummarizer |--------------|------------------------------| | Salience-Aufdeckung (-Fuzzy-)-Embeddings-,-Centrioid-Ähnlichkeit - Zentralität von TF, --IDF | Deterministische Förderung MMR,BM25,C RRF Fusion M,C nach oben MMR-MMR--K Auswahl M|C | Ankerbuch Das abgerufene Segment, das mit Zitier-IDs gesetzt wird | Beschränkte Erzeugung Synthesis-Prompt durch gefundene Beweise begrenzt

Warum das so wichtig istDas Modell entscheidet nicht, was die Retrieval-Pipeline betrifft.Das Modell erzeugt nur fließend innerhalb der Grenzen wir.'.ve set... Aus diesem Grund arbeiten kleine lokale Modelle.Die Anker machen das schwere Heben.

In der Praxis sieht das Anchor-Zeichnungsbuch von " aus wie dieses Konzept von MKK3.

{
  "coverage": "3.2% semantic sample",
  "anchors": [
    { "id": "chunk-12", "text": "Reset requires holding button 10s", "salience": 0.92 },
    { "id": "chunk-45", "text": "Factory reset clears all settings", "salience": 0.88 }
  ],
  "constraints": {
    "terms": { "factory reset": "restore factory settings" },
    "hedging": "sampled 3% - avoid definitive conclusions"
  }
}

Dann in der Synthese-Prompt

  • Jeder Anspruch muss einen enthaltenen Klumpen zitieren.
  • ," , wenn Abdeckung , < , , 5%, , Hedge-Sprache , " ,
  • Verwenden Sie diese Begriffe konsequent.

Dies ist der Grund, warum

  • Längere Kontextfenster sind ein roter Hering Das Problem ist, dass mehr Text passt.
  • Rekursive Zusammenfassung scheitert Es behandelt Zwischenausgabe als Text, nicht eingeschränkte Struktur
  • Die LLM kann ,' , , " , forget , " , geförderte Einschränkungen Nicht Prosa kann es driften aus

CFCD ist die gleiche philosophische Spaltung wie Beschränkte Fuzziness, Beschränkte Fuzzy MoML 347 vom 20.12.2013, S. 671. Bildzusammenfassung Wahrscheinlichkeit schlägt vor, dass der Determinismus andauert und entlang der Zeit angewendet wird

Quantifizierung

ONNX-Modelle können quantifiziert werden Präzise reduzierte ) für kleinere Größe und schnellere Rückschlüsse Der Handel ist minimaler Qualitätsverlust

Modell Quantisierter Qualitätsunterschied Quantifizierter Qualitätsunterschiede
-, MiniLM, -, MKS3, MSC4, , M90MB, MSSK7, MCSK8, MC9, MSV10, MSR11, MWSK11
-bge---small---en---v1.5- -m133-mB- -mb- -

Stapelverarbeitung und -konkurrenz

Für große Dokumente ist das Batch-Embedding von entscheidender Bedeutung für die Performance. InferenceSession kann in der Regel über Threads sicher geteilt werden, aber die Leistung hängt von der Sitzungskonfiguration ab.

public async Task<float[][]> EmbedBatchAsync(IEnumerable<string> texts, CancellationToken ct)
{
    var textList = texts.ToList();
    var results = new float[textList.Count][];
    
    // InferenceSession is safe to share for inference in most cases
    // Tune SessionOptions.IntraOpNumThreads and InterOpNumThreads for your workload
    var maxParallel = Math.Min(Environment.ProcessorCount, 8);
    
    await Parallel.ForEachAsync(
        textList.Select((text, index) => (text, index)),
        new ParallelOptions { MaxDegreeOfParallelism = maxParallel },
        async (item, token) =>
        {
            results[item.index] = await EmbedSingleAsync(item.text, token);
        });
    
    return results;
}

LeistungstippKonfigurieren SessionOptions bei der Erstellung der Sitzung

var sessionOptions = new SessionOptions
{
    IntraOpNumThreads = 4,  // Threads within a single operation
    InterOpNumThreads = 2   // Threads across operations
};
var session = new InferenceSession(modelPath, sessionOptions);

Speicherverwaltung für große Dokumente

Sehr große Dokumente (-Neulinge ,-Rechtsdokumente )-Bestimmungen erfordern eine besondere Handhabung, um zu vermeiden, OO:-Betrachtung

// For documents > MaxSegmentsToEmbed, use hierarchical extraction
if (segments.Count > _config.MaxSegmentsToEmbed)
{
    // Process in batches, keeping only top-K per batch
    // Then re-rank globally
    return await ExtractHierarchicalAsync(segments);
}

Leistungsmerkmale

Reale Leistung auf einer typischen Entwickler-Maschine

Anmerkung zu diesem Abschnitt: |-----------|-----------|-------| | Einbetten 150, Segmente /, sek. |, Batchgröße 64,, alle -, MiniLM, -, L, 6-, quantisiert | Dichte Retrieval Cosine-Ähnlichkeit gegenüber Segmenten von 500 | Bewertung des BM-25 ,| , , <5 , | , In ,-, memory inverted Index , | , | RRF Fusion ,| , , <2 , | , kombinieren , 3 , Rankings , -| | Ende der MSK-Seite |---15-20--|-- Einschließlich Chunking-,-Embedding-MSC4-Retrieval-,--LLM-Synthese

Prüfumgebung: Ryzen 5600X (6-Core-),-M32-GB RAM-MSC5-kein GPU-.-Embedding verwendet alle --MiniLM-MCSK8-MKSK9-v(-quantisierte ,-MSC13-Token max.),-8--thread paralleles Batching.-Retrieval-Corpus:-MSSK18-Segmente. Ihre Kilometerzahl variiert mit verschiedenen Modellen , ,-Hardware , ,- und Dokumentenkomplexität ,.-

Haupttreiber ist die Einbettung des Durchsatzes ( model choice + marked length MS K2 charge size ). wiederherstellen und Fusion sind im Grunde frei .- , sie nehmen Millisekunden .. , Dies verstärkt das . " , LLM last ?" , Prinzip : tun billige CPU-Arbeiten . , , Retrieval MSC11 , zuerst .SK12 , teure LLM Arbeit nur auf gefilterten Inhalt .

SkalierungDie hierarchischen Extraktionsgriffe der Dokumente der Seite 500+.(.novels,.). durch Verarbeitung in Chargen und nur top--.K pro Charge im Speicher..

Zusammenfassung

DocSummarizer zeigt, dass ausgeklügelte NLP-Fähigkeiten don-'-t Cloud-APIs oder Python-Abhängigkeiten erfordern..-t Mit ONNX Runtime for embedddings und Ollama for generation?,-t können Sie eine komplette RAG-Pipeline bauen, die -: -

  • Läuft ganz lokal
  • Produziert rückverfolgbare Zusammenfassungen
  • Handhabt Dokumente jeder Größe
  • Funktioniert offline

Die wichtigsten Erkenntnisse aus dem Aufbau dieses Tools

  1. Einbettungen sind die Grundlage Guter Retrieval hängt von guten Einbettungen ab
  2. Hybride Suche schlägt entweder allein Kombination semantisch und lexikalisch für Robustheit
  3. MMR verhindert Wiederholung Diversität ist ebenso wichtig wie Relevanz
  4. Strukturfragen Beachtet die Dokumentenstruktur, verbessert die Ergebnisse
  5. LLMs sollten zuletzt kommen Kostengünstige CPU-Arbeit zuerst – teure LLM-Arbeit nur auf gefilterten Inhalt

Literaturhinweise

Papiere und technische Referenzen

Verwandte tiefe Tauchgänge

Verpacken der Serie

Damit endet die DocSummarizer-Serie... Hier ist es so, wie die drei Teile zusammenpassen.

Teil erklärt warum Der Pipeline-Ansatz schlägt naive LLM-Aufrufe...Es deckt die Architekturmuster ab. (.chunking.MS K2. Hierarchische Reduktion.,. citation validation.MSC4., die jeden Dokumentzusammenfassung arbeiten gut machen. .. Das Werkzeug, das seit Teil 1. entwickelt wurde, wurde geschrieben, aber die Prinzipien bleiben gültig.

Teil ist dein schnelles --Starthandbuch ,. , Installation , , , Modi , , , Vorlagen ,, , häufige Anwendungsfälle ,. , Wenn du nur das Tool verwenden möchtest , dass , ' , alles was du brauchst .. ,

Teil Dieser Artikel ist der tiefe Tauchgang für Leute, die verstehen wollen Wie Es funktioniert tatsächlich ,: , BERT vs Satz Transformatoren , , , warum ONNX zählt , , , Tokenization gotchas , , , Hybrid-Suchhandel , und was bricht in der Produktion ,. ,

Wenn Sie Ihre eigene Pipeline bauen , lesen Sie alle drei , . , wenn Sie gerade mit dem Tool ,, , Lesen Sie Teil , 2 , und vielleicht skim Teil .3' Fehler Modi Abschnitt , . ,

Verbunden

logo

© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.