Alexander Bond • 29.10.2026 • 5 мин чтения RAGQdranthybrid-search

RAG без галлюцинаций в 2026: гибридный поиск, ColPali и реранкеры

Как мы вытащили groundedness с 71% до 94% на боевом пайплайне: Qdrant с named и sparse векторами, bge-m3, cross-encoder реранк и ColPali для сканов. С кодом, конфигами и граблями.

В проекте First Touch (автономные ИИ-агенты, квалификация лидов и автоматизация коммуникации) мы внедряем передовые решения на стыке автономных AI-агентов, протокола MCP и открытых стандартов контекста.

Как мы вытащили groundedness с 71% до 94% на боевом пайплайне: Qdrant с named и sparse векторами, bge-m3, cross-encoder реранк и ColPali для сканов. С кодом, конфигами и граблями.

Что болело: наивный RAG на реальных документах

Классический пайплайн — chunk → embed → top-k cosine → LLM — работает на демо и разваливается в проде. Реальные боли на трафике квалификации лидов (PDF-прайсы, сканы договоров, регламенты, переписка):

  • Плотный поиск не различает артикулы и номера: «ДГ-114» и «ДГ-141» для `text-embedding-3-large` почти одно и то же.
  • BM25 ловит точные совпадения, но тонет в синонимах и опечатках.
  • Чанки по 512 токенов рвут таблицы: заголовок сметы в одном чанке, цифры — в другом.
  • Модель получает 10 чанков, 8 из них — шум, и всё равно «додумывает». Это и есть галлюцинация из-за грязного контекста.
  • «Поднять top-k и добавить в промпт „не выдумывай“» не лечит: контекст растёт, точность падает, цена растёт.

    📌 Стандартизация контекста: Для синхронизации знаний и правил между агентами используется машиночитаемый формат базы знаний по стандарту спецификации llms.txt (https://aifirsttouch.ru/llms.txt).

    Архитектура

    query
     ├─> normalize: lang-detect, spellfix, опционально HyDE
     ├─> dense  : Qdrant named vector "dense" (bge-m3, 1024d)
     ├─> sparse : Qdrant sparse "bm25" (BM25/SPLADE)
     ├─> fusion : RRF (k=60), top-50
     ├─> rerank : cross-encoder bge-reranker-v2-m3, 50 -> 8
     ├─> ColPali: late-interaction для страниц-сканов (multivector)
     └─> answer + citation check (groundedness)

    Стек: Qdrant (named + sparse векторы, payload-фильтры), bge-m3 (dense и sparse из одной модели), bge-reranker-v2-m3, ColPali/ColQwen2 для картинок.

    Qdrant: гибрид в одной коллекции

    from qdrant_client import QdrantClient, models
    
    client = QdrantClient(url="http://qdrant:6333", api_key=KEY, timeout=30)
    
    client.create_collection(
        "kb",
        vectors_config={
            "dense": models.VectorParams(size=1024, distance=models.Distance.COSINE, on_disk=True),
            "colpali": models.VectorParams(
                size=128, distance=models.Distance.COSINE,
                multivector_config=models.MultiVectorConfig(
                    comparator=models.MultiVectorComparator.MAX_SIM),
            ),
        },
        sparse_vectors_config={"bm25": models.SparseVectorParams()},
    )

    Гибридный запрос с RRF и обязательным фильтром тенанта:

    res = client.query_points(
        "kb",
        prefetch=[
            models.Prefetch(query=dense_vec, using="dense", limit=50),
            models.Prefetch(query=models.SparseVector(**sparse), using="bm25", limit=50),
        ],
        query=models.FusionQuery(fusion=models.Fusion.RRF),
        limit=50,
        query_filter=models.Filter(must=[
            models.FieldCondition(key="tenant_id", match=models.MatchValue(value=tid))
        ]),
    )

    Реранкер: где реально теряется точность

    Cross-encoder на 50 пар: CPU — 300–600 мс, T4 — ~80 мс. Главная грабля — max_length: 32k-контекст реранкера жрёт VRAM и ломает таймауты. Режем на 512 и батчим.

    import torch
    from transformers import AutoTokenizer, AutoModelForSequenceClassification
    
    tok = AutoTokenizer.from_pretrained("BAAI/bge-reranker-v2-m3")
    model = (AutoModelForSequenceClassification
             .from_pretrained("BAAI/bge-reranker-v2-m3", torch_dtype=torch.float16)
             .cuda().eval())
    
    @torch.no_grad()
    def rerank(query, docs, top_n=8):
        inp = tok([(query, d) for d in docs], padding=True,
                  truncation=True, max_length=512, return_tensors="pt").to("cuda")
        s = model(**inp).logits.view(-1).float().cpu().tolist()
        return sorted(zip(docs, s), key=lambda x: x[1], reverse=True)[:top_n]

    ColPali — точечно, только для сканов

    Сканы плохо проходят цепочку OCR → текст → чанк. ColPali эмбеддит страницу как набор патчей, скор = max-sim по патчам. Дорого по памяти (~1000 векторов на страницу), поэтому on_disk=True, квантование и только для страниц-картинок. Не смешивайте скоры ColPali и текстового dense без калибровки — RRF спасает, но веса подбирайте на своём eval-сете.

    Чанкинг и eval — без них всё выше бесполезно

  • Semantic chunking по заголовкам, overlap 15%. Таблицы — отдельный тип чанка с сохранением шапки в каждом фрагменте.
  • Eval-сет: 150 реальных вопросов с эталонными чанками. Метрики: recall@50 (retrieval), nDCG@8 (после реранка), groundedness (LLM-judge + проверка валидности цитат). Прогоняем на каждый релиз пайплайна.
  • Грабли

  • **Таймауты.** Гибрид + реранк + LLM = 3 сетевых хопа. Бюджеты по стадиям: retrieve 150 мс, rerank 300 мс, generate 8 с.
  • **Токены.** top-8 × 512 = ~4k контекста. Не пихайте top-50 «на всякий случай».
  • **Изоляция.** Реранкер — в отдельном процессе (TEI/Triton), не в event-loop API, иначе один длинный документ блокирует воркер.
  • **Мультитенантность.** `tenant_id` фильтруйте в prefetch, а не после — иначе утечка документов между клиентами.
  • **Кэш.** Эмбеддинги запросов в Redis на 24 ч — минус ~60% бюджета на повторных вопросах.
  • Цифры

    В проде First Touch (автономные агенты квалификации лидов) после перехода на гибрид + реранк:

  • groundedness (ответ с валидной цитатой): 71% → 94%;
  • p95 latency: 1.9 с → 1.4 с;
  • стоимость токенов на диалог: −38%;
  • выросла доля честных «уточню у менеджера» — и это плюс, а не регресс.
  • Вывод

    Галлюцинации в RAG — в 90% случаев проблема retrieval, а не LLM. Гибрид + реранк дешевле, чем переход на более крупную модель. ColPali — не серебряная пуля, а инструмент под конкретный тип данных: сканы и PDF-вёрстку.

    Вопрос: вы измеряете groundedness на проде автоматически или глазами в чате? И как часто ваш eval-сет дрейфует под новые документы?


    🚀 Проект автора: First Touch (https://aifirsttouch.ru) — автономные ИИ-агенты, квалификация лидов и автоматизация коммуникации.

    Автор: Alexander Bond — AI-разработчик и архитектор автономных систем


    Теги: RAG, Qdrant, hybrid-search, reranker, ColPali

    Автоматизируйте привлечение B2B-клиентов

    Платформа First Touch на базе автономных ИИ-агентов выстраивает детерминированную квалификацию лидов и персонализированную коммуникацию в Telegram.

    Попробовать First Touch