DEV Community

Omer Hochman
Omer Hochman

Posted on • Originally published at nlqdb.com

Zep gives my agent perfect recall. It still can't answer "average per group" about its own memory.

Originally published at nlqdb.com/blog

If you've wired up Zep you know the pitch: it's the Context Lake — a temporal knowledge graph (Graphiti, 27k+ stars) that stores every fact your agent learns as a node with a validity window, resolves entities, and hands back the most relevant facts at query time. For recall it's genuinely good, and it publishes benchmarks (LongMemEval, DMR) to prove it.

But we kept hitting the same wall. Once the agent had logged a few hundred things, we wanted to ask questions about the memory, not retrieve from it:

  • "Top 10 topics I logged this month, ranked by count."
  • "Average deal size per stage for enterprise customers."

A knowledge graph has no query planner. It returns relevant facts and hopes the LLM does the arithmetic — which is a hallucination generator, not a GROUP BY.

The honest split (the full side-by-side lives at nlqdb vs Zep): Zep wins on temporal validity, entity resolution, and vector recall over conversation. nlqdb wins when the agent needs to aggregate its memory — it's a real Postgres the agent provisions and queries in English, so GROUP BY / JOIN / HAVING actually work. They compose: Zep the recall layer, nlqdb the analytical store. Pick the one that matches the question you actually need answered.

(Landscape facts verified 2026-06-19; both products' weaknesses are in the comparison, not just ours.)

Top comments (1)

Collapse
 
mads_hansen_27b33ebfee4c9 profile image
Mads Hansen

The retrieval-versus-computation split is useful, but “a knowledge graph has no query planner” is broader than necessary. Graph databases can aggregate when the query surface exposes Cypher, Gremlin, or similar; the constraint here is that the agent-facing API returns ranked facts rather than an analytical query interface. The harder architectural issue is keeping Zep and Postgres consistent. I would write each memory event once, then derive both the recall graph and an analytical projection with shared event IDs and watermarks. That makes routing recall vs. aggregate questions clean while keeping freshness lag and auditability measurable.