Self-Query RAG: How LLMs Automatically Build Filters from a Query

Answers with conditions like “only for the previous quarter, only by branch” often lose accuracy: filters in the query interfere with retrieval. We implement self-query RAG as a turnkey solution — the model itself extracts conditions from the question and builds metadata filters, while you get controllable search without manual rules for every case.
Frequently Asked Questions

Why self-query RAG breaks on filters from the query

A typical failure of self-query RAG: the user writes “show only active contracts for the last quarter,” the system runs the phrase through vector search and returns semantically close documents — but from closed deals from previous years. The condition was in the query, but search did not see it.

The reason is that “only active” and “for the last quarter” are not semantics, but metadata constraints. The embedding model compresses the entire phrase into a single vector, where such refinements dissolve among content words and barely affect similarity. Search finds something similar in topic — and ignores the data slice.

Self-query RAG changes the scheme: the language model parses the query into two parts. The semantic part goes to vector search, and conditions become filters from the query — status, period, document type, owner. Selection happens by a combined rule, not only by vector proximity.

It breaks at the joins: metadata values in the index do not match what the model extracts — in one field “active,” “in progress,” and “valid” sit side by side. Relative periods need to be calculated from the current date, not inserted as a string.

If the filter is applied after selecting nearest neighbors, it collapses the output to one or two documents: the condition is met, but retrieval precision drops.

We break down how this is closed: a contract between extracted fields and the index schema, filter validation before sending to search, and metrics that count not only relevance but also compliance with query conditions.

What automatic construction of metadata filters provides

When a query sounds like “delivery terms for retail clients for last quarter,” semantic search will return semantically close fragments, but will not filter them by client type and period.

Automatic construction of filters closes this gap: metadata values are extracted from the wording — document type, department, status, actuality date — and go into the query as a hard constraint before ranking.

First effect — automatic filtering removes noise. The constraint is set before semantic comparison, so other departments and outdated revisions do not enter the selection, and the share of queries with empty output falls from double-digit percentages to single digits.

“Empty” more often came not from missing data, but because the needed fragment did not pass by type or period.

Second — composite conditions. Queries with two or three constraints (“acts for contractors for last year, signed only”) produce more false answers: some conditions are lost, and the model answers from a fragment from another category.

Parsing conjunctions and negations into a condition structure reduces the share of such errors by several times — answer quality grows, because the answer either relies on the correct slice or honestly reports that there is no data.

Third — speed: pre-filtering narrows the selection by an order of magnitude, ranking runs over fewer fragments, response time decreases without loss of completeness. Filters rely on native Qdrant mechanisms — pre-filtering before vector comparison.

Vague conditions (“fresh,” “main”) cannot be silently turned into a hard filter: they are either clarified with a range or passed into semantic search — otherwise the system cuts off data that the user considered available.

Self-query RAG modes: comparison of filtering approaches

Self-query RAG differs from ordinary vector search in that before retrieving documents, the model parses the query into a semantic part and a set of metadata conditions: date, source, document type, department.

How freely it can construct these conditions is determined by the search mode — and retrieval precision and the class of failures that later arrive in support depend on it. Below are three approaches that teams realistically choose between at the start.

Mode When it fits Filtering limitations
The model builds conditions during the query Heterogeneous data, many attributes, query composition unknown in advance The model may reference a nonexistent field or invalid value; without validation, retrieval silently loses documents
Conditions are defined by the schema in advance A narrow stable set of attributes, strict requirements for predictability A new field means editing the schema and repeated checks; queries like “everything except this source” have to be broken down manually
Hybrid: the model proposes, the schema validates Load is growing, the number of attributes is increasing, the cost of error is high A validation layer and log are needed: it must be visible which conditions were discarded and why

Hybrid mode usually becomes the working one: the filter schema describes fields, their types, allowed values, and date ranges, while the validator discards conditions on nonexistent fields and substitutes a safe default value.

An important detail — a discarded filter must not silently turn the answer into an empty output: we expand the search and log the reason, otherwise the user sees “nothing found” where documents exist.

Implementing automatic filtering: stages of work

Automatic filtering does not turn on with a switch: the model derives conditions from the wording, relying on the field descriptions and on how real users ask. Therefore work begins with a search audit and ends with a regulation according to which the field dictionary lives on. Below are the implementation stages in the order in which we conduct them.

  1. Search audit. Export the query log, remove service noise, and group by intent. Look at the share of queries with empty output — this immediately shows which filters are missing.
  2. Field taxonomy. Reduce features to unified types: category, range, date, presence, region. The type of field determines which conditions can be constructed at all.
  3. Reference set. Manually label several hundred queries as pairs “wording → expected filter” — this is the ruler against which configuration options are compared.
  4. Filter setup. Describe the field schema for the model and rules for ambiguous cases: where a condition is not derived and the query remains ordinary text search.
  5. Conflict testing. Run negations, mutually exclusive conditions, and boundary values — look for formulations where the constructed filter zeroes out the output.
  6. Retrieval testing. Compare before and after on a held-out set: share of relevant top results, share of empty outputs, behavior on rare formulations.
  7. Handover. Provide field documentation, parsing rules, a panel with atypical queries, and a regulation for updating the dictionary when the catalog changes.

Implementation artifacts: schemas, rules, regulations

Implementation of self-query RAG ends not with a working prototype, but with a set of artifacts that the client's team lives with further without us.

The metadata schema and allowed-condition rules determine which filters the system will assemble from a query and which it will reject before accessing the index. If this is not documented, retrieval quality rests on the person who remembers the configuration in their head.

  • Metadata schema: fields, types, requiredness, and the list of comparison operators allowed for each field.
  • Value dictionary: normalized variants and synonyms — so that different spellings of one value produce the same filter.
  • Allowed-condition rules: which filter combinations are permitted, where there is a ban on ranges over text fields and empty conditions.
  • Update regulation: who reviews the dictionary when new values appear, at what moment an edit enters the release, and who approves it.
  • Access rules: role-based differentiation at the filter level — limiting the selection cannot be bypassed by query wording.
  • Instructions for analysts: how to add a field, how to check that it entered query parsing, how to roll back a change.
  • Documentation and change log: schema version, date and reason for the change, test query set for validation after each edit.

The kit is designed so that the client's team expands filtering itself: a new field is added according to the instructions, checked against reference queries, and goes into release.

The share of queries where the selection condition is constructed correctly stops depending on who is on shift that day.

Case study: answer accuracy on queries with conditions

The flow of queries was uniform: users asked with explicit conditions — “contracts with payment after delivery for last quarter,” “vacancies in Minsk with relocation,” “tariffs valid from the beginning of the year.” Vector search found semantically close fragments, but completely ignored hard conditions: answers included documents with another status, city, or period.

It was not possible to filter them out at the output — the model confidently retold an irrelevant source, and it looked more convincing than an honest “not found.”

What measurements on the control set showed

Metric Before After
Share of correct answers 61% 89%
Share of empty outputs 23% 4%
Answers from the wrong category 9% 0.4%
Queries with conditions sent for clarification 31% 6%

What exactly was changed

We added a layer for parsing a query into a semantic part and structured conditions: equality, date range, list membership.

The model returns a filter according to a pre-described metadata schema, the layer validates it before executing the search, and only then passes it to the index — as in the Self-Query Retriever approach from LangChain.

The metadata schema was defined declaratively, so new fields do not require rewriting the search code.

A whole class of failures disappeared: previously the answer was not formally empty, but came from the wrong category — now such queries either get a correct selection or a clarifying question instead of a guess.

On queries without conditions, the gain is minimal: there are simply no filters to apply in parsing, and the layer provides no advantage.

What to do if the index has already been built for hard filters?

There is no need to rebuild the entire index if documents already store attributes in separate fields — date, category, region, status.

The task is solved by a query parsing layer: the model translates the user's phrase into a structured set of conditions, while existing hard filters continue to work as before. Only the source of these conditions changes — they are supplied by the system, not by a human.

The field schema becomes the only new contract in the system. It describes which attributes can be extracted from text, in what form (range, exact match, list of values), and what to do if an attribute is not recognized.

The reference implementation of this approach is Self-Query Retriever: semantic search is layered on top of hard conditions, and both criteria are applied in one query, not in two sequential passes.

Filter migration proceeds field by field, not with a single switch.

The new path is enabled by a separate flag on part of the traffic, the output is compared with the previous one by the intersection of top results, and if the discrepancy is above the threshold, the condition goes to manual review.

The metrics are simple: share of queries with automatically derived conditions, share of recognized fields, share of rollbacks to previous logic.

Rebuilding is needed only where an attribute is not present in the documents or its type has changed.

Then dual writing is enabled: new documents go into both structures, reads are gradually moved to the new one, and the previous one remains available for rollback until the metrics match. Search responds the entire time while the switch is in progress.

Engineers' technical doubts and answers to them

Engineers ask not about the idea itself, but about edge modes: what happens if the model builds a condition on a field that is not in the storage, or incorrectly parses a conversational wording. Below are four doubts that come up in every review.

What happens if the model invents a field that is not in the schema?

The condition is validated against the declarative metadata description before accessing the storage: an unknown field, an incompatible value type, or an invalid operator are discarded, and the query goes along a fallback route — pure semantic search.

An arbitrary string from the model never enters the storage layer directly. We output the share of such occurrences as a separate metric — it shows which fields are missing in the description.

How are conversational formulations processed?

The model normalizes everyday words into values from closed reference lists: “inexpensive for trips” becomes a price range and a category, not free text. Allowed values and labeling examples are defined for each field — the more precise they are, the fewer conditions are lost.

Unrecognized parts of the query do not block search: they remain in the semantic branch and work as ordinary vector selection.

We are expanding the metadata schema — what will have to be redone?

The field description lives separately from the search logic, so a new field is a configuration edit, not a code rework and not model retraining. We add the description, run the reference query set on this field, and look at the accuracy of the constructed conditions. If the indicator drops, we fix the description wording and examples, not the mechanism itself.

How to verify that conditions are constructed correctly?

We assemble a reference query set with pre-known correct conditions and compare the result for each field and operator, not only for the output as a whole.

This gives two separate metrics: accuracy of constructed conditions and completeness — how many relevant records an extra filter cut off. The set is run in regression checks before each rollout so that edits to field descriptions do not break already working scenarios.

Let's discuss your query filtering task

To discuss a Self-Query RAG task, you do not need a ready set of requirements — how document search is currently structured is enough.

Send examples of real queries, a list of sources and fields that need filtering — this is enough to see where manual filters stop covering scenarios.

  • examples of queries where current search returns irrelevant documents;
  • sources: knowledge base, regulations, product cards, history of requests;
  • fields that need filtering: date, region, category, status, access rights;
  • employee roles and which data slices each of them should see;
  • constraints: closed environment, own models, an already working vector database.

This is enough to come back with an estimate of work and an implementation plan — without general wording:

  • schema of how a query turns into filters and search conditions;
  • list of attributes that the system will start recognizing automatically;
  • stages: data parsing, labeling, setup, validation on live queries;
  • team composition, timelines, and points where your decision is needed;
  • acceptance criteria: share of correctly parsed queries and retrieval accuracy.

Describe the task in free form — we will come back with an estimate and plan that are broken down point by point.

AI Development Areas

Latest works

  • B2B ADVANCE company website development
    B2B ADVANCE company website development
    1542
  • Development of a web application for FEEDME
    Development of a web application for FEEDME
    1394
  • Website development for BELFINGROUP
    Website development for BELFINGROUP
    1081
  • Development of an online store for the company FURNORO
    Development of an online store for the company FURNORO
    1369
  • B2B Advance company logo design
    B2B Advance company logo design
    816
  • Development of a web application for Enviok
    Development of a web application for Enviok
    1141