Search memories
You can retrieve stored memories using different search techniques.
All examples below use a connected client
See Connect to Engram for how to instantiate one.
import os
from engram import EngramClient
client = EngramClient(api_key=os.environ["ENGRAM_API_KEY"])
Basic search
Provide a query and Engram returns the most relevant memories.
results = client.memories.search(
query="What programming language does the user prefer?",
user_id=test_user_id,
)
for memory in results:
print(memory.content)
{
"memories": [
{
"id": "memory-uuid",
"project_id": "project-uuid",
"user_id": "user-uuid",
"content": "The user works primarily in Python.",
"topic": "UserKnowledge",
"group": "default",
"created_at": "2025-01-01T00:00:00Z",
"updated_at": "2025-01-01T00:00:00Z",
"score": 0.89
}
],
"total": 1
}
Retrieval types
Set the retrieval type with retrieval_config. Pass a retrieval model — VectorRetrieval, BM25Retrieval, or HybridRetrieval — each with an optional limit. To use a type with its default settings, you can also pass its name as a string ("vector", "bm25", "hybrid", or "fetch").
Vector search
Pure semantic search using embeddings. Finds memories that are conceptually similar to your query, even without matching keywords.
results = client.memories.search(
query="What programming language does the user prefer?",
user_id=test_user_id,
retrieval_config=VectorRetrieval(limit=10),
)
BM25 search
Full-text keyword search. Best for finding memories that contain specific terms.
results = client.memories.search(
query="What programming language does the user prefer?",
user_id=test_user_id,
retrieval_config=BM25Retrieval(limit=10),
)
Hybrid search
Combines vector and BM25 for the best of both approaches. This is the recommended retrieval type for most use cases.
results = client.memories.search(
query="What programming language does the user prefer?",
user_id=test_user_id,
retrieval_config=HybridRetrieval(limit=10),
)
Filter by topic
Restrict your search to specific topics by providing a topics array.
results = client.memories.search(
query="user preferences",
topics=["UserKnowledge"],
user_id=test_user_id,
retrieval_config=HybridRetrieval(limit=10),
)
for memory in results:
print(memory.content)
If you omit topics, Engram searches across all topics in the group.
Scoping
Search results are scoped to match the parameters you provide:
user_id— Required for user-scoped topics. Only returns memories for this user.properties— Optional map of custom scope properties (e.g.{"conversation_id": "abc-123"}). Including a key narrows results; omitting a key searches across all values for that key.group— Search within this group. Defaults todefault.
For user-scoped topics, always include the user_id you used when storing the memories. For property-scoped topics, you can omit a property key to search across all values — for example, omit conversation_id to find a user's memories across all conversations at once.
Per-topic property filters
When searching multiple topics with different scope requirements, you can override the global properties filter on a per-topic basis. Pass an object instead of a string in the topics array:
from engram import Topic
results = client.memories.search(
query="...",
user_id="alice",
properties={"conversation_id": "abc-123"}, # global default
topics=[
"user_facts", # not conversation-scoped, ignores the filter
Topic(name="conversation_summary"), # uses the global filter
Topic(name="messages", properties={"conversation_id": None}), # clear filter — all conversations
],
)
A null value clears an inherited global filter for that topic only.
Questions and feedback
If you have any questions or feedback, let us know in the user forum.
