Knowledge Base
Self-contained document ingestion and retrieval for CUGA agents using Docling and local vector stores.
Architecture: Knowledge is the Knowledge Engine in the Capability layer — Docling ingest, embeddings (Persistence layer), and retrieval with citations. See How CUGA works.
CUGA includes a built-in knowledge base powered by LangChain and local vector stores. Docling is integrated for document ingestion: it parses and normalizes PDFs, Office files, HTML, Markdown, images, and other supported types before chunking and embedding, so the pipeline stays self-contained with no external document services.
When enabled, the agent can search, ingest, and manage documents — and it automatically becomes aware of what documents are available.
Enabling Knowledge
Knowledge is enabled by default via settings.toml (see Storage for the embedding provider). To opt out for a specific agent in the SDK:
from cuga import CugaAgent
agent = CugaAgent(tools=[...], enable_knowledge=False)The SDK auto-injects knowledge tools and an awareness block into the agent prompt, so the agent knows what documents are available and how to search them.
Try the Demo
cuga start demo_knowledgeThis is the same chat UI as cuga start demo, with the knowledge engine on — upload documents and query them.
Programmatic Access
from cuga import CugaAgent
import asyncio
agent = CugaAgent(enable_knowledge=True)
async def main():
# Ingest a document
await agent.knowledge.ingest("/path/to/quarterly_report.pdf")
# The agent now automatically knows about this document
result = await agent.invoke("What does the report say about Q4 revenue?")
print(result.answer)
# Direct search (skip the agent loop)
results = await agent.knowledge.search("Q4 revenue figures")
for r in results:
print(f"{r['filename']} (page {r['page']}): {r['text'][:100]}")
# List documents
docs = await agent.knowledge.list_documents()
# Clean up
await agent.aclose()
asyncio.run(main())Scopes
Documents can be agent-scoped (the default — permanent and shared across conversations) or session-scoped (tied to a single thread).
# Permanent, shared across conversations
await agent.knowledge.ingest("/path/to/file.pdf", scope="agent")
results = await agent.knowledge.search("query", scope="agent")thread_id = "user-session-123"
# Temporary, per-conversation
await agent.knowledge.ingest(
"/path/to/file.pdf",
scope="session",
thread_id=thread_id,
)
results = await agent.knowledge.search(
"query",
scope="session",
thread_id=thread_id,
)Supported Document Types
PDF, DOCX, XLSX, PPTX, HTML, Markdown, images, and more — anything Docling can parse.
Storage and Embeddings
The knowledge backend is selected by the global [storage].mode setting:
| Data | mode = "local" | mode = "prod" |
|---|---|---|
| Knowledge vectors | {knowledge.persist_dir}/knowledge_vectors.db (vec0 tables per collection) | storage.postgres_url (pgvector) |
| Knowledge metadata | {knowledge.persist_dir}/metadata.db | Postgres tables cuga_knowledge_meta_*. Uploaded files still live under persist_dir/files/. |
Embeddings are configured under [storage.embedding] and default to a local BAAI/bge-small-en-v1.5 model (no OpenAI key required). See Storage for full options.
The knowledge persistence directory defaults to <cwd>/.cuga/knowledge/ and can be overridden in knowledge_settings.toml.
Citations and sources
Numbered citations in answers are on by default (citations_enabled in knowledge_settings.toml, also a toggle under Knowledge → Settings in the UI).
When the agent cites retrieved chunks, invoke() fills result.sources:
result = await agent.invoke("What does the handbook say about PTO?")
print(result.answer) # may include [1], [2]
for s in result.sources:
print(s["n"], s["filename"], s.get("page"), s.get("snippet"))In the demo UI you can open a cited PDF at the cited page.
Quality profiles and OCR
Pick a RAG profile instead of hand-tuning every knob:
| Profile | When to use |
|---|---|
speed | Fast ingest and search |
standard | Default balance |
balanced | A bit more quality |
max_quality | Best extraction (slower; enables heavier Docling/OCR) |
custom | You set the knobs yourself |
cuga start demo_knowledge --knowledge-profile max_qualitymax_quality is what you want for scanned PDFs (OCR). The default fast Docling path is aimed at digital PDFs.
You can also override embeddings from the CLI (--embeddings-provider, --embeddings-model, --embeddings-base-url, …). Built-in embedding families: local fastembed (default), Hugging Face, OpenAI-compatible, Ollama, and OpenRouter.
Routing Knowledge Through CugaLite
The [advanced_features].force_lite_mode_apps list defaults to ["knowledge"], so knowledge queries always run through CugaLite's faster execution path regardless of lite_mode_tool_threshold. To change this, edit settings.toml:
[advanced_features]
force_lite_mode_apps = ["knowledge", "crm"] # add more apps as neededThe agent's awareness block is rebuilt as documents are ingested or removed, so newly added documents are usable immediately on the next invocation.
