jonnify·redis /redis-patterns/data-modeling/vector-sets/rag-and-recommendations

R7.05.2 · dive 2

RAG and recommendations.

The applications of vector search: the five-step RAG pipeline, semantic caching that cuts LLM costs 40–60%, recommendations by element similarity, and kNN classification.

Every pattern here is a variation on VSIM: retrieve the nearest vectors to a query embedding, to an existing element, or to a threshold. Select a RAG pipeline step; the readout names its operation and the Redis command that drives it.

The five-step RAG pipeline. Select a step; the readout names the operation and the command.
Ingest chunk+embed VADD Query embed question Retrieve nearest VSIM Augment add context to prompt Generate LLM answers from context ingest once → query every request →retrieve → augment → generate
readout · Select a step. The RAG pipeline runs in two phases: ingest (once, offline) embeds documents and stores them with VADD; query (every request) embeds the question, VSIM retrieves the nearest chunks, and the LLM generates from the retrieved context.
§1

Retrieval-augmented generation (RAG)

vector-search-ai.md.txt · Retrieval-Augmented Generation

RAG enhances a Large Language Model by retrieving relevant context from your own data before generating a response. Traditional keyword search fails when a user phrases a question differently from the document — vector search finds semantic matches regardless of exact wording.

The two-phase structure:

  • Ingest (once): split documents into chunks, generate embeddings, store in the vector set with VADD plus JSON metadata (SETATTR).
  • Query (every request): embed the user’s question, run VSIM COUNT 5 to retrieve the most relevant chunks, include them in the LLM prompt as context, generate.
# Ingest — once, offline
VADD docs:index FP32 <embedding> "chunk:doc1:p1" SETATTR '{"doc": "manual.pdf", "page": 1}'
VADD docs:index FP32 <embedding> "chunk:doc1:p2" SETATTR '{"doc": "manual.pdf", "page": 2}'

# Query — every request
VSIM docs:index FP32 <query_embedding> COUNT 5 WITHSCORES
# → [("chunk:doc1:p2", 0.92), ("chunk:doc1:p1", 0.87), ...]

# With metadata filtering: restrict to a specific document
VSIM docs:index FP32 <query_embedding> COUNT 5 FILTER '.doc == "manual.pdf"'

The retrieved chunks become the context argument to the LLM call. The LLM answers from both its own parameters AND the retrieved context — “grounded” in your data rather than hallucinating from training alone.

RAG is two phases: ingest (embed and VADD) and query (VSIM for context, then generate). The vector set makes the retrieval step O(log N) regardless of how many documents you index.

§2

Semantic caching

vector-search-ai.md.txt · Semantic Caching

Traditional caches fail with natural language because different phrasings produce different cache keys:

  • “Who is the US President?”
  • “Current POTUS”
  • “Who leads the United States?”

These mean the same thing but hash to different strings. A semantic cache stores the embedding of each query alongside the LLM’s response. Before calling the LLM, run VSIM COUNT 1 WITHSCORES; if the top result scores above the threshold (typically 0.95), the two queries are semantically close enough that the cached response is valid:

# Check the semantic cache before calling the LLM
VSIM query:cache FP32 <query_embedding> COUNT 1 WITHSCORES
# → [("q:a9f3c", 0.97)]   cache HIT if score > 0.95
# → []                    or score <= 0.95 → cache MISS

# On miss: call LLM, store the result
VADD query:cache FP32 <query_embedding> query_id
SET  response:{query_id} {llm_response} EX 3600

The 0.95 threshold is a practical starting point: scores above it represent queries so semantically close that the same response applies. Adjust lower (0.90) for broader reuse, higher (0.98) for tighter matching. Semantic caching can reduce LLM API costs by 40–60% for applications with repetitive queries such as customer support or FAQ bots, where users ask the same question in different words.

A semantic cache replaces the string-hash key with a vector similarity check: any two queries whose embeddings score above the threshold share a response. One VSIM COUNT 1 per request; the LLM call only fires on a miss.

§3

Recommendations

vector-search-ai.md.txt · Recommendations

Find items similar to one a user has interacted with using VSIM ELE — the existing element serves as the query vector without the client needing to retrieve or transmit the vector itself:

# User liked "product:123" — find similar electronics in stock
VSIM products:embeddings ELE "product:123" COUNT 20 FILTER '.category == "electronics" and .in_stock == 1'

For a user who has liked multiple items, aggregate candidates across them and rank by summed score: items that are similar to many of the liked items rank higher than items similar to only one. The approach is a simple but effective signal for implicit-feedback recommendations (“items you interacted with” rather than explicit ratings).

A recommendation neighbourhood. The liked item is in red. Select a candidate; the readout names its similarity and why it ranks.
product:123 liked Item A score 0.91 Item B score 0.84 Item C score 0.76 Item D score 0.61 VSIM ELE "product:123" COUNT 4 WITHSCORES → A, B, C, D (ranked by score)
readout · Select a candidate. VSIM products:embeddings ELE "product:123" COUNT 4 WITHSCORES returns the four items nearest to the liked product, ranked by similarity score. The liked item is the query; no client-side vector retrieval needed.

Recommendations via VSIM ELE: the element you liked is the query vector. No client needs to store or send the vector — the set holds it. Combine multiple liked items by aggregating and summing scores across multiple VSIM ELE calls.

§4

Classification by k-nearest neighbours

vector-search-ai.md.txt · Classification

Store labeled examples in the vector set and classify new items by majority vote among the k nearest neighbours. No retraining, no separate classifier — this is zero-shot or few-shot classification from examples alone:

# Store labeled examples
VADD classifier FP32 <embedding> "spam:ex1"  SETATTR '{"label": "spam"}'
VADD classifier FP32 <embedding> "ham:ex1"   SETATTR '{"label": "ham"}'
VADD classifier FP32 <embedding> "spam:ex2"  SETATTR '{"label": "spam"}'

# Classify a new item — retrieve 5 nearest, vote
VSIM classifier FP32 <new_item_embedding> COUNT 5 WITHATTRIBS
# → [("spam:ex1", 0.91, {"label":"spam"}), ("spam:ex2", 0.88, {"label":"spam"}),
#     ("ham:ex1", 0.73, {"label":"ham"}), ...]
# majority vote: 2 spam vs 1 ham → "spam"

kNN classification scales to any categorical problem: sentiment, intent detection, topic labeling. Accuracy depends on the quality and coverage of the labeled examples — more examples per class and a well-calibrated embedding model improve results. New classes are added by inserting new labeled examples, no model retraining needed.

The trade versus a trained classifier: kNN is interpretable (you can see which examples influenced the prediction), zero-shot-extensible (add a class by adding examples), but slower than a fixed linear layer at inference time when the example set is large. For moderate example sets, VSIM COUNT 5 is fast enough.

kNN classification is majority vote among VSIM COUNT k results with their labels. Zero training required; new categories are a VADD away. Works well when embedding quality is high and you have at least a handful of examples per class.

§5

The codemojex note — honest absence

echo/apps/codemojex/lib · figure 16

codemojex is the worked consumer of the echo data layer — the BCS architecture’s Telegram emoji-guessing game. This note is transparent about what it ships and what it does not.

codemojex — no vector surfaceA grep of echo/apps/codemojex/lib finds zero occurrences of VADD, VSIM, HNSW, or any embedding operation. There is no Codemojex.* module for vectors, and — unlike the R7.04 bitmaps case, where infra/cm-bitmapist held a spike until its retirement — there is no planned vector spike: infra/ never held a cm-*vector* artifact.

A “rooms and games you might like” recommender would be a natural fit: embed each room’s metadata (game type, emoji set, difficulty, active players) and each player’s interaction history; at session start, run VSIM ELE <player_profile> COUNT 10 (or on Valkey, FT.SEARCH … KNN) to surface semantically similar rooms. Semantic caching would also apply to any AI-generated game summaries. But codemojex neither ships this nor has specced it — the note is a hypothetical illustration of where the pattern would land, not a description of something built.

the pattern

HNSW nearest-neighbour over embeddings — RAG, semantic cache, recommendations, classification via VSIM.

its application (forward-tense)

A codemojex recommender would embed rooms and player histories, find similar rooms via VSIM (Redis 8) or FT.SEARCH … KNN (Valkey-search). Ships zero vector code today.

The pattern is real; the application is forward-tense and honestly absent. A vector recommender is a well-defined extension to codemojex; it is not shipped, not planned in infra/, and not described beyond this note.

R7.05.1 · in this course

The HNSW graph

The graph structure, core commands, quantization trade-offs, and the engine note (Redis 8 native vs valkey-search module). the-hnsw-graph.

R7.05.3 · in this course

Filtered queries

Hybrid search: attach JSON metadata and combine vector similarity with structured predicates in one VSIM FILTER call. filtered-queries.

§6

References

sources · related

Sources

Related in this course