agent-memory-lab

May 13, 2026 · View on GitHub

Five memory patterns for LLM agents, implemented minimally and compared head-to-head.

Agent memory is usually discussed at two unhelpful extremes: "just stuff everything in the context" on one end, and dense research papers on the other. This repo sits in between — five small, readable implementations you can drop into your own agent, plus a tiny benchmark so you can see which one fits your use case before committing.

The five patterns

#PatternWhen to reach for itStatus
1Sliding windowShort tasks, cheapest, forgets anything older than N turns✅ v0
2Summary compressionLong tasks where you can afford one summarization pass per K turns✅ v0
3Vector retrievalLarge knowledge base; you need the relevant turns, not the recent turns✅ v0
4Hierarchical summaryVery long sessions; build a pyramid of summaries that degrade gracefully with age✅ v0
5Structured episodicMulti-session agents; store "episodes" as structured records, query by attribute✅ v0

Design principles

  • One file per pattern. Read it top to bottom in 5 minutes.
  • No external ML deps for the core pattern. Vector retrieval uses a pluggable embedder; everything else is stdlib.
  • Same interface for all patterns (add(msg), view() -> list[Message]) so swapping is one line.
  • Tests over docs. If a pattern needs paragraphs of prose to explain behavior, it's not minimal yet.

Benchmark

A 50-turn recall micro-bench (deterministic, stdlib-only, no network) is in bench/run.py. A target fact is injected at turn 3; each pattern is asked to surface it at the end. Latest run (bench/results/results.md):

patternrecall (turn-3 fact)final-context charsextra callback calls
sliding_windowno3030
summary_compressionno14517
hierarchical_summaryno22513
vector_retrievalyes30387 (one embed per archived msg)
structured_episodicyes3030

Reads as expected: the recency-only patterns drop the early fact; the two patterns with explicit recall (query() and recall_episodes()) surface it on demand. summary_compression keeps a longer rolling buffer but didn't preserve the specific token. hierarchical_summary compresses the most aggressively. The numbers are not a horse race — they make the tradeoff between recall, context cost, and per-turn callback work concrete.

python -m bench.run                            # all patterns, table to stdout
python -m bench.run --pattern sliding_window   # one pattern only
python -m bench.run --output bench/results/results.md
python -m bench.run --multi-seed 10            # variance across 10 filler shuffles
python -m bench.run --model claude-sonnet-4-6  # real Anthropic model as summarize_fn
                                                #   (requires ANTHROPIC_API_KEY + `pip install anthropic`)
                                                #   only affects summary_compression + hierarchical_summary

This is a micro-bench for legibility, not a ranking. It's not designed to argue any pattern is "best" — only to show the shape of each pattern's compromise. The default mock summarizers are deterministic and stdlib-only; --model swaps in a real LLM for the patterns that take a summarize_fn callback, letting you see whether the summarization quality (not just size) affects recall on your own corpora.

Quickstart

Single pattern (any of the five — same interface):

from patterns import SlidingWindow, Message

mem = SlidingWindow(window=20)
mem.add(Message(role="user", content="hello"))
mem.add(Message(role="assistant", content="hi"))
messages_for_llm = mem.view()

Composed (recent + topic recall — the production shape, see examples/compose.py):

from patterns import SlidingWindow, VectorRetrieval, Message
from patterns.vector_retrieval import _hash_bow_embed

recent = SlidingWindow(window=20)
archive = VectorRetrieval(embed=_hash_bow_embed, keep_recent=0)

def add(msg):
    recent.add(msg); archive.add(msg)

# add(...) for a long conversation, then:
context = recent.view()                          # what the LLM sees
extra   = archive.query("specific old fact", k=3)  # topical recall on demand

The two return the same Message shape, so concatenating context + extra is one line.

Installation

Zero runtime dependencies for the shipped patterns. Other patterns document their deps in their own docstrings.

git clone https://github.com/jimliu741523/agent-memory-lab
cd agent-memory-lab
python -m patterns.sliding_window        # runs the module's built-in demo
python -m patterns.summary_compression   # demo with a mock summarizer
python -m patterns.hierarchical_summary  # pyramid of rolling summaries demo
python -m patterns.vector_retrieval      # semantic recall with stdlib hash-BOW embedder
python -m patterns.structured_episodic   # typed episode records, recall by structured key match
python -m unittest discover tests -v     # stdlib-only tests for all patterns (26/26)

Roadmap

See patterns/README.md for per-pattern notes and bench/README.md for the benchmark plan.

Contributing

A new pattern is welcome if it:

  • Fits in one file, ~150 lines or less
  • Exposes the standard add / view interface
  • Comes with a docstring explaining when to use it and when not to
  • Has at least one test in tests/
  • agentic-anti-patterns catalogs agent failure modes; the patterns in this repo are concrete mitigations for:
  • self-evolving-agent — sibling experiment in agent self-improvement; shares the pluggable-callable design (this repo for summarize_fn, self-evolving-agent for ModelFn).

License

MIT.