Back to "DocSummarizer Part 3 - Kehitykselliset käsitteetM SK2 "Jäysin liian pitkälle |🤦" syvänpyynti"

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 Part 3 - Kehitykselliset käsitteetM SK2 "Jäysin liian pitkälle |🤦" syvänpyynti

Sunday, 21 December 2025

Esitys

Tämä on Osa 3 DocSummarizer -sarjasta:

  1. Osa 1: Laatiminen asiakirjan yhteenvetovälineeksi RAG:in avulla - Architektura ja se, miksi putkilähestymistapa voittaa naiivia LLM-puheluja
  2. Osa 2: Ohjelmien käyttö -QuickM SK1CLI:n aloitusohje
  3. Osa 3: Kehityskäsitykset (artikkeliM SK1 - Tekninen syvänpyynti
  4. Osa 4: Rakenne RAG-putket - NuGet-kirjaston avulla rakennetaan omia RAG- sovelluksia

Tämä on osa omaa lähestymistapaani.

DocSummarizer aloitti osoituksena siitä, miten olisi Build document summarizers with LLMs - osaan esittämäni pipeline-lähestymistapa | Most tutorials show you how to shove text into an LLM and hope for the best | . | Halusin osoittaa asianmukaista rakennetta |

Mutta kuten aina, olen kiinnostunut ongelmatilanteesta. Neljä päivää myöhemmin olen tutkinut tutkimusta. Miten tuotanto ja luokitusjärjestelmät todella käsittelevät yhteenvetoa? ? What makes retrieval work well?

Panin täytäntöön näihin lähestymistapaan liittyviä versioita. Se, mikä alkoi "joka on ' oikea malliM SK3, muuttui paikallisesti toimiviksi ONNX-embeddingiksiMSC4 hybridinen haku, joka yhdistää BMMST5 tiheään hakuunMSL6 monimuotoisuuden enimmäismarginaalien merkityksenMSV7 ja signaalien yhdistämiseen sovellettavan vastavuoroisen rangaistusfuusionMSP8

Oikeusvaroitus: Tämä on " menin liian pitkälle" syvänpyyntiM SK3 Jos haluatte vain käyttää välinettäMSC4 lukea osan 2. jos haluatte ymmärtää miksi se toimii ja miten osat sopivat yhteen, lukee edelleenM SK1

Tämä artikla kattaa:

  • Sentenssien sisällyttäminen: Miten transformatorimallit (MiniLM/BGEM SK3GTEMSC4 muuttavat tekstin vektoriksi
  • ONNX:n käyttöaika: ML-mallien käyttäminen paikallisesti ilman Pythonia tai pilvipalveluja
  • RAG (Retrieval-Augmented GenerationM SK2: Grounding LLM-tulos lähteaineessa
  • Hybridinen haku: Semanttinen ja lexikalinen haku yhteensovittaminen RRF:n kanssa

Architecture at a Glance -katsaus

Ennen yksityiskohtien tarkastelua, täällä 'kuten osat sopivat yhteenM SK2

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

Ymmärrys sisällytyksistä

Ongelma: Miten löydetään asiaankuuluva sisältö ilman avainsanoja?

500-sivukirjan yhteenvedon tekemisessä, on löydettävä asiaankuuluvat osatM SK2 Perinteinen avainsanojen haku epäonnistuuMSC3

  • käyttäjä kysyy: " Miten voin palauttaa laitteet?
  • Käsikirjassa sanotaan "Toistaa tehtaiden järjestelytM SK1
  • Tärkeimmät sanat jäävät huomaamatta (ei yhteisiä sanojaM SK1

Tarvitaan semanttinen haku - merkityksen mukaan vastaaminen

Mitä liitännäisaineet ovat?

Siirrot ratkaisevat tämän muuttamalla tekstin tiheään vektoriin. (lukujen järjestelmät ), jotka sisältävät semanttiset merkityksetM SK2 Samankaltaisia merkityksiä.

Tässä on ”'” -intuitio.“:” kuvitelkaa 384-” -ulottuvuusaluetta, jossa jokaisella tekstillä on paikkansa.

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

Miks Sentence Transformers (Not Raw BERTM SK1

Ongelma: Tarvitsinkin semanttiseen samankaltaisuuteen soveltuvia sisällytyksiä . Raaka BERT on suunniteltu luokittelutehtäviin

Ratkaisu: käyttö sentence transformerit ”-” -mallit on koulutettu erityisesti vastaavuustehtäviin, joissa käytetään ristiriitaista oppimista. BERT-arkkitehtuuri mutta hienoa-muunneltu eri tavallaM SK1

Muodot kuten all-MiniLM-L6-v2 ja bge-small-en-v1.5 oli koulutettu miljooniin tekstipareihin, kuten ”:”

  • "Laitteen uudelleensijoittaminenM SK1 ↔ | "Tehtaiden ohjelmien palauttaminen" (samaa tapaaMSC6
  • "Laitteen uudelleensijoittaminenM SK1 ↔ "Product specifications" |(dissimilar | )

Koulutus opettaa heille: samankaltaisia merkityksiä M SK1 läheiset vektorit (yleinen kosineeritys

Yhtenevä: Jos haluatte ymmärtää, miten transformaattoreiden mallit toimivat syvällisemmällä tasolla |- mukaan lukien huomiomekanismit | , | Enkoder | | 3 | Decoder-arkkitehtuuri | 4 | ja miksi sisällytykset toimivat | Miten neurokoneen käännöstoiminta toimii. Se kattaa samat transformaattoreiden käsitteet käännösnäkymissä.

täytäntöönpano: Otamme mallin ' tuotantolaitteen ja soveltamme sitä keskimääräinen poolointi - keskitetään kaikkien tokenien sisällytykset saadakseen yhden vektorin koko tekstille

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: Running ML Models Locally

Ongelma: Pythonin riippuvuus helvetti

Halusin embeddings to "just work", kun joku käyttää välinettä

  1. asentaa Pythonin + PyTorchin + transformaatiot
  2. Laaditaan mallit käsin
  3. Toivon, että versioon liittyvät ristiriidat eivät häiritse kaikkea

Tämä on naurettavaa. käyttäjät haluavat docsummarizer -f doc.pdf, ei ole 30-vaiheen käyttöönottoohje

Miksi ONNX?

ONNX (Open Neural Network Exchange runtime-johdanto ilman Pythonia.

Mitä saan ONNX Runtimesta:

  1. Nolla ulkoiset riippuvuussuhteet - Ei Pythonia
  2. Auto-download models - Ensin HuggingFace-ohjelmasta peräisin olevia laadintoja ~23-34MBM SK2 ja sen jälkeen tallennetut
  3. Puhdas .NET - Soveltuu kaikkialla .NET toimii Windows, LinuxM SK4 macOSMST5 ARMMSC6
  4. CPU:n johtopäätös - Ei tarvita GPU:tä

Kauppa-off: Lyhyesti hitaampaa kuin GPU PyTorch, mutta paljon nopeammin kuin pyydetään käyttäjiä ottamaan käyttöön Python

mallirekisteri

DocSummarizer sisältää useita sisällyttämistä koskevia malleja, kukin eri kaupan kanssaM SK1offs:

malli Mitot Max-tokenit Suuruus Quantized miSK5 MiSK6 käyttötarvikkeita MISK7 vaaditaan ohjeita
AllMiniLmL6V2 384
BgeSmallEnV15 384
GteSmall 384
MultiQaMiniLm 384

Huomio: Kaikki rekisteritulokset viittaavat WordPiece-järjestelmään -onniskelpoisiin ONNXin vienteihin vocab.txt). BPE

BGE-ohjeet: Joissakin muodoissa, kuten BGE:ssä, on edellytettävä optimaalista suorituskykyä.

// 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);

Rekisteri seuraa, mitkä mallit tarvitsevat ohjeita RequiresInstruction ja QueryInstruction kentät. Aina vertailukelpoinen saatavuuden laatu, kun työskennellään ohjeiden kanssa

Tässä on mallirekisterin käyttötapa'

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
        };
    }
}

Tokenointi: WordPiece vs BPE

Erilaiset mallit käyttävät erilaisia tokenizereja. all-MiniLM-L6-v2 mallissa käytetään WordPiece-tokenointia (kuten BERT),, joka jakaa tuntemattomat sanat alasanatokeneihinM SK2 Muissa muissa malleissa voidaan käyttää BPE-tokenseja (ByteMSC4Pair EncodingMST5 tai Unigram tokenizersMSV6

Merkittävä: Mallin tokenisaattorit on sovitettava koulutustokenizeriinM SK1 Rekisterimme seuraa, minkälainen tokenizer kutakin mallia varten tarvitaan Tällä hetkellä toteutettu: WordPiece (via vocab.txt). BPE tokenizer.json on suunniteltu, mutta ei vielä pantu täytäntöön - pysy WordPiece-mallien kanssa rekisterissä toistaiseksi

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;
        }
    }
}

Esimerkki tokenointi:

Tulku Tokenit
"embedding" ["em", "##bed", "##ding"]
"DocSummarizer" ["doc", "##su", "##mm", "##ari", "##zer"]
"the quick brown" ["the", "quick", "brown"]

Keskimääräinen keskittäminen huomio Maskin avulla

Sen jälkeen, kun BERT käsittelee tokkeita, saamme kullekin tokenille peitetyn tilanteen . Keskimääräinen poolointi keskittää nämäM SK2 mutta vain reaalitokkiin (ei paddingMSC4

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;
}

Täysin sisällytetty putki

Tässä' on täydellinen virta tekstistä sisällytykseen :

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);
    }
}

RAG:Retrieval-Augmented Generation

Ongelma: LLM:t eivät voi't lukea M SK2Page-asiakirjoja

Naiivi lähestymistapa epäonnistuu:

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

Jopa 128K konteksti-ohjelmien kanssa, ei voida vain siirtää valtavat asiakirjat :\

  • Poikkeus: Ainoastaan ensimmäiset 100 sivut sopivat
  • Hallucinaatio: LLM keksii "todisteetM SK2 puutteiden täyttämiseksi
  • Kustannus: Tietojenkäsittely 2MB tekstikustannuksista $$$ kysymyksestä kohti
  • Laatu: LLM:t sekoittuvat massiiviseen kontekstiin.

Ratkaisu:RAG M SK1Retrieval-Augmented GenerationMSC3

Sen sijaan, että lähettäisimme kaiken, lähettäisimme vain sen, mikä on asianmukaista.

  1. Englanninkielinen kieli: Siirretään asiakirja osiksi
  2. Sisällyttäminen: Siirtää segmentit vektoreihin (semanttinen esittely
  3. Takaaminen: Ottakaa kysymykseen tarkoituksenmukaisimmat segmentit
  4. Synteesi: LLM tiivistää vain ne segmentit

Miksi tämä toimii: LLM katsoo, että 10KB on erittäin merkityksellinen sisältö sen sijaan, että

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

Dokumenttistrategiat

DocSummarizer tukee useita chunkkistrategioita, jotka perustuvat asiakirjarakenteeseen:

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;
    }
}

Fine-Grained -jäljittämiseen tarkoitetun osa-alueen ekstrakointi

pitempien asiakirjojen osalta

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
        };
    }
}

Ongelma: Semanttinen haku palauttaa päällekkäisyyksiä

Ilman MMR:tä, hakeminen "Kaikkien tallennusten käsittelyä koskevat kysymykset

  1. "Katsauksen yleiskatsausM SK1 (0.95 vastaavuus)
  2. "Introduction Caching-järjestelmään
  3. "Mitkä ovat tallennetukset?
  4. "Cache-järjestelmän täytäntöönpanon yksityiskohdat

Ylimmäistulokset 3 sanovat kaikki samaa:

Ratkaisu: Maksimaali rajallinen merkitys M SK1MMR)

MMR:n tasapaino asianmukaisuus (kysymyksen vastaavuus monimuotoisuus (ylivoimaisuus jo olemassa oleviin toimenpiteisiin

Formula: $$MMR = SSK2lambda S\cdot \textM SK5sim}(sMSC7kysymys_{sM SK1 \valitussa} ,\teksti(s, s

Mitä se tekee: Rangaistetaan ehdokkaita, jotka ovat samankaltaisia jo olemassa oleville segmenteille.

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

Lauseke:

$$MMR = \lambda \cdot sim(s, centroid)-(1-\Lambda)\cdot_{s

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;
}

Hybridinen haku RRF:n avulla

Ongelma: Semanttinen haku ei vastaa täsmällisesti toisiaan

törmäsin tähän testattaessani:

Kysymys: "', mitkä ovat API:n loppupisteet todentamiseksi

Semanttinen haku palasi:

  1. "User login flow overview
  2. " Turvallisuutta koskevat parhaat käytännöt
  3. "

Se, mitä se jäi jäljelle: Todelliset API-yhteyksien loppupisteet kirjatut koodiesimerkeissä: POST /api/v1/auth/login

Miksi?: Embedding-mallit on koulutettu luonnollisella kielellä POST /api/v1/auth/login ' ei vastaa semanttisesti "todistuksen loppukohtaaM SK2 - se' on kirjallinen tekninen viite

Ratkaisu:Hybridinen haku M SK1Semantiikka + Lexikaali

Yhdistetään kaksi jäljittämismenetelmää täydentäviin vahvuuksiin:

hakutyyppi vahvuudet SSK2 heikkoudet
Tiheys (EmbeddingM SK1 Semanttinen ymmärrysM SK1 Synonymit Voi olla virheenmukaisia täsmällisiä vastauksia
Säästö (BMM SK1 Täsmällinen avainsanojen yhteensopivuusM SK1 harvinaisia termejä Semanttista ymmärrystä ei ole

Hybridinen haku yhdistää molemmat vastavuoroisen luokan fuusiota käyttäen (RRFM SK1

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

Huomio: RRF-tulokset ovat ilmentyviä . pysyvä kM SK2 on standardi; todellinen luokitus riippuu täydestä ehdokaskokonaisuudesta

RRF:n täytäntöönpano

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();
    }
}

BM25: Puolustustyövoima

BM25 M SK1Best Matching 25) on klassinen tietopyynnön algorytmi.

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 sisällön keskittämiseksi

Ongelma: Miten erotetaan perussisältöä Triviasta?

Kun esitän yhteenvedon romaanista, sain sellaisia tuloksia kuin:

Watson totesi, että sää oli maltillinen.

Nämä ovat täsmällisiä ekstrahteja, mutta ne väri ( keskeiset plot-kohdat.

Haasteena: Miten sanotte eroa

  • Perussisältö: Ilmenee koko asiakirjan läpi (nimitykset, , pääaiheet,, keskeiset tapahtumat
  • Tukevat yksityiskohdat: Vaikuttaa eräissä kohdissa (subplotsM SK2selvitykset
  • Värvi: HarvinainenM SK1 yksityiskohtaiset tiedot (kuka kenenkään käyttämä tekstiili oli

Keskeisyyden luokitteluun sovellettava ratkaisu

TF-IDF miten keskeinen käsite asiakirjassa on, ei sen todellista arvoa

Logic:

  • Korkeat DF:t (>50% chunkistaM SK1Ydinsisältö
  • Keskikokoinen DF (20-50%):
  • Alhainen DF (<20%):

Tässä ei ole kyse todellisuudesta. Toistuvat väitteet voivat olla virheellisiä, harvinaiset tosiasiat voivat olla totta asiakirjan keskittyminen.

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;
    }
}

BertRag-kaasuputki

DocSummarizerin tuotantoputki 'BertRagSummarizer) yhdistää kaikki nämä käsitteet

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;
    }
}

Yleiset epäonnistumismenettelyt

Kun rakennatte ja hyödynnätte DocSummarizeriä, IM SK1on törmännyt näihin ongelmiin (ja te olette törmänneet niihin myös):

  1. Tokenizerin epäjohdonmukaisuus → järjettömiä sisällytyksiä: Laaditaan WordPiece vocab BPE:n mallille-koulutettu malli tuottaa päteviä -näkökkäitä mutta semantisesti merkityksettömiä vektoreitaM SK3 Tarkistakaa aina, että tokenizer vastaa mallia

  2. Dominantinen-topicinen ennakkoluulot yksittäisessäM SK1centroidien tulosten osalta: Yhden asiakirjan keskittäminen järjestelmällisesti alaspäin, - vähemmistöä koskevien aiheiden tärkeysasteen laskeminen,

  3. BM25 voittaa tiheän etsinnän harvinaisissa termeissä: Jos kysymyksessänne on puutteellisia teknisiä käsitteitä tai asianmukaisia nimikkeitä, embedding-mallissa esitetty - ' koulutustiedot, , lexical matching (BM

  4. OCR-jätte skannattujen PDF:ien muodossa: tiivistelmä on hyvä , mutta OCR-virheet moninkertaistuvatM SK2 Jos näette tiivistetyissä sanoissa hölynpölyä, tarkistakaa ensin tiivistelemästä peräisin olevan merkitsemistuloksen.

  5. Alhainen -coverage-summary on suojattava kielellä: Jos olette nähneet vain 3% asiakirjasta, , lauseet kuten ", viime kädessä " tai " päätelmissä " ovat epärehellisiä . Järjestelmän on sanottava " näytteillä otetuissa kohdissa " ja vältettävä lopullisia päätteitä

  6. Viittaushallucinaatio: Pienet LLM:t (1.5B-3B-paramitM SK3 joskus keksitään todennäköisiä [chunk-N], varmistetaan, että N on olemassa alkuperäisissä chunkeissa, ja ilmoitetaan tai korjataan väitteitä, jotka viittaavat puuttuneisiin chunkkeihin [chunk-999] 10-chunk-asiakirjasta, LLM:ssänne on vaikeuksia tehtävän kanssa

Nämä eivät ole ”'” -virheitä -“ ne” –'“ ovat luonnollisia jännitteitä suunnittelun alueella”–.” Hyvät tuotantojärjestelmät tunnustavat ja lieventävät niitä“.”

Käytännön näkökohdat

Puite- ja näytteenotto rehellisyyttä

Kun hallinnoidaan hyvin suuria asiakirjoja, DocSummarizer ei yritä sisällyttää kaikkea. Tämä tarkoittaa, että yhteenveto perustuu esikuvaan, eikä koko asiakirjaan .

Järjestelmä käsittelee tätä avoimesti:

// 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}";

Merkittävä: Tämä on kerättyjen todisteiden yhteenveto, ei taata, että asiakirja on kattava kokonaisuudessaan -. Kun sanomme, että "\ampled \ 3%",, että '\ on juuri se, mitä tapahtui (-), järjestelmä näki [3%] asiakirjan ja tiivisti sen

Sampling ei ole random - it semantiikka. Me käytämme monimuotoistaM SK1kanker klusterointia varmistaaksemme, että vähemmistökysymykset eivät jää ulkopuolelle 't excluded. Lukuisat ‐3% saattavat jättää huomiotta kaikki rajoitukset ja rajalliset tapauksetMSC5 Semanttinen ‐ 3% yrittää ottaa yhden edustavan osan kunkin tärkeän aiheen sisällöstä.

Adaptiivinen näytteenotto useilla aihekohtaisilla ankareilla: Ennen -filteriä käytetään monenlaisia ankaria |( |k | - | tarkoittaa - ‐tyyppistä ryhmittymää stratifioidussa näytteessä |) | varmistamaan, että vähemmistön aiheet eivät ole järjestelmällisesti suljettu pois ‐' | Tämä estää ‐ " ‐dominanteen aiheellisen ennakkoluulonnon ‐

Siihen 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));

Tämä on tutkimusta-tiedonmukaista (avoittavat yhden ainoan-kysymyksen palauttamisen romahtamistaM SK3 mutta käytännönläheistä MSC4 se toimii sekunnissa CPU:ssäMST5

Miksi ei vain sisällytä kaikkea?

500-sivuasiakirjan (2,000+segmenttien), sisällyttäminen kaikkiin toimisi, mutta ei oleM SK3 optimaalistaMSC4

  • Kustannus:, O, (, N, M SK2, sisällytykset hallitsevat runtime-aikaa
  • Laatu: Kaikkien sisällyttäminen lisää kuormia hakukeskuksessaM SK1 Te tarvitsette edelleen luokitusta, joten miksi sisällytetään segmentit, jotka eivät koskaan ole korkeita?
  • Käytännönmukaisuus: Muistia ja latentiarajoituksia koskevat rajoitukset ovat tärkeitäM SK1 \2,000 \ 384- \dim-vektoreiden säilyttäminen muistissa ja laskemisessa on turhaa.

Monitasoinen-johtomuunnos antaa parhaan mahdollisen laajan aihekokonaisuuden molemmista näkökohdista ja helppotajuisen tietojenkäsittelyn avulla.

Kuten edellä kuvasin, tämä ei ole vain "jäljitettävyys, vaan myös ", -, se on erityinen malli, jota kutsun Rajoitettu hämärän taustan vetäminen (CFCD). Näkemys

Useimmat yhteenvetoasiat lisäävät jatkuvasti asiasisältöä. DocSummarizer etenee vain se, mikä selviytyy deterministisesta valiotuksesta,, sallii sen, että malli kirjoittaa sujuvasti niiden rajojen sisälläM SK1

Tässä on esimerkki siitä, miten DocSummarizerin putkilinja kartoittaa CFCD:tä.

CFCD-käsite DocSummarizerin täytäntöönpano
Salienssin havaitseminen (
Deterministinen edistäminen MMR
Johtokirja Saavutettu segmentti, joka on sidottu lainausnimityksiin.
Rajoitettu sukupolvi Päätöslauselmaesitys rajoittuu kerättyihin todisteisiin

**Miksi tämä on tärkeää?**Tämä on syy siihen, että pienet paikalliset mallit toimivat.

Käytännössä "anchor ledger" näyttää tällaiselta.

{
  "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"
  }
}

Sen jälkeen synteesissä prompt:

  • "Kaikissa vaatimuksissa on mainittava sisällytetty chunk ID
  • "Jos kattavuus on
  • " Käyttäkää näitä termejä johdonmukaisesti

Siksi:

  • Pitkämmät konteksti ikkunat ovat punainen hering Ongelma ei ole se, etteikö teksti olisi sopivampi, vaan se, mikä ansaitsisi selviytyä
  • Rekursiivinen yhteenveto on epäonnistunut - se kohtelee välitulosta tekstinä
  • LLM voi't "forgetM SK2 edistää rajoituksia ”-, ne, ', rakenteelliset rakenteet ja , eivät ole prose, sillä ne voivat vetäytyä

CFCD on sama filosofinen jako kuin Rajoitettu epämääräisyys, Rajoitettu hämärä MoM, ja Kuvan yhteenveto - todennäköisyys ehdottaa

Kvantointi

ONNX-mallit voidaan mitata (vähennetty täsmällisyys ) pienemmät mittasuhteet ja nopeampi johtopäätös

malli täydellinen täsmällisyys määritelty S laatuerot M
, kaikki, -,MiniLM,-,L,6-,v,M SK4, , \90,MB, , 23, MB, ¬ ja
bge -small-enM SK3vMSC4

Määrärahat ja kilpailu

Suurten asiakirjojen osalta InferenceSession voidaan jakaa yleisesti threadeissä turvallisesti, mutta suorituskyky riippuu istunnon järjestelystä

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;
}

suorituskykyhuippu: Ohjelmointi SessionOptions kokouksen luomisen yhteydessä:

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

Suurten asiakirjojen muistin hallinta

Erittäin suuret asiakirjat (novels, oikeudelliset asiakirjanmuodotM SK2 edellyttävät erityistä käsittelyä, jotta vältettäisiin

// 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);
}

suorituskyvyn erityispiirteet

Todellinen-maailman suorituskyky tyypillisellä kehittäjäkoneella M SK1Ryzen 5600X, 32GB RAMMSC5 GPU:ta ei ole

Operaatio Lähtöputki
Sisällyttäminen
Tiukka haku
BM25 -tulokset
RRF:n fuusio
Päätös Page PDF

Testiympäristö: Ryzen 5600X SSK2core), 32GB RAMM SK5 ei GPUMSC6 Integroinnissa käytetään kaikkiaMSSK7MiniLMMST8LMTSK9vMS2 MTSK11quantisoituMSR12 \MSR13\tokenin enimmäismahdollisuus\MST14\ \SST15\tahden rinnakkaista batsointia.\ jäljittämiskokonaisuus\MSSK17\ |MST18\ segmentit\M SSK19\ Mileage vaihtelee eri malleihin nähden,\ Hardware\MTSKS21\ ja asiakirjan monimutkaisuus\ MSSK22\

Pääjohtaja sisällyttää läpikulun (mallin valinta +tokenen pituus | +kuormituksen suuruus \ ). Poistaminen ja fuusio ovat pohjimmiltaan vapaita - ne vievät miljoonia sekuntia \

Laajennus: Hierarkkisen ekstraktion avulla käsitellään SSK1 sivuasiakirjoja (kertomuksia, ,käsitteitä, SSK4 jaloittain ja ainoastaan yläpuolella.

Lyhyesti sanottuna

DocSummarizer osoittaa, että monimutkaiset NLP-valmiudet eivät tarvitse pilvi API:ita tai Pythonin riippuvuuksia. OnNXin runtimen avulla integroinnissa ja generationissa Ollamassa, voidaan rakentaa täydellinen RAG-putken, joka

  • Käytetään täysin paikallisesti
  • Tuotetaan jäljitettävissä olevat, mainitut yhteenvedot
  • Käsittää kaikenlaisista asiakirjoista
  • Toimia offline-tilassa

Keskeiset näkemykset tämän välineen rakentamisesta:

  1. Sisällytykset ovat perusta - Hyvä haku riippuu hyvistä sisällytyksistä
  2. Hybridinen haku voittaa joko yksin - Semanttinen ja lexiikka yhdistetään luovuuteen
  3. MMR estää toistumisen - Monimuotoisuus on yhtä tärkeää kuin merkitys
  4. Rakennekysymykset - Asiakirjojen rakenteen noudattaminen
  5. LLM:n pitäisi tulla viimeiseksi - Tehkää ensin halpa CPU-työ, kallis LLM-työ vain filtroituun sisältöön

Lisä lukeminen

Asiakirjat ja tekniset viittaukset

Vastaavia syvänmeren uima-alueita

  • Miten neurokoneen käännöstoiminta toimii - kattaa muuntajaarkkitehtuurin , huomiomekanismit M SK2 ja sisällytykset käännösnäkymien näkökulmasta | monet samat käsitteet pätevät asiakirjan ymmärtämiseen

Serien laatiminen

Tämä päättää DocSummarizer-sarjasta.

Osa 1 selittää miksi pipeline-lähestymistapa voittaa naiivia LLM-puheluja. Se kattaa rakenteelliset mallit (chunkingM SK2 hierarkiallinen vähentäminen , viittausvaliottaminen ), jotka tekevät jokaisesta asiakirjan yhteenvetoasiakkaasta toimivan hyvin

Osa 2 on nopeaa-käynnistysohjetta. asentaminen , muodotMST3 mallitMTSK4 yleiset käyttökäytännöt MTSK5 Jos haluatte vain käyttää välinettä, seMSSK7 on kaikki, mitä tarvitsette

Osa 3 (this articleM SK1 on syvänmeren uima, jota ihmiset haluavat ymmärtää miten se todellakin toimii: BERT vs sentence transformersM SK1 miksi ONNX on tärkeä, tokenointi gotchasMSC3 hybridi hakukauppaMST4offsMSV5 ja mikä murtaa tuotantoaMSM6

Jos olette rakentamassa omaa putkea, lukekaa kaikki kolme osaa.

Yhtenevä

logo

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