RAG-pipeline: kom i gang
Ingest, retrieval og generation med Liviates RAG-pipeline -- kvikstart for Python- og .NET-SDK'et.
Om RAG-pipelinen
Liviates RAG-pipeline (ingest, embedding, retrieval, rerank og valgfri generation) er tilgængelig via to officielle, open source SDK'er med samme metodesurface:
Alle kodeeksempler herunder findes i begge sprog.
Installation
pip install liviate-rag
dotnet add package Liviate.Rag
Få din API-nøgle
Både Python- og .NET-klienten skal bruge en Liviate API-nøgle — enten sendt direkte til klienten, eller sat som miljøvariablen LIVIATE_API_KEY. Nøglen oprettes i Liviate-konsollen:
Log ind på konsollen.

Gå til Inference → API Keys.

Klik Generate key, og vælg hvad nøglen skal have adgang til:
- Hvilke modeller den må kalde (fx
liviate/embeddingogliviate/reranktil selve RAG-pipelinen, plus en chatmodel hvis I brugerquery()/QueryAsync()til generation). Lad listen stå tom for at tillade alle modeller. - Om den har adgang til Vector Database-scopet, og i så fald hvilke collections (tom liste = alle collections).

- Hvilke modeller den må kalde (fx
Kopiér nøglen med det samme — den vises kun én gang.

Får du en fejl om at nøglen ikke må kalde en bestemt model, navngiver fejlbeskeden selv præcis hvilke modeller nøglen faktisk har adgang til — ret nøglens tilladelser i konsollen i stedet for at gætte.
Hurtig start ("Hello World")
Det mindste program der beviser at installation og API-nøgle virker — ingen collection, ingen modelnavn, intet andet at sætte op:
from liviate_rag import RAGClient
with RAGClient() as client: # læser LIVIATE_API_KEY fra miljøet
result = client.embed(["Hello, world!"])
print(f"Embedded 1 text into a {len(result.vectors[0])}-dimensional vector.")
print(f"Tokens used: {result.usage.tokens}")
using Liviate.Rag;
await using var client = new RagClient(); // læser LIVIATE_API_KEY fra miljøet
var result = await client.EmbedAsync(new[] { "Hello, world!" });
Console.WriteLine($"Embedded 1 text into a {result.Vectors[0].Count}-dimensional vector.");
Console.WriteLine($"Tokens used: {result.Usage.Tokens}");
Fuld pipeline: ingest, retrieve og query
Det næste skridt: læg indhold i en collection, hent den mest relevante kontekst til et spørgsmål, og lad en model generere et svar ud fra den kontekst.
1. Ingest
ingest()/IngestAsync() tager en fil, URL, tekststreng eller stream — og genkender selv hvilken type det er ud fra indholdet, aldrig ud fra filendelsen. En collection oprettes automatisk, første gang du ingester ind i et navn der ikke findes endnu; der er intet separat "opret collection først"-trin.
from liviate_rag import RAGClient
COLLECTION = "hotel-kirstine"
with RAGClient() as client:
result = client.ingest("handbook.pdf", collection=COLLECTION)
print(f"{result.chunks_created} chunk(s) oprettet")
using Liviate.Rag;
const string Collection = "hotel-kirstine";
await using var client = new RagClient();
var result = await client.IngestAsync("handbook.pdf", Collection);
Console.WriteLine($"{result.ChunksCreated} chunk(s) oprettet");
Understøttede filtyper: PDF (.pdf), Word (.docx), Markdown (.md), ren tekst (.txt), CSV (.csv), JSON (.json) og HTML (.html) — samt rå tekst og URL'er (en enkelt side hentes/scrapes automatisk). OCR/scannede billeder er bevidst ikke understøttet i v1; et sådant kald fejler eksplicit i stedet for at halvparse indholdet. Hel-site-crawling er heller ikke en del af SDK'et — crawl med jeres eget værktøj, og send den resulterende liste af URL'er til ingest()/IngestAsync(), som allerede kan tage en hel batch i ét kald.
Ingester I med en ikke-standard embed_model/embedModel, skal I foreløbig sende samme model eksplicit igen ved retrieval/query — backenden husker endnu ikke selv hvilken model en collection blev oprettet med, og et queryembedding fra en anden model end collection'ens giver enten støj eller et direkte dimensionsmismatch.
2. Kun ranked kontekst (uden generation)
Vil I selv kalde jeres egen LLM, kan I hente den rankede kontekst alene, uden at Liviate genererer et svar:
context = client.retrieve("Har I parkering?", collection=COLLECTION, top_k=5)
for source in context.sources:
print(f"({source.score:.3f}) {source.text}")
var context = await client.RetrieveAsync("Har I parkering?", Collection, topK: 5);
foreach (var source in context.Sources)
{
Console.WriteLine($"({source.Score:F3}) {source.Text}");
}
3. Query (retrieval + generation)
query()/QueryAsync() gør begge dele: henter kontekst og lader en model generere et svar ud fra den. Der er bevidst ingen standardmodel her — I navngiver altid selv den model der skal generere svaret:
result = client.query("Har I parkering?", collection=COLLECTION, model="anthropic/claude-sonnet-5")
print(result.answer)
print(result.sources)
print(result.usage)
print(result.timing)
var result = await client.QueryAsync("Har I parkering?", Collection, "anthropic/claude-sonnet-5");
Console.WriteLine(result.Answer);
Console.WriteLine(result.Usage);
Console.WriteLine(result.Timing);
Streaming svar
Til chatlignende brug kan query()/QueryAsync() streame svaret som det genereres, i stedet for at vente på det færdige svar:
for chunk in client.query("Har I parkering?", collection=COLLECTION, model="anthropic/claude-sonnet-5", stream=True):
print(chunk, end="", flush=True)
await foreach (var chunk in client.QueryStreamAsync("Har I parkering?", Collection, "anthropic/claude-sonnet-5"))
{
Console.Write(chunk);
}
Fjern indhold
Slet enten ved id (fx point_ids/PointIds fra et tidligere ingest-kald) eller ved en metadata-filter — præcis ét af de to skal angives:
client.delete(COLLECTION, ids=result.point_ids)
client.delete(COLLECTION, filter={"must": [...]})
await client.DeleteAsync(Collection, ids: result.PointIds);
await client.DeleteAsync(Collection, filter: new { must = new object[] { /* ... */ } });
Fejlhåndtering
Begge SDK'er skelner bevidst mellem to slags fejl:
- Fejl i kald/opsætning (en kilde
ingest()ikke kan klassificere,delete()kaldt med både eller ingen afids/filter) — kastes som Pythons indbyggedeValueErrorhhv. et almindeligtArgumentExceptioni .NET, aldrig som en Liviate-specifik exception. Det er fejl i den kaldende kode, ikke noget en backend-fejl kan forårsage. - Backend-/driftsfejl (dårligt svar fra API'et, timeout, ikke-understøttet filtype) — kastes altid som
LiviateError(Python) hhv.LiviateException(.NET) eller en underklasse deraf, uanset hvilken transport der fejlede:
| Python | .NET | Betydning |
|---|---|---|
LiviateError |
LiviateException |
Fælles basisklasse — fang denne for at ramme alle backend-/driftsfejl på én gang. |
RateLimitError |
RateLimitException |
HTTP 429. |
APIError |
— | Ethvert andet ikke-2xx-svar (kun Python; .NET-SDK'et samler disse under LiviateException direkte). |
UnsupportedFileType |
UnsupportedFileTypeException |
Filens indhold matcher ingen understøttet type. |
IngestTimeout |
IngestTimeoutException |
ingest(..., wait=True)/IngestAsync() overskred sin timeout. Prøv igen med wait=False/StartIngest() og vent på jobbet i stedet. |
ingest()/IngestAsync() på en batch af kilder fejler kun helt, hvis alle elementer i batchen fejler. Fejler nogle, men ikke alle, gennemføres kaldet stadig, og de fejlende elementer optræder i result.warnings.
Konfiguration
| Indstilling | Python (RAGClient(...)) |
.NET (RagClient(...)/RagClientOptions) |
Standard |
|---|---|---|---|
| API-nøgle | api_key= (ellers LIVIATE_API_KEY) |
apiKey: (ellers LIVIATE_API_KEY) |
— (påkrævet) |
| Gateway-URL | base_url= |
Options.BaseUrl |
https://liviate.com |
| Vector store-endpoint | (indstilles internt) | Options.ExchangeUrl |
https://console.liviate.com/api/tenancy/vectordb/exchange-token/ |
| Timeout | timeout= (pr. kald) |
Options.Timeout |
60 sek. (pipelinens samlede ingest-timeout er separat, se IngestTimeoutException ovenfor) |
Peger I base_url/BaseUrl på et andet miljø end standard, følger vector store-endpointet ikke automatisk med — de to bor på hver sin host også i produktion, så sæt dem eksplicit hver for sig, hvis begge skal ændres.