Skip to content
Expedify
AI & the Knowledge Base

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

Nine of twenty-two. The rest are metadata filters, agent overrides and the panel's KB-selection bookkeeping.

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

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

{{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

  1. Add the node on its own, pin kb_id to a library, and run it with a question you know is answered. Read {{alias.best_match_score}} — that number is your baseline.
  2. Now ask something the library does not cover and read the score again. The gap between the two is where your threshold belongs.
  3. Set the threshold above both and confirm the node returns nothing, successfully. That is the behaviour your agent's prompt has to handle.
  4. Attach it to an agent with query as {{ai}}, and ask a question in your own words rather than the document's. Hybrid search is what makes that work.
  5. Finally clear kb_id and 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.