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
RAG för implementerare: CPU-Friendly Semantic Search with ONNX and Qdrant
Thursday, 05 November 2026
Du söker efter “implementera en applikation i en behållare”. Artikeln du behöver heter “Getting Started with DockerM SK3 Ett användbart söksystem borde koppla samman dessa idéerMSC4 även om orden inte matchar exakt
NOTET: uppdaterad 5 november 2026. Ombyggt för | | .| NET | МSK4| med korrekt tokenisering och sammanslagning |,| genomgångar | - | nivåerindexering |, | källkodsbeginning ♫ , | filtrerad sökning och säkrare indexuppdateringar |M. | En ny sektion visar hur EmbeddingGemma | M2 | utökar arkitekturen till bilder |
Detta artikel bygger upp att hämta grunden i C#: köra ett litet embedding-modell lokalt med ONNX Runtime , lagra sina vektorer i Qdrant , och hämta in besläktade postitusar M SK3 Den behöver ingen språk MSC4 genereringsservice och ingen GPU MST5 Den konsumerar fortfarande CPU MSV6 minnen M SV7 lagring och operationell ansträngning M V8 självet M S V9 hosting tar bort bilnoten för varje embedded API-request M MV11 inte kostnaden för att köra programvara M Sv12
Det här är Del 4a av RAG-serien:
- Del 1: RAG ursprung och grundlagen
- Del 2: RAG arkitektur och inre
- Del 3: RAG i praktiken
- Del 4a: Implementering av ONNX och Qdrant — den här artikeln
- Del 4b: Semantisk sökande i aktivitet
- Del 5: Hybridsökning och automatisering-Indexering
- Del 6: GraphRAG
Du ska känna dig bekväm med C#, asyncka metoder och beroende-injictering . I' Jag ska förklara modellen och databasens terminologi när vi möter den
Vad vi bygger
En inbäddar är en rad tal som produceras av en tränad modell.
NX är ett format för att representera en maskin Runtime på ONNX utför den modellen. Qdrant lagrar vektorer och hittar närliggande kandidater, tillsammans med vanliga fält som låter oss identifiera och filtrera resultatenM SK1
Indexeringsvägen börjar med källmaterial, innan något når modellen:
flowchart LR
D[Source document] --> E[Extract body and structure]
E --> S[Passages with headings and source ranges]
S --> T[MiniLM tokenizer and ONNX encoder]
T --> P[Pool and normalize each passage]
P --> V[Qdrant passage vectors and provenance]
Q[Search query] --> T
V --> F[Filter and rank passages]
F --> R[Best passage per post]
R --> B[Load current post details]
Indexering lagrar en vektor för varje passage. sökande inbäddar in sökningen med samma modellrör, filtrerar de lämpliga grejerna och återskapar den bästa matchningen för varje artikeln . Förknippade M SK2postupphävningen använder en separat sammanfattningsvektor
RAG betyder att hitta frampäästelse, -, ökande gener, :, hitta bevis, M SK2, sedan ge det till en modell som genererar ett svar.., vi implementerar att hitta upppääselse här,., ett sökresultat är själv användbart,
Välj representationen innan du väljer databasen
Vi använder sentence-transformers/all-MiniLM-L6-v2, en engelska mening 384-dimensionell vectors. Den lilla storleken gör den till en praktisk CPU-basnivå . Andra inbäddade modeller kan fungera bättre på dina språk
Den viktiga överenskommelsen är större än modellens filename:
| Komponent ♫ | ♫ Vad måste hållas med om mellan indexering och sökande ♫ | ||||
|---|---|---|---|---|---|
| Modell | Samma vikter och export | ||||
| Markifier | Vokabulär | , | Fallbehandlande | , | Namsbeståndsregler och speciella tokens |
| Input-förberedels | Vilket text är inbäddat och hur länge inputer är uppdelade | ||||
| Kollering | Hur per | - | tokenutgångar blir en vektor | ||
| Normalisering | Hur man hanterar vektorstorlekten | ||||
| Databaseringsschema | Dimension | Distans mätning | Pipelineversion |
Två modeller kan producera både 384 floter medan de placerar dessa floter i okompatibla utrymmen
källan lever i Mostlylucid.SemanticSearch. Den genomgående versionen använder sina offentliga gränssnitte ; de kortare inre skisserna härunder förklarar hur den fungerar utan att duplicera hela avdelningar
Utvinning och segmentering bestämmer vad som kan hittas
Anta att en sida innehåller en användbar handledare, ett navigations-menu , tre besläktadeM SK2 postpaneler och en cookie-kommentisering. Att lägga in hela HTML-responsen gör att alla dessa saker är till godo för att hitta igenMSC4 Att upprepa samma navigation på varje sida kan göra att orelaterade sidor ser konstgjordt likadana ut
Utvinning väljer den användbara käll innehållet. Segmentering delar in innehållet i återvinningsbara enheter. Kontext extraktion förbehåller informationen som behövs för att kunna tolka varje enhet: dess titel , sektionsrubriken , källlokalen och M SK3 där relevanta
StyloExtrakt handskas med HTML extraktion genom att analysera, blocksegmentering , klassificering och rendering. Den bevarar titlar , länkar M SK4 listor MSC5 tabeller och kod medan den identifierar sidamöbeln Mska6 Den template induktionsartikel förklarar hur lärad platsstruktur kan stödja efterföljande extraktion före den här inbyggda pipelinen, :, ger modellen en bättre input.
För den här biblioteken, BlogPostDocument.Content borde redan innehålla extraherad text eller rena Markdown. Biblioteket gör inga plaggningar på sidorna, eller tar bort HTML-navigationen
Den inkluderade ContentSegmenter är en liten basnivå : upp till 800 bokstäver per passage , | | 100 | överlappande bokstaver M SK4 | punktgränser där det är praktiskt MSC5 | och den tidigare markeringsruten MST6 | Den sparar exakt start och längd i innehållet som levererats UTF-16 string offsets, inte byterpositioner i originalet HTML ; spara en källkartläggning om du behöver tydliggöra originalet
Varje passage är inbäddad med dess posttitel och mening.. De kontextuella fälten påverkar vektorn men inte är inblandade i citerade källtexter.
Karaktersegmentering är en läsbarhetens heuristik, inte en symbolbudget. Kodern hanterar den faktiska tokengränsen separat . Den här grundlinjen kan dela upp en kodtak eller tabell. DocSummarizer's RAG-rör utvecklar rikare segmentextraktioner och metadata för det nästa steget.
Tillförselns kvalitet är mätbar. Håll exempel med upprepade navigeringar , inbäddade opskrifte M SK2 långa kodblock och tabeller . Kontrollera att den relevanta källan överlever Mska4 att dess kontext är bevarad M Ska5 och att en extraherad passage kan spåras tillbaka till sin källa innan man dömer inbyggande modellen
kör ett litet exempel först
Starta Qdrant lokalt
Från skyddsrum root:
docker compose -f semantic-search-docker-compose.yml up -d
curl --fail http://localhost:6333/readyz
Den autonoma Compose - pliken använder en persisterande volym och binder till loopback:
services:
qdrant:
image: qdrant/qdrant:v1.20.0
restart: unless-stopped
ports:
- "127.0.0.1:6333:6333"
- "127.0.0.1:6334:6334"
volumes:
- qdrant_storage:/qdrant/storage
volumes:
qdrant_storage:
6333 är HTTP Den Qdrant .NET klient använder gRPC. Konfigurera http://localhost:6334, även om redohetsansökan och brädan används 6333. En webbbrowser som visar en hälsosam bräda visar inte att ' bevisar din application
Bilden är kopplad till för återskapbarhet. Omvärdera och testa ett explicit uppgradering snarare än att behandla ett rörligt latest tag som en utplaceringsstrategi. Lokal exemplet har ingen autentisering Qdrant's säkerhetsguidande.
ladda ner modellen och matchande ordspråk
Repositoret består av Bash och PowerShell skript:
bash Mostlylucid.SemanticSearch/download-models.sh
./Mostlylucid.SemanticSearch/download-models.ps1
Båda sätter all-MiniLM-L6-v2.onnx och vocab.txt i Mostlylucid/mlmodels. De hämtar samma pinned modellrevision som servicen . filerna laddas ner till temporära syskon och omväxlas bara efter en lyckad nedlayning , så att en avbrytnad överföring inte lämnar en delmodell som maskeras som en färdig
Servicen kan också få fram förlorade tillgångar när den initialiseras för första gången. För att sätta igång , Att ladda ner dem under förberedelser ger dig möjligheten att kontrollera och behålla tillgångarna innan du serverar trafiken . Att hålla modellerna i ett bestående katalog utanför webrootet M SK3 För en starkare tillgång MSC4 kedjankontroller Mska5 Att behålla provsvarningar med släppen och kontrollera dem innan sätta igång
Att ändra konfigurerad redigering ersätter inte filet som redan finns på samma bana.
Att skapa en konsol-host
Från skyddsrummen root, skapa en liten host som referenserar implementationen
dotnet new console -n SemanticSearchDemo -f net10.0
dotnet add SemanticSearchDemo/SemanticSearchDemo.csproj reference Mostlylucid.SemanticSearch/Mostlylucid.SemanticSearch.csproj
Ersätta dess Program.cs med:
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Mostlylucid.SemanticSearch.Extensions;
using Mostlylucid.SemanticSearch.Models;
using Mostlylucid.SemanticSearch.Services;
var configuration = new ConfigurationBuilder()
.AddInMemoryCollection(new Dictionary<string, string?>
{
["SemanticSearch:Enabled"] = "true",
["SemanticSearch:QdrantUrl"] =
Environment.GetEnvironmentVariable("QDRANT_DEMO_URL") ?? "http://localhost:6334",
["SemanticSearch:ReadApiKey"] = Environment.GetEnvironmentVariable("QDRANT_DEMO_READ_KEY"),
["SemanticSearch:WriteApiKey"] = Environment.GetEnvironmentVariable("QDRANT_DEMO_WRITE_KEY"),
["SemanticSearch:CollectionName"] = "blog_posts_demo_v1",
["SemanticSearch:EmbeddingModelPath"] =
"Mostlylucid/mlmodels/all-MiniLM-L6-v2.onnx",
["SemanticSearch:VocabPath"] = "Mostlylucid/mlmodels/vocab.txt",
["SemanticSearch:MinimumSimilarityScore"] = "-1"
})
.Build();
var services = new ServiceCollection();
services.AddLogging(logging => logging.AddConsole());
services.AddSemanticSearch(configuration);
using var provider = services.BuildServiceProvider();
var search = provider.GetRequiredService<ISemanticSearchService>();
await search.InitializeAsync();
await search.IndexPostsAsync(new[]
{
new BlogPostDocument
{
Id = "docker-deployment",
Slug = "docker-deployment",
Title = "Deploying with Docker",
Content = "Package a web application in a container image and run it with Docker Compose.",
Languages = new[] { "en" }
},
new BlogPostDocument
{
Id = "chocolate-cake",
Slug = "chocolate-cake",
Title = "Baking a chocolate cake",
Content = "Mix flour, butter and chocolate, then bake the cake in an oven.",
Languages = new[] { "en" }
}
});
var results = await search.SearchAsync(
"How do I deploy an application in a container?", limit: 2);
foreach (var result in results)
Console.WriteLine($"{result.Score:F3} {result.Slug}");
kör från källan så att den relativa modellens vägar löser konsekvent:
dotnet run --project SemanticSearchDemo/SemanticSearchDemo.csproj
Dockerposten borde rankas över kakaposten. exemplet använder medvetet en tröskel av -1 att visa båda poängen, ,, inklusive svaga matchar.. Det är en diagnostisk ställning för denna lilla kropp, M SK2, inte en relevant policy att kopiera in i produktion.
Att köra indexkoden igen uppdaterar samma punkter. Ett oföränderligt dokument skippers bort innan man drar slutsatsen . Ingen ny slumpmässig ID genereras på varje gång
Att få inbyggande pipelinen rätt
kens måste matcha den tränade modellen
A symbol är en modell-inputning-enhet. Det kan vara ett helt ord
Ett regex-split följt av ett vokabulära sök upp är otillräckligt. Att hastra ett okänt ord till ett vokalindex är värre : det ger ordet meningen som en orelaterade tränad token
Implementeringen använder BertTokenizer från Microsoft.ML.Tokenizer:
var tokenizer = BertTokenizer.Create(vocabPath, new BertOptions
{
LowerCaseBeforeTokenization = true,
ApplyBasicTokenization = true
});
var ids = tokenizer.EncodeToIds(text, addSpecialTokens: false);
Vi lägger till klassificeringstoken [CLS] och separator [SEP] runt varje modellfenster efteråt 254 innehållsトークn per fönster.
Det här vokabuläret-baserade adapter är specifikt för den här modellenfamiljen . Ett annat model kan kräva en annan tokenisator , inmatnings namn M SK3 fråga- prefix eller sammanslagning- regel .onnx file är inte en modell migration
Passager och modellfenster löser olika problem
Ett genomdrag är enheten vi vill få tillbaka. Ett modellfenster är enhet som kodern kan processa i ett sändande
Två tusen tecken är inte en tokengränsen. Kode , URLs , punktering och olika språk kan skapa olika tokenkolor för samma antal tecken
Kodenaren tokeniserar den kompletta ingången, ,, sen går den genom fönster med en konfigurerad överlappe av innehållstokener, 32 . Varje fönster innehåller sina egna speciella tokens och stannar i positioner,
flowchart TB
A[Passage plus title and heading] --> B[WordPiece token IDs]
B --> C[First window]
B --> D[Overlapping windows through the tail]
C --> E[Masked pooling and normalization]
D --> E
E --> F[Average window vectors and normalize]
F --> G[One vector for this passage]
G --> H[Store source range and context]
Att jämföra flera fönsters vektorer dämpar ändå fin detalj och ger ett kort slutgiltiga fönster lika stort inverkan.. Att hålla passagen rätt så fokuserade minskar problemet. . Det betyder också att en sökning kan ge tillbaka siffran om TLS utan att behöva den detaljen för att dominera en hel artikel.
Den separata dokumentuppfattningen mäter medelvärdet för vector i sträckt relaterade passager-postsuggestioner. Den sammanfattningen är användbar för att upptäcka ; texten i passagen och källkedjan ger bevis för en fråga
ONNX utsätter tecknande vektorer först
Modellet konsumerar tre siffransträngare:
| Input | Form för ett fönster ♫ | ♫ Meningen ♫ | ||
|---|---|---|---|---|
input_ids |
[1, tokenCount] |
Woordeskat IDs | ||
attention_mask |
[1, tokenCount] |
1 för riktiga tokens, 0 för asfaltering |
||
token_type_ids |
[1, tokenCount] |
Allt noll för denna enskilta -text-inputning |
A Tensor är en multidimensionell uppsättning. Här är paketdimensionen ett. tjänsten använder den faktiska rutanslängden ; den gör det inte
Den väljade exporten återkommer last_hidden_state,-formad [1, tokenCount, 384]: en vektor per token . Plattisering som tensorn producerar tokenCount × 384 siffror, inte en enda mening inblandad
Vi validerar input och utputs namn när vi laddar modellen, väljer utputsen med namnen , och avfärdar oväntade former. Det hindrar en annan export från att tyst ändra vad som blir indekserat
Pool, sedan normalisera
Kollning snittar symbolvektorerna. uppmärksamhetsmasken utelämnar padding från både summan och sammanräkningen
windowVector[d] = sum(tokenVector[t, d] where mask[t] = 1)
/ number of included tokens
Speciella token är fortfarande inblandade , som matchar maskerade medelvärder- detta pipelinen använder enpooling-metoden . För implementeringen och dess padding regresstest OnnxEmbeddingService. Den Berättelsetransformatorer förklarar också att en transformatorexport kan kräva sammanslagning och normalisering utanför modellen
L2 normalisering delar vektorn med dess Euklidska längd. Ett icke-zerot resultat så har längden ettM SK1 Vi normaliserar varje venstervektor och den slutliga medelvärden. NollMSC3 storhet och icke - slutgiltiga vektorer är fel
Sammalikhet är en rankingsignal
Kosinelikhet jämför riktningen av två vektorer:
cosine(a, b) = dot(a, b) / (length(a) × length(b))
För enhet-längd vektorer, förenklar detta till deras punktproduktM SK2 Punktresultat kan variera från -1 till 1. En resultat scoring 0.72 gör inte innebär att den har en 72% sannolikhet att vara relevant
Kosinemetriken av Qdrant' normaliserar också vektorer vid upplayning, som beskrivs i vektordokumentation. Vi normaliserar också embedding-tjänsterna så att deras utgångar beter sig konsekvent i tester och jämförelser utanför Qdrant
Ett tröskel som fungerar för liknande-post-suggestioner kan hämma användbara resultat för korta sökningar
Speichera en versionerad sökindex
En bunt samlade består av sökbara punkter. A punkt har en ID, vektor och en Last, betyder vanliga fält som lagras bredvid vektorn
Den standardmäßiga MiniLM-kollektiven använder 384 dimensioner med kosineavstånd . Initialiseringskontroller en existerande kolektion | Vektorschemat | ' | istället för att anta att en matchande namn påstår compatibilitet
Den består av::
| fält | syfte |
|---|---|
slug |
Hitta den kanoniska posten i applikationsdatabasen |
content_hash |
Detektor av ändrade indexing-input |
embedding_version |
Säg okompatibla vektorer utanför samma sök |
published_date |
Enixtidstamp tillgänglig för datumfilterning |
languages |
Available translations of the post |
categories |
fält tillgängliga för filtrering |
record_type |
Separera ett dokuments översikt från ett fragment |
source_text, source_start, source_length |
Ta tillbaka matchet källpassage |
heading, source_uri |
Berätta om dess kontext och länk till dess källa |
modality |
Text |
page, start_seconds, end_seconds |
Optionella plats för media som levereras genom ingestion |
Display titles, Publication details and rendered posts are loaded from PostgreSQL
Servicen skapar nyckelindex på slug, version , languages, categorieerM SK3 inspelningstyp, , modalitet och innehållstyp, hash+, plus en siffra-index vid publiceringsdatum, . Belastningsindex gör att vastava filter är användbara, effektivt, ; genom att lägga till ett belastningsfält enbart, gör det inte så att ' doesn 't skapa en index,.
publicera en komplett generation av passager
En dokumentuppfattning har en deterministisk, osignerad 64-bit ID som kommer från dokumentidentifikationen med xxHash64. Passagidentifikationer inkluderar också pipelineversionen , innehållets fingeravtryck och segmentidentiseringenM SK3 upprepade indexering är idempotenta ; innehållets förändring skapar en ny generation av passagerMska5 Dessa hasser är inte en kryptografisk identitetsschema Mska7 Använd en uthållig ID-karta eller ett lämpligt UUID-schema om kollisionrisken är oacceptabel
Aktualiseringsord är viktigt:
- Lade upp den nya generationen 's passager i begränsade skivor, vänta på att varje skrivande ska göras
- Ge sammanfattningen av dokumentet , vars fingeravtryck fungerar som manifest som identifierar den färdiga generationen.
- Lösa föråldrade passager för den posten
läsare jämför en kandidat passage, fingeravtrycket från ' med dess moderliga manifest... En avtagen sändning kan inte avslöja en halva del.-. Den skrivna generationen.
Det här är ett applikationspubliceringsprotokoll , inte en transaktion mellan Qdrant och PostgreSQL eller ett kort blick över flera sökningar. skrivarlocken täcker en enda tjänstesinstance. Koordinera flera skrivare för samma sändningM SK3 eller riktningsindexering genom en enda anställde
Passagvector är förvarade för ett dokument i taget innan man laddar upp det.. skrivande lager är begränsade. ; det största individuella dokumentet bestämmer fortfarande höjdpunkten för indexeringsminnet.
Reta passager utan att fylla i sidan med ett meddelande
Tio högt rankade bitar från en artikel borde inte konsumera tio sökresultat. MaxSearchCandidates kandidater, avvikande | 4,096. | Ett mycket repetitivt korpus kan därför återskapa mindre än den beansökta antalet poster
Använd den rikare metoden när du behöver bevis
var hits = await search.SearchPassagesAsync(
"configure HTTPS behind a reverse proxy",
new RetrievalFilter(Language: "en", Modality: "text"),
limit: 5);
foreach (var hit in hits)
Console.WriteLine($"{hit.Slug}: {hit.Segment.Heading} — {hit.Segment.Text}");
Språk, kategorin , modalitet och optionell publicering- datumfilter är tillämpade inuti Qdrant-frågan, före rangering och uppsättning i gruppering . De är ansökningsreglern , inte efteråt M SK3 bearbetade dekorationer SearchAsync som användes tidigare, återvänder bara slug och poäng medan man använder den här sträckningsavtagstigen under.
Fingerprint varje inmatning som spelar roll
Den indekserade fingeravtrycket innefattar ID, slug , titel, innehållet fulloM SK3 publiceringsdatumMska4 sorterade olika språk och kategorier, och effektiva pipelineversionenMske6 titelnMssa7 endast eller metadataMsa8 endast redigeringar räknas därför också som förändringarMsä9
Den effektiva versionen innefattar konfigurerad algoritmetikett, pinned model revision , tokenoverlap and passage segmentation settings. ändra algoritmetiket när dokument är förbereitadM SK3 tokensisering eller sammanslagning av ändringarMska4 Passerande dimensioner är inte tillräckligt för att bevisa att två versioner är jämförbaraMske5
sökningar och liknande-post-uppsökfilter på den här versionen
För en direkt migration, skapa en ny samling , bygga upp den igen , verifiera relevans och komplettitet M SK3 och byta läsare efter att den är redo MSC4 Att hålla den tidigare samlingen tillfälligt ger en rollback-väg
Förknippade postituser behöver en vektor för att jämföra
Att hitta payload-fält tar inte nödvändigtvis fram vektorer.
Den relevanta frågan är:
var related = await readClient.QueryAsync(
collectionName: collectionName,
query: sourceVector,
filter: filterWithVersionAndSourceExclusion,
limit: (ulong)limit,
scoreThreshold: minimumScore,
payloadSelector: true,
cancellationToken: cancellationToken);
Här filterWithVersionAndSourceExclusion är filtret som konstrueras i vektorn sourceVector är den hämtade vektorn. Den kompletta metoden finns i QdrantVectorStoreService.
Koppla det till ASP.NET Core
Registrera tjänster en gång genom förlängningen:
builder.Services.AddSemanticSearch(builder.Configuration);
The embedding service, vector-store service and orchestrator are singletons . Modelsessionen är dyr att bygga och återanvändasM SK3 Modelldownloads use a named HTTP clientMSC4 and the host disposes of the services when it shuts down
Konfigurationssektionen är:
{
"SemanticSearch": {
"Enabled": true,
"QdrantUrl": "http://localhost:6334",
"CollectionName": "blog_posts",
"EmbeddingModelPath": "mlmodels/all-MiniLM-L6-v2.onnx",
"VocabPath": "mlmodels/vocab.txt",
"VectorSize": 384,
"EmbeddingVersion": "minilm-segments-v2",
"IntraOpNumThreads": 2,
"MaxConcurrentEmbeddings": 1,
"ChunkOverlapTokens": 32,
"SegmentMaxCharacters": 800,
"SegmentOverlapCharacters": 100,
"MaxSearchCandidates": 4096,
"IndexBatchSize": 16,
"MinimumSimilarityScore": 0.5,
"SearchResultsCount": 10,
"RelatedPostsCount": 5
}
}
ModelRevision defaults to the commit pinned in SemanticSearchConfig. Biblioteket validerar inställningar som dimensioner , positiva gränser och överlappar mindre än innehållsfenoret .
Initialisera under uppstart eller en styrd varm process- uppgångsprocess . Om sökandet är optionellt, hålla resten av platsen tillgänglig när initialiseringen misslyckasM SK3 samtidigt som man rapporterar om att sökandet inte är tillgängligt ärligtMSC4 Ett HTTP-gränssnitt bör skilja på en lyckad sök utan matchar från ett misslyckat söksystemMska5
Den dedikerade sökende slutpunkten bekräftar nu querylängden och resultatgränserna, passerar begäranskröjningstokenM SK1 och återskaper 503 för operationella misslyckanden. Biblioteket låter undantag och avkröjning nå inkallarenMSC4 den inte gör ett misslyckat inbäddande till nollor eller hävdar att ett misslöst skrivande indexerats framgångsrikt
Related-post-キャッシュing varierar efter slug, krävt språk , resultatgränsen och HTMX-responsformatet M SK3 När du integrerar något annat , måste kasknycklarna inkludera varje inmatning som ändrar reaktionen Mska5 plus indexversionen om din kask kan överleva en modellimplementering M Ska6
Vad språkstöd betyder här
Boken indexerar den kanoniska käll innehållet och registrerar dess tillgängliga översättningar på sammanfattnings- och uttalandepunkter. A languages payload entry betyder att en översättning existerar
Interfejsen sätter upp den aktuella meddelandets detaljerna för den tillfrågade språken. Interfejs för att svara på meddelanden kan fortfarande skicka tillbaka färre meddelanden efter språket RetrievalFilter; led som tillförlitlig applikations preferens i din sökpunkt när det behövs. Ett språkflagg beskriver tillgänglighetM SK2 inte varje lagd passages språk
Bedöma en multilinguell modell eller en dokumenterad query-översättningspfad för multilinguella sökningar . Varenda val ändrar pipelinen och kräver en migration av indexen
säkerhets- och operationella gränser
Båda ReadApiKey och WriteApiKey hamnar på servern. En offentlig sökpunkt gör inte databases nyckel offentligt. Konfigurera faktiska kännetecken genom miljövariabler eller din platssparkopie
Vektorvaran konstruerar separata klienter. När båda nycklarna är konfigurerade , sökningar använder läsaren och mutationer använder skrivaren . En avdelning som konfigureras med bara en läs nyckling avfärdar skrivar M SK3 Om endast en skrift nyckl är konfigurerad MSC4 läser nödvändigtvis använder den också
En kombinerad webbprocess har fortfarande tillgång till dess indexeringsberättelser. För starkare isolering , sättsberättande samlas separat och kör indexering i en arbetare med skrivangsänklighet , lämnar query-servicen läsbar MSC3 endast M SK4 En processgränsning och databasen
När det gäller privat eller flera, måste tillståndet också begränsa sökningen.., ett relevantt resultat är inte nödvändigtvis ett tillåtet resultat, '. Apply access filter using trusted application context and check permission again before returning content.
Protokollera inte kompletta sökningar eller dokumentfragmenter standardmässigt: de kan innehålla känslig information . Kontrolloperationers namn M SK2 räknar , i stället beräkningar och felkategorier
Vad händer när indexering misslyckas
Qdrant och applikationsdatabasen delar inte ett affär.
Biblioteket sprider nu misslyckanden så att en ringer kan försöka igen. En robust utlagningsprocess bör krävas upp ett indexarbete efter att databasen skickat in datan , bevara misslyckad arbete och pröva det om och om igen . En periodisk sammanfördelning kan jämföra den kanoniska korpusen med indexen M SK3 reparera förlorade punkter och lösa punkter för bortlägsna meddelanden
bloggarna's startindexering och observatörintegrationer är användbara ingångspunkter , men de är inte ett hållbart utloppsmedel . Om varje uppdaterade sak måste till slut vara sökbar,
Språkaktualiseringar förtjänar liknande omsorg. Biblioteket serialiserar samtidigt AddLanguageAsync ringer inom en tjänstes instans, men det låser inte andra processer.. In i en realisering med flera skrivare, skriver , upp den fullvärdiga språklistan från databasen genom en koordinerad indexing
CPU-presterande utan uppfunna löften
ONNX Runtime kan utföra samtida urdrag på en sessie för stödda konfigurationer; runtime's session API documents thread-safe runs. En semafor är därför en resurs
MaxConcurrentEmbeddings begränsningar tillät embedding operationer. IntraOpNumThreads begränsar CPU-parallelism inom en operation. Att öka båda kan göra ett litet VPS långsammare genom att utplåna dess CPU tilldelning. Runtime threading guide förklarar kontrollen; med de faktiska CPU-gränserna hos din host eller behållare.
En async metoden inte gör CPU inferens fria. Den här implementeringen avgör arbetet på trådpoolen och kontrollerar avbrytningen mellan modellfensterna . En pyyntö som avbryts under en initial inferens sträckning kan fortfarande konsumera CPU tills den sträckningen kommer tillbaka M SK3 Under långvarig trafik , lägga till begränsad inmatning och avfärda eller skjuta upp överskott istället för att tillåta en oändlig väntande kö
Den Plural Embedding-metoden bearbetar för tillfället dokument i ordning.; det är inte tensorlagning. . Qdrant Uploadlagning och ONNX inferenslagning är olika optimeringar.
minne och lagring
En 384-dimensionell float32 vektor består av
384 × 4 bytes = 1,536 bytes = 1.5 KiB
100,000 raw vectors ≈ 146.5 MiB
Det är enbart vektordata.
Qdrant använder vanligtvis HNSW, en ungefär närmaste - grannindex, för att söka större samlingar effektivtM SK3 Ungefär så kan resultatet sättas tillbaka för hastighetenMska4 små samlingar eller specifika filter kan använda andra sökstrategierMske5 När man väljer Qdran doesn’ t establish a universal latency or capacity figure for your workload
Extend samma design till multimodell återvinning
MiniLM inbäddar text. multimodala inbäddar låta en fråga om text få fram en bild, ljudsegment eller videoklipp i ett kompatibelt lärt utrymme
EmbeddingGemma 2 är en konkret uppgraderingsväg modellkort beskriver ett gemensamt 768-dimensionellt utrymme för texten ,kod, bilderM SK3 ljud och videoMSC4 med en ♫ 8,192- ♫ token-kontext ♫. ♫ Det supporterar också kortare ♫ ♫ МSK7 ♫ EmbeddingGemma 2; inte ' inte anta att liknande modeller har samma in- eller utgångskontrakt
Ersätta koderkontraktet medvetet
För utforskande , Google's utvecklare vägledning använder meningstransformatorer 6.1 eller senare . Textfrågan och -dokument använder olika uppgiftersproppar
pip install -U "sentence-transformers[image,audio,video]>=6.1.0" transformers
import torch
from sentence_transformers import SentenceTransformer
model = SentenceTransformer(
"google/embeddinggemma-2",
device="cpu",
model_kwargs={"torch_dtype": torch.float32},
)
query = model.encode(
"a diagram showing a reverse proxy in front of a web application",
prompt_name="SearchQuery",
normalize_embeddings=True,
)
passage = model.encode(
"A reverse proxy forwards incoming requests to the application server.",
prompt_name="Document",
normalize_embeddings=True,
)
diagram = model.encode(
{"image": "reverse-proxy.png"}, normalize_embeddings=True,
)
clip = model.encode(
{"video": "deployment-demo.mp4"}, normalize_embeddings=True,
)
assert query.shape == passage.shape == diagram.shape == clip.shape == (768,)
Det här är ett exempel på en förlängning med hjälp av lokala mediadater, istället för en ersättning Program.cs för MiniLM demo. Pin Pythons beroenden och modellrevision när man omvandlar experimentet till en utplacerad arbetare precisionledning specifikerar float32 eller bfloat 16 och utelämnar explicit float~16, som kan generera ofullständiga eller föråldrade vektorer.
Den multimodell vägledning förklarar selektiv laddande: deaktiverar oanvända syn- eller ljudkodare genom config_kwargs. Att ladda bara de koder som en sökarbetare behöver kan minska sin fotavtryck, medan inspegningsarbetarna hanterar den rikare median.
Att transportera provenansen över gränsen
Storagelayern accepterar redan förutberäknade vektorer genom ISegmentedVectorStore.IndexSegmentsAsync. EmbeddedSegment par float[] med en ContentSegment; den latter har en källkod, URI, url, modalitet, ,, optionell sida och optionell start, /, sluttid och källtext, ., det är gränsen mellan en media, -, bearbetare och Qdrant.
Till exempel
| källenhet | Vektorinputning | Evidens förblivit med punkten | ||||
|---|---|---|---|---|---|---|
| Artiklisektion | Titel, titel och passage | Utvunnet text och teckenspektrum | ||||
| Arkitekturdiagramm | Bild eller bild med omgivningsberättelse | МSK2 | Original Asset URI | |||
| Den skannade manualen | Den bild som presenteras på sidan | Seitennummern | МSK3 | Dokumentets URI och separat extraherad OCR | ||
| Demonstrationsklipp | En begränsad videoklipp ♫ | Originalinspelning URI och start ♫ | ||||
| Berättande förklaring | En avgränsad ljudklipp | Inspelning URI | МSK3 | Timmstämpningar och alla separat producerade transkriptioner |
En inbäddar inte producerar en OCR-transkription eller kontrollerar captioner. Bildintelligens utforskar att hålla OCR och visuella signaler tydliga; AudioSummarizer visar varför tidstämningar och återvinningsbara ljudberättelser är viktiga. Beteckningar , OCR- och transkriptioner kan även förstärka lexisk extraheration
För att koppla detta exempel till C#, gör en ny 768-kosineinsamling i dimensioner och konfigurera en separat pipelineidentitet som innehåller den faktiska modellrevisionen , förhandlings- och inledningsreglern . skicka IndexSegmentsAsync; skicka frågor skapade av matchande modellen till SearchSegmentsAsync. Storleken validerar generiska vektordimensioner , och dess integreringstestinlärningar | 768- |dimensionella mediarekord och modalitetsfilter
Det standardsättet OnnxEmbeddingService förblir MiniLM-specifik och avfärdar en icke-384 konfigurationM SK2 En live EmbeddingGemma sökpfad behöver därför en separat IEmbeddingService adapter, eller en arbetare/ klientpar som exponerar dokument och query-encodring explicitt . inte släppa olika vikter in i BERT-adaptern eller blanda MiniLM-queries med EmbeddingGemma-punkter M SK4 Python-exemplet följer den publicerade API ; fulla EmbedingGemma modellen är inte part av den här artikeln
Ett gemensamt vektorsutrymme gör det möjligt att göra korsliga-motoriska rangeringar, inte automatiskt väl kalibreradeM SK2 Bedöma texten - till- bild , text MSC6 till - ljud och textMST8 till mst.MST9 videofrågan separat MST10 inklusive distraherer M st.11 Om du använder orelaterade specialiserade kodare Mst.12 spara separata samlingar eller namnge vektorrutor och sammanfoga deras resultatrangeringar istället för att jämföra okompatibla råresultat Mstr.13
Testa dragningskvalitet och korrekthet
Den semantic-sökningstestprojekt täcker tokenisering, sammanslagning , fönstrets gränserM SK2 ofullständiga vektorer , avlägsnande
dotnet test Mostlylucid.SemanticSearch.Test/Mostlylucid.SemanticSearch.Test.csproj
De riktiga testerna är opt-in. rikta dem mot en isolerad Qdrant instans och laddade tillgångar :
MINILM_TEST_MODEL=/absolute/path/all-MiniLM-L6-v2.onnx \
MINILM_TEST_VOCAB=/absolute/path/vocab.txt \
QDRANT_TEST_URL=http://localhost:6334 \
dotnet test Mostlylucid.SemanticSearch.Test/Mostlylucid.SemanticSearch.Test.csproj
För en autentiserad testinstance, också ställt QDRANT_TEST_READ_KEY och QDRANT_TEST_WRITE_KEY. Testen skapar och löser sin egen, unikt namnda samling . Never point integration tests at a collection containing your production data
Ett framgångsrikt röktest borde demonstrera mer än “o undantag ”:
- Embeddinger har 384 ändevärden och enhetens längdM SK1
- Den besläktade texten är högre än ett tydligt orelaterade exempel.
- innehållet bortom det första modellens fönster påverkar dess inbäddning.
- Omloppskällorna återskapar texten exakt.
- Filterar väljer de eligibla kandidaterna innan dokumentgruppenering.
- Oengagerade passeringsgenerationer är fortfarande osynliga, och reindexering tar bort föråldrade chunks.
- Ett färdigt skriv är omedelbart synligt för följande läsning.
- Förknippade resultat utesluter deras källkod post.
- Gamla-pipeline-vektorer är uteslutna även när de har samma dimension
- Att ändra en titel eller relevanta metadata ändrar fingeravtrycket i indexeringen.
- En misslyckad beroende kan skilja sig från ett riktigt tomt resultat.
Sedan sammanställ representativa frågor med meddelanden du tycker är relevanta. Inbegrip synonymer, exakta identifiseringar , fel meddelandenM SK3 korta frågorMska4 tvetydiga frågor och frågor utan användbar svarMske5 Belägg hur ofta relevanta meddelanden dyker upp i de första tio resultaten och hur mycket de första användbara resultaten är rankeradeMsko6 mät pMsek7 och p95 latens separat för inbädding, sök och display av databasenMksK10 datauppvakningMvsK11 inklusive kylangång och hållbar belastningMnsK12
För approximate sökningar , jämför ett prov med exakta sökningar också. Det skiljer problem i inbäddade representationer från kandidater som misslyckas med sökindexet
Var semantiskt sök behöver hjälp
Dense vektorer är användbara för parafraser. exakta felkoder , ovanliga paket namn och versionsträngar gynnar ofta lexisk sökning också Hybridsökning tar upp båda typerna av kandidater och kombinerar deras klassificeringar. Reciprokal klassificeringsfusion kombinerar klassificerade positioner utan att anta att lexisk poäng och kosine poäng betyder samma sak
A reranker kan sedan undersöka varje fråga– kandidatpar för att bestämma en liten kandidat noggrannare
Del 4b täcker gränssnittet och hybriden Del 5 följer integreringen i publicering och indexering. Self-Hosted Vector Databases with Qdrant.
Ett användbart söksystem bevarar beviset den hittade, :, passagen, ,, kontexten som gör det meningsfullt,,, och källan som läsaren kan kontrollera... Modelluppgraderingar och rikare medier kan sedan förbättra vad den hittar utan att göra det svårare att inspektera.