Skip to content

Commit 51d7846

Browse files
committed
fix: batch missing search embeddings
1 parent a4f1b5b commit 51d7846

2 files changed

Lines changed: 49 additions & 4 deletions

File tree

src/memos/api/handlers/search_handler.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
_ENV_CONTEXT_RECALL = "MEMOS_DREAM_CONTEXT_RECALL"
3333
_ENV_CONTEXT_RECALL_TOP_K = "MEMOS_DREAM_CONTEXT_RECALL_TOP_K"
3434
_DEFAULT_CONTEXT_RECALL_TOP_K = 2
35+
_MISSING_EMBEDDING_BATCH_SIZE = 10
3536

3637

3738
def _env_enabled(name: str, default: str = "off") -> bool:
@@ -590,10 +591,13 @@ def _extract_embeddings(self, memories: list[dict[str, Any]]) -> list[list[float
590591
missing_documents.append(mem.get("memory", ""))
591592

592593
if missing_indices:
593-
computed = self.searcher.embedder.embed(missing_documents)
594-
for idx, embedding in zip(missing_indices, computed, strict=False):
595-
embeddings[idx] = embedding
596-
memories[idx]["metadata"]["embedding"] = embedding
594+
for start in range(0, len(missing_documents), _MISSING_EMBEDDING_BATCH_SIZE):
595+
batch_documents = missing_documents[start : start + _MISSING_EMBEDDING_BATCH_SIZE]
596+
batch_indices = missing_indices[start : start + _MISSING_EMBEDDING_BATCH_SIZE]
597+
computed = self.searcher.embedder.embed(batch_documents)
598+
for idx, embedding in zip(batch_indices, computed, strict=False):
599+
embeddings[idx] = embedding
600+
memories[idx]["metadata"]["embedding"] = embedding
597601

598602
return embeddings
599603

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
from memos.api.handlers.base_handler import HandlerDependencies
2+
from memos.api.handlers.search_handler import SearchHandler
3+
4+
5+
class BatchLimitedEmbedder:
6+
def __init__(self, *, limit: int):
7+
self.limit = limit
8+
self.calls: list[list[str]] = []
9+
10+
def embed(self, texts: list[str]) -> list[list[float]]:
11+
self.calls.append(list(texts))
12+
if len(texts) > self.limit:
13+
raise AssertionError(f"batch too large: {len(texts)}")
14+
return [[float(len(text)), 0.0] for text in texts]
15+
16+
17+
def _handler(embedder: BatchLimitedEmbedder) -> SearchHandler:
18+
searcher = type("FakeSearcher", (), {"embedder": embedder})()
19+
return SearchHandler(
20+
HandlerDependencies(
21+
naive_mem_cube=object(),
22+
mem_scheduler=object(),
23+
searcher=searcher,
24+
deepsearch_agent=object(),
25+
)
26+
)
27+
28+
29+
def test_extract_embeddings_batches_missing_documents():
30+
embedder = BatchLimitedEmbedder(limit=10)
31+
handler = _handler(embedder)
32+
memories = [
33+
{"memory": f"memory {idx}", "metadata": {}}
34+
for idx in range(25)
35+
]
36+
37+
embeddings = handler._extract_embeddings(memories)
38+
39+
assert [len(call) for call in embedder.calls] == [10, 10, 5]
40+
assert len(embeddings) == 25
41+
assert all(mem["metadata"]["embedding"] for mem in memories)

0 commit comments

Comments
 (0)