Общая картина · 01 / 12
RAG: найти опору для ответа
Когда ответ должен опираться на загруженный документ, сначала находят относящийся к вопросу фрагмент. context-retriever выполняет этот поиск и возвращает текст с источником.
Готовит материал
Делит документ на чанки и сохраняет текст, векторы и связь с файлом.
Ищет фрагменты
Сопоставляет вопрос с чанками в общей БД и возвращает подходящие.
Формирует ответ
Может передать найденный текст языковой модели вместе с вопросом.
RAG. Retrieval-Augmented Generation — генерация с поиском. Найденный текст даёт модели контекст, которого может не быть в её знаниях. Чанк — небольшой фрагмент документа; у него сохраняется связь с исходным файлом. Retriever возвращает контекст, а окончательный ответ остаётся задачей вызывающего приложения.
01 / 12Сквозной пример · 02 / 12
Один вопрос к документу
Вымышленное «Положение о командировках» уже обработано ingestor. Вопрос звучит иначе, чем нужный абзац.
Положение о командировках.pdf.Пояснение. «Компенсируют дорогу» и «возмещает проезд» близки по смыслу, хотя слова различаются. Ответ по приведённому правилу: после возвращения и при наличии подтверждающих документов. Поисковый сервис передаёт приложению исходный фрагмент, чтобы оно могло сформулировать ответ без потери условий.
02 / 12Идея поиска · 03 / 12
Три способа найти нужный чанк
Вопрос можно сопоставить с сохранёнными фрагментами по смыслу, по словам или обоими способами вместе.
Близкие векторы
Помогает связать «компенсируют дорогу» с отрывком про «возмещение проезда».
Совпавшие лексемы
Ищет по словам и их формам в русском тексте; вопрос с «проездом» найдёт соответствующий чанк.
Два списка кандидатов
Учитывает место чанка в смысловой и словесной выдаче, затем формирует общий порядок.
search_type. В веб-форме заранее выбран hybrid, а запрос HTTP API без этого поля использует semantic.Пояснение. Смысловой путь требует вектора вопроса. Полнотекстовый обращается к словам, поэтому может работать без векторизации. Гибридный поиск сочетает два набора кандидатов по их местам в списках. Ни один режим не проверяет истинность найденного правила — он отбирает контекст для дальнейшего ответа.
03 / 12Связь сервисов · 04 / 12
Где выполняется поиск
Ingestor сохраняет чанки в PostgreSQL. Retriever ищет в этой БД; для semantic и hybrid он через NATS получает вектор вопроса от ingestor.
semantic и hybrid.Пояснение. Для semantic и hybrid retriever отправляет ingestor запрос vectorize.request и получает вектор. Режим fulltext обходится без этого обмена. Во всех режимах SQL-запросы к чанкам выполняет retriever.
Смысловой путь · 05 / 12
Вектор вопроса создаёт ingestor
Чтобы сравнить вопрос с векторами чанков, retriever отправляет его текст в document-ingestor через NATS и получает эмбеддинг в ответ.
Вопрос
Retriever принимает текст и выбранный режим поиска.
NATS
Запрос идёт по теме vectorize.request с адресом для ответа.
Ingestor
Считает вектор через настроенный механизм эмбеддингов.
Ответ
Вектор возвращается retriever и участвует в SQL-поиске.
src/context_search.rb#vectorize_query, document-ingestor/src/config.ru · Как работает запрос–ответ NATSПояснение. NATS доставляет сообщение и ответ, а не выполняет векторизацию. Вектор создаёт ingestor тем же настроенным механизмом, которым он обрабатывает документы. Retriever ждёт ответ до 10 секунд; отсутствие NATS или ошибка векторизации прерывает semantic и hybrid, но не требуется для fulltext.
Поиск в PostgreSQL · 06 / 12
Смысловой поиск по векторам
Вектор вопроса сравнивается с векторами сохранённых чанков. Ближайшие по косинусному расстоянию фрагменты становятся кандидатами для результата.
Вопрос
«Когда компенсируют дорогу?» превращается в набор чисел той же размерности, что и сохранённые векторы.
Чанки в БД
PostgreSQL упорядочивает фрагменты по расстоянию от вектора вопроса.
pgvector: оператор <=> означает косинусное расстояние; для ответа сервис вычисляет similarity = 1 − distance.src/models/chunk.rb#search_similar · Операторы pgvectorПояснение. Порядок условный. Сервис сортирует чанки с заполненным embedding, ограничивает список через limit и затем применяет заданный min_similarity. HNSW-индекс создаёт ingestor; его использование зависит от плана PostgreSQL.
Поиск в PostgreSQL · 07 / 12
Полнотекстовый поиск по словам
PostgreSQL хранит поисковое представление текста каждого чанка. Вопрос разбирается на русские лексемы, после чего сервис выбирает совпавшие фрагменты.
«Возмещают проезд?»
Слова нормализуются с русской конфигурацией PostgreSQL.
Хотя бы одно слово
Лексемы соединяются оператором «или»; порядок слов не требуется.
Ранжирование
ts_rank_cd ставит выше более подходящие совпадения в сохранённых чанках.
content_tsv @@ to_tsquery('russian', …) — проверка совпадения. В этом сервисе fulltext не означает поиск точной фразы.src/models/chunk.rb#search_fulltext, document-ingestor/src/models/chunk.rb · Полнотекстовый поиск PostgreSQLПояснение. Поле content_tsv автоматически создаётся из текста чанка и индексируется GIN. Запрос превращается в отдельные лексемы, соединённые через OR: совпадения хотя бы одного значимого слова достаточно, затем кандидаты сортируются по ts_rank_cd. Этот режим обращается к БД напрямую и не запрашивает вектор через NATS.
Совмещение результатов · 08 / 12
Гибридный поиск объединяет два списка
Смысловой и полнотекстовый поиск независимо выбирают кандидатов. Метод RRF повышает чанки, которые стоят высоко в обоих списках.
Близость векторов
Совпадение лексем
RRF
1 / (k + место). В коде k = 60, исходно берётся до 20 кандидатов каждого вида; отсутствующий в списке чанк получает вклад 0.Пояснение. Порядок в примере условный. RRF складывает вклады мест, а не сами оценки косинусной близости и полнотекстового ранга: у этих оценок разные шкалы. После объединения кандидаты снова читаются из таблицы chunks, сортируются по сумме RRF и ограничиваются limit.
Контекст результата · 09 / 12
Поиск добавляет соседние чанки
Найденный чанк может обрываться посреди правила. После смыслового или гибридного поиска сервис проверяет соседние фрагменты того же документа и при близком содержании добавляет их.
Пояснение. EXPANSION_ENABLED включён: на один исходно найденный чанк возвращается не более трёх фрагментов, включая его самого. Сосед должен быть в том же документе, иметь соседний chunk_index и близость к предыдущему чанку цепочки не ниже 0.6. Для fulltext расширение не выполняется.
Интерфейсы · 10 / 12
Как обратиться к поиску
Веб-страница, HTTP-клиент, ассистент и другой сервис могут запустить одну и ту же логику ContextSearch.search через разные входы.
POST /api/search
Sinatra принимает вопрос и параметры, возвращает JSON с чанками. Главная страница вызывает этот маршрут.
MCP · context_search
StackServiceBase открывает поиск клиенту MCP как инструмент с параметрами вопроса.
NATS · context.search
Принимает запрос по теме и отправляет результат по адресу ответа.
POST /api/vectorize лишь проверяет получение вектора через ingestor; сам поиск чанков выполняет POST /api/search или соответствующий MCP/NATS-вызов.Пояснение. HTTP и NATS context.search без указания режима используют semantic; веб-форма выбирает hybrid. В MCP-схеме режим обязателен, хотя обработчик предусматривает hybrid как запасной вариант. Для HTTP и MCP вопрос ограничен 10 000 символами; limit по умолчанию 10, максимум 50.
Данные ответа · 11 / 12
Ответ содержит текст и источник
Результат содержит текст чанка, сведения о документе и оценку для выбранного режима. Ниже — сокращённый ответ на вопрос из примера.
{
"query": "Когда компенсируют дорогу?",
"search_type": "hybrid",
"results_count": 1,
"results": [{
"content": "Компания возмещает расходы на проезд...",
"score": 0.0325,
"document": { "file_name": "Положение о командировках.pdf" }
}]
}
score: 0.0325 · условное значение для hybridchunk_id, номер чанка, метаданные и, когда доступны, подробные оценки scores. Для hybrid добавляется search_metadata.src/context_search.rb#format_results · Описание полей ответа (на URL сервиса)Пояснение. Число score условное. Для исходных кандидатов это косинусная близость в semantic, текстовый ранг в fulltext или RRF в hybrid. У добавленного соседа оценка может означать близость к предыдущему чанку, а не к вопросу. Оценки не являются вероятностью ответа; после расширения results_count может превысить limit.
Условия работы · 12 / 12
Что нужно для поиска
Retriever работает с чанками, уже подготовленными ingestor. Все режимы обращаются к PostgreSQL; смысловой и гибридный дополнительно запрашивают вектор вопроса.
Готовые чанки
Для демонстрации дождитесь статуса completed у загруженного документа.
PostgreSQL
Сервис читает текст, векторы, поисковое поле и сведения об исходном файле.
NATS и ingestor
Нужны для векторизации нового вопроса; fulltext обходится без этого шага.
GET /presentation на адресе ingestor
Пояснение. Без доступной БД ни один режим не прочитает чанки. Если NATS или обработчик векторизации недоступны, semantic и hybrid завершаются ошибкой; fulltext может искать по БД. Возвращённые фрагменты с источником приложение может передать языковой модели для ответа пользователю.