Objective
Before an agent can act, it has to know what the user wants: is this a billing question, a bug report, a sales lead, or a cancellation? Brittle keyword rules break on paraphrase, and spinning up a classifier service is overkill. Here you'll classify intent by meaning: store a few labeled examples per intent, embed them, and match an incoming message to the nearest examples — a k-NN intent classifier that needs no training job and adds new intents by inserting rows. The same classifier works from any framework or a voice agent — see Use it from your agent at the end.
Step 1: Create the labeled-examples store
Each row is an example utterance tagged with its intent label and embedded for matching.
CREATE TABLE IF NOT EXISTS recipe_intent_examples (
example_id INTEGER PRIMARY KEY,
intent TEXT, -- the label this example teaches
utterance TEXT, -- a sample way users phrase that intent
embedding VECTOR(384)
);
Step 2: Seed a few examples per intent
A handful of phrasings per intent is enough — the embedding model generalizes to unseen wording.
INSERT INTO recipe_intent_examples (example_id, intent, utterance) VALUES
(1,'billing','Why was I charged twice this month?'),
(2,'billing','I need a copy of my last invoice.'),
(3,'billing','How do I update my credit card?'),
(4,'tech_support','The app crashes when I open the dashboard.'),
(5,'tech_support','I keep getting a 500 error on upload.'),
(6,'tech_support','The export button does nothing.'),
(7,'sales','Do you offer a plan for large teams?'),
(8,'sales','Can I get a demo before buying?'),
(9,'sales','What''s included in the enterprise tier?'),
(10,'cancel','I want to close my account.'),
(11,'cancel','How do I stop my subscription?'),
(12,'cancel','Please cancel my plan and refund me.');
Step 3: Embed the examples
The embedding model runs in-database; this is the labeled index the classifier searches.
UPDATE recipe_intent_examples SET embedding = EMBED(utterance);
Step 4: Classify a new message by nearest examples
Find the closest labeled examples to the incoming message — their intent is the prediction.
SELECT intent, utterance,
COSINE_SIMILARITY(embedding, EMBED('my card got declined, can you help me pay?')) AS similarity
FROM recipe_intent_examples
ORDER BY similarity DESC
LIMIT 3;
Step 5: Vote across the top-k for a robust label
Average similarity per intent over the nearest examples — majority-by-meaning beats a single match.
SELECT intent, AVG(similarity) AS confidence, COUNT(*) AS votes
FROM (
SELECT intent,
COSINE_SIMILARITY(embedding, EMBED('the page keeps throwing an error when I click save')) AS similarity
FROM recipe_intent_examples
ORDER BY similarity DESC
LIMIT 5
)
GROUP BY intent
ORDER BY confidence DESC
LIMIT 1;
Step 6: Gate low-confidence intents to a fallback
Return the predicted intent only when it clears a threshold; otherwise the agent should ask, not assume.
SELECT intent, confidence,
CASE WHEN confidence >= 0.30 THEN intent ELSE 'unknown_ask_clarify' END AS routed_intent
FROM (
SELECT intent, AVG(similarity) AS confidence
FROM (
SELECT intent,
COSINE_SIMILARITY(embedding, EMBED('hi there, hope you are well')) AS similarity
FROM recipe_intent_examples
ORDER BY similarity DESC
LIMIT 5
)
GROUP BY intent
ORDER BY confidence DESC
LIMIT 1
);
Cleanup (Optional)
DROP TABLE IF EXISTS recipe_intent_examples;
Expected Outcomes
- Step 4 classifies "my card got declined" as billing, matching examples with no shared keywords.
- Step 5 votes "the page throws an error on save" to tech_support with a confidence and vote count.
- Step 6 routes a content-free greeting to unknown_ask_clarify because no intent clears the gate — the agent asks instead of guessing.
You now have a k-NN intent classifier that needs no training run, adds intents by inserting rows, and routes confidently or asks when unsure.
Use it from your agent (framework-agnostic — this is the whole point)
Intent classification is just labeled examples + a nearest-neighbor query, so any agent uses it with no framework lock-in:
- REST / SDK —
POST /v1/query/execute(any language), or@synapcores/sdkclient.executeQuery(...). On each incoming message your agent runs the Step-5/6 query, readsrouted_intent, and branches its logic accordingly. Add or correct intents by inserting example rows — no retraining. - 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 onePOST /v1/auth/login→access_token). Thequerytool returns the intent; theexecutetool adds new labeled examples — classification and continuous improvement as tool calls. - Scale-up option — once you have many labeled rows, train a supervised classifier with
CREATE EXPERIMENT … task_type='binary_classification'(one model per intent, or one-vs-rest) and serve it withAUTOML.PREDICT. The vector classifier here needs zero training and is ideal to start. - Any framework — OpenClaw, LangChain routers, a custom loop, or a voice agent all classify against the same examples table. The database is the brain; the framework is swappable.
Key Concepts Learned
- Embedding labeled examples turns intent classification into nearest-neighbor search — no training job, robust to paraphrase.
- Voting across the top-k (averaging similarity per intent) gives a stable label and a confidence.
- A confidence gate routes ambiguous messages to clarification instead of a wrong branch.
- Because it's plain data ops (SQL / REST / MCP), intent classification works for any agent — the agent-agnostic backend pattern this cluster builds on.