How it works

Check memory.
Think on novelty.
Never trust blindly.

Three mechanisms, each tested. This page mirrors the implementation in reflex/ — not a metaphor.

1 · The reflex check (<10ms)

Embed → vector search → calibrated score → gate.

Agent requestany languageREFLEX CHECKembed + search + score<10msSERVE FROM MEMORY~0–50ms · ₹0 · 0 LLM callsscore ≥ 0.85LLM (System 2)OpenAI · Claude · Gemini · Ollama…novelty onlyDISTILL → SAVEconfidence 0.8 · TTL inferrednext time: System 1
score = 0.6·similarity        # how close is this situation?
      + 0.2·hit_consistency   # has this reflex been right before?
      + 0.1·recency           # when was it last verified?
      − 0.5·correction_rate   # how often was it overruled?

score ≥ 0.85 → reflex      # pure memory, zero LLM calls
0.65 – 0.85  → reverify     # memory + background re-check
score < 0.65 → llm       # novel: think, distill, save
POST /ask  {"message": "refund??", "explain": true}

{
  "answer": "Your refund is being processed…",
  "source": "reflex",
  "similarity": 0.98,          # why this memory matched
  "matched_situation": "hii what status refund",
  "expanded_from": "Hii what is status for my refund",  # follow-up trail
  "threshold": 0.85
}

2 · Memory that corrects itself

👎 buries mistakes

A thumbs-down drops confidence 0.08 and counts a correction. ~3 reports push any reflex below the band — the next ask goes back to the LLM, which re-learns into the same record.

TTL is a hard wall

Processing / ETA / status answers auto-expire in 1 day; stable FAQs live 30. Expired memory is never served — it re-thinks instead.

Verification loop

Every 24h, stale reflexes are re-asked to the LLM: CONFIRM bumps the timestamp, CONFLICT slashes confidence. Run it manually: POST /verify/run.

3 · Follow-ups resolve like a human would

Day 1: “Hii what is status for my refund” → Day 2: “refund??” → same answer. Single-token queries expand from your last message (persistent, restart-proof); no history, no expansion — safe miss instead.

Try it yourself

4 · Ask twice. Watch the flip.

First ask thinks (LLM badge). Same ask again — memory answers, ₹0 (REFLEX badge). Needs a running server.

CUSTOMER SUPPORT BOTS
When will my refund arrive?¿Dónde está mi entrega?Cancel my order, please
TICKET TRIAGE & ROUTING
Route this: charged twice, need billing helpWo ist meine Rückerstattung?Delivery is late, where is my package?
VOICE AGENTS & LIVE CHAT
Refund status?Cancel orderMy delivery?
Your answer lands here — with the badge that proves where it came from.

Live demo — free server, so the first question can take ~30 seconds to wake up. After that, answers are instant.

Try it in 5 minutes
Objections, answered

5 · “Isn’t this just RAG?”

The two objections every engineer raises — with the exact reason they miss the point.

Isn’t this just RAG?

RAG is retrieval-augmented generation: every request retrieves chunks, stuffs them into a prompt, and the LLM generates an answer — a call per request, forever. Memflex is a memory, not generation: the LLM answers once (the miss), the finished answer is distilled and stored, and every repeat is served verbatim from SQLite with zero LLM calls — the provider is never even instantiated (reflex/api/routes.py). If there were no LLM step at all, it would be plain vector search; the LLM is amortized to one call per distinct question, not removed.

Doesn’t the LLM’s KV / prompt cache already do this?

No — they operate on different layers, and only one of them eliminates the call.

KV / prompt cacheMemflex
Match typeToken-exact prefix — change one word, language or phrasing = missSemantic — “Refund kab aayega?” and “When will my refund arrive?” hit the same memory
LLM callStill happens every request (network RTT + rate limits consumed)Never instantiated on a hit — 0 calls
Output tokensGenerated at full price every time (the expensive half)Zero — the stored answer returns as-is
LifetimeMinutes to hours; provider evicts at willDays to months, TTL-controlled, in your own SQLite file
ScopeOne continuing conversation (prefix must be identical)Any user, any conversation, cross-session, persistent
LatencyHundreds of ms (prefill is cheaper, still a full round trip)~0–50ms served from local memory

Prompt caching makes the same LLM call cheaper; Memflex eliminates the call. They’re complements — use both.

But the embedding model runs on every query anyway, right?

Yes — and that’s exactly the point. Retrieval needs a query vector, so the embedder runs on every ask. It’s local and tiny (~1ms, or keyless hashing in CI) versus an LLM call. Running an embedder is what makes it a memory/cache layer — the same thing GPTCache, Mem0 and every semantic cache do. Embedding is the retrieval half; it doesn’t make the system RAG, because the “generation” half is skipped entirely on hits.

So when does the LLM run?

Only on novelty: a question memory has never confidently seen. The answer is then distilled into a reflex, so the next time it’s pure memory. Repeat-heavy traffic (support bots, voice agents, FAQs) drifts past 70% memory-served quickly — see the comparison and GET /metrics on your own server.