DocSummarizer Teil 3- > Fortgeschrittene Konzepte :- > Die "- > Ich war zu weit entfernt von Deep Dive
Einleitung
Das ist Teil von der DocSummarizer-Serie
- Teil .1: . Aufbau eines Dokument-Zusammenfassung mit RAG Die Architektur und warum der Pipeline-Ansatz naive LLM-Aufrufe schlägt
- Teil mit dem Werkzeug Kurzanleitung für den CLI
- Teil - Fortgeschrittene Konzepte Dieser Artikel ist zu weit gegangen, der technische Tieftauchgang
- 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.
- Installieren Sie Python-Transformatoren
- Modelle manuell herunterladen
- 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
- Null externe Abhängigkeiten Keine Python- oder PyTorch-Treiber
- Auto-Modelle herunterladen Erste Downloads von HuggingFace ausführen
- Reines .-NET Funktioniert überall, wo . NET läuft.( Windows, , Linux, MacOS,, ARM-64)
- 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.
- ZuckenUnterteilen Sie das Dokument in Segmente
- EinbettenSegmente nach Vektoren umrechnen
- WiedereinsetzungSuchen Sie die relevantesten Segmente für die Abfrage
- 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?
- Übersicht über das Einstecken von Daten"Ausblenden von Daten
- Einführung in das Caching", Ähnlichkeit mit (0.94,
- Was ist Caching??"?
- 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
- Benutzer-Login-Flussübersicht" hohe Ähnlichkeit)
- Sicherheits-bewährte Verfahren
- "-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
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.
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.
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.
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 ,. .
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
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
- Einbettungen sind die Grundlage Guter Retrieval hängt von guten Einbettungen ab
- Hybride Suche schlägt entweder allein Kombination semantisch und lexikalisch für Robustheit
- MMR verhindert Wiederholung Diversität ist ebenso wichtig wie Relevanz
- Strukturfragen Beachtet die Dokumentenstruktur, verbessert die Ergebnisse
- LLMs sollten zuletzt kommen Kostengünstige CPU-Arbeit zuerst – teure LLM-Arbeit nur auf gefilterten Inhalt
Literaturhinweise
Papiere und technische Referenzen
- BERT Papier Der originale Transformator-Encoder
- Satz: --BERT BERT für Satzeinbettungen
- Erklärt Der klassische Retrieval-Algorithmus
- RRF Papier Zusammenwachsender Rang Fusion
- ONNX Laufzeit --Kreuzung--Plattform-ML-Inferenz
Verwandte tiefe Tauchgänge
- Wie neurale maschinelle Übersetzung funktioniert Überdeckt die Transformatorenarchitektur,. Aufmerksamkeitsmechanismen,. und Einbettungen aus einer Übersetzungsperspektive.Viele der gleichen Konzepte gelten für Dokumentenverständnis.).
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
- Teil 5------DoomSummarizer--:-Tiefforschung Diese Konzepte werden weitergeführt::, Signal-Adaptive RRF-,, Entitätsprofilvektoren mit HNSW Entdeckung,, TextRank Komprimierung, und eingeschränkte parallele lange Generation-
- CSV-Analyse mit lokalen LLMs
- Abrufen und Analysieren von Webinhalten mit LLMs