Grounding And Citations
Inject retrieved evidence, expose search tools, and validate that answers cite allowed sources.
Use plain retrieval when a prompt needs helpful background. Use grounding() when the answer must cite retrieved evidence and Crux should validate that citation contract.
import { prompt } from "@use-crux/core";
import { citationSchema, grounding } from "@use-crux/core/citations";
import { z } from "zod";
const groundedDocs = grounding({
id: "docs-grounding",
retriever: docs.retriever(),
query: ({ input }) => input.question as string,
limit: 6,
citations: {
required: true,
quotes: "required",
},
});
export const answerDocs = prompt({
id: "answer-docs",
use: [groundedDocs],
input: z.object({ question: z.string() }),
output: z.object({
answer: z.string(),
citations: z.array(citationSchema),
}),
system: "Answer only from the provided sources.",
prompt: ({ input }) => input.question,
});Knowledge bases and recipes expose convenience forms:
const groundedKnowledgeBase = docs.grounding({
query: ({ input }) => input.question as string,
});
const groundedRecipe = docsAnswer.asGrounding({
query: ({ input }) => input.question as string,
citations: { required: true },
});Injection Modes
Grounding can inject retrieved context directly, expose search tools, or do both.
const baseGrounding = {
id: "docs-grounding",
retriever: docs.retriever(),
citations: { required: true },
};
grounding({
...baseGrounding,
inject: "context",
query: ({ input }) => input.question as string,
});
grounding({
...baseGrounding,
inject: "tool",
tools: { prefix: "docs", include: ["search", "getSource"] },
});
grounding({
...baseGrounding,
inject: "both",
query: ({ input }) => input.question as string,
tools: { prefix: "docs", include: ["search", "getSource"] },
});Use context when the prompt should always receive evidence before generation. Use tool when the model should decide whether to search. Use both when an assistant should start with likely evidence and still have lookup tools for follow-up questions.
Tool-only grounding does not require a query up front. If the model cites a source before searching, citation validation fails with a clear unknown-hit issue.
Grounding Session
Each grounded generation has a grounding session. The session records:
- hits injected as context
- hits returned by retrieval tools
Retrieval tools return typed crux.retrieval.hits payloads. The tool middleware records those payloads into the session, and citation validation reads the session at validation time. Crux does not parse tool strings or close over mutable hit arrays.
This keeps single-process runtimes and serialized runtimes aligned: adapters can reconstruct the session from persisted typed tool results without maintaining a second evidence table.
Tool Visibility
The search tool returns lean evidence: source identity, score, content, and URL when present. It does not expose internal provenance by default.
getSource has explicit visibility:
grounding({
id: "docs-grounding",
retriever: docs.retriever(),
inject: "tool",
tools: {
prefix: "docs",
include: ["search", "getSource"],
getSource: { visibility: "discovered" },
},
});| Visibility | Meaning |
|---|---|
discovered | getSource can read only hits already recorded in the grounding session. |
namespace | getSource can read any active indexed chunk in the retriever namespace. |
Use namespace visibility when you want the model to expand known source ids. Use discovered visibility when source access should stay tied to prior search results.
Rendering
Default rendering is source-oriented and citation friendly. Customize it when your UI needs page numbers, URLs, titles, or domain-specific labels.
const groundedDocs = grounding({
id: "docs-grounding",
retriever: docs.retriever(),
query: ({ input }) => input.question as string,
render: ({ hits }) =>
hits
.map((hit, index) => {
const label = `${hit.source.id}/${hit.chunkId}`;
return `[${index + 1}] ${label}\n${hit.content}`;
})
.join("\n\n"),
});What Grounding Validates
Grounding validates that the answer follows the citation contract:
grounding({
id: "docs-grounding",
retriever: docs.retriever(),
citations: {
required: true,
quotes: "required",
},
});Typical constraints:
| Setting | Meaning |
|---|---|
required: true | The answer must cite retrieved or searched evidence. |
quotes: 'required' | Citations must include quote text from the evidence. |
select | Read citations from a custom output shape. |
Use normal retriever context when citations are helpful but not contractual. Use grounding when the output schema, review workflow, or user experience depends on citations being structured and checkable.