Brainby arc-labs/docs
Sdk pythonSearch
Python SDK

Search

Hybrid memory retrieval via recall.memories.search — query, filters, response shape, and tradeoffs against context.build().

POST/v1/searchAPI keystable
def search(
    self,
    query: str,
    limit: int = 10,
    *,
    memory_type: Optional[str] = None,
    min_confidence: Optional[float] = None,
) -> Any: ...

search is the primary read API. Internally it runs Recall's seven-stage read pipeline — query rewrite, parallel retrievers (semantic + BM25 + entity graph + temporal), Reciprocal Rank Fusion (RRF) at k=60, type filter, deduplication, and final ranking — and returns the top limit results.

Parameters

ParameterTypeRequired
querystrrequired

Natural-language search string. The server's query-rewrite stage normalises and (optionally) expands this before retrieval.

limitintoptional

Maximum number of memories to return. The server clamps to [1, 100]. Renamed from top_k in v0.3.0; the wire field on POST /v1/search is also now limit. The server still accepts the legacy top_k and topK aliases for unmigrated clients.

memory_typestroptional

Filter by memory category. One of 'fact', 'preference', 'event', 'entity', 'relation'. Sent as filters.memory_type on the wire.

min_confidencefloatoptional

Drop results whose confidence is below this threshold. Range [0.0, 1.0]. Sent as filters.min_confidence. Useful when you only want high-certainty memories influencing the agent's response.

Wire-shape

The Python SDK preserves snake_case field names on the wire:

{
  "query": "UI preferences",
  "limit": 5,
  "filters": {
    "memory_type": "preference",
    "min_confidence": 0.6
  }
}

The filters block is omitted entirely when neither memory_type nor min_confidence is provided.

Response shape

{
  "results": [
    {
      "id": "m_01HEX…",
      "content": "User prefers dark mode.",
      "memory_type": "preference",
      "confidence": 0.92,
      "score": 0.81,
      "tags": ["ui"],
      "created_at": "2026-04-30T12:34:56Z",

    }
  ],
  "trace_id": "trace_…"
}

Each hit carries the canonical Memory shape (see Types) plus a score field — the RRF-fused relevance score in [0, 1]. The trace_id ties the read to a span in the server's tracing pipeline.

Examples

from recall import Recall

recall = Recall(url='https://api.recall.arc-labs.ai', api_key='rcall_…')

hits = recall.memories.search(
    query='What does the user think about the UI?',
    limit=5,
    memory_type='preference',
    min_confidence=0.7,
)
for hit in hits['results']:
    print(f"{hit['confidence']:.2f}  {hit['content']}")
import asyncio
from recall import AsyncRecall

async def main():
    async with AsyncRecall(
        url='https://api.recall.arc-labs.ai',
        api_key='rcall_…',
    ) as recall:
        hits = await recall.memories.search(
            query='What does the user think about the UI?',
            limit=5,
            memory_type='preference',
            min_confidence=0.7,
        )
        for hit in hits['results']:
            print(f"{hit['confidence']:.2f}  {hit['content']}")

asyncio.run(main())

Pagination

Search returns a relevance-ranked list — there is no stable cursor for the next page. If you need to walk every memory matching a filter, use recall.memories.list(...) with cursor= instead.

In practice, when an agent needs more results, increase limit rather than paginating. The retrieval pipeline is optimised to surface the single most relevant page in one shot; deeper "page 2" queries on a relevance-ranked corpus rarely produce useful results.

Streaming variant

For real-time UI integration (showing pipeline stages, intermediate reranking, etc.) use the streaming variant on the pipelines resource:

for event in recall.pipelines.search_stream(query='UI preferences', limit=5):
    print(event.event, event.data)

See Streaming for the full event taxonomy. The non-streaming search() returns the same final result set in one shot — prefer it unless you need the intermediate stage events.

When to use search vs context.build

search() returns raw memory rows. context.build() returns a prompt-ready string assembled from the top-N memories under a token budget. Use search() when:

  • You're building a custom prompt assembly (your own template, your own ordering).
  • You want to display memories as evidence ("here's what we know about the user") rather than feed them to an LLM.
  • You need filter-based queries (only event memories from last week).

Use context.build() when:

  • You just need to inject memory into an LLM prompt and want Recall to pick the right shape and length.
  • You want token-budget enforcement.
  • You want recipe-driven formatting ('summary', 'bullet_points').

Type filter semantics

The five memory types — fact, preference, event, entity, relation — partition the memory space. Filtering by type is exact match (no prefix or wildcard). To search across multiple types, run the call twice with different filters and merge client-side, or omit the filter to search across all types.

The server's RRF fusion treats types uniformly during retrieval — a high-scoring relation will outrank a low-scoring fact in the unfiltered case. The type filter is applied after retrieval, so it doesn't change which candidates are surfaced; it only narrows the returned set.

Confidence threshold

min_confidence is a hard cutoff. The server drops every memory whose confidence field is below the threshold before returning. Reasonable defaults:

  • 0.5 — exclude only the very low-confidence noise.
  • 0.7 — keep only memories the extractor was reasonably sure about.
  • 0.9 — only show ground-truth-grade memories. Recall's grounding guard caps confidence at 0.9 for LLM-extracted memories without explicit evidence spans, so this threshold effectively requires a grounded memory.

Errors

CodeStatusRetry
RecallAuthError401/403fatal
Auth failed.
RecallValidationError422fatal

Invalid memory_type value, min_confidence outside [0,1], etc.

RecallRateLimitError429fatal
Rate limit exceeded.
RecallServerError5xxfatal
Server failure (retried).

Migration: top_k → limit

Pre-0.3.0 SDK calls used top_k. Update to limit:

hits = recall.memories.search(query='…', top_k=5)

# After (0.3.0+)
hits = recall.memories.search(query='…', limit=5)

The server still accepts top_k and topK for unmigrated clients, so old SDK code keeps working through the deprecation window. The Python SDK's search() no longer accepts top_k= as a kwarg — passing it will silently land in **_options and be ignored. Switch to limit.

Was this page helpful?

On this page