Performance Tips
Optimize knowledge base performance, search quality, and content loading speed.
Agno's defaults work well for most use cases. But if you're seeing slow searches, memory issues, or poor results, a few strategic changes might help.
Quick Wins
1. Choose the Right Vector Database
Choose a database that fits your workload and operating environment; measure retrieval latency and quality on representative data:
| Database | Use Case |
|---|---|
| LanceDB/ChromaDB | Development, testing (zero setup) |
| PgVector | Use PostgreSQL operations and SQL alongside vectors |
| Pinecone | Managed service, auto-scaling |
from agno.vectordb.lancedb import LanceDb
from agno.vectordb.pgvector import PgVector
# Development
dev_db = LanceDb(table_name="docs", uri="./local_db")
# Production
prod_db = PgVector(table_name="docs", db_url=db_url)2. Skip Already-Processed Files
Skipping unchanged files can reduce repeated ingestion work:
knowledge.insert(
path="documents/",
skip_if_exists=True, # Don't reprocess existing files
)
# Batch loading with filters
knowledge.insert_many(
paths=["docs/", "policies/"],
skip_if_exists=True,
include=["*.pdf", "*.md"],
exclude=["*temp*", "*draft*"]
)3. Use Metadata Filters
validate_filters() checks keys against metadata tracked by an attached contents database. Without that database, validation is skipped and keys are returned unchanged. Configure a contents database before relying on this check.
Narrow the search space before searching:
# Search without filters
results = knowledge.search("deployment process")
# Restrict results by metadata
results = knowledge.search(
query="deployment process",
filters={"department": "engineering", "type": "procedure"}
)
# With a contents DB and tracked metadata, validate filter keys
valid_filters, invalid_keys = knowledge.validate_filters({
"department": "engineering",
"invalid_key": "value" # This gets flagged
})4. Match Chunking to Content
| Strategy | Tradeoff to evaluate |
|---|---|
| Fixed Size | Predictable character limits; can split sentences |
| Semantic | Uses embedding similarity; adds processing cost and needs retrieval evaluation |
| Recursive | Splits using ordered separators with fallback for long text |
from agno.knowledge.chunking.fixed import FixedSizeChunking
from agno.knowledge.chunking.semantic import SemanticChunking
# Fast processing
FixedSizeChunking(chunk_size=5000, overlap=200)
# Evaluate similarity-based boundaries
SemanticChunking(similarity_threshold=0.5)5. Use Async for Batch Operations
Process multiple sources concurrently:
import asyncio
async def load_knowledge():
await asyncio.gather(
knowledge.ainsert(path="docs/hr/"),
knowledge.ainsert(path="docs/engineering/"),
knowledge.ainsert(url="https://company.com/api-docs"),
)
asyncio.run(load_knowledge())Common Issues
Irrelevant Search Results
Causes: Chunks too large/small, wrong chunking strategy.
Fixes:
- Try semantic chunking for better context
- Increase
max_resultsto check if relevant results are ranked lower - Add metadata filters to narrow scope
# Debug search quality
results = knowledge.search("your query", max_results=10)
for doc in results:
print(doc.content[:200])Slow Content Loading
Causes: Reprocessing existing files, semantic chunking on large datasets.
Fixes:
- Use
skip_if_exists=True - Switch to fixed-size chunking
- Process in batches
# Only process new PDFs
knowledge.insert(
path="documents/",
include=["*.pdf"],
exclude=["*draft*", "*backup*"],
skip_if_exists=True,
)Memory Issues
Causes: Loading too many large files at once, chunk sizes too large.
Fixes:
- Process in smaller batches
- Reduce chunk size
- Use include/exclude patterns
- Clear outdated content with
knowledge.remove_content_by_id(content_id)
Advanced Optimizations
Hybrid Search
Combine vector and keyword search:
from agno.vectordb.pgvector import PgVector, SearchType
vector_db = PgVector(
table_name="docs",
db_url=db_url,
search_type=SearchType.hybrid,
)Reranking
Improve result ordering:
from agno.knowledge.reranker.cohere import CohereReranker
vector_db = PgVector(
table_name="docs",
db_url=db_url,
reranker=CohereReranker(model="rerank-v3.5", top_n=10),
)Smaller Embedding Dimensions
Reduce vector dimensions to reduce storage and arithmetic; measure the resulting quality and latency on your workload:
from agno.knowledge.embedder.openai import OpenAIEmbedder
embedder = OpenAIEmbedder(
id="text-embedding-3-large",
dimensions=1024, # Instead of 3072
)Monitoring
These fragments reuse a configured knowledge object. Content listing and status reads require a synchronous contents database with tracked ingestion records; see contents database setup. For an async contents database, use aget_content() and aget_content_status() with await.
import time
# Time searches
start = time.time()
results = knowledge.search("test query", max_results=5)
print(f"Search: {time.time() - start:.2f}s")
# Check failed content
content_list, total = knowledge.get_content()
for content in content_list:
if content.status == "failed":
status, message = knowledge.get_content_status(content.id)
print(f"{content.name}: {message}")