Agent Memory Engine
中文文档:README-zh.md
Architecture overview — see docs/architecture.md for the full breakdown.
Web dashboard — recall a query, browse recent memories, and watch live multi-agent sessions.
A long-term memory engine for coding agents (opencode / claude-code / any HTTP-speaking agent). Lets an agent "remember" past sessions across restarts: each new turn auto-recalls related history, each finished turn auto-stores a new memory.
Why? Coding agents forget — every new session starts blind, with past decisions, fixes, and conventions gone. This engine gives them cheap, persistent memory: each turn auto-recalls related history, each finished turn auto-stores a new memory.
Inspired by SJTU's MemRL paper, with an engineering tradeoff: borrow its two-stage retrieval + gating, drop the full RL (dialogue has no clean reward signal - see design.md).
Why it (differs from Mem0 / Chroma)
Most memory layers do pure semantic recall - nearest neighbors go straight into the prompt. This engine is different:
| Feature | What it buys you |
|---|---|
| Two-stage retrieval + gating | Wide KNN recall (15) → drop pure noise → rerank by score = α·strength + (1-α)·sim → top-k. No more "semantically-adjacent-but-useless" junk in your prompt. |
| Hybrid recall (vector + BM25) | Vector KNN for semantic match + FTS5 BM25 for keyword match, fused via RRF. Catches keyword hits the vector path alone would miss. Disable with AME_HYBRID_ENABLE=0. |
| Cross-encoder rerank (optional) | After hybrid fusion, a cross-encoder (bge-reranker-v2-m3) re-scores (query, candidate) pairs for precise relevance — the classic two-stage IR pattern (cheap wide recall → expensive precise rerank). Off by default; gracefully skipped if the model isn't loaded. Enable with AME_RERANKER_ENABLE=1. |
| Multi-agent collaboration | Sessions register their current task; siblings see "who's doing what" via GET /sessions/active. A fast-finishing agent can pick up a sibling's in-progress work without you writing a handoff doc. |
| LLM summarization | Optionally condenses each turn into a semantic sentence before embedding (better retrieval than raw dialogue). Falls back to raw text if no LLM is configured. |
| Ebbinghaus decay | Frequently-recalled memories decay slower (τ *= 1.5 per recall). Long-unused ones naturally fade. Use-it-or-lose-it, no RL training needed. |
| Single SQLite file | Structured data + vector index in one .db. No separate vector server, no extra process - just copy the file. |
| Agent & LLM agnostic | Plain HTTP. Default embedder is BGE-m3 (local, free); LLM summary uses any OpenAI-compatible endpoint (GLM / OpenAI / Ollama). |
Benchmark
A retrieval-quality ablation on 40 coding-agent memories + 24 hand-labeled
queries (graded relevance). Decay is neutralized so the numbers reflect pure
retrieval/reranking quality. Full method: benchmark/README.md.
| Condition | nDCG@5 | Recall@5 |
|---|---|---|
| pure-vector | 0.842 | 0.875 |
| hybrid (vector + BM25, RRF) | 0.868 | 0.896 |
| hybrid + cross-encoder rerank | 0.927 | 0.979 |
Each stage earns its keep:
| step | nDCG@5 gain | Recall@5 gain |
|---|---|---|
| +hybrid (RRF fusion) | +0.026 | +0.021 |
| +reranker (cross-encoder) | +0.059 | +0.083 |
The cross-encoder is the biggest single win — reading (query, candidate)
jointly beats encoding them separately, exactly as IR theory predicts.
Reproduced 2026-07-28 (BGE-m3 + bge-reranker-v2-m3). Run it yourself:
python benchmark/run_benchmark.py.
Quick start
Live demo (no install): https://ljftwq-dev.github.io/agent-memory-engine/demo/ Runs
all-MiniLM-L6-v2in your browser — real semantic recall over demo data.
From PyPI:
pip install agent-memory-engine-ljf
From source:
git clone https://github.com/ljftwq-dev/agent-memory-engine
cd agent-memory-engine
pip install -e ".[all]" # core + real embeddings + dev deps
cp .env.example .env # adjust if needed (defaults work out of the box)
python -m engine.server # start HTTP server (default :8765)
The engine works in two modes:
- No embedding model installed → automatic hash-fallback (deterministic,
reproducible, no real semantics). Great for trying the API, bad for recall
quality. To get real semantics install the
[embed]extra (BGE-m3). - BGE-m3 installed → full multilingual semantic embeddings.
Any agent talks to it over HTTP:
GET /health service status
GET /recall?q=&k=3 two-stage semantic recall (the core)
GET /recent?k=5 latest k memories (by time)
GET /search?q= keyword LIKE match
POST /remember store a memory {topic, summary, raw?, ...}
POST /forget run an Ebbinghaus decay pass {purge?, threshold?}
Want LLM summarization? Set AME_LLM_BASE_URL + AME_LLM_API_KEY in .env
(any OpenAI-compatible endpoint). Leave them empty and it's a pure retrieval
engine - still fully usable.
Seed some demo data and try it:
python examples/seed_demo.py
python -m engine.recall "vector search" -k 3
Repository layout
agent-memory-engine/
├── engine/ core engine
│ ├── config.py .env / env-var loader (no hardcoded paths)
│ ├── db.py SQLite + sqlite-vec schema
│ ├── embed.py BGE-m3 embedder + hash fallback
│ ├── recall.py two-stage retrieval + gating (core)
│ ├── reranker.py optional cross-encoder precision rerank
│ ├── remember.py store + optional LLM summary + dedup-merge
│ ├── forget.py Ebbinghaus decay loop (nightly cron)
│ └── server.py stdlib HTTP server
├── examples/
│ ├── seed_demo.py load generic demo data
│ ├── opencode/memory.ts reference opencode plugin (inject + recall + store)
│ └── claude-code/ .mcp.json + CLAUDE.md snippet (model-driven)
├── tests/
│ ├── conftest.py temp DB + forced hash fallback (CI-friendly)
│ ├── test_recall.py gating / dedup / decay / reinforcement tests
│ └── test_reranker.py rerank fallback / mock-promote tests
└── docs/
├── architecture.md four-layer memory model + module map
└── design.md why two-stage, why no full RL
How the design works (in one paragraph)
Problem: pure semantic match causes context pollution - "semantically close" ≠ "useful", so you shovel adjacent junk into the prompt. Solution (wide in, strict out):
- Gate only kills pure noise (distance > threshold). In hybrid mode, BM25 hits bypass the gate.
- Fuse + rerank decides relevance: in hybrid mode relevance = RRF-fused vector + BM25 rank; otherwise
sim = 1 - distance. If the cross-encoder reranker is on, it replaces that relevance with a precise(query, candidate)score. Finalscore = α·strength + (1-α)·relevance, take top-k. strengthis lightweight utility: Ebbinghausexp(-Δt/τ), where each recall doesτ *= 1.5. Frequently-recalled memories stay strong. This replaces MemRL's Q-value without needing reward data.- No full RL: dialogue has no clean reward signal; a fabricated proxy adds more noise than the Q-value is worth.
Full writeup: docs/design.md.
Configuration (.env)
| Key | Default | Meaning |
|---|---|---|
AME_DB_PATH |
~/.agent-memory/memory.db |
database path |
AME_EMBED_MODEL |
BAAI/bge-m3 |
embedding model (local & free) |
AME_EMBED_DIM |
1024 |
vector dim (must match the model) |
AME_LLM_BASE_URL |
(empty = off) | OpenAI-compatible API base |
AME_LLM_API_KEY |
(empty) | LLM key |
AME_LLM_MODEL |
glm-4-flash |
model name for summarization |
AME_RECALL_THRESHOLD |
0.9 |
distance gate (larger = looser) |
AME_RECALL_POOL |
15 |
stage-A wide recall count |
AME_ALPHA |
0.5 |
strength weight in rerank (0..1) |
AME_MIN_STRENGTH |
0.05 |
drop memories below this real-time strength |
AME_DEDUP_THRESHOLD |
0.45 |
on store, distance ≤ this merges into existing |
AME_HYBRID_ENABLE |
1 |
vector + BM25 hybrid recall (0 = vector only) |
AME_BM25_POOL |
15 |
stage-A BM25 recall count (hybrid mode) |
AME_RERANKER_ENABLE |
0 |
cross-encoder precision rerank after fusion (opt-in) |
AME_RERANKER_MODEL |
BAAI/bge-reranker-v2-m3 |
cross-encoder model (multilingual) |
AME_RERANKER_POOL |
0 |
how many gated candidates to rerank (0 = all) |
AME_BACKUP_ENABLE |
1 |
periodic safe snapshots of the memory DB |
AME_BACKUP_INTERVAL_HOURS |
6 |
how often to snapshot |
AME_BACKUP_KEEP |
5 |
keep only the newest N backups |
AME_SESSION_TIMEOUT_HOURS |
2 |
session goes stale after this long w/o heartbeat |
Tests
pip install -e ".[dev]"
pytest -q
Tests run on the hash-fallback embedder (no model download) so they're fast and CI-friendly. They cover: create, exact-match recall, gating, dedup-merge, Ebbinghaus decay, recall-time reinforcement, vector-dim consistency, hybrid RRF rescue/normalization, and the reranker fallback + mock-promote behavior.
License
MIT
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file agent_memory_engine_ljf-0.1.1.tar.gz.
File metadata
- Download URL: agent_memory_engine_ljf-0.1.1.tar.gz
- Upload date:
- Size: 39.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
481c616dbbd0a91b65db1096e2bfcbec6425720c8b4d94776361358d6593b575
|
|
| MD5 |
6d2ac445a44de5657c2dc10cd65beee5
|
|
| BLAKE2b-256 |
5f010b0d7af9d55b92fff962c75ca33ca4053cd41b8f1a76a1af622e08766232
|
File details
Details for the file agent_memory_engine_ljf-0.1.1-py3-none-any.whl.
File metadata
- Download URL: agent_memory_engine_ljf-0.1.1-py3-none-any.whl
- Upload date:
- Size: 37.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fece7c2fde8ab7e50686b841bbed4906569bc7587d8328f48800e8ec6704b7e9
|
|
| MD5 |
4ff2507a6aedb0d6cfd2348a092ff34d
|
|
| BLAKE2b-256 |
e27862f3e1f90765436c460d9cfbfe0ea48d37cf46439a2bb7dd40e66a131d82
|