Tämä on Osa 5 DocSummarizerin sarjasta , ja se ' on myös huippukokonaisuus GraphRAG-sarja ja Semanttinen hakusarja. Me' yhdistämme kaikki yhteen sovellettavissa olevaan web-sovelluseen
🚨🚨 Tarkistus ARTICLE 🚨🚨 Työskentelemme vielä parissa kinkissä ja lisäämme ominaisuuksiaM SK2 Mutta ydin on tehty ja se toimii hyvin. Odotamme seuraavien viikkojen aikana saatavia päivityksiäMSC4 Se tulee lucidRAG-sivuilleMST5comMst6 MinäM st7 Lisään täällä screenshoteja, kun saan mallin valmiiksiMSt8
RAG-infrastruktuurin rakentamisen tarkoituksena on käyttää sitä todelliseen toimintaan.
Viime viikkoina olemme rakentaneet
Nyt yhdistämme ne yhteen lucidRAG - yksittäinen web-sovellus monien asiakirjojen kysymyksiin vastaamiseen tietografiikan visualisoinnin avulla
verkkosivusto: lucidrag.com | Lähde: GitHub
Laajentaa asiakirjoja. Pitä kysymyksiäM SK1 Saa vastauksia viittauksineen ja tietotaulukkoon, jossa kuvataan, miten käsitteet liittyvät toisiinsa
Tärkeimmät ominaisuudet:
Suunnitelmarajoitukset:
Mitään LLM:itä ei missään vaiheessa käytetä chunkkiin, sisällytykseen , entity extraction, tai varastointiin M SK3 ainoastaan löydettyjen vastausten synteesimiseen
Ainoastaan vektorinen haku katkeaa tietyille kysymyksentyypeille:
| Kysymyksen tyyppi | Vektorin hakuongelma | Graph-ratkaisu | |||
|---|---|---|---|---|---|
| Yhdyskunta-asiakirjat, -asiakirja, SSK2 " Miten X liittyy Y:hen? | |||||
| Yhteinen osapuoliM SK1keskinen | SSK3Entä Docker, ?" | Yhdestä osapuolesta peräisin oleva Graph traversal | ||||
| Maailmanlaajuiset yhteenvedot |
lucidRAG käyttää sekä: vektoreita täsmällisyyden varmistamiseksiM SK1 grafiikkoja kontekstin varmistamiseen . Graph-kyselyt ovat pitkiä-rajoitettuja MSC4max SSK5 hyökkäyksiäMST6 ja laajennettuja löydettyihin asiakirjoihin, jotta estettäisiin rajaton läpikulku suurten yritysten osaltaMSL7
App-layerissä on kolme hanketta, jotka olemme jo rakentaneet: ' ja ,. StyloFlow - signaali
lucidRAG
├── Controllers/Api/ # REST endpoints
├── Services/ # Business logic
│ ├── DocumentProcessingService # Wraps DocSummarizer
│ ├── EntityGraphService # Wraps GraphRAG
│ └── Background/ # Async queue processing (StyloFlow waves)
└── Views/ # HTMX + Alpine.js UI
Miksi StyloFlow? Kukin käsittelyvaihe on ennakolta "aalto, ", joka antaa signaalejaM SK3aallot toimivat, kun niiden lähtö- ja lähtöolosuhteet vastaavat toisiaan,, mikä mahdollistaa rinnakkaisen täytäntöönpanon. StyloFlow:Signaali täytäntöönpanon yksityiskohdat.
Kun laaditte asiakirjan, se kulkee kolmeen vaiheeseen:
Laadinnan loppupiste vahvistaa tiedoston, laskee sisällöllisen hassin päällekkäisyydeksiM SK1 ja järjestelee sen taustakäsittelyyn :
public async Task<Guid> QueueDocumentAsync(Stream fileStream, string fileName)
{
// Compute hash to detect duplicates
var contentHash = ComputeHash(fileStream);
var existing = await _db.Documents
.FirstOrDefaultAsync(d => d.ContentHash == contentHash);
if (existing != null)
return existing.Id; // Already processed
Tärkein näkemys: haaskaamme ensin, säästämme myöhemminM SK2 Näin vältetään päällekkäisissä laatimissaan tiedostoihin liittyvän käsittelyajan tuhlaaminenMSC3
// Save to disk, create DB record
var docId = Guid.NewGuid();
await SaveFileToDiskAsync(fileStream, docId, fileName);
// Queue for background processing
await _queue.EnqueueAsync(new DocumentProcessingJob(docId, filePath));
return docId;
}
Taustakäsittely ottavat esille asiakirjat, jotka ovat joukossa ja hallinnoivat niitä DocSummarizerin kautta:
var result = await _summarizer.SummarizeFileAsync(job.FilePath, progressChannel);
Tämä yksisuuntainen linja tekee paljon työtä (katso DocSummarizer -osuus 1):
Yhdenmukaistamisen jälkeen otamme GraphRAG:n heuristisen lähestymistavan mukaiset entiteet
var segments = await _vectorStore.GetDocumentSegmentsAsync(documentId);
var entityResult = await _entityGraph.ExtractAndStoreEntitiesAsync(documentId, segments);
Siinä käytetään IDF:n tulosta ja rakenteellisia signaaleja sen sijaan, että per -chunk LLM-puheluja - katso GraphRAG-osuus 2 Lisätietoja.
Naiivin täytäntöönpanossa käytettäisiin rajattomia queueja, vaarantaminen--muistien romahdus Uploadin tulvien aikanaM SK3Me käytämme rajattuja kanavia, joilla on selvät kapasiteetin rajoitukset
private readonly Channel<DocumentProcessingJob> _queue =
Channel.CreateBounded<DocumentProcessingJob>(new BoundedChannelOptions(100)
{
FullMode = BoundedChannelFullMode.Wait
});
Kun queue täyttyy, Wait mode estää uusia kirjoituksia siihen asti, kunnes avaruus avautuu. lisätään tauko, jotta käyttäjät saavat selvän virheen sen sijaan, että häntelevät
using var timeoutCts = CancellationTokenSource.CreateLinkedTokenSource(ct);
timeoutCts.CancelAfter(TimeSpan.FromMinutes(5));
try {
await _queue.Writer.WriteAsync(job, timeoutCts.Token);
} catch (OperationCanceledException) when (!ct.IsCancellationRequested) {
throw new InvalidOperationException("Queue full. Try again later.");
}
Suurten asiakirjojen käsittely voi kestää minuutteja.
while (!stoppingToken.IsCancellationRequested)
{
var job = await _queue.DequeueAsync(stoppingToken);
// 30-minute timeout per document
using var timeoutCts = CancellationTokenSource.CreateLinkedTokenSource(stoppingToken);
timeoutCts.CancelAfter(TimeSpan.FromMinutes(30));
try {
await ProcessDocumentAsync(job, timeoutCts.Token);
} catch (OperationCanceledException) when (!stoppingToken.IsCancellationRequested) {
await MarkDocumentFailedAsync(job.DocumentId, "Processing timed out");
}
}
Liitetyllä tokenilla varmistetaan, että noudatamme edelleen sovelluksen sulkemista lisättäessä per-asiakirjan rajaaM SK1
Jokainen käsittelyasiakirja saa etenemiskanavan SSE-tarkistuksia varten. Mutta jos käyttäjä sulkee browserinsa keskiössäM SK1upload, se kanaali jää orphanediksi . Seuraamme luomisen aikoja ja puhdistetaan säännöllisestiMSC4
private readonly ConcurrentDictionary<Guid, ProgressChannelEntry> _progressChannels = new();
public int CleanupAbandonedChannels()
{
var cutoff = DateTimeOffset.UtcNow - TimeSpan.FromHours(1);
var cleaned = 0;
foreach (var kvp in _progressChannels.Where(x => x.Value.CreatedAt < cutoff))
{
if (_progressChannels.TryRemove(kvp.Key, out var entry))
{
entry.Channel.Writer.TryComplete();
cleaned++;
}
}
return cleaned;
}
A PeriodicTimer kutsuu tämän joka 15 minuutti taustaprosessissa .
Käytämme kahta tietokantaa eri tarkoituksiin:
PostgreSQL/SQLite (EF CoreM SK2 tallennetaan asiakirjan metadataa - mikä on olemassa , käsittelytilanneM SK2 suhteet. Nämä tiedot ovat kestäviä ja kysyttävät
DuckDB-ohjelma varastoi vektorit ja entiteetin grafiikka. Se' on väliaikainen M SK2 voitte rakentaa sen uudelleen lähteistä asiakirjoista . Tämä ero merkitsee, että vector store korruption ei tapahdu
// Metadata in PostgreSQL
public class DocumentEntity
{
public Guid Id { get; set; }
public string Name { get; set; }
public string ContentHash { get; set; }
public DocumentStatus Status { get; set; }
}
// Vectors in DuckDB (managed by DocSummarizer)
// Entities in DuckDB (managed by GraphRAG)
Kysymykset etenevät agentisen etsinnän kautta:
[HttpPost]
public async Task<IActionResult> ChatAsync([FromBody] ChatRequest request)
{
// 1. Get or create conversation for memory
var conversation = await GetOrCreateConversationAsync(request.ConversationId);
// 2. Search with hybrid retrieval
var searchResult = await _search.SearchAsync(request.Query, new SearchOptions
{
TopK = 10,
IncludeGraphData = request.IncludeGraphData
});
hakupalvelu käsittää kysymyksen hajoamisen tarpeen mukaan, ja tuo sen jälkeen yhteen vastauksen
// 3. Generate answer with LLM
var answer = await _summarizer.SummarizeAsync(
request.Query,
searchResult.Segments,
new SummarizeOptions { IncludeCitations = true });
// 4. Save to conversation history
await SaveToConversationAsync(conversation.Id, request.Query, answer);
return Ok(new ChatResponse
{
Answer = answer.Text,
Sources = answer.Citations,
GraphData = searchResult.GraphData
});
}
UI on yksi sivu, jossa asiakirjat ovat vasemmalla, chat oikealla:
┌──────────────────┬─────────────────────────────────────┐
│ 📁 Documents │ 💬 Chat │
│ ───────────── │ [Answer] [Evidence] [Graph] │
│ [+ Upload] │ │
│ 📄 api-docs.pdf │ Q: How does auth work? │
│ 📝 readme.md │ A: JWT tokens stored... [1][2] │
│ ───────────── │ │
│ 🕸️ Graph: 168 │ ┌─────────────────────────────┐ │
│ │ │ Ask about your documents... │ │
└──────────────────┴──┴─────────────────────────────┴───┘
Alpine.js hallinnoi tilannettaM SK1 HTMX käsittelee asiakirjaluettelon päivityksiä:
function ragApp() {
return {
messages: [],
isTyping: false,
async sendMessage() {
const query = this.currentMessage.trim();
this.messages.push({ role: 'user', content: query });
this.isTyping = true;
const result = await fetch('/api/chat', {
method: 'POST',
body: JSON.stringify({ query })
}).then(r => r.json());
this.messages.push({
role: 'assistant',
content: result.answer,
sources: result.sources
});
this.isTyping = false;
}
};
}
Lucidragin kaltaisten julkisten käyttöönottojen osalta demo-modus estää laadinnon ja käyttää ennalta laadittua sisältöä.
public class DemoModeConfig
{
public bool Enabled { get; set; } = false;
public string ContentPath { get; set; } = "./demo-content";
public string BannerMessage { get; set; } = "Demo Mode: Pre-loaded RAG articles";
}
A DemoContentSeeder taustapalvelu seuraa sisällön luetteloa ja käsittelee kaikki pudotetut asiakirjat:
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
if (!_config.DemoMode.Enabled) return;
await SeedExistingContentAsync();
StartFileWatcher(_config.DemoMode.ContentPath);
}
Tämä antaa mahdollisuuden päivittää demo-sisältöä yksinkertaisesti kopioimalla asiakirjoja.
dotnet run --project Mostlylucid.RagDocuments -- --standalone
Käytetään SQLitea + DuckDB paikallisesti. Avataan http://localhost:5080.
services:
lucidrag:
build: .
ports: ["5080:8080"]
depends_on: [postgres, ollama]
| Osuus | Lähde | Tavoite SSK3 | ||||
|---|---|---|---|---|---|---|
| Asiakirjojen parsiminen | DocSummarizer | |||||
| ONNX-embeddings | DocSummarizer | Local | ||||
| Entiteettilähetys | GraphRAG | IDF | + | rakenteelliset signaalit | ||
| Yhdistetty haku | Molemmat | BM\25 | ||||
| Asynkkikäsittely | Uudet | Rajoitettuja kanavia | ||||
| Web- UI | Uusi | HTMX M+ AlpineM SK4js MPSK5 |
Nolla API-kustannuksia indeksointia varten - sisällytykset ovat ONNXM SK1 entiteet onuristisia . maksatte LLM-synteesistä vain kysymyksen aikana, ja se toimii paikallisen Ollaman kanssa
© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.