Гибридный RAG для внутренней документации: как поднять p95 < 800ms и убрать галлюцинации — 4 июля 2026 г. в 11:56:45.314
Гибридный RAG для внутренней документации: как поднять p95 < 800ms и убрать галлюцинации Корпоративные базы знаний — не тестовый полигон для чатов с LLM. Обычный dense-поиск по векторам стабильно проваливается на специфичных терминах, логах, внутренних аббревиатурах и версиях ПО. Если вы строите ассистанта для DevOps или техподдержки, вам нужен гибридный пайплайн: BM25 для точного лексического совпадения + dense embeddings для семантики + reranker для фильтрации информационного шума. Ниже — рабочая архитектура, которую можно развернуть на одном сервере с Debian 12 и RTX 4090 без облачных API. Начинаем с парсинга. PDF, Markdown и Confluence-дампы нужно разбирать через unstructured или pymupdf, но критично сохранять древовидную структуру заголовков. Без этого чанки теряют родительский контекст, а модель начинает галлюцинировать на разорванных фрагментах. Рекурсивное разбиение по токенам (chunk_size=512, chunk_overlap=64) работает стабильнее семантического сплиттинга для технической документации, где абзацы несут независимое значение. После очистки от артефактов верстки данные летят в индекс. Векторная база должна поддерживать гибридный поиск из коробки. Qdrant закрывает это требование: встроенный SparseVector для BM25 и DenseVector для эмбеддингов. Индексируем через HNSW с параметрами m=16, ef_construction=100. Для балансировки скорости и точности на inference ставим hnsw_ef_search=96. Эмбеддинги генерируем локально через BGE-M3 — модель поддерживает мультилингвальность и динамическое окно до 8K токенов, что критично для длинных README, архитектурных спецификаций и логов. Главная ошибка в RAG — скидывать сырые результаты поиска прямо в контекстное окно LLM. Это мгновенно съедает window budget и провоцирует loss of focus. Вставляем reranker между retriever и generator. Локальный BGE-Reranker-V2-M3 работает через FastAPI-обёртку с кэшированием в Redis и отрезает 60–70% нерелевантных чанков, сохраняя top-4 для финальной генерации. Промпт для LLM должен быть детерминированным: явный разделитель между instruction и retrieved context, строгое требование цитировать источники по UUID чанка, hard fallback на "информация не найдена" при отсутствии подтверждённых фактов. Для локальных моделей вроде Hermes-3-Llama-3.1-8B или Qwen3 обязательно включаем temperature=0.1, top_p=0.9, и ограничиваем вывод 4096 токенами. Мониторинг пайплайна закрываем через OpenTelemetry + Prometheus. Метрики: latency на каждом этапе (parse, embed, retrieve, rerank, generate), hit-rate retriever, accuracy reranker. Алертинг на p95 > 1s или drop в quality score ниже 0.8 позволяет быстро находить узкие места при росте нагрузки и ротации документации. - Парсинг: unstructured partition_pdf "spec.pdf" --strategy hi_res --extract_image_block_to_text false + сохранение metadata в JSON для трекинга источников и версионности - Чанкинг: RecursiveCharacterTextSplitter(chunk_size=512, chunk_overlap=64, separators=["\n\n", "\n", " ", ""]) с принудительным наследованием header_metadata от родительского блока - Qdrant конфиг: HNSWIndexConfig(m=16, ef_construction=100) + sparse vector для BM25, массовая вставка через qdrant_client.upsert(collection_name="corp_docs", points=[...]) с batch_size=32 - Гибридный запрос: QdrantHybridSearch(weight_dense=0.7, weight_sparse=0.3) с нормализацией скор через sklearn MinMaxScaler перед linear aggregation и deduplication по чанк-ID - Reranker локально: pip install fastapi uvicorn sentence-transformers + эндпоинт /rerank принимающий список чанков + query, возвращающий top-4 с sorted relevance scores и кэш TTI < 120ms - LLM промпт-шаблон: система требует <answer> и <citations>[id1, id2]</citations>, валидация через regex r"<citations>\[([a-f0-9\-]+(,\s*[a-f0-9\-]+)*)\]</citations>" перед отдачей пользователю - Метрики: `o...

