Recall Agent Memory by Meaning + Recency

Make an AI agent recall the right memories by blending semantic relevance with recency — fresh, on-point context in one SQL query, no separate vector store or cache. Works with Claude Code, OpenClaw, LangChain, or a voice agent.

All recipes· agents· 12 minutesintermediateen
Instance: localhost:8080

Opens your running SynapCores (Recall Agent Memory by Meaning + Recency will be staged for a preview — nothing runs until you click Run). No instance yet? Install free in ~30s.

Share

Objective

An agent that only ranks memories by meaning will happily resurface a stale fact over a fresh one. Real recall blends relevance (semantic match to the current message) with recency (how recently the memory was formed), so "what's the user working on now?" beats "what they worked on a year ago." Here you'll build a single recall query that scores both — no separate cache, no time-decay service, just SQL. The same store works from any framework or a voice agent — see Use it from your agent at the end.

Step 1: Create the agent memory store with an age

One row per memory, with an embedding for semantic recall and an age_days we can decay against.

CREATE TABLE IF NOT EXISTS recipe_agent_recall (
  memory_id   INTEGER PRIMARY KEY,
  agent_id    TEXT,
  content     TEXT,
  age_days    INTEGER,                               -- how many days ago this memory was formed
  created_at  TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  embedding   VECTOR(384)
);

Step 2: Write memories formed at different times

Two are about the same topic (the user's job) but one is stale and one is current; recency should break the tie.

INSERT INTO recipe_agent_recall (memory_id, agent_id, content, age_days) VALUES
 (1,'assistant','The user was a junior analyst learning SQL.',                        900),
 (2,'assistant','The user is now a senior data engineer leading a Rust platform team.', 3),
 (3,'assistant','The user prefers concise, technical answers.',                          7),
 (4,'assistant','The user once asked about beginner Python tutorials.',                820),
 (5,'assistant','The user is currently migrating a service to async Rust.',             1);

Step 3: Embed the memories

The embedding model runs inside the database — no external API call.

UPDATE recipe_agent_recall SET embedding = EMBED(content);

Step 4: Recall by meaning only (the naive baseline)

Pure semantic recall — note it can't tell the stale job memory from the current one.

SELECT memory_id, content, age_days,
       COSINE_SIMILARITY(embedding, EMBED('What is the user''s current role?')) AS relevance
FROM recipe_agent_recall
WHERE agent_id = 'assistant'
ORDER BY relevance DESC
LIMIT 3;

Step 5: Add a recency score with explicit time decay

Turn "days since the memory was formed" into a 0..1 freshness score that fades smoothly over time.

SELECT memory_id, content, age_days,
       1.0 / (1.0 + age_days / 30.0) AS recency
FROM recipe_agent_recall
WHERE agent_id = 'assistant'
ORDER BY recency DESC
LIMIT 5;

Step 6: Blend relevance + recency into one recall score

Weight semantic match 70% and freshness 30% so the current job memory wins over the stale one.

SELECT memory_id, content,
       COSINE_SIMILARITY(embedding, EMBED('What is the user''s current role?')) * 0.7
       + (1.0 / (1.0 + age_days / 30.0)) * 0.3 AS score
FROM recipe_agent_recall
WHERE agent_id = 'assistant'
ORDER BY score DESC
LIMIT 3;

Step 7: Ground a reply in the freshest relevant memory

Materialize the single top blended memory (projecting the score so we can order by it), then feed it to GENERATE() so the agent answers from current context.

CREATE TABLE IF NOT EXISTS recipe_agent_recall_top (
  memory_id INTEGER PRIMARY KEY,
  content   TEXT,
  score     DOUBLE
);
INSERT INTO recipe_agent_recall_top (memory_id, content, score)
SELECT memory_id, content,
       COSINE_SIMILARITY(embedding, EMBED('What is the user''s current role?')) * 0.7
       + (1.0 / (1.0 + age_days / 30.0)) * 0.3 AS score
FROM recipe_agent_recall
WHERE agent_id = 'assistant'
ORDER BY score DESC
LIMIT 1;
SELECT GENERATE(
  'Given this current fact about the user: ' || content ||
  '. Greet the user in one sentence that references what they do now.') AS greeting
FROM recipe_agent_recall_top;

Cleanup (Optional)

DROP TABLE IF EXISTS recipe_agent_recall;
DROP TABLE IF EXISTS recipe_agent_recall_top;

Expected Outcomes

  • Step 4 ranks both job memories near each other — pure meaning can't tell the current role from the stale one.
  • Step 5 orders memories purely by freshness, newest first.
  • Step 6 promotes "now a senior data engineer" above "was a junior analyst," because recency breaks the semantic tie.
  • Step 7 greets the user from their current role — recall that is both on-topic and up to date.

You now have recency-aware semantic recall: the agent remembers what's relevant and what's recent, in one query.

Use it from your agent (framework-agnostic — this is the whole point)

Recall is just data + one scoring query, so any agent uses it with no framework lock-in:

  • REST / SDKPOST /v1/query/execute (any language), or @synapcores/sdk client.executeQuery(...). Your agent runs the Step-2 INSERT to remember and the Step-6 SELECT to recall the freshest relevant context before each turn. (In production, store the real timestamp and compute age_days from it client-side, or with your engine's date functions, before scoring.)
  • MCP (native, on by default) — point any MCP client (Claude Code, Cursor, a custom loop, a voice runtime) at ws://<your-instance>/mcp?token=<jwt> (the JWT comes from one POST /v1/auth/loginaccess_token). The query tool runs the blended recall; the execute tool writes new memories — "remember this" and "what's relevant now?" become MCP tool calls, no SDK required.
  • Any framework — OpenClaw's memory plugin, LangChain / LlamaIndex / Semantic Kernel, a custom loop, or a voice agent all read and write the same store. The database is the brain; the framework is swappable.

Key Concepts Learned

  • Pure semantic recall ignores time — agents need both relevance and recency.
  • A 1 / (1 + age/halflife) term turns an age into a smooth 0..1 freshness score, all in SQL.
  • Weighting COSINE_SIMILARITY and recency into one score gives human-like recall in a single query.
  • Because it's plain data ops (SQL / REST / MCP), recency-aware recall works for any agent — the agent-agnostic backend pattern this cluster builds on.

Tags

ai-agentagent-memoryrecencyvectorembeddingssemantic-recallmcp

Run this on your own machine

Install SynapCores Community Edition free, paste the SQL or Cypher above into the bundled web UI, and watch it run.

Download Free CE