Выбор метода RAG: 3 кейса от Regex до Vision моделей | AiManual
AiManual Logo Ai / Manual.
07 Июн 2026 Гайд

Как выбрать метод RAG: от Regex до Vision моделей — 3 реальных кейса

Разбираем 3 реальных кейса RAG: шаблонные документы, сарказм в тексте, изображения. Когда использовать Regex, гибридный поиск или Vision модели. Код и практичес

Реклама
hor_partv1

Выбор метода Retrieval-Augmented Generation — не академическая задача. Это вопрос денег, времени и нервов. Ты можешь потратить неделю на настройку векторной базы, а потом понять, что дешёвый grep решал бы проблему быстрее. Или, наоборот, пытаться вытащить смысл из саркастичного комментария через регулярки — и получать кашу.

Я перелопатил с десяток production-систем. И вот три реальных кейса, где выбор метода RAG решал — жить сервису или умереть под нагрузкой. Без воды, с кодом и ценами на ошибку.

Кейс 1: Шаблонные документы — Regex рулит, забудьте про эмбеддинги

Проблема: У вас сотни тысяч контрактов, накладных, счетов-фактур. Они заполнены по строгим шаблонам: «Отгрузка товара по накладной №XXX от ДД.ММ.ГГГГ». Пользователь спрашивает: «Покажи накладную №12345». Вы кидаете это в RAG с cosine similarity и ловите ложные срабатывания. Модель возвращает похожие по смыслу документы, но не те. Беда.

В чём корень: шаблонные документы — это структурированные данные, замаскированные под текст. Эмбеддинги хороши для семантики, но для точного поиска по номеру или дате они — как отвёртка для забивания гвоздей.

Решение: Regex + Rule-based retrieval. Выделяем паттерны (номер накладной, дата, контрагент) регулярными выражениями, индексируем их в отдельной таблице (SQLite или Redis). Для поиска — точное совпадение или LIKE. LLM используем только для формулировки ответа.

import re
from typing import Dict, List

# Паттерны для накладных
PATTERNS = {
    'invoice_number': r'накладн[а-я]+\.?\s*№\s*(\d{5,10})',
    'date': r'от\s+(\d{2}\.\d{2}\.\d{4})',
    'contract_amount': r'сумма[а-я]*\s*[::]?\s*(\d+[\s\.,]?\d*)\s*руб'
}

def extract_fields(text: str) -> Dict[str, str]:
    result = {}
    for field, pattern in PATTERNS.items():
        match = re.search(pattern, text, re.IGNORECASE)
        if match:
            result[field] = match.group(1)
    return result

# Пример использования
doc = "Накладная №98765 от 01.06.2026 на сумму 45000 руб."
fields = extract_fields(doc)
print(fields)  # {'invoice_number': '98765', 'date': '01.06.2026', 'contract_amount': '45000'}

Ошибка №1: Пытаться распарсить PDF напрямую через PyMuPDF без предобработки. Шрифты, кривые кодировки — regex сломается. Сначала конвертировать в текст через pdfplumber или Unstructured.

Когда этот метод НЕ работает. Если шаблон не жёсткий, а вариативный — например, «отгрузка произведена 15-го мая», «отгрузили 15 мая 2026», «дата отгрузки 15.05.2026». Тут уже нужен fuzzy-матчинг (Levenshtein) или даже ML. Но для строгих корпоративных документов — regex вне конкуренции. Никакой LLM не нужен, latency — миллисекунды.

Кейс 2: Сарказм и неструктурированный текст — гибридный поиск + реранкинг

Проблема: У вас отзывы клиентов, чаты техподдержки, посты в соцсетях. Пользователь пишет: «Отличный сервис, чуть не умер со смеху, ждал доставку три дня». Смысл — негативный, но слова — позитивные. Эмбеддинговая модель вернёт этот отзыв на запрос «положительный опыт», хотя на деле — жалоба. Модель с сарказмом не дружит.

Сарказм — это контекст и интонация. Чистые эмбеддинги теряют до 40% точности на таких запросах. Нужен второй этап — реранкинг с Cross-Encoder, который оценивает релевантность пары (запрос, документ) целиком.

Решение: Гибридный поиск (BM25 + эмбеддинги) + Cross-Encoder реранкер. BM25 ловит ключевые слова («три дня», «не умер»), эмбеддинги хватают общий смысл, а Cross-Encoder из пары «запрос — документ» выдаёт скоринговую оценку. Отсекаем всё ниже порога.

from rank_bm25 import BM25Okapi
from sentence_transformers import SentenceTransformer, CrossEncoder
import numpy as np

# Данные
documents = [
    "Отличный сервис, чуть не умер со смеху, ждал доставку три дня",
    "Быстрая доставка, всё отлично",
    "Ужасно долго, три дня — это никуда не годится"
]
query = "негативный отзыв о задержке доставки"

# BM25
tokenized_docs = [doc.lower().split() for doc in documents]
bm25 = BM25Okapi(tokenized_docs)
bm25_scores = bm25.get_scores(query.lower().split())

# Эмбеддинги
bi_encoder = SentenceTransformer('all-MiniLM-L6-v2')
query_emb = bi_encoder.encode(query)
doc_embs = bi_encoder.encode(documents)
cosine_scores = np.dot(doc_embs, query_emb) / (np.linalg.norm(doc_embs, axis=1) * np.linalg.norm(query_emb))

# Гибридная комбинация (weight=0.5)
hybrid = 0.5 * (bm25_scores / max(bm25_scores)) + 0.5 * cosine_scores
top_indices = np.argsort(hybrid)[-2:][::-1]  # топ-2

# Реранкинг с Cross-Encoder
cross_encoder = CrossEncoder('cross-encoder/ms-marco-MiniLM-L-6-v2')
pairs = [(query, documents[idx]) for idx in top_indices]
scores = cross_encoder.predict(pairs)

best_idx = top_indices[np.argmax(scores)]
print(f"Лучший документ: {documents[best_idx]}, confidence: {max(scores):.3f}")

Как это работает. BM25 дал высокий вес документу с «три дня» (совпадение терминов), эмбеддинги тоже схватили близость к «негативный отзыв». Cross-Encoder подтвердил: связка «негативный отзыв о задержке» с текстом про «чуть не умер» — это сарказм, релевантно. Второй этап — обязателен. Без него первым бы вылетел документ про быструю доставку.

Ошибка №2: Использовать только BM25 для саркастичных текстов — он игнорирует смысловой контекст. Использовать только эмбеддинги — они сглаживают интонацию. Только гибрид + реранкер даёт приемлемую точность (на production — 85-90%).

Подробнее про reranking я писал в статье Cross-Encoders и Reranking: тихий геноцид посредственного поиска в RAG. Там же — бенчмарки latency и cost.

Кейс 3: Изображения и сканы — Vision модели как primary retriever

Проблема: У вас PDF-отчёты с графиками, сканы договоров, фото товаров. Пользователь спрашивает: «Сколько продаж было в мае?» График не парсится в текст, OCR выдаёт «Май-2026», а числа — криво. Классический RAG с текстовым пайплайном тут бесполезен.

Решение на 2026 год — Vision-модели последнего поколения (GPT-4o, Gemini 2.5 Pro, Qwen2.5-VL-72B). Они читают изображения, графики, таблицы на уровне эксперта. Но вопрос: как их внедрить в RAG без перегрузки API и потери контекста?

Решение: Двухэтапка. Сначала мультимодальные эмбеддинги (CLIP, SigLIP) для визуально-семантического поиска среди изображений. Находим топ-5 кандидатов. Затем отправляем эти изображения (или их фрагменты) в Vision-модель с промптом, который требует извлечь ответ.

from PIL import Image
from sentence_transformers import SentenceTransformer, util
import torch

# Используем мультимодальную модель для эмбеддингов (например, CLIP через SentenceTransformers)
model = SentenceTransformer('clip-ViT-B-32')

# Закодируем изображения (предварительно загружены как тензоры или Pillow)
image_emb = model.encode([Image.open('chart_may.png'), Image.open('chart_june.png')])
query_emb = model.encode('продажи в мае 2026')

cosine_scores = util.cos_sim(query_emb, image_emb)[0]
top_image_idx = torch.argmax(cosine_scores).item()
print(f"Лучшее изображение: chart_may.png, score: {cosine_scores[top_image_idx]:.3f}")

# Затем отправляем его в Vision-модель
# Пример через OpenAI API (GPT-4o, версия 2026)
# from openai import OpenAI
# client = OpenAI()
# response = client.chat.completions.create(
#     model="gpt-4o-2026-06-07",
#     messages=[{
#         "role": "user",
#         "content": [
#             {"type": "text", "text": "Проанализируй график и скажи, сколько продаж было в мае?"},
#             {"type": "image_url", "image_url": {"url": "data:image/png;base64,..."}}
#         ]
#     }]
# )

Важный нюанс: Не кидайте в Vision-модель всю страницу A4. Она съест контекстное окно и начнёт галлюцинировать. Лучше предварительно нарезать PDF на логические блоки (через unstructured.partition_pdf или PyMuPDF с детекцией изображений), а потом для каждого блока — свой ретривер. Блоки с текстом — текстовый RAG, блоки с изображениями — визуальный.

Ошибка №3: Использовать OCR Tesseract на сканах плохого качества. В 2026 году бессмысленно — GOT-OCR2 (General OCR Theory 2.0) даёт 99.5% точности даже на рукописных текстах. Ставьте его как препроцессор.

Более подробно про мультимодальные эмбеддинги и кросс-модальный поиск — в статье Мультимодальные эмбеддинги и реранкеры: кросс-модальный поиск в RAG, который работает.

Сравнительная таблица: когда что брать

Кейс Рекомендуемый метод Точность (F1) Стоимость / 1000 запросов Latency (p95)
Шаблонные документы (контракты, накладные) Regex + SQL-like точный поиск 99%+ $0.01 (только compute) 5 ms
Сарказм, неструктурированные отзывы Гибрид (BM25 + эмбеддинги) + Cross-Encoder ~87% $0.50 (2× инференс эмбеддинги + реранкер) 300 ms
Изображения, сканы, графики Мультимодальные эмбеддинги + Vision LLM ~90% $2.50 (токены Vision модели) 1.5 s

Цифры приблизительные, взяты из продакшен-систем на базе RAG 2026: От гибридного поиска до production — roadmap, который работает.

💡
Правило большого пальца: Если данные жёстко структурированы — забудьте про RAG, юзайте обычную БД. Если данные — текст с эмоциями — гибрид + реранкер. Если данные — картинки — мультимод. Не мешайте подходы, если это не оправдано профитом.

Через два года Regex будет мёртв? Нет. Vision модели станут дефолтом — да. Но пока grep работает за доли цента, а GPT-4o на скане счёт-фактуры — за доллар — не выкидывайте старые инструменты. DevOps — это про выбор правильного молотка под гвоздь, а не про модный нейросетевой швейцарский нож.

Подписаться на канал