Agentic RAG
Give an agent a library card instead of a photocopied packet — it decides when to search your dataset, searches again if the first answer was thin, and every search it ran is recorded and replayable.
Ordinary retrieval works like a photocopied packet. Before the model sees your question, the runtime searches your documents once, staples the top few passages to the prompt, and hands the whole thing over. If the search picked the wrong passages, the model has no way to ask for different ones.
Agentic RAG gives the agent a library card instead. The agent gets a search tool it can call itself. It decides when to search, writes its own search wording, reads what came back, and searches again if the first result was thin. Then it answers from what it actually found.
"RAG" is retrieval-augmented generation: answering from your documents rather than from what a model happens to remember.
What has to be true before this works
Three things. The runtime has to be built with the hnsw build — that is what
makes datasets and the search tool exist at all. A model has to be served. And
you need a dataset, a searchable collection of your text — see
Datasets.
If the search tool is not available, kx agent run --dataset does not pretend.
It prints a line saying the agentic-RAG recipe is not provisioned and runs a
plain agent with no search tool instead.
Run it
Start the runtime. Everything below talks to it.
kx serve --dev-allow-localSee Serving for what that flag means and what to use in place of it away from your own machine.
Put some text in a dataset. Each --text or --file adds a document.
kx datasets ingest handbook --file ./handbook.mdAsk the agent a question against that dataset.
kx agent run --goal "What does the handbook say about parental leave?" --dataset handbook--dataset is what turns an ordinary agent run into an agentic search loop. The
agent now holds the retrieve tool and points it at handbook. The command
prints a line confirming that, so you can tell the search loop actually started.
Read the receipt. Every search the agent ran is recorded in turn order.
kx react list --limit 20You see each retrieve call, including any re-query, so you can tell whether an
answer came from one lucky search or from three.
kx agent run --goal "What does the handbook say about parental leave?" --dataset handbook
kx react list --limit 20from kortecx import KxClient, REACT_RAG_RECIPE_HANDLE
with KxClient("http://127.0.0.1:50151") as kx:
answer = kx.invoke(
REACT_RAG_RECIPE_HANDLE,
{
"instruction": "What does the handbook say about parental leave?",
"dataset": "handbook",
},
wait=True,
)
print(answer.text or "")import { KxClient, REACT_RAG_RECIPE_HANDLE, type Result } from "@kortecx/sdk";
const kx = new KxClient("http://127.0.0.1:50151");
const answer = (await kx.invoke(
REACT_RAG_RECIPE_HANDLE,
{
instruction: "What does the handbook say about parental leave?",
dataset: "handbook",
},
{ wait: true },
)) as Result;
console.log(answer.text ?? "");http://127.0.0.1:50151 is where the runtime listens by default.
What the search tool can and cannot do
The tool the agent holds is called retrieve. It takes three things: which
dataset to search, the search wording, and optionally how many passages to bring
back (1 to 64, default 4). It returns passages in relevance order, each with the
text, a content hash of the passage, a hash of the document it came from, and
which chunk of that document it is.
Its limits are deliberate and enforced by the runtime, not by the model's good behaviour:
- Read-only. It searches. It cannot write anything, anywhere. Because it only reads, the human-in-the-loop gate lets it through without asking you (see Approvals).
- No network reach. It has no egress. It cannot call out to anything.
- No filesystem reach. It has no filesystem scope at all. It reaches the dataset store through an in-process handle, not through a path.
- Unknown arguments are refused. The argument shape is typed and rejects any key it does not recognise.
- It fails soft. A dataset that is missing, empty, stale, or has no embedder available comes back as an empty result with a plain-language note attached — not a crash. The agent reads the note and recovers: it can search a different dataset or answer from what it already has. Only a hard backend fault stops the run, and it stops honestly rather than returning a fake empty.
- Long results are trimmed, and say so. If the passages together would be too large for the model's input window, the least relevant ones are dropped and the result carries a note saying it was truncated. The most relevant passage is always kept. Nothing is dropped silently.
The receipt
This is the part that separates agentic search from a black box.
Each retrieve call commits the ordered content references of the passages it
read. A content reference is a hash of the exact bytes of that passage. So the
record does not say "it searched the handbook and found something useful" — it
says "on turn 2 it searched for these words and read exactly these passages, in
this order."
Similarity scores are deliberately left out of the record. The model proposes the search; the runtime records only exact references. That keeps the recorded fact something you can check rather than something you have to trust.
Because every settled turn is written to the durable journal before the next one
starts, the trail survives a restart: the searches an interrupted run had already
committed are still there to read back. Read them with kx react list, or
through Observability.
When to use it
Use plain single-shot retrieval when the question maps cleanly onto the words in your documents. It is faster and it is enough:
kx chat --message "What is the parental leave allowance?" --dataset handbookUse agentic RAG when the agent has to work out what to look for. Questions that span several documents, questions where the right search wording is not the question's wording, questions where a first search will probably come back thin. That is when letting the agent search again is worth the extra turns.
There is no agentic vision loop
--image and --dataset cannot be combined on kx agent run. The command
rejects it with a usage error. An agent cannot loop over an image and a dataset
together — that recipe does not exist. For a single-shot answer grounded on both
an image and your text, use kx chat --image ./photo.png --dataset handbook.
Search quality
The search behind the tool is hybrid: it matches on keywords and on meaning at the same time, fuses the two rankings, and then demotes near-duplicate passages so the agent does not read the same paragraph three times. A term that a weaker meaning-based search would misrank is still caught by the keyword half.
There is a second, optional reranking pass where a model reorders the candidates.
It is off by default and turned on by setting KX_SERVE_RAG_LLM_RERANK=1 on the
served runtime. It is fail-closed: if the model returns anything that is not a
valid reordering, the original order stands. A rerank can never scramble your
results into nonsense.
Retrieval quality is mostly a function of how you built the dataset — chunking and the choice of embedding model matter more than anything on this page. See Datasets.