← Back to research
Guides17 min readPublished 2026-07-22

RAG API Cost: How to Cut Embedding and Chat Bills (2026)

RAG API cost is usually driven by repeated context and chat output. Cache embeddings, cap retrieval, and route routine questions to cut monthly spend safely.

By LumeAPI Engineering Team

Gemini API hub → AI API Pricing →

Last verified: July 22, 2026

Short path: See the Gemini API hub, compare rates on AI API pricing, and read Gemini Pro vs Flash before changing RAG routes.

Your RAG API cost is probably not coming from one bad model choice. It is usually the result of three smaller mistakes multiplying together: embedding the same text repeatedly, sending too many retrieved chunks to the chat model, and using an expensive reasoning model for questions a smaller model could answer.

That is why a RAG pipeline can cost three times more than the original estimate even when traffic has barely changed. The fix is not “use a cheaper model everywhere.” Cache document embeddings, control the context budget, and route easy questions to a lower-cost model while preserving a stronger model for uncertain or high-risk answers.

Quick Answer

To lower RAG API cost without damaging answer quality:

  1. Embed documents once. Store the vector with a content hash and re-embed only changed chunks.
  2. Cache query embeddings where useful. Repeated FAQs, navigation questions, and identical support queries do not need a new embedding request every time.
  3. Limit retrieved context. Start with a small top-k, deduplicate overlapping chunks, and cap the final context by tokens.
  4. Measure input and output separately. Output tokens often cost several times more than input tokens.
  5. Use a cheaper chat tier for routine questions. For example, gemini-3-flash costs $0.25 per 1M input tokens and $1.50 per 1M output tokens through LumeAPI in the supplied catalog.
  6. Escalate only when retrieval confidence or answer validation says to.
  7. Do not assume a gateway replaces provider-native Batch jobs or prompt caching. See prompt caching for LLM APIs — those features can still be the better choice for bulk indexing or stable prefixes.

A practical starting rule: retrieve three to five chunks, cap the assembled context, use gemini-3-flash for routine grounded answers, and escalate uncertain cases to gemini-3.5-flash or a stronger model. Keep embeddings in a persistent vector store instead of generating them inside every request path.

In short

The biggest RAG bill mistake is treating every user query as a fresh full pipeline. Most production cost comes from repeated work: re-embedding unchanged text, re-sending redundant chunks, and paying premium output rates for routine answers. Fix that pipeline first; then use lower per-token rates through an OpenAI-compatible gateway such as LumeAPI to reduce the remaining chat spend.

What most guides get wrong

The common myth is: “RAG cost is mainly the embedding bill.”

That is often false once a system has a real document corpus. Initial indexing may create millions of embedding tokens, but it is usually a one-time or occasional operation. The recurring bill comes from query embeddings plus the chat completion that receives the retrieved context. If your application sends six 1,200-token chunks and asks for a 700-token answer on every request, the chat model is processing roughly 7,900 tokens before counting the system prompt, conversation history, and tool metadata.

A second mistake follows from the first: teams optimize the embedding model while leaving retrieval and generation untouched. Saving a few dollars during indexing does not help much if every support question sends the same 8,000-token policy manual to a premium model.

The useful unit is not “cost per document.” It is cost per answered query, split into indexing, retrieval, input context, output, retries, and cache hits.

A realistic production scenario

Maya’s five-person support platform uses Postgres, pgvector, a Python FastAPI service, and a direct OpenAI integration. Their first estimate assumed 40,000 monthly questions, one query embedding, four retrieved chunks, and a short answer.

The invoice was three times higher than expected by the second month.

The postmortem found three causes. A nightly ingestion job re-embedded every document because it used the file modification timestamp instead of a content hash. The retriever returned overlapping chunks from the same handbook page, so the prompt carried duplicate policy text. Finally, the application used the same premium chat model for “What is your refund window?” and “Can this contract clause be applied to an enterprise renewal?”

Maya’s team changed the ingestion key to a normalized-content hash, limited retrieval to distinct source sections, and logged token counts before the API call. They then sent routine questions to gemini-3-flash and escalated low-confidence answers — the same tier-routing pattern in our cheap Gemini API guide.

That distinction matters. Lowering rates cannot rescue a noisy prompt.

Expert take

RAG cost has a pipeline shape:

\[ \text{Monthly cost} = \text{indexing embeddings} + \text{query embeddings} + \text{chat input} + \text{chat output} + \text{retries} \]

Each term behaves differently.

Indexing embeddings are bursty. A full re-index after a parser change can be expensive, but it should not happen because a worker restarted. Use a stable document ID, normalized text, chunking version, and content hash. If any of those changes intentionally, re-index; otherwise reuse the vector.

Query embeddings are recurring. Cache exact or normalized repeated queries, but do not blindly cache every semantic variation. “How long can I return this?” and “What is the refund period?” may be equivalent to a human and different to a string cache. A semantic cache needs an evaluation set and a safe similarity threshold.

Chat input is where retrieval design becomes a billing issue. Increasing top-k from 5 to 12 may improve recall for a small benchmark while quietly tripling input tokens in production. Retrieval quality is not the same as context volume. Rerank candidates, remove near-duplicates, and pass only evidence that supports the answer.

Chat output deserves its own budget. A model that writes a 900-token explanation for a yes/no policy question can cost more than the retrieved context. Set a maximum output token limit, ask for a concise answer format, and expand only when the user asks for detail.

Retries multiply all of it. A timeout after the provider generated a response may leave your client unsure whether the request was billed. Blindly retrying a long RAG prompt is a particularly expensive failure mode. Use request IDs or application-level idempotency where supported, record attempts, and avoid retrying validation failures.

Do not follow the “route everything to the cheapest model” advice when the answer has legal, financial, medical, or operational consequences. A smaller model can be suitable for classification, extraction, or straightforward grounded responses, but your escalation policy should be based on measured failure cases. Also, provider-native Batch processing or prompt caching may beat a gateway for some workloads. LumeAPI is an independent third-party gateway, not OpenAI, Anthropic, or Google, and gateway routing does not guarantee identical behavior or access to every native API feature.

Where the bill actually comes from

Before changing models, add a cost ledger to each RAG request. At minimum, record:

  • request_id
  • tenant or project
  • query hash
  • embedding cache hit or miss
  • number of retrieved chunks
  • unique source IDs
  • input tokens
  • output tokens
  • model ID
  • retry count
  • answer validation result
  • escalation reason

A useful dashboard has four rates:

  • cost per indexed document
  • cost per query
  • cost per successful answer
  • cost per answer accepted by an evaluator or human

“Cost per query” can look good while “cost per successful answer” gets worse because cheap answers trigger follow-up questions or human review.

The most common hidden multipliers are:

Re-embedding unchanged content

A crawler often emits a new timestamp, UUID, or HTML wrapper on every run. If that value is part of the cache key, the system believes every chunk changed.

Use normalized text:

python
import hashlib
import re

def normalize_for_hash(text: str) -> str:
    text = text.replace("\r\n", "\n").strip()
    text = re.sub(r"[ \t]+", " ", text)
    return text

def content_hash(text: str, chunk_version: str = "v1") -> str:
    payload = f"{chunk_version}\n{normalize_for_hash(text)}"
    return hashlib.sha256(payload.encode("utf-8")).hexdigest()

Store the hash beside the vector. A parser or chunking change should deliberately change chunk_version; a routine crawl should not.

Sending retrieval results twice

Some applications include retrieved text in both a system message and a user message. Others pass the same chunk as a tool result and then quote it again in the conversation. The model sees both copies, and you pay for both.

Build the final prompt from one evidence representation. Keep source IDs and metadata compact. Do not include full HTML, navigation menus, or 40-line JSON records when the answer only needs a paragraph and a URL.

Using conversation history as a second knowledge base

A multi-turn support chat may contain the original retrieved chunks in every subsequent request. If the user asks three follow-ups, the same evidence can be billed four times.

Summarize history, retain source IDs, and rehydrate only the evidence needed for the current turn. If the provider supports prompt caching and the workload has a stable prefix, compare that native feature against gateway routing before implementing your own cache.

Cost math: a stated RAG scenario

Assume 40,000 monthly questions with this traffic shape:

  • one query embedding per question
  • 3,000 input tokens per chat request, including retrieved context
  • 500 output tokens per answer
  • no retries
  • no embedding price supplied in the live catalog
  • all requests use one model
  • prices below are per 1 million tokens

The monthly chat volume is:

  • Input: 40,000 × 3,000 = 120 million tokens
  • Output: 40,000 × 500 = 20 million tokens

The formula is:

\[ (\text{input millions} \times \text{input rate}) + (\text{output millions} \times \text{output rate}) \]

ModelOfficial input / output per 1MLumeAPI input / output per 1MOfficial monthly chat costLumeAPI monthly chat cost
gpt-5.6-terra$2.50 / $15.00$0.75 / $4.50$600$180
gpt-5.4-mini$0.75 / $4.50$0.225 / $1.35$180$54
claude-sonnet-4-6$3.00 / $15.00$1.50 / $7.50$660$330
gemini-3.5-flash$1.50 / $9.00$0.75 / $4.50$360$180
gemini-3-flash$0.50 / $3.00$0.25 / $1.50$120$60

These totals cover chat tokens only. They do not include embedding requests, vector storage, reranking, application hosting, or taxes. The catalog provided for this article contains text model rates but no embedding model rates, so do not pretend the table includes the embedding API cost.

The table still exposes the main decision. If quality testing shows that gemini-3-flash handles routine grounded questions, moving those questions from gpt-5.6-terra to that model changes the monthly chat estimate from $180 to $60 through LumeAPI for this scenario. That is a $120 difference before any context reduction.

Now reduce the prompt from 3,000 input tokens to 1,500 while keeping the 500-token output cap. At 40,000 requests:

  • Input: 60 million tokens
  • Output: 20 million tokens
  • gemini-3-flash through LumeAPI: (60 × $0.25) + (20 × $1.50) = $45

That second reduction comes from retrieval discipline, not model switching. If you route half the requests to gemini-3-flash and half to gpt-5.6-terra, with the original 3,000/500 token shape, the estimated LumeAPI chat total is:

  • 20,000 gemini-3-flash requests: $30
  • 20,000 gpt-5.6-terra requests: $90
  • Total: $120 per month

That is the kind of calculation your routing policy should make possible. “Use a cheaper model” is not a budget plan until you know which requests move and how many tokens each request carries.

For provider reference rates and native feature differences, check the OpenAI API pricing documentation and OpenAI embeddings guide. Provider pricing and feature availability can change, so use the live pages when you make a purchasing decision.

A practical cost-reduction sequence

1. Separate indexing from serving

Do not let a user request trigger an implicit full-document embedding operation. Index documents in a job with a queue, a content hash, and a status such as pending, indexed, or failed.

A document record should include:

text
document_id
source_uri
content_hash
chunk_version
embedding_model
embedding_dimensions
indexed_at

When the crawler sees the same hash and chunk version, it skips the embedding call. When only metadata changes, update metadata without replacing the vector.

This also makes cost attribution honest. Indexing costs belong to ingestion, not to the user who happened to ask a question while a re-index ran.

2. Cache query embeddings deliberately

Exact-query caching is cheap and safe for repeated traffic. Normalize case and whitespace, but be careful with language, tenant, permissions, and filters. A query vector generated for one tenant must not be reused to search another tenant’s corpus unless the vector is applied only within the correct access boundary.

For semantic query caching, start with a narrow use case:

  • repeated FAQ questions
  • known navigation intents
  • support macros
  • read-only public documentation

Do not semantic-cache account-specific questions or anything whose answer changes frequently. A stale retrieval result can be worse than a slightly higher embedding bill.

3. Reduce retrieval before reducing model quality

A good first pass is:

  • retrieve 8–12 candidates
  • rerank them if your stack supports it
  • keep 3–5 distinct source sections
  • remove chunks with high text overlap
  • enforce a token budget
  • include source IDs for citation and debugging

The exact numbers are starting points, not universal settings. Measure answer acceptance and groundedness as you lower context. If quality drops, inspect which chunks disappeared; do not simply restore top-k to 20.

Chunk size also affects the bill. Tiny chunks may require more retrieved items and create fragmented answers. Huge chunks send irrelevant text. Tune chunk size against retrieval recall and final prompt tokens, not against a generic recommendation.

4. Put a ceiling on output

A RAG answer should not be allowed to turn a short question into a memo by default. Use a concise response contract:

text
Answer using only the supplied sources.
Give the direct answer first.
Use no more than five bullet points unless the user asks for detail.
If the sources do not support the answer, say so.
Cite the source IDs used.

Set a model-specific output ceiling in the API request. Keep the ceiling high enough for legitimate cases, but low enough that a prompt bug cannot create thousands of output tokens.

5. Route by task and uncertainty

A two-tier policy is easier to operate than a six-model maze.

Send routine requests to gemini-3-flash when:

  • the query maps to a known FAQ or intent
  • retrieval returns strong, non-conflicting evidence
  • the answer is a short extraction or summary
  • no sensitive action is being authorized

Escalate to gemini-3.5-flash, gpt-5.6-terra, or another tested model when:

  • top retrieved results disagree
  • retrieval scores are weak
  • the user asks for multi-step reasoning
  • the answer needs careful comparison across documents
  • the first answer fails a citation or grounding check

Do not use output length alone as the escalation signal. A long answer can be easy to produce, while a one-sentence compliance answer can require careful reasoning.

OpenAI-compatible implementation

LumeAPI exposes an OpenAI-compatible Chat Completions endpoint at https://api.lumeapi.site/v1. The following Python example sends only the selected context, limits output, and records usage for later cost analysis.

It does not call an embedding endpoint because the supplied gateway facts guarantee Chat Completions, not embedding API parity. Keep your existing embedding provider or vector infrastructure unless the current LumeAPI documentation explicitly confirms the endpoint and model you need.

python
import os
from typing import Iterable

from openai import OpenAI

client = OpenAI(
    api_key=os.environ["LUMEAPI_KEY"],
    base_url="https://api.lumeapi.site/v1",
)

def build_context(chunks: Iterable[dict], max_chars: int = 18000) -> str:
    """Keep distinct source sections and cap prompt growth."""
    seen_sources = set()
    parts = []
    total = 0

    for chunk in chunks:
        source_id = chunk["source_id"]
        text = chunk["text"].strip()

        if source_id in seen_sources or not text:
            continue

        remaining = max_chars - total
        if remaining <= 0:
            break

        text = text[:remaining]
        parts.append(f"[{source_id}]\n{text}")
        seen_sources.add(source_id)
        total += len(text)

    return "\n\n".join(parts)

def answer_with_rag(question: str, chunks: list[dict], model: str) -> dict:
    context = build_context(chunks)

    response = client.chat.completions.create(
        model=model,
        temperature=0,
        max_tokens=500,
        messages=[
            {
                "role": "system",
                "content": (
                    "You answer questions using only the supplied sources. "
                    "Give the direct answer first. If the sources are insufficient, "
                    "say that clearly. Cite source IDs in brackets."
                ),
            },
            {
                "role": "user",
                "content": (
                    f"Sources:\n{context}\n\n"
                    f"Question: {question}"
                ),
            },
        ],
    )

    usage = response.usage
    return {
        "answer": response.choices[0].message.content,
        "model": model,
        "input_tokens": getattr(usage, "prompt_tokens", None),
        "output_tokens": getattr(usage, "completion_tokens", None),
    }

# Example policy: classify or score confidence before selecting this model.
result = answer_with_rag(
    question="What is the refund window?",
    chunks=[
        {
            "source_id": "billing-policy-12",
            "text": "Customers may request a refund within 30 days of purchase.",
        },
        {
            "source_id": "billing-faq-04",
            "text": "Refund requests are reviewed by the billing team.",
        },
    ],
    model="gemini-3-flash",
)

print(result)

The important cost controls are visible in the example:

  • the model is selected by policy, not hard-coded as the only tier
  • duplicate source IDs are removed
  • context has a hard ceiling
  • output is capped
  • usage is returned to your ledger

For a request that needs escalation, call the same function with a tested stronger model such as gemini-3.5-flash or gpt-5.6-terra. Do not silently change model IDs in production based on a marketing name; keep an allowlist tied to your evaluation results.

A simple curl smoke test can verify the base URL and authentication before you migrate application traffic:

bash
curl https://api.lumeapi.site/v1/chat/completions \
  -H "Authorization: Bearer $LUMEAPI_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gemini-3-flash",
    "temperature": 0,
    "max_tokens": 120,
    "messages": [
      {
        "role": "user",
        "content": "Answer briefly: what is 2 + 2?"
      }
    ]
  }'

LumeAPI is an independent third-party gateway. Test authentication, model behavior, error formats, streaming, tool calls, safety handling, and any structured-output requirements before moving a critical RAG workload. An OpenAI-compatible request shape does not mean every provider-native feature behaves identically.

A routing matrix that protects answer quality

Request typeDefault modelContext policyEscalate when
FAQ lookup with one strong sourcegemini-3-flash1–3 source sections, concise answerSource is missing or contradictory
Product documentation questiongemini-3.5-flash3–5 deduplicated chunksRetrieval confidence is low
Cross-document comparisongpt-5.6-terra or tested equivalentExplicit source grouping and citationsEvidence conflicts or answer validation fails
Account or policy actionStrongest tested modelMinimum necessary context, no broad historyAlways require application-level authorization
Bulk document indexingExisting embedding provider or native batch workflowHash-based incremental indexingParser or chunking version changes

The winner is not the cheapest model for every row. The winner is the lowest-cost model that passes your grounded-answer evaluation for that row.

Run evaluations using real anonymized questions, not only synthetic prompts. Include incomplete queries, contradictory documents, stale documents, and questions with no answer in the corpus. Record both quality and token usage. A model that is 30% cheaper but causes 10% more follow-up questions may not reduce the actual cost per resolved ticket.

What to measure after the change

Use a seven-day comparison if your traffic permits it, but do not present that as a benchmark for other systems. Compare your own baseline with your own revised pipeline.

Track:

  • median and p95 input tokens
  • median and p95 output tokens
  • embedding cache-hit rate
  • document re-embedding rate
  • retrieved chunk count
  • unique source count
  • escalation rate
  • retry rate
  • citation failure rate
  • user correction or follow-up rate
  • cost per successful answer

Set alerts for structural regressions:

  • input tokens per query rise by 25%
  • embedding cache misses exceed a threshold
  • output tokens hit the maximum frequently
  • retry count increases after a provider or gateway change
  • one tenant generates unusual context volume

A cost dashboard without token dimensions is just an invoice viewer. You need to know whether the increase came from traffic, model mix, context size, output length, or failure handling.

When a gateway is and is not the right lever

A compatible gateway can reduce the variable chat portion of a RAG bill when its catalog rates are lower than direct provider rates and your application mainly needs a compatible Chat Completions surface. In the supplied catalog, the listed GPT models are 70% below the stated official rates, while the listed Claude and Gemini models are 50% below those rates.

That does not make the gateway the correct answer for every part of RAG.

Keep provider-native infrastructure in the loop when you depend on:

  • Batch pricing or batch scheduling
  • provider-specific prompt caching
  • native embedding endpoints not exposed by the gateway
  • specialized safety or grounding controls
  • provider-specific tool, vision, or response-format behavior
  • contractual or data-residency requirements that require a direct relationship

The practical architecture can be mixed: keep indexing and embeddings where they work best, send compatible chat traffic through LumeAPI, and preserve a direct-provider fallback for features or incidents that require it. Test the failure path. Do not describe a mixed setup as automatic failover unless you have built and operated that failover yourself.

FAQ

What is the fastest way to reduce RAG API cost?

Reduce repeated chat context first. Log input tokens, remove duplicate retrieved chunks, cap the context, and limit output tokens. Then route routine grounded questions to a lower-cost model. Re-optimizing document embeddings will not help much if every query still sends the same oversized prompt.

Why is my RAG API expensive when the document collection is small?

A small collection can still create a large per-query bill if retrieval returns whole pages, conversation history is repeated, or the same evidence appears in multiple messages. Inspect tokens per request rather than document count. A 2,000-document corpus can be more expensive than a 20,000-document corpus if its prompts are poorly bounded.

How do I lower embedding API cost without hurting retrieval?

Hash normalized content and embed only changed chunks. Cache repeated query embeddings where the access boundary and freshness rules allow it. Avoid changing chunk size or embedding models casually: those changes invalidate the vector index and can trigger a full re-embed. Keep the embedding model and dimensions recorded with every vector.

Should I use gemini-3-flash for all RAG questions?

No. Use it as a low-cost default only for request classes that pass your grounded-answer tests. Escalate questions with weak retrieval, conflicting sources, complex comparisons, or consequential decisions. A cheaper first attempt is useful; a blanket model downgrade is not a quality strategy.

Can LumeAPI handle my embeddings as well as chat completions?

The supplied LumeAPI facts guarantee an OpenAI-compatible Chat Completions endpoint, not embedding endpoint parity or a specific embedding model. Keep your current embedding provider unless the current LumeAPI documentation confirms the embedding API, model, pricing, and behavior your pipeline needs.

Does reducing RAG context always reduce answer quality?

No, but removing relevant evidence can. Start by removing duplicates, boilerplate, stale chunks, and unrelated metadata. Then evaluate with real questions and citation checks. The target is not the smallest prompt; it is the smallest prompt that still contains the evidence required for a correct answer.

Next steps

  1. Add token and cache instrumentation. Record embedding hits, retrieved source IDs, input tokens, output tokens, model IDs, and retries for every request.
  2. Run a controlled routing test. Keep complex cases on the current model, send a defined routine subset to gemini-3-flash, and compare grounded-answer quality with cost per successful answer.
  3. Move compatible chat traffic only after feature checks. Test the gateway with staging credentials, verify your response and error handling, then review AI API pricing and the LLM cost reduction checklist before setting a production budget.

The core fix is architectural: stop paying to repeat work. Cache unchanged embeddings, keep retrieval narrow and distinct, cap generation, and use premium models only where they earn their place. Once those controls are in place, lower chat rates can make a measurable difference instead of hiding an inefficient RAG loop.