Self-Checking / Grounded Generation (validate the answer)

Stop your AI agent from hallucinating — generate an answer, then have the agent verify it against your source data before returning it, all in one SQL database. Self-checking RAG for Claude Code, OpenClaw, LangChain, or a voice agent.

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

Opens your running SynapCores (Self-Checking / Grounded Generation (validate the answer) will be staged for a preview — nothing runs until you click Run). No instance yet? Install free in ~30s.

Share

Objective

A grounded answer is only worth as much as your trust that it is grounded. The strongest guardrail against hallucination is a second pass: generate the answer, then have the model check its own answer against the source context and flag anything unsupported. Here you'll build that loop — retrieve, generate, then verify — entirely in one database, so an agent can refuse or revise a draft it can't back up. The same pattern works from any framework or a voice agent — see Use it from your agent at the end.

Step 1: Create the grounding knowledge base

One row per fact the answer must be checkable against, embedded for retrieval.

CREATE TABLE IF NOT EXISTS recipe_selfcheck_facts (
  fact_id   INTEGER PRIMARY KEY,
  content   TEXT,
  embedding VECTOR(384)
);

Step 2: Load the source facts

The agent may only assert things supported by these rows.

INSERT INTO recipe_selfcheck_facts (fact_id, content) VALUES
 (1,'The Pro plan costs $29 per month and includes unlimited projects.'),
 (2,'The Pro plan includes email support with a 24-hour response time.'),
 (3,'The free plan allows up to 3 projects and community support only.'),
 (4,'Annual billing on the Pro plan gives a 20% discount.'),
 (5,'There is no phone support on any plan.');

Step 3: Embed the facts

The embedding model runs in-database — your verification index in one line.

UPDATE recipe_selfcheck_facts SET embedding = EMBED(content);

Step 4: Retrieve context and generate a draft answer

Standard RAG: pull the relevant facts into a single context row, then produce a first-pass answer from it. Materializing the retrieved context once lets every later step reuse the exact same source.

CREATE TABLE IF NOT EXISTS recipe_selfcheck_top (
  fact_id   INTEGER PRIMARY KEY,
  content   TEXT,
  relevance DOUBLE
);
INSERT INTO recipe_selfcheck_top (fact_id, content, relevance)
SELECT fact_id, content,
       COSINE_SIMILARITY(embedding, EMBED('What support does the Pro plan include?')) AS relevance
FROM recipe_selfcheck_facts
ORDER BY relevance DESC
LIMIT 3;
CREATE TABLE IF NOT EXISTS recipe_selfcheck_ctx (id INTEGER PRIMARY KEY, source TEXT);
INSERT INTO recipe_selfcheck_ctx (id, source)
SELECT 1, GROUP_CONCAT(content, ' ') FROM recipe_selfcheck_top;
SELECT GENERATE(
  'Answer using the context. Context: ' || source ||
  ' Question: What support does the Pro plan include? Answer:') AS draft_answer
FROM recipe_selfcheck_ctx;

Step 5: Self-check the draft against the source

The second pass: ask the model to verify each claim in the draft is supported, and return a verdict — over the same materialized source.

SELECT GENERATE(
  'You are a fact-checker. Given the SOURCE and a DRAFT answer, reply SUPPORTED if every claim in the draft is backed by the source, or UNSUPPORTED followed by the offending claim if not. SOURCE: ' ||
  source ||
  ' DRAFT: The Pro plan includes email support with a 24-hour response time. Verdict:') AS verdict
FROM recipe_selfcheck_ctx;

Step 6: Catch a hallucination in the act

Run the same self-check on a draft that claims something the source contradicts — the checker should reject it. We check against the full fact set, so build a context row over every fact.

CREATE TABLE IF NOT EXISTS recipe_selfcheck_all (id INTEGER PRIMARY KEY, source TEXT);
INSERT INTO recipe_selfcheck_all (id, source)
SELECT 1, GROUP_CONCAT(content, ' ') FROM recipe_selfcheck_facts;
SELECT GENERATE(
  'You are a fact-checker. Given the SOURCE and a DRAFT answer, reply SUPPORTED if every claim in the draft is backed by the source, or UNSUPPORTED followed by the offending claim if not. SOURCE: ' ||
  source ||
  ' DRAFT: The Pro plan includes 24/7 phone support. Verdict:') AS verdict
FROM recipe_selfcheck_all;

Step 7: Produce a verified final answer

Combine draft + verdict so the agent only returns an answer it could defend against the source.

SELECT GENERATE(
  'Given this fact-check verdict, return the final answer only if SUPPORTED, otherwise return "I can only confirm what is in our documentation: " plus the safe facts. Verdict: SUPPORTED. Draft: The Pro plan includes email support with a 24-hour response time. Final:') AS final_answer;

Cleanup (Optional)

DROP TABLE IF EXISTS recipe_selfcheck_facts;
DROP TABLE IF EXISTS recipe_selfcheck_top;
DROP TABLE IF EXISTS recipe_selfcheck_ctx;
DROP TABLE IF EXISTS recipe_selfcheck_all;

Expected Outcomes

  • Step 4 drafts an answer about Pro-plan support, grounded in the retrieved facts.
  • Step 5 returns SUPPORTED — every claim in the email-support draft is backed by the source.
  • Step 6 returns UNSUPPORTED for the phone-support draft, naming the claim the source contradicts — a hallucination caught before it reaches the user.
  • Step 7 emits a final answer only because the verdict was SUPPORTED.

You now have a self-checking agent: it generates, verifies its own answer against the source, and refuses to ship claims it can't back up.

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

Self-checking is just generate, then verify against the same store, 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 Step 4 to draft, Step 5 to verify, and only returns the answer when the verdict is SUPPORTED.
  • 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 both the draft and the self-check GENERATE calls — grounded, verified answers as tool calls.
  • Any framework — OpenClaw, LangChain / LlamaIndex evaluators, a custom loop, or a voice agent all run the same retrieve → generate → verify loop. The database is the brain; the framework is swappable.

Key Concepts Learned

  • The strongest anti-hallucination guardrail is a second pass that checks the answer against the source.
  • GENERATE() plays both roles: the generator (draft) and the fact-checker (verdict) over the same retrieved context.
  • Gating the final answer on a SUPPORTED verdict means the agent ships only defensible claims.
  • Because it's plain data ops (retrieve + generate + verify / REST / MCP), self-checking works for any agent — the agent-agnostic backend pattern this cluster builds on.

Tags

ai-agentgrounded-generationself-checkhallucinationraggeneratemcp

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