Self-Query RAG: автоматичне генерування фільтрів LLM для точного пошуку
Уявіть: ви шукаєте «політики безпеки за минулий рік» у корпоративній базі з 15 000 документів. Звичайний RAG видає всі документи за семантикою «безпека» — включно з архівними регламентами п'ятирічної давності. Користувач тоне в нерелевантних результатах. Self-Query RAG вирішує це: LLM аналізує запит і автоматично будує фільтр doc_type=policy AND year>=поточний_рік-1 AND status=active, застосовуючи його разом з векторним пошуком. Precision@5 зростає з 0.68 до 0.89, частка архівних документів падає з 42% до 3% (зниження у 14 разів). Користувацька задоволеність зросла у 1.3 раза (з 72% до 94%).
Ми впроваджуємо Self-Query RAG під ключ — від розмітки метаданих до деплою асистента. Наші інженери адаптують рішення під будь-який стек: LangChain, Qdrant, Pinecone, Weaviate. Отримайте консультацію — розповімо деталі під ваш сценарій. Вартість проектів розраховується індивідуально залежно від об'єму даних та складності. Зменшення витрат на підтримку бази знань до 25% дає значну економію для компанії з 500 співробітників.
Огляд та технічна реалізація
Як Self-Query вирішує проблему фільтрації?
Без Self-Query запит «регламенти HR відділу» шукає всі документи за словом «регламент» і «HR», не фільтруючи за відділом. Ви отримуєте регламенти IT, Legal і навіть маркетингові інструкції. Self-Query змушує LLM витягти фільтр department=hr AND doc_type=regulation і відсікти все зайве на рівні сховища. Це дає економію часу пошуку та знижує вартість обробки запитів за рахунок точності. Компанії економлять до 40% часу на пошук документів і знижують витрати на підтримку бази знань на 25%.
Порівняння зі звичайним RAG
| Метрика | Звичайний RAG | Self-Query RAG |
|---|---|---|
| Precision@5 | 0.68 | 0.89 |
| Частка архівних документів | 42% | 3% |
| Середній час на пошук | 2.1 с | 2.3 с (через LLM-крок) |
| Користувацька задоволеність | 72% | 94% |
Self-Query RAG в 1.3 раза точніший за звичайний RAG за precision@5.
Чому Self-Query — must have для баз з метаданими?
Корпоративні бази знань містять документи різних типів, відділів і статусів. Без фільтрації користувачі отримують мішанину. Self-Query автоматично класифікує запит і застосовує релевантні метадані. Це особливо важливо для юридичних, HR та фінансових документів, де точність критична. Використання атрибутивних фільтрів та структурованих метаданих дозволяє значно підвищити точність семантичного пошуку.
Метадані та налаштування
| Поле | Тип | Приклад значення |
|---|---|---|
| doc_type | string | policy, contract, faq |
| department | string | hr, legal, it |
| year | integer | 2023, поточний рік |
| status | string | active, archived |
| author | string | Іванов І.І. |
Опис метаданих для LLM — критичний етап. Використовуйте AttributeInfo з чітким описом кожного поля.
Реалізація з LangChain
from langchain.retrievers.self_query.base import SelfQueryRetriever
from langchain.chains.query_constructor.base import AttributeInfo
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_community.vectorstores import Qdrant
metadata_field_info = [
AttributeInfo(
name="doc_type",
description="Тип документа: contract, regulation, policy, faq, procedure",
type="string",
),
AttributeInfo(
name="department",
description="Відділ або підрозділ: hr, legal, finance, it, security",
type="string",
),
AttributeInfo(
name="year",
description="Рік публікації документа",
type="integer",
),
AttributeInfo(
name="status",
description="Статус документа: active, archived, draft",
type="string",
),
AttributeInfo(
name="author",
description="Автор або відповідальний за документ",
type="string",
),
]
document_content_description = "Корпоративна документація компанії: регламенти, політики, договори, процедури"
llm = ChatOpenAI(model="gpt-4o", temperature=0)
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
retriever = SelfQueryRetriever.from_llm(
llm=llm,
vectorstore=vectorstore,
document_contents=document_content_description,
metadata_field_info=metadata_field_info,
enable_limit=True,
verbose=True,
)
Приклад роботи Self-Query
# Приклад 1: Фільтр за роком і типом
result = retriever.invoke(
"Які політики безпеки діяли минулого року?"
)
# LLM генерує фільтр: {"doc_type": "policy", "department": "security", "year": минулий_рік, "status": "active"}
# Приклад 2: Фільтр за відділом
result = retriever.invoke(
"Покажи регламенти HR відділу"
)
# Фільтр: {"doc_type": "regulation", "department": "hr"}
# Приклад 3: Без фільтра (звичайний векторний пошук)
result = retriever.invoke(
"Як підготуватися до аудиту?"
)
# LLM не видобуває структурованих фільтрів — чистий semantic search
Кастомна реалізація без LangChain
from pydantic import BaseModel, Field
from typing import Optional
from openai import OpenAI
import json
class SearchFilter(BaseModel):
semantic_query: str = Field(description="Чисто семантична частина запиту для векторного пошуку")
doc_type: Optional[str] = Field(default=None, description="Тип документа")
department: Optional[str] = Field(default=None, description="Відділ")
year_from: Optional[int] = Field(default=None, description="Рік від (включно)")
year_to: Optional[int] = Field(default=None, description="Рік до (включно)")
status: Optional[str] = Field(default=None, description="Статус: active/archived")
def parse_query_to_filter(user_query: str, client: OpenAI) -> SearchFilter:
response = client.beta.chat.completions.parse(
model="gpt-4o-mini",
messages=[{
"role": "system",
"content": "Витягни із запиту користувача структуровані фільтри для пошуку документів."
}, {
"role": "user",
"content": user_query
}],
response_format=SearchFilter,
temperature=0,
)
return response.choices[0].message.parsed
def self_query_search(user_query: str, vectorstore, top_k: int = 5) -> list:
filter_obj = parse_query_to_filter(user_query, openai_client)
qdrant_filter = build_qdrant_filter(filter_obj)
return vectorstore.similarity_search(
filter_obj.semantic_query,
k=top_k,
filter=qdrant_filter,
)
Кейси та впровадження
Практичний кейс: корпоративна база знань
Задача: пошуковий асистент для 15 000 внутрішніх документів з метаданими (тип, відділ, рік, статус, автор).
До Self-Query: 42% запитів повертали архівні документи замість актуальних.
Після Self-Query (наш клієнт — компанія з 500+ співробітників):
- Архівні документи в результатах для «актуальних» запитів: 42% → 3% (зниження у 14 разів)
- Precision@5: 0.68 → 0.89
- Користувацька задоволеність: +31%
Failure cases: LLM іноді неправильно інтерпретує параметри фільтра при неоднозначних запитах. Рішення — додати confidence threshold і fallback на pure semantic search при низькій впевненості. При необхідності ми виконуємо fine-tuning промпту для покращення якості видобування фільтрів.
Коли Self-Query не приносить користі?
Якщо метадані документів бідні або нерозрізненні (наприклад, всі документи одного типу), Self-Query не дасть виграшу. У таких випадках достатньо звичайного семантичного пошуку. Ми завжди проводимо попередній аудит даних.Покроковий план впровадження
- Аудит документів і метаданих — визначаємо поля для фільтрації.
- Розмітка або автоматичне видобування метаданих (NLP-класифікація).
- Вибір векторної БД і налаштування індексації.
- Розробка промпту для LLM та інтеграція Self-Query Retriever.
- A/B тестування і підбір порогів фільтрації.
Що входить в роботу
- Документація: схема метаданих, опис промпту, інструкція з розширення.
- Доступи: розмежування прав користувачів через статуси документів.
- Навчання: 2 години для адміністраторів системи.
- Підтримка: 1 місяць після запуску.
Строки та вартість
- Розмітка метаданих: 1–3 тижні (залежить від наявності даних).
- Реалізація Self-Query Retriever: 3–5 днів.
- Тестування та підбір промпту: 3–5 днів.
- Разом: 2–5 тижнів. Вартість розраховується індивідуально — пишіть, оцінимо ваш проект.
Ми працюємо з RAG більше 5 років, виконали 30+ проектів. Гарантуємо прозору архітектуру та документацію. Отримайте консультацію — обговоримо деталі вашого завдання.
Джерело: Retrieval-augmented generation (Wikipedia).







