Как работает поиск, какие параметры за что отвечают, и что в итоге попадает в ответ.
Система определяет режим работы по двум параметрам:
| Режим | Условие | Что вы получите |
|---|---|---|
| Извлечение ключа | Указан json_key |
Система найдёт все значения указанного ключа по каталогу. LLM для ответа не вызывается. llm_answer_enabled игнорируется. |
| LLM-ответ | llm_answer_enabled=true, json_key не указан |
LLM сгенерирует текстовый ответ на основе найденных чанков и графового контекста |
| Только данные | llm_answer_enabled=false, json_key не указан |
Вернутся только найденные чанки, граф и структуры — без текстового ответа |
Это всегда первый шаг — независимо от режима. Система ищет чанки, похожие на ваш вопрос.
| Параметр | Дефолт | Что происходит |
|---|---|---|
top_k | 4 | Сколько чанков вернуть. Система ищет в 4× больше кандидатов, но в итоге оставляет только top_k лучших. Увеличьте, если нужно больше контекста (6–8 для каталога, 4–5 для LLM). |
hybrid_enabled | true | Добавить поиск по ключевым словам. Если включён — к векторному поиску добавляется нечёткий поиск по тексту. Результаты смешиваются: 75% семантика + 25% ключевые слова. Выключайте, если хотите чисто семантический поиск. |
correction_enabled | true | Исправлять опечатки. Перед поиском система пробует исправить ошибки в запросе. Полезно для пользовательского ввода, можно отключить для точных запросов. |
score_threshold | 0.0 | Отсеять слабые результаты. Чанки с оценкой ниже порога не попадут в ответ. 0 = не фильтровать (подходит для каталога). 0.3–0.5 для LLM — убрать шум. |
Когда срабатывает: если graph_enabled=true (по умолчанию) и найдены чанки с object_id (т.е. структурированные данные — JSON/XLSX). Если выключить — поиск опирается только на векторную базу.
Система берёт найденные чанки и по их object_id идёт в Neo4j за дополнительными данными:
| Что Neo4j отдаёт | Параметр | Дефолт | Простыми словами |
|---|---|---|---|
| Связи между сущностями Entity → Entity (общий бренд, категория...) |
graph_context_limit | 8 | Сколько связей тащить из графа. Связь = «объект А и объект Б имеют общую сущность». Чем больше — тем шире контекст, но медленнее. Также ограничивает количество seed-объектов, от которых идёт поиск. |
| Структура объектов Item = {Название: "...", Цена: "..."} |
neo4j_items_limit | 5 | Сколько карточек объектов вернуть. Каждый объект — набор полей ключ:значение. Для json_key эти данные сканируются при извлечении. Для LLM — попадают в промпт. |
| Смысловые блоки текста SemanticBlock = разделы PDF/DOCX |
graph_context_limit | — | Только для текстовых документов. Лимитируется тем же graph_context_limit. |
| Похожие объекты «У этих объектов общая категория/бренд» |
graph_context_limit | — | Объекты, связанные через общие сущности. Для LLM попадают в промпт с properties связанных объектов. |
Если graph_enabled=false — весь этот шаг пропускается. Ответ строится только на чанках из pgvector.
Когда срабатывает: только если указан json_key и graph_enabled=true.
Помимо чанков из шага 1, система находит похожие объекты через граф и дофетчивает все их чанки. Это нужно, чтобы найти значения ключа в записях, которые не попали в первый поиск, но связаны через общие сущности.
| Параметр | Дефолт | Что происходит |
|---|---|---|
graph_expand_limitтолько json_key | 6 | Сколько связанных объектов найти. Система идёт в Neo4j и по сущностям из чанков находит объекты с общими связями. Каждый объект = запись в каталоге. Увеличьте для полноты, уменьшите для скорости. Влияет только при указанном json_key. |
max_graph_kтолько json_key | 10 | Максимум дополнительных чанков. Найденные объекты содержат неизвестное число чанков (1 объект может дать 3-5 чанков). Этот параметр ограничивает итоговое число дополнительных чанков. Защита от взрывного роста ответа. Влияет только при указанном json_key. |
graph_score_threshold | 0.6 | Минимальный балл для запуска расширения. Если лучший чанк набрал меньше — система считает, что поиск не попал в цель, и не тратит время на графовое расширение. |
json_key — извлечение значений
Система сканирует все найденные данные и извлекает значения указанного ключа:
{NAME: "iPhone"})NAME: iPhone){NAME: "iPhone"})Результат: массив значений key_values. LLM не вызывается.
ОПЦИОНАЛЬНО key_llm_enabled=true — LLM отфильтрует найденные значения по релевантности вопросу.
LLM — генерация ответа
Все найденные данные собираются в промпт для LLM:
Результат: сгенерированный текст answer.
Лимиты работают последовательно — каждый следующий обрезает результат предыдущего. Итог всегда ограничен наименьшим звеном в цепочке.
graph_context_limit определяет сколько записей каталога (object_id) отправить в Neo4j-запрос. neo4j_items_limit — сколько карточек (ключ:значение) вернуть из тех, что Neo4j нашёл.
top_k чанков → уникальные object_id (записи каталога)
→ [:graph_context_limit] ← сколько записей спросить у Neo4j
→ get_items_by_object_ids(...) ← Neo4j возвращает карточки {Название: "...", Цена: "..."}
→ [:neo4j_items_limit] ← сколько карточек оставить
| graph_context_limit | neo4j_items_limit | Итог neo4j_items | Что произошло |
|---|---|---|---|
| 2 | 5 | 2 | Спросили про 2 записи → получили max 2 карточки → лимит 5 не сработал |
| 8 | 2 | 2 | Спросили про 6 записей → получили 6 карточек → обрезали до 2 |
| 3 | 5 | 3 | Спросили про 3 → получили 3 → лимит 5 не сработал |
| 8 | 8 | 6 | Нашлось всего 6 записей (top_k=6) → оба лимита не ограничили |
Совет: ставьте graph_context_limit ≥ neo4j_items_limit, иначе первый будет «душить» второй. Если хотите 5 карточек — graph_context_limit=8, neo4j_items_limit=5.
graph_expand_limit — сколько похожих записей каталога найти через граф (у них общие сущности с вашими чанками: тот же бренд, категория...). max_graph_k — сколько чанков из этих записей реально вернуть в ответ. Одна запись = несколько чанков (строк таблицы).
seed_oids (object_id из top_k чанков — найденные записи) → get_related_item_object_ids(limit=graph_expand_limit) ← найти похожие записи через граф → related_oids (похожие записи: общая категория, бренд...) → fetch_chunks_by_object_ids(...) ← fetch ВСЕХ чанков каждой записи → graph_expanded_chunks (может быть много: 3 записи × 4 чанка = 12) → [:max_graph_k] ← оставить только лучшие
| graph_expand_limit | max_graph_k | Чанков пришло | Итог expanded | Что произошло |
|---|---|---|---|---|
| 3 | 5 | ~12 | 5 | Нашли 3 похожие записи → fetch дал 12 чанков → оставили 5 лучших |
| 6 | 5 | ~24 | 5 | Нашли 6 записей → 24 чанка → всё равно 5, max_graph_k не дал разрастись |
| 3 | 20 | ~12 | 12 | Нашли 3 записи → 12 чанков → лимит 20 не сработал, всё прошло |
| 2 | 10 | ~8 | 8 | Нашли 2 записи → 8 чанков → лимит 10 не сработал |
Совет: для каталога ставьте graph_expand_limit побольше (6–10) — найдёт больше похожих записей. А max_graph_k ограничит итог — защита от раздувания ответа. Хорошая пара: graph_expand_limit=6, max_graph_k=10.
Зелёный = эти данные используются для формирования ответа. Серый = возвращаются, но не влияют. Красный = отсутствуют.
| Данные | json_key + граф | json_key без графа | LLM + граф | LLM без графа |
|---|---|---|---|---|
| Чанки из pgvector | Сканируются для извлечения ключа + возвращаются | То же, но без расширения | Попадают в промпт LLM | Попадают в промпт LLM |
| Доп. чанки из похожих объектов | Тоже сканируются | Не запускается | Не создаётся | Не запускается |
| Карточки объектов (neo4j_items) | Сканируются для извлечения ключа | Не запускается | Попадают в промпт | Не запускается |
| Рёбра (Entity → Entity) | Возвращаются, но ключи не извлекают | Не запускается | Попадают в промпт | Не запускается |
| Похожие объекты (related links) | Возвращаются | Не запускается | Попадают в промпт | Не запускается |
| Смысловые блоки | Возвращаются | Не запускается | Попадают в промпт | Не запускается |
| Параметр | Дефолт | Что меняет |
|---|---|---|
graph_enabled | true | Главный выключатель графа. Если false — поиск только по векторной базе. |
graph_context_enabled | true | Похожие объекты + блоки. Работает только при graph_enabled=true. |
hybrid_enabled | true | Смешанный поиск. Векторный + ключевые слова. |
correction_enabled | true | Исправлять опечатки. |
reranker_enabled | false | Пересортировать чанки нейросетью. |
citations_enabled | false | Добавить цитаты (откуда данные). |
key_llm_enabled | false | LLM фильтрует найденные ключи (json_key). |
llm_answer_enabled | false | Генерировать ответ через LLM. При json_key — игнорируется. |
| Параметр | Дефолт | Простыми словами | Когда влияет |
|---|---|---|---|
top_k | 4 | Сколько чанков вернуть из поиска. | Всегда |
graph_context_limit | 8 | Сколько связей из графа тащить. Ограничивает количество seed-объектов, смысловых блоков, похожих объектов. | LLM + граф |
neo4j_items_limit | 5 | Сколько карточек объектов (ключ:значение) вернуть из Neo4j. | json_key + граф, LLM + граф |
graph_expand_limit только json_key | 6 | Для json_key: сколько похожих записей найти через граф. | json_key + граф |
max_graph_k только json_key | 10 | Максимум доп. чанков от похожих объектов. | json_key + граф |
graph_hops | 1 | Глубина обхода графа. 1 = прямые соседи, 2 = соседи соседей. | LLM + граф |
| Параметр | Дефолт | Простыми словами |
|---|---|---|
graph_score_threshold | 0.6 | Порог для расширения. Если лучший чанк набрал меньше — расширение не стартует. |
score_threshold | 0.0 | Порог для чанков. 0 = все проходят. 0.3–0.5 = отсеивать слабые. |
Каждый чанк имеет поле search_type:
| search_type | Как появился |
|---|---|
semantic | Найден векторным поиском по смыслу |
keyword | Найден поиском по ключевым словам (hybrid_enabled) |
expanded | Дофетчен как принадлежащий тому же объекту |
graph_expanded | Дофетчен из похожего объекта через граф (json_key) |
Все чанки хранятся в pgvector. Neo4j используется только для определения какие объекты дофетчить.
| Поле | Что содержит |
|---|---|
answer | Ответ LLM, или значения ключа, или пустая строка |
key_values | Массив значений json_key. [] для LLM |
chunks | Все чанки: top_k + graph_expanded |
graph_context | Связи из графа + похожие объекты |
neo4j_items | Карточки объектов: {ключ: значение} |
semantic_blocks | Смысловые блоки документов |
citations | Цитаты (если citations_enabled) |
search_ms | Время поиска (мс) |
llm_ms | Время LLM (мс) |
total_ms | Общее время (мс) |
curl -X POST http://localhost:8007/ask \
-H "Content-Type: application/json" \
-d '{"user_id":"search","question":"Ассимилятор"}'
curl -X POST http://localhost:8007/ask \
-H "Content-Type: application/json" \
-d '{"user_id":"search","question":"Ассимилятор","json_key":"NAME","top_k":6}'
curl -X POST http://localhost:8007/ask \
-H "Content-Type: application/json" \
-d '{"user_id":"search","question":"какие смартфоны дешевле 50000?","llm_answer_enabled":true,"graph_context_limit":12}'