Build a Customer-Support Agent on One Database

Build a complete AI customer-support agent on one database — semantic ticket memory, RAG over your help docs, intent routing, priority scoring, and a customer graph, no five-service stack. Works with Claude Code, OpenClaw, LangChain, or a voice agent.

All recipes· agents· 22 minutesadvancedsql
Instance: localhost:8080

Opens your running SynapCores (Build a Customer-Support Agent on One Database will be staged for a preview — nothing runs until you click Run). No instance yet? Install free in ~30s.

Share

Objective

A real support agent needs five things at once: it must remember the customer's past tickets, answer from your help docs (RAG), route the request to the right queue, score urgency, and understand how the customer relates to accounts and products. Teams usually stitch a vector store + a cache + a graph DB + a model server + glue to get there. Here you'll build the whole agent on one database, composing the building-block recipes from this cluster into a working support brain. The same brain drives any framework or a voice agent — see Use it from your agent at the end.

Step 1: Create the support knowledge base (for RAG)

Help-doc chunks the agent answers from, embedded for retrieval.

CREATE TABLE IF NOT EXISTS recipe_support_kb (
  chunk_id  INTEGER PRIMARY KEY,
  source    TEXT,
  content   TEXT,
  embedding VECTOR(384)
);
INSERT INTO recipe_support_kb (chunk_id, source, content) VALUES
 (1,'refunds.md','Refunds are available within 30 days of purchase to the original payment method.'),
 (2,'login.md','If you are locked out, use Forgot Password on the sign-in page to reset via email.'),
 (3,'billing.md','To update your card, go to Settings > Billing and edit the payment method.'),
 (4,'outage.md','Service status and incident history are posted at status.example.com.'),
 (5,'data.md','Export your data anytime from Settings > Privacy as a JSON download.');
UPDATE recipe_support_kb SET embedding = EMBED(content);

Step 2: Create the intent router (labeled examples)

A few examples per support intent so the agent can route by meaning.

CREATE TABLE IF NOT EXISTS recipe_support_intents (
  example_id INTEGER PRIMARY KEY,
  intent     TEXT,
  utterance  TEXT,
  embedding  VECTOR(384)
);
INSERT INTO recipe_support_intents (example_id, intent, utterance) VALUES
 (1,'billing','I was charged twice and need a refund.'),
 (2,'billing','How do I update my credit card?'),
 (3,'access','I can''t log in, I''m locked out.'),
 (4,'access','Reset my password please.'),
 (5,'outage','Is the service down right now?'),
 (6,'outage','Everything is timing out for my whole team.');
UPDATE recipe_support_intents SET embedding = EMBED(utterance);

Step 3: Create the customer memory (past tickets)

Per-customer ticket history, embedded so the agent recalls relevant prior issues.

CREATE TABLE IF NOT EXISTS recipe_support_memory (
  ticket_id   INTEGER PRIMARY KEY,
  customer_id TEXT,
  summary     TEXT,
  embedding   VECTOR(384)
);
INSERT INTO recipe_support_memory (ticket_id, customer_id, summary) VALUES
 (1,'cust-7','Reported slow report exports; resolved by enabling pagination.'),
 (2,'cust-7','Asked about upgrading to the Pro plan for more projects.'),
 (3,'cust-7','Had trouble logging in after changing email; resolved via password reset.');
UPDATE recipe_support_memory SET embedding = EMBED(summary);

Step 4: Train a priority-scoring model (AutoML)

Learn which ticket features predict an urgent (P1) ticket from past resolutions.

CREATE TABLE IF NOT EXISTS recipe_support_history (
  hist_id        INTEGER PRIMARY KEY,
  affects_team   INTEGER,                             -- 1 if multiple users impacted
  is_paying      INTEGER,                             -- 1 if on a paid plan
  mins_blocked   INTEGER,                             -- minutes the user has been blocked
  prior_tickets  INTEGER,                             -- how many tickets this customer filed before
  urgent         INTEGER                              -- label: 1 = P1
);
INSERT INTO recipe_support_history
 (hist_id, affects_team, is_paying, mins_blocked, prior_tickets, urgent) VALUES
 (1,1,1,120,3,1),(2,0,0,5,0,0),(3,1,1,200,5,1),(4,0,1,15,1,0),
 (5,1,1,90,2,1),(6,0,0,3,0,0),(7,1,1,150,4,1),(8,0,1,10,1,0),
 (9,1,1,75,2,1),(10,0,0,8,0,0),(11,1,1,180,6,1),(12,0,1,20,1,0),
 (13,1,1,110,3,1),(14,0,0,4,0,0),(15,1,1,140,5,1),(16,0,1,12,1,0),
 (17,1,1,95,2,1),(18,0,0,6,0,0),(19,1,1,160,4,1),(20,0,1,18,1,0);
CREATE EXPERIMENT support_priority_exp AS
SELECT affects_team, is_paying, mins_blocked, prior_tickets, urgent AS target
FROM recipe_support_history
WITH (
  task_type = 'binary_classification',
  target_column = 'target',
  optimization_metric = 'auc',
  algorithms = ['logistic_regression', 'random_forest', 'gradient_boosting'],
  validation_strategy = 'stratified_kfold',
  n_folds = 3,
  max_trials = 15
);
DEPLOY MODEL support_priority FROM EXPERIMENT support_priority_exp;

Step 5: Build the customer graph (relationships)

Who the customer is, the account they belong to, and the product they use — for relationship-aware handling.

MERGE (c:Customer {id: 'cust-7', name: 'Dana'})
MERGE (a:Account {id: 'acct-9', tier: 'Pro'})
MERGE (p:Product {name: 'Analytics'})
MERGE (c)-[:MEMBER_OF]->(a)
MERGE (a)-[:USES]->(p)
MERGE (c)-[:OPENED]->(t:Ticket {id: 'T-100', topic: 'login'});

Step 6: A ticket arrives — route it by intent

Classify the incoming message so it lands in the right queue.

SELECT intent, AVG(similarity) AS confidence
FROM (
  SELECT intent,
         COSINE_SIMILARITY(embedding, EMBED('my whole team is getting timeouts, nothing loads')) AS similarity
  FROM recipe_support_intents
  ORDER BY similarity DESC
  LIMIT 4
)
GROUP BY intent
ORDER BY confidence DESC
LIMIT 1;

Step 7: Score the ticket's priority

Use the trained model to decide whether this is a P1 — team-wide outage, paying customer, long block.

SELECT AUTOML.PREDICT('support_priority', 1, 1, 130, 3) AS p1_probability;

Step 8: Recall the customer's relevant history

Pull the prior tickets that bear on this issue so the agent doesn't ask the customer to repeat themselves.

SELECT summary,
       COSINE_SIMILARITY(embedding, EMBED('cannot access the service, timeouts and login trouble')) AS relevance
FROM recipe_support_memory
WHERE customer_id = 'cust-7'
ORDER BY relevance DESC
LIMIT 2;

Step 9: Answer from the help docs (RAG) with full context

Retrieve the right doc chunks into a context row, then generate a grounded reply that uses the customer's history.

CREATE TABLE IF NOT EXISTS recipe_support_top (
  doc_id    INTEGER PRIMARY KEY,
  content   TEXT,
  relevance DOUBLE
);
INSERT INTO recipe_support_top (doc_id, content, relevance)
SELECT chunk_id, content,
       COSINE_SIMILARITY(embedding, EMBED('service is timing out and I cannot log in')) AS relevance
FROM recipe_support_kb
ORDER BY relevance DESC
LIMIT 2;
CREATE TABLE IF NOT EXISTS recipe_support_ctx (id INTEGER PRIMARY KEY, context TEXT);
INSERT INTO recipe_support_ctx (id, context)
SELECT 1, GROUP_CONCAT(content, ' ') FROM recipe_support_top;
SELECT GENERATE(
  'You are a support agent. Use ONLY the context to answer, and acknowledge the customer''s history. Context: ' ||
  context ||
  ' Customer history: previously had login trouble resolved via password reset.' ||
  ' Question: The service is timing out and I cannot log in, what should I do? Answer:') AS reply
FROM recipe_support_ctx;

Step 10: Use the graph to escalate the right way

Check the customer's tier and product so escalation goes to the correct team.

MATCH (c:Customer {id: 'cust-7'})-[:MEMBER_OF]->(a:Account)-[:USES]->(p:Product)
RETURN c.name AS customer, a.tier AS tier, p.name AS product;

Cleanup (Optional)

DROP TABLE IF EXISTS recipe_support_kb;
DROP TABLE IF EXISTS recipe_support_intents;
DROP TABLE IF EXISTS recipe_support_memory;
DROP TABLE IF EXISTS recipe_support_history;
DROP TABLE IF EXISTS recipe_support_top;
DROP TABLE IF EXISTS recipe_support_ctx;
MATCH (n:Customer) DETACH DELETE n;
MATCH (n:Account) DETACH DELETE n;
MATCH (n:Product) DETACH DELETE n;
MATCH (n:Ticket) DETACH DELETE n;

Expected Outcomes

  • Step 6 routes the team-wide timeout to the outage queue by meaning.
  • Step 7 scores the ticket a high P1 probability — team impact + paying customer + long block.
  • Step 8 recalls the customer's prior login/password-reset ticket, so the agent doesn't re-ask.
  • Step 9 returns a grounded reply that cites the reset flow and acknowledges the history.
  • Step 10 returns the customer's Pro tier and Analytics product, so escalation is routed correctly.

You've built a complete support agent — memory, RAG, intent routing, priority ML, and a customer graph — on one database, no five-service stack.

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

The support brain is just five tables/graphs + the same data ops, so any agent shell drives it with no framework lock-in:

  • REST / SDKPOST /v1/query/execute (any language), or @synapcores/sdk client.executeQuery(...). Your agent runs route → score → recall → RAG → graph (Steps 6–10) per ticket and returns the reply + priority + escalation target.
  • 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> (JWT from one POST /v1/auth/loginaccess_token). The query tool runs routing/scoring/RAG; the execute tool runs Cypher for the graph and writes new ticket memories — the whole support loop as tool calls.
  • Any framework — OpenClaw, a LangGraph support workflow, a custom loop, or a voice support line all call the same brain; the channel changes, the database doesn't. The database is the brain; the framework is swappable.

Key Concepts Learned

  • A complete agent is a composition of the building blocks: memory + RAG + routing + ML scoring + graph.
  • One engine serves all five surfaces, so there's no five-service stack to operate or keep in sync.
  • The brain is channel-agnostic: the same queries power a web widget, a Slack bot, or a voice line.
  • Because it's plain data ops (SQL + Cypher + AutoML / REST / MCP), the support agent works from any framework — the agent-agnostic backend pattern this cluster builds on.

Tags

ai-agentcustomer-supportragintent-routingautomlknowledge-graphmcp

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