Cost-Aware Rag Caching: Reuse Answers for Identical Code Questions

Cost-Aware RAG Caches: Reuse Answers for Identical Code Questions
7 views

This guide covers cost-aware RAG caching with production-focused examples and trade-offs.

Teams ask the same “where is rate limiting enforced?” twenty times a day. Without a cache keyed on normalized question + repo SHA, you pay Bedrock twenty times for one answer that drifts the moment main moves. Cost-aware RAG caches cut spend without serving ghosts from deleted modules.
⚡ TL;DR: Normalize question text, hash with tree SHA (or package digest), store answer + citations + model ID in Redis/Dynamo with TTL bounded by merge rate. Invalidate on path touches cited in the answer. Never cache across tenants. Pair with LLM Cost Controls and Bedrock Knowledge Base Sync.

Cache key design — cost-aware RAG caching

typescript
import { createHash } from "node:crypto";

export function cacheKey(opts: {
  tenantId: string;
  repo: string;
  treeSha: string;
  question: string;
  modelId: string;
}) {
  const q = opts.question
    .toLowerCase()
    .replace(/[`*_]/g, "")
    .replace(/\s+/g, " ")
    .trim();
  const material = [opts.tenantId, opts.repo, opts.treeSha, opts.modelId, q].join("|");
  return createHash("sha256").update(material).digest("hex");
}

// ❌ Keying only on question → stale answers after refactors
// ❌ Omitting tenantId → cross-tenant leakage

DynamoDB item shape

typescript
type RagCacheItem = {
  pk: string; // tenant#repo
  sk: string; // key hash
  treeSha: string;
  answerMd: string;
  citations: { path: string; start: number; end: number }[];
  modelId: string;
  tokensSaved: number;
  expiresAt: number; // epoch seconds (TTL attribute)
};
On hit, increment tokensSaved metrics for FinOps dashboards (LLM Cost Controls).

Invalidation that tracks citations

typescript
export async function invalidateForPaths(repo: string, changed: string[]) {
  // Query GSIs of cached citations overlapping changed paths
  const items = await queryByCitedPaths(repo, changed);
  await Promise.all(items.map((i) => deleteItem(i)));
}

// Hook from git webhook after merge — same channel as KB sync
Webhook-driven freshness beats blind TTLs alone; see KB sync webhooks.

Stampede and single-flight

Monday standups produce identical questions. Use single-flight (one in-flight Bedrock call per key) so ten IDE clients do not fan out ten full RAG paths:
typescript
const inflight = new Map<string, Promise<RagAnswer>>();

export async function getOrRetrieve(key: string, produce: () => Promise<RagAnswer>) {
  const hit = await cache.get(key);
  if (hit) return hit;
  let p = inflight.get(key);
  if (!p) {
    p = produce().finally(() => inflight.delete(key));
    inflight.set(key, p);
  }
  const ans = await p;
  await cache.set(key, ans);
  return ans;
}

When not to cache

Question type Cache?
“Explain auth middleware” on fixed SHA Yes
“What is failing in my working tree?” No
“Draft a patch for this diff” No
On-call with Live Tail context No

Closing checklist

  • [ ] Key includes tenant, repo, tree SHA, model ID, normalized question
  • [ ] TTL + citation-path invalidation on merge
  • [ ] Metrics: hit rate, tokens saved, stale-serve incidents
  • [ ] No cache for working-tree or incident-contextual prompts
  • [ ] Encryption at rest; no secrets in cached answers (redact first)
  • [ ] Load test cache stampede on Monday mornings

Related reading

Last updated on September 11, 2026

Related: RAG Evaluation on Bedrock: Offline Suites Before You Trust Code Answers · Day 77: Caching RAG Answers Safely · Code RAG Rerankers: Cross-Encoders After Cheap Vector Recall

Watch: 100 Days of AI on YouTube

Short videos from CheatCoders, one AI engineering topic per day.

Open the playlist on YouTube · CheatCoders on YouTube

Deep-dive PDF

Get the expanded guide for this post — extra diagrams-style checklists, failure modes, and a production walkthrough. Free when you subscribe to CheatCoders.

Already subscribed? or open the subscribe page.


Discover more from CheatCoders

Subscribe to get the latest posts sent to your email.

Comments

No comments yet. Why don’t you start the discussion?

Leave a comment

No account needed. Name and email are optional.