Draai het RAG-brein van Quivr op een aangepast OpenAI-compatibel endpoint.

Updated 2026-07-29

De LLMEndpointConfig van quivr-core neemt een veld llm_base_url. Houd de supplier op openai, zet llm_base_url op https://api.apisrouter.com/v1, geef één sleutel door, en elke brain.ask() genereert zijn antwoord via de gateway met elk catalogus-model-ID.

Snel antwoord: llm_base_url in LLMEndpointConfig.

Huidige Quivr is quivr-core, een Python RAG-bibliotheek, en zijn LLM-bekabeling is expliciet. LLMEndpointConfig draagt supplier (standaard openai), model, llm_base_url, en llm_api_key; LLMEndpoint.from_config() bouwt de daadwerkelijke client uit die velden, en voor de supplier openai is die client de ChatOpenAI van LangChain, gebouwd met je base URL. Zet llm_base_url op https://api.apisrouter.com/v1, zet model op elk catalogus-ID, en geef het endpoint aan je Brain. De sleutel kan komen uit het configveld of de omgeving: wanneer llm_api_key niet is ingesteld, lost quivr-core hem op vanuit een omgevingsvariabele genoemd naar de supplier, wat voor de supplier openai OPENAI_API_KEY is. Beide paden zijn upstream-gedrag, leesbaar in quivr_core/rag/entities/config.py en quivr_core/llm/llm_endpoint.py.

from quivr_core.llm import LLMEndpoint
from quivr_core.rag.entities.config import (
    DefaultModelSuppliers, LLMEndpointConfig)

llm = LLMEndpoint.from_config(LLMEndpointConfig(
    supplier=DefaultModelSuppliers.OPENAI,
    model="claude-sonnet-4-6",          # any catalog id
    llm_base_url="https://api.apisrouter.com/v1",
    llm_api_key=os.environ["APISROUTER_API_KEY"],
))

Wat Quivr nu is, en waar de LLM-slot zit.

Quivr (QuivrHQ op GitHub, ruim 39K sterren) begon als een volwaardige tweedebrein-applicatie en draaide om naar quivr-core: een opinionated RAG-bibliotheek die je in je eigen product embedt. Je voedt het bestanden, het parst en knipt ze, embedt de fragmenten in een vector store (standaard FAISS, PGVector ondersteund), en beantwoordt er vragen over via een configureerbare retrieval-workflow. Het Brain-object is de eenheid: Brain.from_files() neemt op, brain.ask() haalt op en genereert. Generatie is de enige stap die een chatmodel nodig heeft. De retrieval-workflow verzamelt context uit je documenten, en de LLMEndpoint die je hebt doorgegeven schrijft het gegronde antwoord. Dat endpoint wordt eenmalig gebouwd uit LLMEndpointConfig, dus de base-URL-beslissing wordt op constructiemoment genomen en geldt voor elke ask() op dat brein. Omdat ChatOpenAI het model-veld als platte string doorgeeft over /v1/chat/completions, kan het ID Claude, DeepSeek, GPT, of Gemini zijn wanneer het endpoint achter llm_base_url ze bedient. Eén eerlijke opmerking over de projectstatus: de repository is stil sinds midden 2025, dus behandel quivr-core als een stabiele bibliotheek in plaats van een snel bewegende. Het hier beschreven configoppervlak komt overeen met de laatste main-branch, en de stille geschiedenis betekent dat het waarschijnlijk niet onder je verandert; het betekent ook dat oude tutorials die de gepensioneerde full-stack-app beschrijven (backend .env-bestanden, een gehoste frontend) niet meer overeenkomen met de code.

Volledige instelling: een brein met een LLM via de gateway.

Het complete patroon geeft de geconfigureerde LLMEndpoint door aan Brain.from_files. Al het andere aan het brein (parsen, knippen, de FAISS-store, de retrieval-workflow) is onafhankelijk van het LLM-endpoint en behoudt zijn standaarden. Let op de embedder. Als je er geen doorgeeft, bouwt quivr-core de OpenAIEmbeddings van LangChain met zijn eigen standaarden, die authenticeert met OPENAI_API_KEY en het standaard OpenAI-endpoint target. Dat is een aparte client dan de chat-LLM: generatie via de gateway routeren verplaatst hem niet. Geef je eigen embedder door (een lokale sentence-transformers-wrapper, of elke LangChain Embeddings-instantie die je configureert) als je niet wilt dat de embeddinghelft van een OpenAI-account afhangt.

import os
from quivr_core import Brain
from quivr_core.llm import LLMEndpoint
from quivr_core.rag.entities.config import (
    DefaultModelSuppliers, LLMEndpointConfig)

llm = LLMEndpoint.from_config(LLMEndpointConfig(
    supplier=DefaultModelSuppliers.OPENAI,
    model="claude-sonnet-4-6",
    llm_base_url="https://api.apisrouter.com/v1",
    llm_api_key=os.environ["APISROUTER_API_KEY"],
    max_output_tokens=2048,
    temperature=0.3,
))

brain = Brain.from_files(
    name="team-docs",
    file_paths=["handbook.pdf", "runbook.md"],
    llm=llm,
    # embedder=...  # separate component; see note above
)

print(brain.ask("What is the on-call escalation policy?").answer)

Een generatiemodel kiezen voor RAG-antwoorden.

Kandidaten vergelijken is een wijziging op constructiemoment: bouw twee LLMEndpoints tegen dezelfde base URL, twee breinen over dezelfde bestanden, en diff de antwoorden op een vaste vragenset. Het gebruikslogboek per sleutel prijst elke kandidaatrun, dus kwaliteit per token wordt gemeten in plaats van bediscussieerd.

  • RAG-generatie is input-zwaar: opgehaalde fragmenten domineren de prompt. De prijs per inputtoken bepaalt de kosten van een antwoord, en daarom halveert een snel ID vaak de rekening zonder de retrievalkwaliteit aan te raken.
  • claude-sonnet-4-6 is de betrouwbare standaard voor gegronde antwoorden die de opgehaalde context respecteren en netjes afwijzen wanneer de documenten het antwoord niet bevatten.
  • High-volume ingebedde producten (het gestelde gebruiksgeval van Quivr) draaien goed op claude-haiku-4-5-20251001, deepseek-v4-flash, of gemini-3.5-flash voor de alledaagse vragenmix.
  • max_context_tokens in dezelfde config bepaalt hoeveel opgehaalde context de pipeline inpakt; het verhogen ervan gaat natuurlijk samen met langecontext-ID's en verhoogt de inputuitgaven evenredig.
  • Onbekende modelvoorvoegsels vallen terug op een generieke tokenizer voor budgettering, wat cosmetisch is; het verzoek zelf draagt je ID onveranderd naar het endpoint.

Betaal naar gebruik · onder officiële prijzen

Selected models are priced below official list prices. Exact input, output, cache, and per-request prices are shown for each model.

ModelOfficiële prijsOnze prijs
Claude Sonnet 4.6$3.00 / $15.00 per M$2.40 / $12.00 per M
Claude Haiku 4.5 20251001$1.00 / $5.00 per M$0.80 / $4.00 per M
GPT-5.4 mini$0.75 / $4.50 per M$0.60 / $3.60 per M
DeepSeek V4 Flash$0.14 / $0.28 per M$0.10 / $0.30 per M
Gemini 3.5 Flash$1.50 / $9.00 per M$1.20 / $7.20 per M

Correcties op veelvoorkomende Quivr-mythes.

Gidsen die in omloop zijn, beschrijven oppervlakken die Quivr niet meer heeft, dus het is de moeite waard om te stellen wat de huidige code daadwerkelijk doet. quivr-core is LangChain-gebaseerd, niet LiteLLM-gebaseerd. De supplier-enum selecteert een LangChain-chatklasse, en openai mapt naar ChatOpenAI met je llm_base_url. Als een tutorial je vertelt om een LiteLLM-proxy of api_base-instelling binnen Quivr te configureren, beschrijft het een oudere architectuur; het huidige veld is llm_base_url op LLMEndpointConfig. De full-stack-app is gepensioneerd. Instructies over een backend .env, Supabase-instelling, of een in-app modelkiezer verwijzen naar de pre-pivot-applicatie, die niet meer is wat de repository levert. Configuratie gebeurt nu in je Python-code (of je eigen app rond de bibliotheek). De sleutel-omgevingsvariabele is supplier-afgeleid. Voor supplier openai is dat OPENAI_API_KEY, zelfs wanneer het endpoint niet OpenAI is. Als je die naam liever niet overlaadt, geef dan expliciet llm_api_key door in de config, wat voorrang heeft en de omgeving schoon houdt. De embedder staat apart. Generatie-routering verplaatst embeddings niet; de standaardembedder is OpenAIEmbeddings met zijn eigen credentials. Beslis de twee helften onafhankelijk, en herembedding van een bestaande store is alleen nodig als je het embeddingmodel zelf verandert.

Wie routeert quivr-core via een gateway.

  • Productteams die RAG in hun apps embedden en het generatiemodel een configwaarde willen laten zijn, geen leveranciersverplichting die in de stack is gebakken.
  • Developers die veel breinen op verschillende kwaliteitsniveaus draaien: één sleutel, één endpoint, model-ID per brein.
  • Teams die Claude-kwaliteit gegronde antwoorden willen achter een OpenAI-gevormde config zonder een tweede SDK of provideraccount toe te voegen.
  • Bouwers die generatiemodellen benchmarken over een vast corpus, waar elke kandidaat één LLMEndpointConfig-wijziging is.
  • Developers zonder toegang tot de facturering van een bepaalde leverancier. Toegang op basis van opwaarderen zonder kaartvereiste verwijdert de aanmeldingsafhankelijkheid per provider.

Verifieer het endpoint en debug de eerste ask().

Bevestig dat de gateway je model vermeldt voordat je iets inneemt; het model-veld moet exact overeenkomen met een bediend ID. Fouten bij de eerste run zijn voorspelbaar. Een waarschuwing dat de API-sleutel voor supplier openai niet is ingesteld, betekent dat noch llm_api_key noch OPENAI_API_KEY zichtbaar was toen de config werd gebouwd; de waarschuwing gebeurt bij constructie, de fout bij de eerste ask(). Een 401 betekent dat de opgeloste sleutel niet bij het endpoint in llm_base_url hoort. Een model-not-found-fout is een tikfout in het ID tegen /v1/models. En een embedding-gerelateerde authenticatiefout tijdens Brain.from_files is de aparte standaardembedder die om zijn eigen OpenAI-credentials vraagt, wat geen enkele llm_base_url-instelling zal oplossen; geef een embedder door die je zelf beheert. Zodra antwoorden vloeien, toont de APIsRouter-console model per verzoek, tokenaantallen en uitgaven. Voor een bibliotheek die opgehaalde fragmenten in elke prompt inpakt, is het tokens-per-antwoord-getal op je echte corpus het cijfer dat je modelkeuze zou moeten sturen.

curl -s https://api.apisrouter.com/v1/models \
  -H "Authorization: Bearer $APISROUTER_API_KEY" | head -50

Veelgestelde vragen

Ondersteunt Quivr een aangepaste OpenAI-compatibele base URL?

Ja. De LLMEndpointConfig van quivr-core heeft een veld llm_base_url, en voor de supplier openai bouwt de bibliotheek de ChatOpenAI van LangChain tegen die URL. Zet hem op het gateway-endpoint en geef elk catalogus-model-ID door.

Is Quivr LiteLLM-gebaseerd?

Niet in de huidige codebase. quivr-core selecteert LangChain-chatklassen per supplier; de supplier openai gebruikt ChatOpenAI met je llm_base_url. Gidsen die een LiteLLM api_base binnen Quivr beschrijven, verwijzen naar een oudere architectuur.

Kan brain.ask() antwoorden met Claude- of DeepSeek-modellen?

Ja. Het model-veld wordt als platte string doorgegeven over /v1/chat/completions, dus claude-sonnet-4-6, deepseek-v4-flash, of elk ander ID dat het endpoint bedient werkt onder de supplier openai.

Welke omgevingsvariabele bevat de sleutel?

Wanneer llm_api_key niet is ingesteld in de config, leidt quivr-core de variabele af van de suppliernaam: OPENAI_API_KEY voor supplier openai. Een expliciete llm_api_key in LLMEndpointConfig heeft voorrang en voorkomt het overladen van die naam.

Verplaatst llm_base_url ook de embeddings?

Nee. De standaardembedder is een aparte OpenAIEmbeddings-client met zijn eigen credentials en endpoint. Routeer generatie via de gateway en geef je eigen embedder door als je de embeddinghelft ook van OpenAI wilt afhalen.

Wordt het Quivr-project nog onderhouden?

De repository is stil sinds midden 2025, dus behandel het als een stabiele bibliotheek in plaats van een actieve. Het hier gedocumenteerde llm_base_url-oppervlak komt overeen met de laatste main-branch, en de pre-pivot full-stack-app die het verving is gepensioneerd.