Objective
Nothing says "we don't know you" like a returning caller having to re-explain everything. A personalized voice agent recognizes the caller, recalls their recent issues and stated preferences by meaning, and understands how they relate to an account and product — so it opens with "Hi Dana, is this still about the export speed?" instead of a cold script. Here you'll build that on one database: a semantic caller-memory store plus a small relationship graph. Your STT/TTS and telephony live outside; the caller brain is the database. See Use it from your agent for wiring it into any voice stack.
Step 1: Create the caller-memory store
Per-caller memories — past issues, preferences, commitments — embedded for recall.
CREATE TABLE IF NOT EXISTS recipe_caller_memory (
memory_id INTEGER PRIMARY KEY,
caller_id TEXT, -- stable id, e.g. phone hash or account
content TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
embedding VECTOR(384)
);
Step 2: Seed memories for a returning caller
What the agent learned on prior calls with this caller.
INSERT INTO recipe_caller_memory (memory_id, caller_id, content) VALUES
(1,'caller-7','Called last week about slow report exports; we promised a fix by Friday.'),
(2,'caller-7','Prefers to be called Dana, not Ms. Cole.'),
(3,'caller-7','Gets frustrated by long hold times; keep it efficient.'),
(4,'caller-7','Is on the Pro plan and uses the analytics product daily.'),
(5,'caller-9','Called about billing; resolved a double charge.');
Step 3: Embed the memories
The embedding model runs in-database, making every caller memory recallable by meaning.
UPDATE recipe_caller_memory SET embedding = EMBED(content);
Step 4: On answer, recall this caller's relevant history
The phone rings from a known caller; pull the memories that bear on a likely follow-up.
SELECT content,
COSINE_SIMILARITY(embedding, EMBED('issue with exports being slow')) AS relevance
FROM recipe_caller_memory
WHERE caller_id = 'caller-7'
ORDER BY relevance DESC
LIMIT 2;
Step 5: Recall a stored preference to personalize tone
Retrieve how this caller likes to be addressed and handled — small touches that build trust. Project the similarity as relevance so we can order by it.
SELECT content,
COSINE_SIMILARITY(embedding, EMBED('how does the caller prefer to be addressed and treated?')) AS relevance
FROM recipe_caller_memory
WHERE caller_id = 'caller-7'
ORDER BY relevance DESC
LIMIT 2;
Step 6: Map the caller's relationships (graph)
Model the caller's account and product so the agent has the right context for the conversation.
MERGE (c:Caller {id: 'caller-7', name: 'Dana'})
MERGE (a:Account {id: 'acct-3', tier: 'Pro'})
MERGE (p:Product {name: 'Analytics'})
MERGE (c)-[:HOLDS]->(a)
MERGE (a)-[:USES]->(p)
MERGE (c)-[:LAST_ISSUE]->(i:Issue {topic: 'export-speed', status: 'open'});
Step 7: Walk the graph for the caller's open issue and account
One query gives the agent the caller's tier, product, and unresolved issue to open the call.
MATCH (c:Caller {id: 'caller-7'})-[:HOLDS]->(a:Account)-[:USES]->(p:Product)
MATCH (c)-[:LAST_ISSUE]->(i:Issue)
RETURN c.name AS caller, a.tier AS tier, p.name AS product, i.topic AS open_issue, i.status AS status;
Step 8: Generate a personalized greeting
Combine the recalled preference + open issue into a warm, context-aware opener. Materialize the top recalled memory (projecting the score we order by), then generate from that row.
CREATE TABLE IF NOT EXISTS recipe_caller_top (memory_id INTEGER PRIMARY KEY, content TEXT, relevance DOUBLE);
INSERT INTO recipe_caller_top (memory_id, content, relevance)
SELECT memory_id, content,
COSINE_SIMILARITY(embedding, EMBED('slow export issue we were fixing')) AS relevance
FROM recipe_caller_memory
WHERE caller_id = 'caller-7'
ORDER BY relevance DESC
LIMIT 1;
SELECT GENERATE(
'Write a one-sentence warm phone greeting. Address the caller as Dana. ' ||
'Reference this open issue from a prior call: ' || content ||
'. Be efficient and friendly.') AS greeting
FROM recipe_caller_top;
Cleanup (Optional)
DROP TABLE IF EXISTS recipe_caller_memory;
DROP TABLE IF EXISTS recipe_caller_top;
MATCH (n:Caller) DETACH DELETE n;
MATCH (n:Account) DETACH DELETE n;
MATCH (n:Product) DETACH DELETE n;
MATCH (n:Issue) DETACH DELETE n;
Expected Outcomes
- Step 4 recalls the open "slow export, fix promised by Friday" memory for the returning caller.
- Step 5 retrieves "prefers to be called Dana" and "keep it efficient" — preferences that shape tone.
- Step 7 returns Dana's Pro tier, Analytics product, and the open export-speed issue in one graph walk.
- Step 8 generates a warm opener that uses her name and references the unresolved issue — recognition, not a cold script.
You now have a voice agent that recognizes returning callers, recalls their context by meaning, and knows their account relationships — personalization from the first second of the call.
Use it from your agent (framework-agnostic — the DB is the brain, the voice stack is swappable)
Caller personalization is just a memory store + a relationship graph, queried by caller_id from any voice runtime:
- REST / SDK —
POST /v1/query/execute(any language), or@synapcores/sdkclient.executeQuery(...). On call-answer, look up the caller by phone/account, run the Step-4/5 recall and the Step-7 graph walk, and feed the Step-8 greeting to TTS. Works with Vapi, LiveKit Agents, Pipecat, Twilio, or Retell. - MCP (native, on by default) — point your voice runtime's MCP client at
ws://<your-instance>/mcp?token=<jwt>(JWT from onePOST /v1/auth/login→access_token). Thequerytool recalls caller memory; theexecutetool runs Cypher for the relationship graph and writes new memories after the call — personalization as tool calls. - Any framework — the same caller brain powers a phone line, a returning-user web voice widget, or a chat channel. The database is the brain; the framework (and the voice stack) is swappable.
Key Concepts Learned
- Keying memories by a stable
caller_idgives cross-call recognition and continuity. - Semantic recall surfaces the relevant prior issue, not the whole call history.
- A small relationship graph supplies account, product, and open-issue context in one walk.
- Because it's plain data ops (SQL + Cypher / REST / MCP), caller personalization works with any STT/TTS stack — the database-as-the-brain pattern the voice cluster builds on.