Skip to content

Filtering

retrievalagent supports metadata filters on every search request. Filters use a Meilisearch-style string syntax, automatically translated to each backend's native dialect.

Syntax

# Equality
'brand = "Bosch"'
'in_stock = true'
'price < 100'

# Inequality
'category != "archived"'

# AND
'in_stock = true AND price < 100'

# NOT CONTAINS (substring exclusion)
'NOT supplier CONTAINS "house-brand"'

# Chained
'category = "tools" AND brand != "generic" AND price < 50'

Always-on filter

Pass filter= to Agent or init_agent to apply the same filter to every query — BM25, vector, and hybrid:

from retrievalagent import init_agent

rag = init_agent(
    "products",
    model="openai:gpt-5.4",
    backend="meilisearch",
    filter="in_stock = true",
)

Per-query filters (auto-detected via the tool-calling agent) are AND-joined with this base filter.

Per-query filter

from retrievalagent.backend import SearchRequest

state = rag.invoke("brake cleaner", filter_expr='brand = "WD-40"')

Backend filter dialects

Backend Equality NOT CONTAINS AND
Meilisearch field = "v" NOT field CONTAINS "v" A AND B
LanceDB field = 'v' field NOT ILIKE '%v%' A AND B
DuckDB field = 'v' field NOT ILIKE '%v%' A AND B
pgvector field = 'v' field NOT ILIKE '%v%' A AND B
Qdrant FieldCondition(MatchValue) FieldCondition(MatchText) in must_not native dict
ChromaDB {"field": "v"} (dropped — no substring op) {"$and": [...]}
Azure AI Search OData field eq 'v' not search.ismatch(...) A and B

retrievalagent's filter translator handles all dialect differences automatically. You write Meilisearch syntax; retrievalagent converts it for the active backend.

ChromaDB limitation

ChromaDB has no metadata substring operation. NOT CONTAINS clauses are silently dropped rather than raising an error, so queries still run — just without that constraint.