Semantic Search & Retrieval

+15 Mana ✨

Introduction

When an agent needs to recall information beyond the currently loaded daily logs, OpenClaw provides powerful semantic search through the memory_search tool. This tool combines vector similarity search with keyword matching to surface the most relevant memories. This lesson explores the hybrid search pipeline, MMR deduplication, and temporal decay.

Key Concepts

  • memory_search — the primary retrieval tool that performs hybrid semantic and keyword search across all memory files.
  • Hybrid Search — combines vector similarity scores with BM25 text matching scores using configurable weights.
  • MMR (Maximal Marginal Relevance) — a diversity algorithm (lambda 0.7) that reduces redundant results by penalising documents too similar to already-selected ones.
  • Temporal Decay — an exponential decay function with a 30-day half-life that favours recent memories over older ones.
  • memory_get — a targeted tool for reading a specific memory file when you know exactly which one you need.

Real World Context

Consider a developer assistant that has accumulated months of daily logs. When the user asks "How did we fix the authentication bug?", pure keyword search might miss entries that discuss "OAuth token refresh" without using the word "authentication". Pure vector search might surface semantically similar but irrelevant entries about "authorization policies". Hybrid search combines both approaches to find the most relevant result, and temporal decay ensures that the recent fix is ranked above a similar discussion from six months ago.

Deep Dive

The memory_search Tool

The memory_search tool is the agent's primary interface for recalling past information:

text
memory_search(query: "How to configure deployment")

Behind the scenes, this triggers a multi-stage retrieval pipeline. Before examining each stage, understand that the goal is to combine the precision of keyword matching with the recall of semantic understanding.

Hybrid Search Formula

OpenClaw computes a final relevance score by blending two signals:

text
finalScore = (vectorWeight × vectorScore) + (textWeight × textScore)

The vectorScore comes from embedding the query and comparing it against pre-computed embeddings of memory chunks using cosine similarity. The textScore comes from BM25, a classical information retrieval algorithm that scores documents based on term frequency and inverse document frequency.

After computing these scores, they are combined using the configured weights (which default to balanced values). This hybrid approach catches both semantically similar content and exact keyword matches.

MMR — Reducing Redundancy

After scoring, the results pass through Maximal Marginal Relevance with a lambda of 0.7:

text
MMR(d) = λ × Sim(d, query) - (1 - λ) × max(Sim(d, selected))

Before applying MMR, you might get five results that all discuss the same topic from slightly different angles. MMR addresses this by iteratively selecting results that are both relevant to the query (the first term) and diverse from already-selected results (the second term).

With lambda at 0.7, the algorithm weights relevance more heavily than diversity, ensuring that highly relevant results are not discarded just because they overlap with each other. The 0.3 diversity component is enough to prevent near-duplicate results from flooding the output.

Temporal Decay

All scored results are then adjusted by temporal decay:

text
decayFactor = e^(-λt)
# Where t is the age of the document and half-life is 30 days

This exponential decay means a memory from 30 days ago receives half the temporal boost of a memory from today. After 60 days, it receives one quarter, and so on.

Critically, evergreen files like MEMORY.md are exempt from temporal decay. Since MEMORY.md contains curated, always-relevant information, it would be counterproductive to penalise it for age.

memory_get — Targeted Retrieval

When the agent knows exactly which file it needs, it can bypass search entirely:

text
memory_get(file: "memory/2025-06-15.md")

This reads the specified file directly, which is faster and more precise than searching. It is useful when the agent has already identified the relevant file through a prior search or contextual reasoning.

Common Pitfalls

  • Relying solely on vector search — pure semantic search can miss exact keyword matches. The hybrid approach exists because neither method alone is sufficient.
  • Ignoring the 30-day half-life — if your agent needs to recall events from months ago with high priority, the default temporal decay may suppress those results. Consider adjusting decay settings for long-memory use cases.
  • Over-searching when memory_get suffices — if you know the exact file path, memory_get is faster and more reliable than memory_search. Reserve search for when you need discovery.

Best Practices

  • Write descriptive daily log entries — both vector and keyword search benefit from clear, detailed entries. Vague notes like "fixed bug" are hard to retrieve later.
  • Trust the hybrid pipeline — resist the urge to over-engineer query strings. The combination of vector similarity, BM25, MMR, and temporal decay handles most retrieval scenarios well out of the box.
  • Use memory_get for known files — when you already know which daily log or memory file contains the information, skip the search pipeline and read directly.

Summary

  • memory_search performs hybrid retrieval combining vector similarity and BM25 keyword scoring.
  • The formula finalScore = (vectorWeight × vectorScore) + (textWeight × textScore) blends both signals.
  • MMR with lambda 0.7 reduces redundant results while preserving relevance.
  • Temporal decay (30-day half-life) favours recent memories; evergreen files like MEMORY.md are exempt.
  • memory_get provides direct file access when the target is already known.
✓ Completed