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:

DatabaseUse Case
LanceDB/ChromaDBDevelopment, testing (zero setup)
PgVectorUse PostgreSQL operations and SQL alongside vectors
PineconeManaged 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

StrategyTradeoff to evaluate
Fixed SizePredictable character limits; can split sentences
SemanticUses embedding similarity; adds processing cost and needs retrieval evaluation
RecursiveSplits 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_results to 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

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}")

Next Steps