Skip to main content

ConvMemory

A lightweight reranker for long-term agent memory. Better memory retrieval, at a fraction of the cost of running a large cross-encoder over the pool.

CI PyPI License: MIT Python

ConvMemory recovering the answer a dense search missed, on a 680-memory pool

Real output from examples/demo_locomo.py on held-out conversations. Reproduce it in one command.

You already have a memory store and a vector search. ConvMemory is one layer after it:

        user query
            |
   vector / hybrid search        mem0 · LangChain · LlamaIndex · your own store
            |          top-k candidates
       ConvMemory                14 MB reranker, no cross-encoder over the pool
            |          reordered memory context
          agent

Keep your existing memory store. Add ConvMemory as the reranking layer. Drop-in adapters for mem0, LangChain, LlamaIndex and plain vector stores are about ten lines each.

Every mechanism claim here is backed by a five-seed retrained attribution study with paired-bootstrap intervals. The write-up of how that study was designed, and what it changed: I thought ConvMemory worked because of temporal reasoning. Five seeds proved me wrong.

Install

The reranker is a small torch model, and the encoder stack is optional — a store that already holds embeddings runs on the core install alone:

pip install "convmemory[encode]"   # text in, text out
pip install convmemory             # reranker only: numpy + torch

Three lines

from convmemory import ConvMemory

model = ConvMemory.from_pretrained("Purdy0228/ConvMemory-LoCoMo-MPNet")
results = model.rerank(query=query, memories=candidates, top_k=10)

memories is a list of {"id": ..., "text": ...} in the order your store keeps them. Each result carries rank, memory_id, score, and text.

Already have embeddings? Then you never need the encoder — this is the path the core install is built for, and it is roughly 50x faster because nothing is re-encoded:

results = model.rerank_embeddings(
    query_embedding=query_embedding,
    memory_embeddings=memory_embeddings,   # what your store already has
    memory_ids=memory_ids,
    memory_texts=memory_texts,
    query=query,
    top_k=10,
)

Why ConvMemory?

Retrieval quality vs reranking latency on LoCoMo: raw dense, ConvMemory v1, ConvMemory v1+v2, and mxbai-rerank-large-v1

Reranking a 500-candidate pool with a large cross-encoder means 500 transformer forward passes per query. ConvMemory scores the pool with a small learned model over embeddings you already have, and lands on the cost/quality frontier:

Method R@10 MRR ms/query
raw dense (no reranker) 0.5345 0.3254 <1
BGE-reranker-base, full pool 0.6967 0.5469 —
BGE-reranker-large, full pool 0.7621 0.6120 —
ConvMemory v1 0.7798 0.5824 16.8
ConvMemory v1 + v2 0.7798 0.6560 28.6
mxbai-rerank-large-v1, full pool 0.8080 0.6688 1960.2

ConvMemory v1 + v2 beats both BGE rerankers on Recall@10 and MRR, at 28.6 ms — against models that run a full cross-encoder pass over all 500 candidates. It reaches 98% of the mxbai MRR for 1/68th of the latency.

On a CPU box, or anywhere a query budget is measured in milliseconds, this is the reranking layer you can deploy today.

LoCoMo, 5 split seeds, top-500 pool, RTX 4080 SUPER, memory embeddings precomputed. BGE latency comes from this repo's LongMemEval harness (BGE-large, 556 ms/query) rather than the timed LoCoMo run. Complete results across six datasets: docs/BENCHMARKS.md.

See it on real data

examples/demo_locomo.py runs dense retrieval and dense + ConvMemory side by side on the held-out conversations of the released checkpoint's split:

python examples/demo_locomo.py --data data/locomo10.json --device cuda

Output on the five held-out conversations (937 questions, candidate pools of 369-680 memories):

metric          dense only    dense + ConvMemory
hit@5           464 (49.5%)          682 (72.8%)
hit@10          569 (60.7%)          769 (82.1%)

per-query time (memory embeddings precomputed, lexical signatures prewarmed):
  query encoding (shared by both paths): 8.05 ms
  dense scoring:                         0.26 ms
  ConvMemory reranking:                 18.53 ms

A single question from that run, pool of 680 memories:

Q: When did John take a trip to the Rocky Mountains?

dense only
  1.    John: Wow, that sounds awesome! How challenging was the trek through the Himalayas?
  2.    John: We went camping in the mountains and it was stunning! The air was so refreshing.
  3.    Tim: The book mentioned that the trek was tough but worth it, with challenging terrain...
  4.    John: I stumbled across this spot while hiking. The sound of that river was so soothing...
  5.    John: Wow, great view! Have you visited any other places?

dense + ConvMemory
  1. OK John: ... This was my Rocky Mountains trip last year and it was stunning. Seeing those
        mountains, fresh air - it makes you realize how incredible the world is.
  2.    John: We went camping in the mountains and it was stunning! The air was so refreshing.
  3.    Tim: I snapped that pic on my trip to the Smoky Mountains last year...

ConvMemory promotes the evidence turn to rank 1. Dense similarity alone fills the top of the list with memories that are about mountains.

Held-out conversations of the released checkpoint's split; LoCoMo is in-domain for this checkpoint. Get locomo10.json from snap-research/locomo.

Where it fits

ConvMemory is built for candidate pools of hundreds to thousands — the regime where dense recall slides from 0.90 to 0.55 on the LongMemEval stress setting, and where a cross-encoder over the whole pool prices itself out.

It is tuned for conversational and agent memory: conversations, user histories, agent traces, task logs, session notes. Results across six datasets, with the scope of each, are in docs/BENCHMARKS.md.

How it works

A lightweight learned reranker over fused dense + lexical features, with a small neighborhood window. Every feature is cheap once your embeddings exist, and there is no per-candidate transformer forward pass in the v1 path — that is where the 68x comes from.

That description is the one the evidence supports, and earning it took a five-seed retrained attribution study with paired-bootstrap intervals across question slices. The design of that study is the most useful thing this project can hand another ML engineer:

→ I thought ConvMemory worked because of temporal reasoning. Five seeds proved me wrong.

Slice tables, intervals, and protocol: docs/NEGATIVE_RESULTS.md.

Integrations

Keep your store, add the layer. Examples in examples/integrations/:

Example What it shows
basic_vector_store.py numpy vector store, no framework
langchain_retriever.py a LangChain-compatible retriever wrapper
llamaindex_postprocessor.py a LlamaIndex node postprocessor
mem0_rerank.py reranking mem0 search results
custom_agent.py a plain agent memory loop

Benchmark it on your own data

convmemory benchmark --queries queries.jsonl --memories memories.jsonl

Reports Recall@k, MRR and latency before and after ConvMemory on your memories, and writes a --json summary that is easy to paste into an issue. See docs/BENCHMARK_CLI.md for the file format.

Bring queries with labelled gold_ids. The "before" row is dense retrieval in the checkpoint's own embedding space — how to read the delta.

Whatever you measure, an issue with your numbers is welcome — reports from real memory stores are what shape the next checkpoint.

More layers

The v1 reranker above is the core. These are opt-in and off by default:

Layer What it adds Docs
v2 evidence reranker token-level rescoring of the protected v1 top-10; +0.073 MRR, recall-preserving EVIDENCE_RERANKER.md
v3 validity context surfaces the later update evidence alongside a memory VALIDITY_CONTEXT.md
Chinese models dual-space GTE retriever, BGE student, OPC-v3 validity CHINESE.md
CCGE-LA (alpha) conflict-aware editing of stale/current memory pairs CCGE_LA.md
Memory-MLA (experimental) prefix-protected recall expander MEMORY_MLA.md

Ask "where does Alice work now" and relevance alone will rank the superseded memory alongside the current one, because both are on topic. The v3 validity layer handles that case: it attaches the update evidence to a memory so the agent can reason about it.

Checkpoints

Checkpoint Hub
ConvMemory v1 (LoCoMo/MPNet) Purdy0228/ConvMemory-LoCoMo-MPNet
v2 evidence reranker Purdy0228/ConvMemory-v2-Evidence-Reranker
v3 validity context Purdy0228/ConvMemory-v3-Validity-Context
CCGE-LA alpha editor Purdy0228/ConvMemory-CCGE-LA
Chinese dual-space GTE Purdy0228/ConvMemory-ZH-DualSpace-GTE
Chinese OPC student (BGE) Purdy0228/ConvMemory-OPC-Student-BGE

The v1 checkpoint is also a GitHub release asset; offline setup instructions are in docs/MODEL_CARD.md. Checkpoints and embeddings must share an embedding model family and dimension.

API surface

Stable: ConvMemory.from_pretrained, .rerank, .retrieve, .expand_context, .rerank_embeddings, .encode, .prewarm_lexical.

Public alpha: .load_ccge_editor, .attach_ccge_editor, CCGELowAmplitudeEditor, build_ccge_features.

Research preview: context-expansion policies, cascade fusion with cross-encoder scoring, JSONL adapters for external datasets. See docs/MODULES.md.

Technical report

ConvMemory: A Lightweight Learned Memory Reranker, a Negative Attribution Result, and a Research-Preview Conflict Editor (May 2026)

Reproducibility: EVALUATION_PROTOCOL.md, MODEL_CARD.md, TRAINING.md. Raw datasets, checkpoints, embedding caches, and per-question CSVs live outside Git history to keep the repository light.

License

MIT

Metadata

Release files for convmemory 0.7.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for convmemory 0.7.0
File Size Uploaded
convmemory-0.7.0.tar.gz 66.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for convmemory 0.7.0
File Interpreter ABI Platform
convmemory-0.7.0-py3-none-any.whl Python 3 none any Details

Total release size: 122.7 kB

Release files / convmemory-0.7.0.tar.gz

Download URL convmemory-0.7.0.tar.gz
Size 66.6 kB
Tags Source
SHA-256 checksum
How to use checksums
142aea0b0863e0141ff8930efaa2f9d8f50d8025883fecdff9dbcae7a972475c
BLAKE2b-256 checksum
How to use checksums
e7ccd965e324aadb10e46a546b90c35ab9d1cbebf701bc6cf67fca703e5bed77
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.3

Release files / convmemory-0.7.0-py3-none-any.whl

Download URL convmemory-0.7.0-py3-none-any.whl
Size 56.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
f537db0e71f11b1f4d88d85a5e0ce03d605b591f6716eeed16de1ee06e6d1e29
BLAKE2b-256 checksum
How to use checksums
174df132e1218c357114b0988aae7217afddfcee15896982f18837b9b585b708
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.3

Release history Release notifications | RSS feed

This release

0.7.0 This release

2 release files

0.6.2

2 release files

0.6.0

2 release files

0.5.0

2 release files

0.4.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page