# Search memories

You can retrieve stored memories using different search techniques.

::::accordion{title="All examples below use a connected client"}
See [Connect to Engram](../engram/quickstart.md#step-3-connect-to-engram) for how to instantiate one.

:::code-group{sync="languages"}
```python title="Python"
import os
from engram import EngramClient

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

```python title="Python (Async)"
import os
from engram import AsyncEngramClient

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

```bash title="cURL"
export ENGRAM_API_KEY="eng_..."
```
:::
::::

## Basic search

Provide a query and Engram returns the most relevant memories.

:::code-group{sync="languages"}
```python title="Python"
results = client.memories.search(
    query="What programming language does the user prefer?",
    user_id=test_user_id,
)

for memory in results:
    print(memory.content)
```

```pyindent title="Python (Async)"
results = await client.memories.search(
    query="What programming language does the user prefer?",
    user_id=test_user_id,
)

for memory in results:
    print(memory.content)
```

```bash title="cURL"
curl -X POST https://api.engram.weaviate.io/v1/memories/search \
  -H "Authorization: Bearer $ENGRAM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "What programming language does the user prefer?",
    "user_id": "user-uuid",
    "group": "default",
    "retrieval_config": {
      "retrieval_type": "hybrid",
      "limit": 5
    }
  }'
```
:::

```json
{
  "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](../engram-concepts/search.md) 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.

:::code-group{sync="languages"}
```python title="Python"
results = client.memories.search(
    query="What programming language does the user prefer?",
    user_id=test_user_id,
    retrieval_config=VectorRetrieval(limit=10),
)
```

```pyindent title="Python (Async)"
results = await client.memories.search(
    query="What programming language does the user prefer?",
    user_id=test_user_id,
    retrieval_config=VectorRetrieval(limit=10),
)
```

```bash title="cURL"
curl -X POST https://api.engram.weaviate.io/v1/memories/search \
  -H "Authorization: Bearer $ENGRAM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "What programming language does the user prefer?",
    "user_id": "user-uuid",
    "group": "default",
    "retrieval_config": {
      "retrieval_type": "vector",
      "limit": 10
    }
  }'
```
:::

### BM25 search

Full-text keyword search. Best for finding memories that contain specific terms.

:::code-group{sync="languages"}
```python title="Python"
results = client.memories.search(
    query="What programming language does the user prefer?",
    user_id=test_user_id,
    retrieval_config=BM25Retrieval(limit=10),
)
```

```pyindent title="Python (Async)"
results = await client.memories.search(
    query="What programming language does the user prefer?",
    user_id=test_user_id,
    retrieval_config=BM25Retrieval(limit=10),
)
```

```bash title="cURL"
curl -X POST https://api.engram.weaviate.io/v1/memories/search \
  -H "Authorization: Bearer $ENGRAM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "Python",
    "user_id": "user-uuid",
    "group": "default",
    "retrieval_config": {
      "retrieval_type": "bm25",
      "limit": 10
    }
  }'
```
:::

### Hybrid search

Combines vector and BM25 for the best of both approaches. This is the recommended retrieval type for most use cases.

:::code-group{sync="languages"}
```python title="Python"
results = client.memories.search(
    query="What programming language does the user prefer?",
    user_id=test_user_id,
    retrieval_config=HybridRetrieval(limit=10),
)
```

```pyindent title="Python (Async)"
results = await client.memories.search(
    query="What programming language does the user prefer?",
    user_id=test_user_id,
    retrieval_config=HybridRetrieval(limit=10),
)
```

```bash title="cURL"
curl -X POST https://api.engram.weaviate.io/v1/memories/search \
  -H "Authorization: Bearer $ENGRAM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "What programming language does the user prefer?",
    "user_id": "user-uuid",
    "group": "default",
    "retrieval_config": {
      "retrieval_type": "hybrid",
      "limit": 10
    }
  }'
```
:::

## Filter by topic

Restrict your search to specific [topics](../engram-concepts/topics.md) by providing a `topics` array.

:::code-group{sync="languages"}
```python title="Python"
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)
```

```pyindent title="Python (Async)"
results = await 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)
```

```bash title="cURL"
curl -X POST https://api.engram.weaviate.io/v1/memories/search \
  -H "Authorization: Bearer $ENGRAM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "user preferences",
    "topics": ["UserKnowledge"],
    "user_id": "user-uuid",
    "group": "default",
    "retrieval_config": {
      "retrieval_type": "hybrid",
      "limit": 10
    }
  }'
```
:::

If you omit `topics`, Engram searches across all topics in the group.

## Scoping

Search results are [scoped](../engram-concepts/scopes.md) 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 to `default`.

:::callout{intent="tip"}
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:

```python
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

Have a question or feedback? Here's how to reach us.

::::card-grid
:::card{title="Community Forum" href="https://forum.weaviate.io/c/support" icon="messages-square"}
Ask questions and connect with other developers on our **Community forum**.
:::

:::card{title="Support" href="/guides/support-overview" icon="life-buoy"}
Weaviate Cloud user or customer? Find the right channel on the **Support page**.
:::
::::

## Related pages

- [Agents](./agents-index.md)
- [AI-assisted Weaviate code generation](./ai-assisted-vibe-coding-index.md)
- [APIs](./apis-index.md)
- [Authorization and authentication](./authorization-and-authentication-index.md)
- [Benchmarks](./benchmarks-index.md)
- [Best practices](./best-practices-index.md)
- [Client libraries](./clients-index.md)
- [Client Libraries / SDKs](./client-libraries-index.md)
- [Cloud](./cloud-index.md)
- [Cloud account management](./cloud-account-management-index.md)

# Agent Instructions

This portal answers questions programmatically. To receive a synthesized,
source-cited answer instead of crawling page by page, append the `?ask=`
query parameter to any page URL on this site:

    /guides/quickstart?ask=how+do+I+authenticate

Optional parameters:

- `&goal=<what-you-are-trying-to-do>` steers the answer toward your
  objective (e.g. `&goal=write+a+python+client`).
- `&version=<label>` scopes the answer to a mounted version when the
  portal publishes more than one.

The response is `text/markdown`: the answer followed by a `# Sources` list
of the portal pages it was grounded in. Status codes are the contract:

- `200` — the answer; `402` — the portal owner’s plan or answer credits are
  exhausted (surface this to your operator; do NOT retry); `429` — you are
  rate-limited; back off for the `Retry-After` seconds; `503` — the answer
  lane is temporarily unavailable; fall back to crawling the `.md` pages.

For the full corpus map read `llms.txt` at the site root; for the tool
surface (search + page fetch as MCP tools) see `/mcp`.
