# RAG-kosten optimaliseren [[TOC]] ## Kostenstructuur van RAG Een RAG-systeem maakt kosten op twee momenten. **Indexeringskosten (eenmalig plus incrementeel):** - Embedding van alle document-chunks. - Opslag in een vectordatabase. **Query-kosten (per gebruikersvraag):** - Embedding van de gebruikersvraag. - Optioneel: LLM-aanroepen voor query-expansie en reranking. - LLM-aanroep voor het genereren van het antwoord. Bij een actief systeem domineren de query-kosten. De embedding-aanroep per query is relatief goedkoop. De LLM-aanroep voor generatie is verreweg de grootste post. :::info title="Kosteninschatting per query" Indicatieve kosten bij standaard RAG met Claude Haiku 4.5 (prijspeil juni 2026: $1,00 per 1M input-tokens, $5,00 per 1M output-tokens): - Embedding van de vraag: ongeveer $0,0001 - LLM-generatie (1500 input-tokens context plus 500 output-tokens): ongeveer $0,004 - Totaal: ongeveer $0,004 per query Bij 10.000 queries per dag komt dat neer op circa $40 per dag, dus ongeveer $1.200 per maand. Prijzen wijzigen regelmatig: reken na met de actuele tarieven van je provider. ::: ## Semantische caching De meest effectieve kostenreductie is herhalende vragen uit de cache beantwoorden in plaats van de volledige pipeline draaien. ```typescript class CostOptimizedRAG { private cache: SemanticCache; private cacheHits = 0; private cacheMisses = 0; async query(question: string): Promise { const embedding = await this.embedWithCost(question); const cached = await this.cache.get(question, embedding); if (cached) { this.cacheHits++; return cached; } this.cacheMisses++; const answer = await this.fullRAGPipeline(question, embedding); this.cache.set(question, embedding, answer, 7200); return answer; } get cacheHitRate(): number { const total = this.cacheHits + this.cacheMisses; return total > 0 ? this.cacheHits / total : 0; } } ``` Een cache-hit-rate van 30 tot 50 procent is realistisch voor systemen met herhalende vragen. Dat kan de kosten ongeveer halveren. :::tip title="Combineer met prompt caching" Naast semantische caching op antwoordniveau bieden providers prompt caching aan. Anthropic rekent voor gecachte input-tokens tot 90 procent minder. Als je systeem-prompt en context tussen queries stabiel zijn, levert dit extra besparing bovenop je eigen cache. ::: ## Tiered model-selectie Gebruik goedkopere modellen voor eenvoudige queries en duurdere modellen alleen waar dat echt nodig is. ```typescript async function tieredQuery(question: string, context: string): Promise { const complexity = await classifyQuestionComplexity(question); const modelConfig = { simple: { model: "claude-haiku-4-5", max_tokens: 512 }, medium: { model: "claude-haiku-4-5", max_tokens: 1024 }, complex: { model: "claude-opus-4-7", max_tokens: 2048 }, }[complexity]; const response = await anthropic.messages.create({ ...modelConfig, system: RAG_SYSTEM_PROMPT, messages: [{ role: "user", content: `Context: ${context} Vraag: ${question}` }], }); return response.content[0].type === "text" ? response.content[0].text : ""; } async function classifyQuestionComplexity(question: string): Promise<"simple" | "medium" | "complex"> { if (question.length < 50 && !question.includes("vergelijk") && !question.includes("analyseer")) { return "simple"; } if (question.includes("vergelijk") || question.includes("voor- en nadelen") || question.includes("wanneer")) { return "complex"; } return "medium"; } ``` Op prijspeil juni 2026 is Claude Haiku 4.5 (ongeveer $1,00 input en $5,00 output per 1M tokens) circa vijf keer goedkoper dan Claude Opus 4.7 (ongeveer $5,00 input en $25,00 output per 1M tokens). In de praktijk kan een meerderheid van de queries prima door Haiku worden afgehandeld, dus reserveer Opus voor de complexe gevallen. ## Embedding-kosten reduceren ```typescript async function batchEmbedWithDeduplication(texts: string[]): Promise> { const unique = new Set(texts); const toEmbed = Array.from(unique); const embeddings = await openai.embeddings.create({ model: "text-embedding-3-small", input: toEmbed, }); const embeddingMap = new Map(); toEmbed.forEach((text, i) => { embeddingMap.set(text, embeddings.data[i].embedding); }); return embeddingMap; } ``` Gebruik `text-embedding-3-small` ($0,02 per 1M tokens) in plaats van `text-embedding-3-large` ($0,13 per 1M tokens) als het kwaliteitsverschil voor jouw data acceptabel is. Dat scheelt ongeveer 85 procent in embedding-kosten. Toets dit met je RAGAS-scores voordat je het in productie zet. Met de batch-API liggen beide tarieven nog eens de helft lager. ## Context-lengte reduceren Minder tokens betekent lagere kosten. Stuur alleen de meest relevante chunks mee en kap de lengte af. ```typescript function buildMinimalContext( docs: { content: string; score: number }[], question: string, maxTokens = 2000 ): string { const sorted = [...docs].sort((a, b) => b.score - a.score).slice(0, 3); const parts = sorted.map(doc => { const words = doc.content.split(/\s+/); const maxWords = Math.floor(maxTokens / 3 / 1.3); return words.slice(0, maxWords).join(" "); }); return parts.join(" "); } ``` :::warn title="Snoei niet te agressief" Te weinig context verlaagt de antwoordkwaliteit en leidt tot meer vervolgvragen, wat per saldo juist duurder kan uitpakken. Meet altijd het effect op je RAGAS-scores en het aantal herformuleringen, niet alleen de tokenkosten. ::: ## Kostenmonitoring Houd per query bij wat je verbruikt, zodat je optimalisaties kunt onderbouwen met cijfers. ```typescript const COSTS = { "text-embedding-3-small": 0.02 / 1_000_000, "text-embedding-3-large": 0.13 / 1_000_000, "claude-haiku-4-5-input": 1.0 / 1_000_000, "claude-haiku-4-5-output": 5.0 / 1_000_000, "claude-opus-4-7-input": 5.0 / 1_000_000, "claude-opus-4-7-output": 25.0 / 1_000_000, }; function estimateQueryCost( questionTokens: number, contextTokens: number, responseTokens: number, model: string ): number { const embeddingCost = questionTokens * COSTS["text-embedding-3-small"]; const inputCost = (questionTokens + contextTokens) * COSTS[`${model}-input`]; const outputCost = responseTokens * COSTS[`${model}-output`]; return embeddingCost + inputCost + outputCost; } ``` De getallen hierboven zijn een momentopname (juni 2026). Werk de tarieven bij vanuit de officiele prijspagina van je provider, zodat je monitoring blijft kloppen. :::faq ### Wanneer mag ik een hogere cache-hit-rate verwachten? Bij klantenservice en interne helpdesk zijn veel vragen herhalend, dus daar ligt de hit-rate hoger. Bij onderzoeksvragen of analytische queries die vrijwel altijd uniek zijn, blijft de hit-rate laag. ### Lonen kleinere embedding-modellen voor productie? Voor de meeste use cases is `text-embedding-3-small` voldoende en het scheelt rond de 85 procent in embedding-kosten. Test het wel eerst met je RAGAS-benchmark voordat je overstapt. ### Hoe budgetteer ik RAG-kosten bij onbekend gebruik? Stel per gebruiker daglimieten in, bijvoorbeeld maximaal 50 queries per dag. Monitor je P95- en P99-tokenverbruik per query. Plan op basis van het aantal actieve gebruikers, niet het totale gebruikersbestand. ### Kan ik de vectordatabase gratis hosten? Chroma en pgvector kun je gratis self-hosted draaien. Je betaalt dan alleen voor server-resources. Bij managed diensten zoals Pinecone of Weaviate Cloud betaal je voor opslag en queries. ### Welke optimalisatie levert het meeste op? Begin bij de grootste post: de LLM-generatie. Semantische caching en tiered model-selectie raken die direct. Embedding- en opslagoptimalisaties leveren meestal minder op, omdat ze maar een klein deel van de query-kosten vormen. ### Hoe zit het met batch-verwerking? Voor indexering en niet-interactieve taken bieden zowel OpenAI als Anthropic een batch-API met ongeveer 50 procent korting. Interactieve queries lenen zich daar niet voor, maar het herindexeren van grote document-sets wel. :::