# Memory Retrieval Strategy Using BM25 + Vector Retrieval with RRF in TencentDB Agent‑Memory

> Explore the TencentDB Agent Memory retrieval strategy combining BM25 keyword search, vector semantic search, and RRF for superior relevance. Learn how hybrid retrieval enhances agent memory recall.

- Repository: [Tencent Cloud/TencentDB-Agent-Memory](https://github.com/TencentCloud/TencentDB-Agent-Memory)
- Tags: deep-dive
- Published: 2026-08-31

---

**The TencentDB-Agent-Memory hybrid retrieval pipeline combines BM25 keyword search with dense-vector semantic search, then merges results using Reciprocal Rank Fusion (RRF) to return the most relevant agent memories.**

TencentDB-Agent-Memory implements a sophisticated **memory retrieval strategy** that unifies lexical and semantic search. This approach ensures agents recall facts whether they match exact keywords or capture conceptual meaning. The implementation lives in the open-source `TencentCloud/TencentDB-Agent-Memory` repository, with core logic in TypeScript and SDKs available for Python and Node.js.

## How the Hybrid Retrieval Pipeline Works

The memory search tool executes a four-stage pipeline: capability detection, parallel retrieval, RRF merging, and post‑processing. Each stage is designed to maximize recall quality while maintaining low latency.

### Capability Detection: FT25 vs. Embeddings

When a `memory_search` request arrives, the system first probes which backends are available:

- `hasFts` — true when the store supports BM25 via SQLite **FTS5** (line 27 of [`memory-search.ts`](https://github.com/TencentCloud/TencentDB-Agent-Memory/blob/main/memory-search.ts))
- `hasEmbedding` — true when an `EmbeddingService` is configured (lines 26–27)

These flags determine which retrieval paths execute.

### Parallel BM25 and Vector Retrieval

When **both capabilities are present**, the engine launches two independent queries:

**BM25 (keyword) search**
- Builds an FTS5 query via `buildFtsQuery`
- Executes `vectorStore.searchL1Fts` (lines 87–101 in [`memory-search.ts`](https://github.com/TencentCloud/TencentDB-Agent-Memory/blob/main/memory-search.ts))

**Vector (embedding) search**
- Generates query embedding via `embeddingService.embed`
- Executes `vectorStore.searchL1Vector` (lines 124–132)

Both searches run concurrently, returning ranked lists ordered by their respective scoring functions.

## Reciprocal Rank Fusion (RRF) Implementation

The `rrfMergeL1` function combines the two ranked lists without requiring score normalization.

### RRF Score Formula

```typescript
// From MemoryCore/src/core/tools/memory-search.ts
const RRF_K = 60;  // lines 52–53 — follows original RRF paper

// For each item across all lists:
score += 1 / (RRF_K + rank + 1);  // lines 65–71, rank is 0‑based

```

The constant **RRF_K = 60** is taken directly from the original RRF research, providing a stabilization term that prevents top-ranked items from dominating.

### Merging and Re‑ranking

After computing summed RRF scores:

1. Items are sorted by accumulated RRF score (descending)
2. The original `score` field is replaced with the RRF score (lines 78–80)
3. The merged list proceeds to filtering

This rank-based approach inherently **upweights items appearing in both lists**, since they receive contributions from both BM25 and vector rankings.

## Fallback Strategies and Native Hybrid Shortcuts

The implementation includes graceful degradation:

| Scenario | Behavior | Strategy Value |
|----------|----------|----------------|
| BM25 only | Return FTS5 results directly | `"fts"` |
| Embedding only | Return vector results directly | `"embedding"` |
| Native hybrid endpoint | Short‑circuit to single call (lines 45–52) | Implementation-defined |

The native hybrid shortcut detects when the underlying vector store (e.g., TCVDB) implements dense + sparse + RRF internally, avoiding redundant client-side computation.

## Post‑Processing and Result Formatting

After RRF merging, additional filters apply:

- **Type filter** — restrict to specific memory types (person, org, fact, etc.)
- **Scene filter** — scope to relevant interaction contexts
- **Limit truncation** — trim to user‑specified `limit`
- **Response formatting** — `formatSearchResponse` produces human‑readable output (lines 88–104)

The final output is a concise string ready for LLM consumption, with RRF scores indicating relative relevance.

## Practical Usage Examples

### TypeScript SDK

```typescript
import { skillClient } from "tencentdb-agent-memory/v3";

async function recallFacts() {
  const result = await skillClient.searchMemory({
    query: "如何在 MySQL 中创建只读用户？",
    limit: 5,
    filter: { team_id: "team-123" },
  });

  console.log(result); // RRF‑merged BM25 + vector results
}
recallFacts();

```

### Python SDK

```python
from tencentdb_agent_memory.v3 import SkillClient

client = SkillClient()
resp = client.search_memory(
    query="What is the quota for a COS bucket?",
    limit=3,
    filter={"team_id": "team-xyz"},
)
print(resp)  # Human‑readable, RRF‑scored list

```

Both SDKs invoke the same backend pipeline transparently—you benefit from hybrid retrieval without manual orchestration.

## Key Source Files

| Component | File Path |
|-----------|-----------|
| Core search logic with RRF | [`MemoryCore/src/core/tools/memory-search.ts`](https://github.com/TencentCloud/TencentDB-Agent-Memory/blob/main/MemoryCore/src/core/tools/memory-search.ts) |
| RRF merge implementation (`rrfMergeL1`) | Lines 62–80 of above |
| BM25 sparse encoder | [`MemoryCore/src/core/store/bm25-local.ts`](https://github.com/TencentCloud/TencentDB-Agent-Memory/blob/main/MemoryCore/src/core/store/bm25-local.ts) |
| Vector store interface (native hybrid detection) | [`MemoryCore/src/core/store/tcvdb.ts`](https://github.com/TencentCloud/TencentDB-Agent-Memory/blob/main/MemoryCore/src/core/store/tcvdb.ts) |
| Python skill client | [`sdk/memory-core/python/tencentdb_agent_memory/v3/skill_client.py`](https://github.com/TencentCloud/TencentDB-Agent-Memory/blob/main/sdk/memory-core/python/tencentdb_agent_memory/v3/skill_client.py) |

## Summary

- **BM25 + vector retrieval** runs in parallel when both FTS5 and embeddings are available
- **RRF with K=60** merges ranks without score calibration, favoring items present in both result sets
- **Automatic fallback** to single-mode retrieval when only one backend is configured
- **Native hybrid shortcut** leverages database-native RRF when supported
- **Consistent SDK interface** across TypeScript and Python hides implementation complexity

## Frequently Asked Questions

### What is RRF and why use it for memory retrieval?

**Reciprocal Rank Fusion** is a rank-based combination method that scores items by their position across multiple ordered lists. In `TencentDB-Agent-Memory`, RRF avoids the problem of incompatible score scales between BM25 (unbounded relevance scores) and vector similarity (typically cosine or dot product). By using rank position with a stabilization constant (K=60), RRF produces a robust unified ranking without requiring training data.

### Does the system always use both BM25 and vector search?

No. The pipeline checks `hasFts` and `hasEmbedding` flags at runtime. If only BM25 is available, it returns FTS5 results with `strategy: "fts"`. If only embeddings are available, it returns vector results with `strategy: "embedding"`. The hybrid RRF merge executes only when both capabilities are present.

### How does RRF handle the same memory appearing in both search results?

The RRF formula `1/(K + rank + 1)` is additive across lists. An item ranked 2nd in BM25 and 5th in vector search receives a higher total score than an item ranked 10th in both. This property naturally surfaces memories with strong lexical and semantic relevance without requiring explicit intersection logic.

### Can I configure the RRF constant or retrieval weights?

The current implementation hardcodes `RRF_K = 60` following the original research paper (lines 52–53 of [`memory-search.ts`](https://github.com/TencentCloud/TencentDB-Agent-Memory/blob/main/memory-search.ts)). The repository does not expose weighting parameters for the fusion—scores are computed purely from rank positions. For stores with native hybrid support, the RRF computation may occur server-side with implementation-specific constants.