Идеальная база знаний, а RAG возвращает мусор — проблема не там, где кажется
Продолжение предыдущего поста про микрочанки, где 3 мусорных документа отравили весь RAG. Тогда проблема была в данных. Сейчас — данные идеальные, а поиск всё равно не работает.
Контекст
Строю локальную мультиагентную систему. Собрал базу знаний: 85 архитектурных блоков, 160 чанков в ChromaDB, реальный опыт — не синтетика. Embedding модель — стандартная all-MiniLM-L6-v2. Документы на русском с вкраплениями английских терминов (DPO, LoRA, VRAM — как у всех).
Симптом
Спрашиваю: "DPO патч для OOM" — в базе есть целый блок про это. RAG возвращает документ про права доступа к Project Context. Вообще мимо.
Спрашиваю: "positive feedback loop" — в базе есть блок №57 ровно с таким названием. RAG его не находит, dist=0.746.
Диагностика
Подозрение — embedding модель не понимает русский текст. Проверяю: один и тот же смысл, три формулировки.
queries = [ ("positive feedback loop", "английский"), ("петля положительной обратной связи", "русский"), ("цикл доверие данные результат", "русский контекст"), ] for q, lang in queries: results = col.query(query_texts=[q], n_results=1, include=["documents", "distances"]) dist = results['distances'][0][0] print(f"[{lang}] dist={dist:.3f} | '{q}'")
[английский] dist=0.746 | 'positive feedback loop' [русский] dist=0.566 | 'петля положительной обратной связи' [русский контекст] dist=0.504 | 'цикл доверие данные результат'
Один смысл — разница в полтора раза. При этом документы в базе на русском. Английский запрос к русским документам — модель не может их сопоставить.
Почему так
all-MiniLM-L6-v2 обучалась на английских текстах. Она превращает текст в вектор из 384 чисел. Для английского — вектор осмысленный, семантически правильный. Для русского — видит буквы, но не понимает смысл. Вектор получается случайный.
Это как нанять переводчика, который знает только английский, и попросить его искать по русской библиотеке.
А может перевести всё на английский?
Первая мысль — перевести все документы на английский, запросы тоже переводить на лету, а результат обратно на русский. Английские embedding модели объективно лучше отточены, больше данных, больше бенчмарков.
Но для локальной системы с русскими документами это плохой вариант. Технические термины с контекстом теряются при переводе. Появляется двойная задержка — перевод запроса туда, результата обратно. Нужен ещё один сервис (переводчик), а задача — держать всё локально. И главное — ошибки накапливаются: плохой перевод → плохой вектор → плохой результат.
Для чисто английских доков — да, держите всё на английском. Но когда документы изначально на русском с кучей специфики — мультиязычная модель проще. Меньше движущихся частей.
Решение
Заменил all-MiniLM-L6-v2 на paraphrase-multilingual-MiniLM-L12-v2. Модель обучена на 50+ языках, включая русский. Понимает смешанный текст типа “DPO обучение на LoRA адаптере” — то, что в локальных ML-проектах встречается на каждом шагу.
Пересоздал все коллекции с новой моделью. Результат:
# Было (all-MiniLM-L6-v2): # 'positive feedback loop' → dist=0.746, нашёл мусор # Стало (multilingual): # 'positive feedback loop' → dist=0.35, нашёл именно блок про Feedback Loop
Поиск заработал сразу. На все запросы — и русские, и английские, и смешанные.
Вывод
Если строите RAG на русском (или любом не-английском) — не берите all-MiniLM-L6-v2 по дефолту. Она стоит первой в каждом туториале, но для нелатинских языков это ловушка. Данные могут быть идеальными, чанкинг правильным, а поиск будет возвращать мусор — потому что “переводчик” не знает ваш язык.
Замена embedding модели на мультиязычную — одна строчка кода и пересоздание коллекций. Пять минут работы, которые сэкономят дни дебага.
# Было ef = SentenceTransformerEmbeddingFunction(model_name="all-MiniLM-L6-v2") # Стало ef = SentenceTransformerEmbeddingFunction(model_name="paraphrase-multilingual-MiniLM-L12-v2")
