What retrieval types does Engram support?

Short answer: Vector ranks by embedding similarity, BM25 by keywords, hybrid combines both (the recommended default), and fetch returns a bounded memory by topic and scope without scoring.

Retrieval types decide how a search query matches stored memories via retrieval_config on memories.search. Hybrid is the recommended default for most agent prompts because operator language mixes exact tokens with fuzzy intent. Prefer vector alone for similarity-only recommendations; BM25 alone for brittle codes and SKUs strings. Fetch answers a different question: you already know which bounded memory you want—ConversationSummary or UserProfile—so you address by topic and scope rather than searching a neighborhood. Topic filters and limits compose with retrieval; start small for chat, widen for admin recall. If quality is weak, confirm commit, matching user_id and group, then try BM25 or hybrid before rewriting topics or raising limits.

Retrieval types in Weaviate Engram decide how a search query is matched against stored memories. Vector retrieval ranks by embedding similarity. BM25 retrieval ranks by keyword evidence. Hybrid retrieval combines both and is the recommended default for most agent prompts. Fetch retrieval is different. It returns a bounded memory by topic and scope without scoring the query for relevance. This chapter explains each mode, when to prefer one over another, how retrieval_config is set on memories.search, how topic filters compose with retrieval, and how Engram keeps recall useful without replaying an entire chat history.

Writing memories is only half the product. Agents feel intelligent when the right memory returns at the right time. The retrieval type is the dial that shapes that return.

What problem does retrieval_config solve?

After memories are committed, the next question is how to ask for them. A natural-language user message is not always looking for the same kind of match. Sometimes the agent needs conceptual neighbors, such as “what does this person like to drink” when the memory says “prefers specialty coffee.” Sometimes it needs an exact code, lot number, or product SKU. Sometimes it needs both signals at once.

Engram exposes that choice through retrieval_config. You can pass VectorRetrieval, BM25Retrieval, HybridRetrieval, or FetchRetrieval, each with an optional limit. You can also pass the string names "vector", "bm25", "hybrid", or "fetch" for defaults. Topic filters, group, user id, and properties still apply on top of the retrieval type.

Search results include a score when ranking is meaningful. That score helps you threshold what enters a prompt. Fetch is the exception. It addresses one known object rather than ranking a neighborhood.

When should you use vector or BM25 alone?

Vector search uses embeddings to find memories that mean something similar even when the words differ. It is strong for paraphrases, soft preferences, and conceptual questions. It is weaker when the user needs a rare exact token and that token’s neighbors drown it out.

BM25 is full-text keyword search. It shines when a specific term should dominate, such as a batch id, error code, or chemical name. It is predictable and transparent. It is weaker when the user asks with synonyms the memory never used.

Use vector alone when you are exploring fuzzy personal context. Use BM25 alone when missing an exact string is worse than missing a paraphrase. Most chat personalization paths should not stay on either extreme for long. They usually want hybrid.

Why is hybrid the recommended default?

Hybrid runs vector and BM25 together and fuses the rankings. You get resilience to wording changes and still reward exact matches. Engram’s docs recommend hybrid for general-purpose memory search for that reason. Tutorials that build chat loops typically pass HybridRetrieval(limit=5) before each model call.

That pattern pairs well with keeping only the last few raw turns in the prompt. Hybrid Engram search supplies older relevant facts. Recent messages handle deixis like “that” and “it.” The agent stays grounded without stuffing the full transcript into every request.

Limits still matter. A smaller limit keeps prompts lean. A larger limit helps when many weak memories might still contain a useful fragment. Start small for chat. Widen for admin recall or debugging. You can also narrow with a topics array so hybrid only ranks inside the categories that matter for the current tool or skill.

When is fetch the right retrieval type?

Fetch answers a different question. You already know which bounded memory you want. A ConversationSummary or UserProfile topic is the usual case. Fetch returns that memory by topic and scope. The query string is not used for ranking. You are addressing, not searching a neighborhood.

Enable the summary topic when you create the project if you need this path. Without it, search can fail with a topic-not-found condition. With it enabled, each add updates the single summary for that conversation scope, and fetch pulls the current document for the prompt at constant token cost.

Do not use fetch for open-ended preference lookup. Do not use hybrid when you truly need the one canonical profile object. Match the retrieval type to whether you are ranking candidates or loading a known singleton.

How do these modes look together in application code?

Here is a fresco restoration scaffold that stores notes, then compares keyword-sensitive recall with hybrid recall for the same bench.

import os
from engram import EngramClient, BM25Retrieval, HybridRetrieval, VectorRetrieval

client = EngramClient(api_key=os.environ["ENGRAM_API_KEY"])

scaffold = "fresco-scaffold-2"

run = client.memories.add(
    "Scaffold 2 is consolidating secco patches on the north aisle vault. "
    "Mix code FX-19 needs more acrylic dispersion than FX-11. "
    "Keep relative humidity near 55 percent while the lime putty cures.",
    user_id=scaffold,
    group="default",
)
client.runs.wait(run.run_id)

by_code = client.memories.search(
    query="FX-19",
    user_id=scaffold,
    group="default",
    retrieval_config=BM25Retrieval(limit=5),
)

by_meaning = client.memories.search(
    query="which consolidant mix for the north aisle vault patches",
    user_id=scaffold,
    group="default",
    retrieval_config=HybridRetrieval(limit=5),
)

semantic_only = client.memories.search(
    query="binder adjustment versus the older batch",
    user_id=scaffold,
    group="default",
    retrieval_config=VectorRetrieval(limit=5),
)

assert any("FX-19" in m.content for m in by_code)
assert any(
    "FX-19" in m.content or "humidity" in m.content.lower() or "secco" in m.content.lower()
    for m in by_meaning
)
assert semantic_only is not None

BM25 is the right first try for the mix code. Hybrid is the right default for the restorer’s natural question. Vector alone still helps when the question is paraphrased heavily. In production chat, start with hybrid and keep BM25 or fetch as specialized tools the agent can call when the task demands them.

Engram’s search layer sits on the same Weaviate-backed memory store the pipeline writes. You do not maintain a separate index for keywords and another for vectors. You choose a retrieval type per question. That is the practical payoff of treating memory as a managed service rather than a pile of prompt text.

If retrieval quality is weak, change one variable at a time. Confirm the memory was committed. Confirm the same user_id and group were used on write and read. Then try BM25 for exact tokens or hybrid for natural questions. Only after those checks should you rewrite topic descriptions or raise limits.

Our next chapter, How does asynchronous processing and run status work in Engram?, returns to the write path’s timing. You will see how run status, waiting, and eventual consistency fit beside these retrieval choices.