Module · Knowledge
Knowledge Base node
Lesson 6 of 6 · 16 min
You have a Knowledge Base with your policies in it. Nothing has read it yet. This node is what does — it takes a question, finds the chunks that answer it, and hands them to whatever comes next.
It works in two quite different ways depending on where you put it. Wired into a flow, it is an ordinary step: a fixed query runs and results come out. Attached to an agent, it becomes a tool the agent reaches for when it needs to know something — and that is how almost every support assistant is built.
The fields
| Field | What it holds |
|---|---|
kb_id | Knowledge base ID to search |
query | Search query |
top_k | Number of vectors to retrieve before filtering (higher = more candidates) Defaults to 20. |
limit | Maximum number of results to return after filtering Defaults to 5. |
threshold | Minimum similarity score for results (0-1) Defaults to 0.3. |
use_hybrid_search | Enable BM25 + Vector hybrid search for better keyword matching Defaults to true. |
bm25_weight | Weight for BM25 in hybrid search (0.0 = pure vector, 1.0 = pure BM25) Defaults to 0.5. |
use_reranking | Re-rank results with cross-encoder for higher precision Defaults to false. |
use_mmr | Apply MMR to diversify results and reduce redundancy Defaults to false. |
kb_id
- What it holds
- Knowledge base ID to search
query
- What it holds
- Search query
top_k
- What it holds
- Number of vectors to retrieve before filtering (higher = more candidates) Defaults to
20.
limit
- What it holds
- Maximum number of results to return after filtering Defaults to
5.
threshold
- What it holds
- Minimum similarity score for results (0-1) Defaults to
0.3.
use_hybrid_search
- What it holds
- Enable BM25 + Vector hybrid search for better keyword matching Defaults to
true.
bm25_weight
- What it holds
- Weight for BM25 in hybrid search (0.0 = pure vector, 1.0 = pure BM25) Defaults to
0.5.
use_reranking
- What it holds
- Re-rank results with cross-encoder for higher precision Defaults to
false.
use_mmr
- What it holds
- Apply MMR to diversify results and reduce redundancy Defaults to
false.
Always set kb_id. Leave it empty and the search runs across every Knowledge Base in the organisation — which sounds convenient and means a customer-facing agent can retrieve from your internal libraries. Naming one KB is both the accuracy fix and the security boundary.
The two numbers people confuse
| Field | Default | What it controls |
|---|---|---|
top_k | How many candidate chunks are fetched from the index before anything is filtered. Raise it when the right answer exists but is not being returned. | |
limit | How many survive and are handed on. Raise it when the agent needs more context; lower it when replies are getting long and vague. | |
threshold | The minimum similarity a chunk needs to count. This is the one that decides whether “nothing relevant” is a possible answer. |
top_k
- Default
- What it controls
- How many candidate chunks are fetched from the index before anything is filtered. Raise it when the right answer exists but is not being returned.
limit
- Default
- What it controls
- How many survive and are handed on. Raise it when the agent needs more context; lower it when replies are getting long and vague.
threshold
- Default
- What it controls
- The minimum similarity a chunk needs to count. This is the one that decides whether “nothing relevant” is a possible answer.
The threshold is the interesting one. Search always ranks; it never says no. Setting a floor is what lets a search legitimately return nothing — which is what you need in order to write an agent that admits it does not know. Set it to zero and there is always an answer, however unrelated, and your agent will use it.
0.3 is a permissive default. If your agent quotes things that are almost-but-not-quite on topic, raise it before you touch the prompt.
How the searching works
Hybrid search is on by default, and it is two searches combined. One matches on meaning — “how long do I have to send it back” finds a paragraph about a returns window without sharing a word with it. The other matches on the words themselves, which is what you need for a product code, an order reference or a term of art. bm25_weight balances the two, at even by default.
Three further options are off unless you turn them on: re-ranking, which reorders results with a second, slower model; MMR, which trades a little relevance for variety so five results are not five paraphrases of one paragraph; and query expansion, which searches for rephrasings of the question as well as the question. Each costs time. Turn one on at a time and measure, rather than enabling all three and wondering why retrieval got slow.
A worked example
A support assistant with exactly one library and no permission to answer from anywhere else.
One agent, one pinned library
kb_id is fixed; only the query is the agent's to write.
Scroll for all 4 steps →
The tool is configured the way the Core Agent lesson described: kb_id is pinned to one library and query is left as {{ai}}. The agent decides what to search for and cannot decide where.
Three lines in that prompt are doing the real work. One says always search before answering — without it an agent will answer policy questions from general knowledge, and general knowledge about returns policies is a fiction. One says what to do when the search finds nothing. And one says the numbers may not be changed, because a model paraphrasing “within 30 days” into “within about a month” has changed your policy.
What comes back
| Reference | What you get |
|---|---|
{{alias.results}} | The matching chunks with their metadata. |
{{alias.contents}} | Just the text — the usual input to a model. |
{{alias.total_found}} · {{alias.results_returned}} | How many passed the threshold, and how many were handed on. If the first is zero, the library genuinely had nothing. |
{{alias.best_match}} · {{alias.best_match_score}} | The single strongest chunk and its score. The score is what to look at when tuning the threshold. |
{{alias.llm_formatted_result}} | The results already arranged for a model to read. Saves formatting them yourself. |
{{alias.results}}
- What you get
- The matching chunks with their metadata.
{{alias.contents}}
- What you get
- Just the text — the usual input to a model.
{{alias.total_found}} · {{alias.results_returned}}
- What you get
- How many passed the threshold, and how many were handed on. If the first is zero, the library genuinely had nothing.
{{alias.best_match}} · {{alias.best_match_score}}
- What you get
- The single strongest chunk and its score. The score is what to look at when tuning the threshold.
{{alias.llm_formatted_result}}
- What you get
- The results already arranged for a model to read. Saves formatting them yourself.
What breaks
An empty search and a bad answer look identical downstream. If nothing passes the threshold the node succeeds with no results, and an agent handed nothing will still produce a reply — a fluent, plausible, invented one. The two defences are the prompt line telling it what to do with an empty search, and, when it really matters, a Condition on {{alias.total_found}} before you let the agent speak at all.
Retrieval quality is a writing problem more often than a settings problem. When the right chunk does not come back, the instinct is to raise top_k or lower the threshold. Look at the document first. A paragraph that starts “It must be returned within 14 days” cannot be retrieved by a question about returning a phone, because the chunk never says what “it” is. That is the previous lesson's advice and this is where you feel it.
Nothing tells the agent when the library was last updated. Retrieval returns whatever is stored, with no sense of age. A superseded document sits alongside its replacement, both plausible, and the search may prefer either. Deleting the old version is the only control there is.
Searching every library is one empty field away. The consequence of leaving kb_id blank is not an error — it is a broader search that mostly works, until the day a customer's question happens to match your internal pricing notes. If a workflow is customer-facing, check this field specifically.
Try it
- Add the node on its own, pin
kb_idto a library, and run it with a question you know is answered. Read{{alias.best_match_score}}— that number is your baseline. - Now ask something the library does not cover and read the score again. The gap between the two is where your
thresholdbelongs. - Set the threshold above both and confirm the node returns nothing, successfully. That is the behaviour your agent's prompt has to handle.
- Attach it to an agent with
queryas{{ai}}, and ask a question in your own words rather than the document's. Hybrid search is what makes that work. - Finally clear
kb_idand ask something generic. Watch results arrive from libraries you did not intend to expose.
Next: that completes AI and the Knowledge Base. The last path covers webhooks, finding out why a run failed, and three complete builds.

