Skip to content
Browse documentation

Concepts

Cited answers

POST /v1/answer retrieves the enforced hits, then asks a Workers AI LLM to answer strictly from that cited context — returning a grounded answer where every claim carries a citation that points at the exact sub-unit span, or an honest refusal when the evidence doesn't support one.

The retrieve → synthesize → cite loop#

A cited answer is not a bare LLM completion. SuperChargeDB runs a bounded pipeline over the enforced hybrid search results and refuses to speak past what the evidence supports:

  • Retrieve — cheap, high-recall hybrid search across every requested plane (dense + BM25 fused by RRF), scope-clamped and ACL-filtered.
  • Localize — narrow to the top hits and pin each candidate to its exact Locator (moment, bbox region, passage, or line).
  • Synthesize — a Workers AI LLM answers strictly from the numbered context passages, with a hard instruction to refuse when the context does not contain the answer.
  • Cite — the answer carries inline [n] markers, each resolving to a citation with a unit_id, source_uri, and Locator; a groundedness score reports the share of sentences that are cited.

Model policy & fallback chain#

Grounded synthesis now runs a real LLM — it is no longer always extractive. Providers are tried in a strict order so a single unavailable model can never silently disable answers, and the engine never hallucinates: the worst case is a grounded extractive stitch of the top snippets, never an ungrounded completion.

OrderProviderModelWhen
1Cloudflare Workers AI@cf/meta/llama-3.1-8b-instruct-fp8Primary.
2Cloudflare Workers AI@cf/meta/llama-3.3-70b-instruct-fp8-fastCF fallback if the primary errors / returns empty.
3OpenAIgpt-4o-miniOnly when OPENAI_API_KEY is set and every CF model failed.
4ExtractiveLast resort: stitch the top snippets, each tagged with its citation.

The OpenAI chat model is configurable via OPENAI_CHAT_MODEL. The winning provider is surfaced in the trace’s synth stage detail (e.g. cloudflare, openai:gpt-4o-mini (cf fallback), or extractive fallback), and the response answer.extractive flag is true only when both model paths were unavailable. Retrieval, RRF fusion, and reranking all use @cf/baai/bge-m3 (1024-d embeddings) and @cf/baai/bge-reranker-base — see Hybrid search.

Honest refusal

If the retrieved context does not support the question, the answer is exactly “The retrieved context does not contain an answer to this question.” with no citations. The LLM judges relevance itself; the extractive fallback additionally applies a lexical-support guard so a nonsense query never gets a confident cited answer over unrelated passages.

Endpoint#

POST/v1/answer

Grounded answers are a Pro / Enterprise feature: a Free-tier principal receives 402 upgrade_required (required_tier: "pro"). See Pricing & billing.

Requires the read permission. The request body is an AegisQuery with answer: true — the same validated query object used by POST /v1/search, so planes, modalities, filters, rerank, and budget all apply. Scope is set via the X-Aegis-Scope header or ?scope=, never the body.

FieldTypeDefaultNotes
qstring— (required)The natural-language question.
answerbooleantrueMust be true on this route; synthesis is always requested.
planesPlane[]["text"]Planes to retrieve from — add visual/audio/doc_visual for multimodal evidence.
modalitiesModality[]unsetRestrict the evidence to specific modalities.
budgetBudgetunsetBounds rounds, MLLM calls, inference units, and latency (see Query).

Request#

curl
curl -s -X POST "https://superchargedb.krisch1218.workers.dev/v1/answer?scope=acme/alpha/backend" \
  -H "Authorization: Bearer aegis_sk_alice" \
  -H "Content-Type: application/json" \
  -d '{
    "q": "Where does the Q3 keynote demo the failover, and how fast was the cutover?",
    "answer": true,
    "planes": ["text", "audio", "doc_visual"],
    "top_k": 8,
    "rerank": true
  }'

The same call with the JavaScript / TypeScript fetch API:

answer.ts
const res = await fetch("https://superchargedb.krisch1218.workers.dev/v1/answer?scope=acme/alpha/backend", {
  method: "POST",
  headers: {
    Authorization: "Bearer aegis_sk_alice",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    q: "Where does the Q3 keynote demo the failover?",
    answer: true,
    planes: ["text", "audio", "doc_visual"],
    top_k: 8,
  }),
});

const { answer, hits, trace, context } = await res.json();
for (const c of answer.citations) {
  console.log(`[${c.index}]`, c.source_uri, c.locator);
}
console.log("faithfulness", answer.nli_faithfulness);

Response#

The response is a superset of the search response: the same hits, trace, and enforcement context, plus a populated answer object.

200 OK (abridged)
{
  "answer": {
    "text": "The live failover is demonstrated 12:47 into the keynote, where the primary region is drained and traffic re-homes with no dropped requests [1]. The runbook confirms a sub-second cutover [2].",
    "citations": [
      {
        "index": 1,
        "unit_id": "u-keynote-shot-19",
        "source_uri": "acme/alpha/keynotes/keynote-q3.mp4#t=767",
        "locator": { "kind": "time_range", "t_start_ms": 767000, "t_end_ms": 782000, "shot_idx": 19 }
      },
      {
        "index": 2,
        "unit_id": "u-runbook-p14",
        "source_uri": "acme/alpha/backend/runbooks/failover.pdf#page=14",
        "locator": { "kind": "bbox", "box": [72, 512, 540, 611], "page": 14 }
      }
    ],
    "nli_faithfulness": 1.0
  },
  "hits": [ /* SearchHit[] — same shape as POST /v1/search */ ],
  "trace": {
    "stages": [
      { "stage": "embed", "ms": 40, "neurons": 120 },
      { "stage": "vectorize", "ms": 58, "detail": "text+audio+doc_visual" },
      { "stage": "d1_fts", "ms": 8 },
      { "stage": "rrf", "ms": 1, "detail": "k=60" },
      { "stage": "rerank", "ms": 175, "neurons": 900 },
      { "stage": "synth", "ms": 640, "neurons": 1700, "detail": "@cf/meta/llama-3.1-8b-instruct-fp8; 2 citations" }
    ],
    "total_ms": 1002,
    "total_neurons": 2720,
    "est_cost_usd": 0.0299,
    "cache": "miss"
  },
  "context": { "effective_scopes": ["acme/alpha/backend"], "perms": ["read", "write", "admin"] }
}

Citations resolve to Locators

Each entry in answer.citations carries the inline marker index, the source unit_id and source_uri, and an optional Locator. Because the Locator is the same discriminated union used everywhere else, an audio citation resolves to a timestamp window, a doc-visual citation to a page bbox, and a text citation to a character span — so a UI can deep-link to the exact spot.

The faithfulness score

nli_faithfulness is a 0.0–1.0 groundedness score: the fraction of the answer’s sentences that carry at least one citation marker. It is a cheap, deterministic proxy for full NLI entailment (a dedicated MLLM-judge verification stage is on the roadmap). A score below your threshold is a signal to fall back to raw hits or to widen retrieval rather than trust the prose.

FieldMeaning
answer.textThe synthesized answer with inline [n] citation markers.
answer.citations[]{ index, unit_id, source_uri, locator? } — one per marker.
answer.nli_faithfulness0–1 share of answer sentences that are cited.
answer.extractivetrue only when both LLM providers were unavailable and the answer is a grounded snippet stitch.

Verify, don't assume

The extra synth stage appears in the trace — with the winning provider/model in its detail — so you can see exactly what each answer cost in latency and inference units. Assert on invariants — every sentence has a citation, citations resolve to visible Units, faithfulness meets your bar — rather than on exact wording, which shifts as models evolve.

Response shape

The body is { answer, hits, trace, context, hidden_by_acl } where answer matches the shared CitedAnswer schema ({ text, citations, nli_faithfulness, extractive }). The response is buffered JSON today; streaming (SSE/WS) is on the roadmap.