Om du är helt ny på RAG, börja med RAG förklaras och RAG arkitektur. Denna artikel är till för punkten där du ' har byggt en RAG-kanal som mest fungerar… och nu är duM SK1 som betalar för det i kostnaden, sprödlighet , och | " varför svarade det på det?
Vad detta täcker: Architektoniska mönster bakom produktionen RAG. För händerna - för realisationen M SK2 se Att bygga en dokumentuppfattare med RAG.
Var det kommer ifrån: Jag byggde DocSummarizer (Document RAG-motor DataSummarizer (Data RAG-motor ImageSummarizer (Image RAG-motor AudioSummarizer (Audio RAG-motor lucidRAG (multi
NOTA: Du har kanske med rätt märkt att den semantiska sökningen på den här sidan är bruten ... och ja, det ' är en konfigurationsproblem jag inte har M SK3 har inte haft tid att fixa än MSC4 Inte dålig teori MST5
| Begrenspunkt | Vad det betyder | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| RAG | Att få fram data - Förstärkt skapande ♫ | ♫ Ge ett LLM till ditt företag innan du svarar ♫ | |||||||||||
| Folketing | Splittring av dokument i mindre bitar | Breckning av en PDF i paragrafer | |||||||||||
| Top-k | Ta sökresultatet från en sökning. | ||||||||||||
| Vektorsökning | Att hitta liknande text med hjälp av inbäddar | ||||||||||||
| BM25 | Keyword search | МSK2 | Hitta dokument som innehåller | ' | timeout | ' | och | ' | databasen | ||||
| Kontextfenster | Hur mycket text kan du få plats i ett prompt | Fint och dyrt | |||||||||||
| Signaler | Faktum extraherat utan AI | " | Utformade | 3 | 4 | 5 | Prioriterad | 6 | Hög | 7 | 8 |
Retrieval-Augmented Generation (RAG) har blivit en av de fraser som betyder allt och ingenting.
För många lag är det nu RAG , ” och ":
Det fungerar. Tills den inte gör det
Det är svårt att resonera med det, det är dyrt och det ger modellen tyst ansvar, det analyserar strukturen, det tvingar in filterna, det bestämmer vad som är viktigt, det förbereder motsägelser, det hindrar och det är självsäkrat.
När folk säger “, RAG hallucinerar, ” eller “, ARG filtrerar inte bra ’, ”,, de anklagar ofta fel komponenten
Problemet är’t RAG. Problemet är lat RAG.
Denna artikel beskriver en annan standard Reduzerad RAG - använda LLMs mindre, inte mer , genom att extrahera deterministiska signaler framifrån och behandla modeller som syntetiska motorer, inte databutiker.
Ett kontextfenster är:
Det är inte en databank.
När du “ bara kliver mer i prompten ”, så frågar du den modellen till
Det är därför RAG-demos ser bra ut och produktions RAG -system ruttnar tyst.
Reduzerad RAG vänder den standardinställningen.
I stället för:
Ta upp texten och låta modellen bestämma vad som är viktigt.
Du gör det
Bestäm vad som är viktigt en gång.
I praktiken betyder det deterministisk ingestion , billiga spårning, begränsad generation.
Om det låter välbekant, så är det samma systemform som Begränsad otydighet: låter sannolikhetskomponenter föreslå; låter deterministiska system bestämma.
Först ska vi se vad de flesta lag gör, och varför det är dyrt.
flowchart LR
subgraph Traditional["❌ Traditional RAG: Everything Through the LLM"]
T1[Documents] --> T2[Chunk Everything]
T2 --> T3["Embed All Chunks<br/>(once)"]
T3 --> T4[Vector Search]
T4 --> T5["Paste Top-K<br/>(per query)"]
T5 --> T6["LLM Decides<br/>(per query)"]
T6 --> T7[Answer]
end
style Traditional stroke:#ef4444,stroke-width:3px
style T6 stroke:#ef4444,stroke-width:3px
style T5 stroke:#ef4444,stroke-width:2px
Problemet:
Här är "'", den Reduced RAG-metoden.
flowchart TB
subgraph Ingestion["✅ Ingestion (Once - Pay Upfront)"]
I1[Source Docs] --> I2[Parse Structure]
I2 --> I3["Extract Signals<br/>(deterministic)"]
I3 --> I4[(Structured Fields)]
I2 --> I5[Semantic Units]
I5 --> I6[(Vector Store)]
I2 --> I7[(Evidence Store)]
end
subgraph Query["Query Time (Cheap Per Query)"]
Q1[User Question] --> Q2{Extract Filters}
Q2 --> Q3["Filter Database<br/>(no LLM)"]
Q2 --> Q4["BM25 Search<br/>(no LLM)"]
Q2 --> Q5["Vector Search<br/>(no LLM)"]
Q3 --> R[Candidate Set]
Q4 --> R
Q5 --> R
R --> S["Small Evidence Pack<br/>(5 sources not 50)"]
end
subgraph Generation["LLM (Bounded Synthesis Per Query)"]
S --> L[Synthesize Answer]
L --> A[Answer + Citations]
end
style Ingestion stroke:#22c55e,stroke-width:3px
style Query stroke:#3b82f6,stroke-width:3px
style Generation stroke:#f59e0b,stroke-width:2px
style I3 stroke:#22c55e,stroke-width:3px
style Q3 stroke:#3b82f6,stroke-width:3px
style L stroke:#f59e0b,stroke-width:3px
Nyckelskillnader:
| Fasen | Traditionell RAG | Reduzerad RAG | ||
|---|---|---|---|---|
| Intag | Bara skräddarskiva och inbädda | Extrahera datum | ||
| Filter | Säg till LLM att filtrera i uppspringen | Databas därklauseln finns | ||
| söka | enbart vektorn | BM25 + vektor M+ Strukturerade filter | ||
| LLM: s roll | analysera, filtera , Och svara | Synthesera bara svaret | ||
| kostnaderna | Varje fråga betalar för hela kontexten | Ingestion en gång |
Vid intagningstid, analysera vad du kan utan en LLM.
exempel: Support Ticket System
Istället för att bara stapla in bilbiljetter i text
Traditional: "Ticket #1234: Customer complained about slow loading..."
→ Embed entire text
→ Hope the LLM figures out it's about performance
Extrahera signaler upp fronten:
// Parse once during ingestion
var ticket = new SupportTicket
{
Id = "1234",
CreatedDate = DateTime.Parse("2025-01-15"),
Category = "Performance", // ← Deterministic field
Product = "WebApp", // ← Filterable
Priority = "High", // ← Sortable
Customer = "Enterprise", // ← Segment filter
SentimentScore = -0.3, // ← Computed once
Tags = ["slow-loading", "timeout"], // ← Searchable
Text = "Customer complained about..." // ← Still keep for RAG
};
Vad du kan extrahera deterministiskt:
| Signaltyp ♫ | ♫ exempel ♫ | ♫ Varför det spelar roll ♫ | |||||||
|---|---|---|---|---|---|---|---|---|---|
| Tydliga | Datum skapat , Datum uppdaterad M SK2 utgångsdatum | ||||||||
| Kategoriserad | Status | ||||||||
| Numeriska | pris , kvantitet | ||||||||
| Identitet | bokförfattare, kundidentifisator | , | SKU | , | beteckningar # | M SK6 | Vill biljetter från Kunden X | ||
| Jakt | OCR-förtroende | ||||||||
| Förekomst | källsystem |
Gör det en gång
Den hårda delen av RAG är: "'", det är inte modellen, det är - det är allt före modellen. För konkreta implementeringar, ,, se Att bygga en dokumentuppfattare med RAG och DocSummarizer: Byggnader RAG Pipelines.
Istället för att behandla """, "" chunks, " "", som enhet av sanning, ",", lagra strukturerade fält, "", , "", signal, M SK4 "", kompakta enheter, , "", inbäddar, MSC6 "", och peka tillbaka till källan.
Texten är fortfarande en del av systemet - men den blir bevis, inte " vad vi än råkade skriva in i prompten
Detta är skillnaden mellan "RAG- Svaret är viber " och " RAG- svaren är inspektbara
Du gör det inte
Det är hela poängen med att lagra råsignaler istället för LLM-bearbetade sammanfattningar.
Traditionella RAG ( dyrt att byta
// ❌ You asked the LLM to "summarize the key points"
var summary = await llm.Summarize(ticket.Text); // Expensive
await db.SaveAsync(summary); // Threw away the original structure
// Later: "Actually, we need sentiment scores too"
// 😱 Have to re-process 10,000 tickets through LLM again!
Reduzerad RAG (billig att ändraM SK1
// ✅ Store raw signals extracted deterministically
var signals = new TicketSignals
{
Text = ticket.Text, // ← Keep original
WordCount = ticket.Text.Split().Length, // ← Cheap to compute
ContainsErrorCode = Regex.IsMatch(ticket.Text, @"ERR-\d+"),
MentionedProducts = ExtractProducts(ticket.Text), // ← Heuristic
SentimentWords = CountSentimentWords(ticket.Text), // ← Word lists
CreatedHour = ticket.Created.Hour // ← Maybe useful later?
};
// Later: "We need to prioritize by sentiment"
// ✅ Just add a computed column - no LLM re-run needed!
await db.ExecuteSqlAsync(@"
ALTER TABLE Tickets ADD COLUMN SentimentScore AS
(SentimentWords->>'positive' - SentimentWords->>'negative')
");
Vad har just hänt?
Detta är samma mönster som ":".
Reglerna: Kom ihåg före LLM. uppdatera din M SK1memory" (avtagningslogikMska4 gratisMske5
Nyckeln till arkitektoniska nytta Eftersom du lagrar deterministiska signaler tillsammans med inbäddar ( inte istället för dem ), varje del av systemet kan förändras oberoende av sig M SK2 byta inbäddade modeller ? bytta tillbaka MSC4 inbädda utan att röra vid signalern Mska5 lägga till ett nytt signal M Ska6 beräkna det från lagrad text utan att göra något om detM Ska7 inbyggda M ska8 Ranga upp tonerna M Sk9 justera signalvikten och scorningslogiken utan att indexera om det igen
Med multi-vektorbutiker ( som Qdrant), kan man till och med lägga till flera inbäddar per dokument. Vill prova ett nytt inbäddat-modell ? Lägg till det tillsammans med det existerandet och förvandla det gradvis M SK2 Testa både i produktionen , jämför kvalitet MSC4 och avfärda det gamla ♫ - utan att indexera eller störa servicen ♫.
Varje komponent kan utvecklas utan att tvinga en hel pipeline att byggas om - och utan att försämra de andra ♫ . ♫
Speichera allt du kan bearbeta billigt och deterministiskt.
viktigt: Signaler är bara korta textsträngar , siffror, och booleans—, inte gigantiska datastrukturer ., du ', sparar M SK3, prestationsnivån, ", | | (8, grejer, ),, inte ", kunden klagade på långsamt laddande tid.
public class DocumentSignals
{
// Always extract (almost free)
public int CharCount { get; set; } // Example: 1247
public int WordCount { get; set; } // Example: 203
public int ParagraphCount { get; set; } // Example: 5
public string[] UniqueWords { get; set; } // Example: ["timeout", "error", "api"]
// Structural (parse once)
public bool HasCodeBlocks { get; set; } // true/false
public bool HasLinks { get; set; } // true/false
public int HeadingCount { get; set; } // Example: 3
// Heuristic (simple patterns)
public string[] MentionedProducts { get; set; } // Example: ["WebApp", "API"]
public string[] ErrorCodes { get; set; } // Example: ["ERR-404", "ERR-500"]
public Dictionary<string, int> SentimentWords { get; set; } // { "positive": 3, "negative": 7 }
// Metadata (already available)
public DateTime Created { get; set; } // Example: 2025-01-15T14:23:00
public string Author { get; set; } // Example: "[email protected]"
public string Category { get; set; } // Example: "Performance" (not essay-length)
// Computed (cheap math)
public double ReadingTimeMinutes { get; set; } // Example: 4.2
public double KeywordDensity { get; set; } // Example: 0.034
}
Storhetskostnadsvergleich:
| Vad du sparar | Storlek per dokument | |||||
|---|---|---|---|---|---|---|
| Hela texten | ~5 Kb | |||||
| Alla dessa signaler | ~500 byter | MB | ||||
| LLM-genererad sammanfattning | ~2 Kb |
Signaler är 10x mindre än text, 4x mindre än LLM sammanfattningar, och oändligt billigare att räkna tillbaka ( eftersom du inte behöver
När du inser att du behöver en annan signal: Bara beräkna det från lagret rådata.
Detta är anledningen till att "+-+Extraktion-"+ är säkert- :+ du betalar en gång i lager-
De flesta "RAG-sökningar" är egentligen bara söksökningar med begränsningar
Traditionella RAG ( dyrt , otillförlitligt M SK2
// ❌ Paste everything into prompt and hope
var chunks = await vectorSearch.SearchAsync(query, k: 50); // 50 chunks!
var prompt = $@"
Given these 50 chunks of text, answer the question but ONLY use
docs from last week and ONLY for UK customers.
Chunks: {string.Join("\n", chunks)}
Question: {userQuestion}
";
var answer = await llm.GenerateAsync(prompt); // Expensive + unreliable
Reduzerad RAG ( billigt , deterministiskt M SK2
// ✅ Filter first, retrieve less, synthesize last
var candidates = await db.Tickets
.Where(t => t.CreatedDate > DateTime.Now.AddDays(-7)) // ← Database does this
.Where(t => t.Region == "UK") // ← Not the LLM!
.ToListAsync();
// Hybrid search on the filtered set
// (In production: push BM25 to database/index, not in-memory LINQ)
var bm25Results = candidates.Where(c => c.Text.Contains(keyword));
var vectorResults = await vectorSearch.SearchAsync(query, k: 5, filter: candidates);
// Small evidence pack
var evidence = RRF.Merge(bm25Results, vectorResults).Take(5);
// LLM only synthesizes
var answer = await llm.GenerateAsync($@"
Synthesize an answer using ONLY these 5 sources:
{FormatEvidence(evidence)}
Question: {userQuestion}
");
Vad har just hänt?
Det är därför hybridsökningar är viktiga i produktionen. Hybridsökning & Auto-Indexering är det mest praktiska exemplaret i hela RAG-serien.
Om en fråga är riktigt stökig, så kan använda en liten modell för att extrahera intens
// Use small model to propose filters (ephemeral - discarded after use)
var intent = await smallModel.ExtractIntent(userQuestion);
// Returns: { intent: "troubleshoot", filters: { priority: "high", product: "api" } }
// Validate the proposal against known fields (deterministic)
var validatedFilters = ValidateAgainstSchema(intent.filters);
// Use validated filters for retrieval
var results = await db.Tickets.Where(validatedFilters).ToListAsync();
Grundprincipen: LLM föreslår
Detta är grunden till Begränsad otydighet mönster.
För att dyka djupare in i efemerala utdragsmönster där du använder LLM tillfälligt utan att upprätthålla deras resultat Ogen och Don't Bort glöm.
Bara efter att ha tagit fram informationen kallar du LLM. Du ger den en liten set av fakta med bevispunkter och tydliga instruktioner för osäkerhet
Modellet ' jobbet: Syntesize , förklara, jämföra. Inte kräva begränsningar , bestämma sanningen, uppfinna struktur.
Om du bryr dig om “LLMs att dra hela kontextfenoret in i svaren, så har du redan sett misslyckande modet. Begränsat Fuzzy Kontexttdragning: det ’ är inte ondskefulla - det\ ’ det är vad du bad den göra
Order-av-skillnadsvergleich för ett typiskt RAG-system
Scenario: 10,000 stödbiljetter
| tillvägagångspunkt | Ingestionskostnader | Per | ||||
|---|---|---|---|---|---|---|
| Traditionella RAG | Embetera 10 k-biljetter**$75/dag** | |||||
| Reduzerad RAG | Embetera + extrahera signaler | 5 bitar ♫ ♫ × ♫ liten kontext ♫$7.50/dag |
Order av magnitude: ~10x kostnadsförlust per dag
Ännu bättre Med bra bevis och deterministisk filtering, behöver du troligen inte ' någon gränsmodell överhuvudtagetM SK2 Ett lokalt Ollama-modell ( friaMSC4 med en liten mängd bevis presterar ofta bättre än GPTMska5 matade mska6 bitar som den måste analysera själv
Plus: reduced debugging time
Traditionella RAG (
// ❌ Prompt says "only UK customers" but model can ignore it
var answer = await llm.Generate(prompt); // No guarantee
Reduzerad RAG (avtryckt filtrering
// ✅ Database physically prevents non-UK results
var results = db.Tickets.Where(t => t.Region == "UK"); // Guaranteed
Varför är det säkrare? Filter tvingas införa innan en generation. Modelen aldrig ägde dem. Modellen kan inte glömma dem, och hallucinationer är begränsade av bevis du kontrollerar.
Traditionell RAG: "Modelet sa detta , men jag är inte säker på varför eller vilken del den kom från
Reduzerad RAG:
// You know exactly why each result matched
var result = new SearchResult
{
Text = "Server timeout error",
MatchedBecause = new[]
{
"Region = UK (database filter)",
"Created in last 7 days (date filter)",
"BM25 score: 4.2 (keyword 'timeout')",
"Vector similarity: 0.89 (semantic match)"
},
SourceChunks = [chunk1, chunk2], // ← Audit trail
ConfidenceScore = 0.89
};
Du kan inspektera varför varje resultat matchas , visa bevis när självförtroendet är lågt, och lösa problem med produktionen genom att undersöka kandidaten som sattes innan LLM-synthesen
Om du redan har ett fungerande RAG-system
Innan:
public class Document
{
public string Id { get; set; }
public string Text { get; set; } // ← Only unstructured text
public float[] Embedding { get; set; }
}
Efter:
public class Document
{
public string Id { get; set; }
public string Text { get; set; } // ← Keep for evidence
public float[] Embedding { get; set; }
// Add deterministic signals (extract once during ingestion)
public DateTime CreatedDate { get; set; } // ← Parse from metadata
public string Category { get; set; } // ← Extract from filename/tags
public string Author { get; set; } // ← From file properties
public string[] Tags { get; set; } // ← Parse from content/metadata
public double QualityScore { get; set; } // ← Compute heuristics
}
Innan:
var prompt = "Only use docs from last month for product 'API'. Query: " + userQuery;
var chunks = await vectorStore.Search(userQuery, k: 50);
var answer = await llm.Generate(prompt + chunks); // ❌ LLM might ignore filters
Efter:
// ✅ Database enforces filters
var candidates = await db.Documents
.Where(d => d.CreatedDate > DateTime.Now.AddMonths(-1))
.Where(d => d.Category == "API")
.ToListAsync();
// Search only the filtered candidates
var results = await vectorStore.Search(userQuery, k: 5, filter: candidates.Select(c => c.Id));
var answer = await llm.Generate(FormatEvidence(results)); // Much smaller context
// Combine keyword and semantic search
var keywordResults = await db.Documents
.Where(d => EF.Functions.ToTsVector("english", d.Text)
.Matches(EF.Functions.ToTsQuery("english", keywords)))
.ToListAsync();
var vectorResults = await vectorStore.Search(userQuery, k: 20);
// Merge using Reciprocal Rank Fusion (RRF)
var merged = RRF.Merge(keywordResults, vectorResults, k: 5);
Se Hybridsökning & Auto-Indexering för en komplett implementation.
spåra dessa mätvärden före och efter
public class RAGMetrics
{
public int PromptTokens { get; set; } // Should drop by 80-90%
public int CandidatesRetrieved { get; set; } // Should drop from 50+ to 5-10
public TimeSpan QueryLatency { get; set; } // Should improve
public bool FiltersEnforced { get; set; } // Should be true
public List<string> EvidenceSources { get; set; } // Should be traceable
}
Om ditt system är beroende av att alltid
| Intens | Gör RAG förutsägbar, , billigt, |
| Krafter | |
| Lösningen | Extraherar signaler när → tvingar begränsningar deterministiskt ♫ → ♫ tar fram bevis ♫→ ♫ låter LLM syntetiseras i ett budget ♫ |
| Konsequenser | Mer ingenjörskonst i förspetsningen |
Reduced RAG är anti--, anti-LLM och anti-'.
Tänk på det så här.
Traditional RAG = "LLM, here's 50 chunks. Figure out what matters and answer."
Reduced RAG = "Database, filter to 100. BM25, find keywords. Vector, find similar.
Now LLM, here are the 5 most relevant sources. Synthesize an answer."
Nyckeln:
Primitiverna:
Pattern:
Det är vad som händer när man tillämpar en vanlig mjukvaruingenjörskonst på system som råkar inkludera språkmodeller.
Om du är redo att bygga den här
Referensimplementeringar:
Infrastrukturen finns redan där.
© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.