Skip to main content
KnowledgeBase searches a folder of documents. The agent calls it as a tool and answers from the passages it gets back. It works the same on LiveKit and Pipecat. On this page: It needs the [knowledge] extra. See Install for the install line and the one setting Linux needs.

What it gives you

Quickstart

agent.py
The embedder package, here llama-index-embeddings-openai, is yours to install. Keyword mode needs none.

How it works

  1. The folder holds .txt, .md and .pdf files.
  2. bake() reads them, splits them into passages, and writes the index to index_dir. Run it when you build the image.
  3. start() loads the index when the process starts. It never runs during a call.
  4. await look_up(query) searches the index and returns at most top_k passages.
  5. The content is fixed at start. A lookup never reads a file and never builds the index again.
Without a baked index, start() reads and embeds the documents in memory. That works. But every worker process pays the full cost, and the log warns about it. So call bake() at build time:

What a lookup returns

look_up never raises. It returns one of three shapes, so the model can tell them apart.
  1. source is the file name, never the path. The agent may say it aloud.
  2. score is a similarity from the meaning search. Keyword hits have no score.
  3. The query and the passages never go to the log.

Every argument KnowledgeBase takes

KnowledgeBase

str
required
The base name. It appears in log lines and errors.
Path
required
The folder that holds the documents.
Path | None
default:"None"
Where bake() writes the index and start() looks for it. None never bakes.
meaning | keyword | hybrid
default:"hybrid"
meaning uses embeddings. keyword uses BM25. hybrid runs both and interleaves the hits.
int
default:"90"
Passage size in tokens. 90 tokens is about 65 words. From 1 to 2048.
int
default:"20"
Tokens that neighbouring passages share. From 0 to chunk_size.
int
default:"3"
How many passages a lookup returns. From 1 to 20.
float
default:"0.0"
Drop meaning hits below this score. From 0 to 1. Keyword hits are always kept.
Callable[[], BaseEmbedding] | None
default:"None"
A function that builds the llama-index embedder. Needed for meaning and hybrid.
str | None
default:"None"
The environment variable the embedder needs.
  1. embed is a function, not an embedder. It runs at start() or bake().
  2. A keyword base takes no embed and needs min_score at 0. A base that embeds needs embed. A wrong mix, a bad mode, chunk_size, top_k or min_score, or a chunk_overlap above chunk_size raises a Pydantic ValidationError when you build it. It is a ValueError. It names the field and the allowed values.
  3. credential_env is checked at start() and bake(). A missing key stops the process at once and names the variable.
  4. A baked index remembers the settings it was built with. start() refuses an index built with other settings. Bake it again.
  5. start() and bake() raise KnowledgeError for a missing folder, a folder with no text, or a PDF with no text layer.
Let the process stop on a KnowledgeError. An agent that knows nothing should not take calls.

Use it in an agent

KnowledgeBase.tool(name, description) builds the tool for you. The model reads its description, so say when to use it. The library adds a note on weak results, so you need not write one.
  1. description is up to you. It says when to look up.
  2. The tool ends the description with: “The results may not answer the question. They are ordered best first, and each carries a relevance score where a higher number means a closer match. If nothing returned actually answers what was asked, say you do not have that information rather than offering the closest result.”
  3. The tool has one parameter, query. The model reads it as “What to look up. Use the caller’s own words.”
  4. name defaults to look_up. With no description, the description is the note alone.
  5. The tool is a ToolSpec. Pass it to ToolRegistry.
For a task step, list the tool in the step’s tools. See Tasks and Tools.

Advanced

Keyword mode

Keyword mode needs no embedder and no API key.

Use a lookup in your own code

You can call await REFUNDS.look_up(question) in your own code. Put the passages in a prompt you write yourself.

Troubleshooting

PermissionError: Security Violation [pathsec.open] on the first lookup

llama-index reads NLTK data files. NLTK refuses a file with more than one hardlink, and uv makes hardlinks on Linux by default. Fix: install with copies. Install has the details, also for a Dockerfile.

The log warns that every worker embeds the documents

There is no baked index, so each process embeds the folder at start. Fix: run bake() when you build the image and set index_dir.

start() refuses the index

The index was built with other settings. Fix: bake it again.

The model gets {"error": "lookup unavailable"}

look_up ran before start(), or the search failed. Fix: call start() once at process start, before the first call.

Where to go next

Tools

The tool that wraps a lookup, and its announce line.

Tasks

Offer a lookup to one step of a task.

Install it

The [knowledge] extra and UV_LINK_MODE.

Unmute knowledge

How agent.yaml declares a knowledge base.