Comments 51
Большое человеческое спасибо за то, что потратили время и поделились.
Очень подробная и при этом написанная понятным языком статья. Спасибо большое за то что поделились решением!
Давно таких шикарных статей не видел! Огромное спасибо!!!
Отличная статья, спасибо большое!
Илья, снимаю шляпу. Спасибо.
Может быть, сериализованные таблицы надо было использовать только для retrival нужных страниц, и потом добавлять в augmentation страницы без сериализованных таблиц, плюс только заматченные чанки из сериализованных таблиц? Чтобы понять, сматчился чанк из сериализованной таблицы или нет, можно было бы хранить атрибут в векторной базе.
Отлично рассказано, поздравляю с победой!
И огромное спасибо за детальный рассказ!
Наверное только одно могу добавить: если использовать готовую векторную базу данных, например Qdrant, то название компании можно внести в метаданные и по ним фильтровать в запросе.
Интересно было бы Ваше мнение, какие экономичные модели эмбединга сейчас наиболее хорошо работают с русскими текстами.
А что в вашем понимании - экономичные? Локальные модели с небольшим количеством параметров? Или просто API модели с низким прайсом?
Локальная модель, которая будет с приличной производительностью работать на CPU и хорошо подходит для русского языка.
У меня такой же вопрос, только про api, если бы нужно было подобную систему реализовывать, но для русского языка, какие бы относительно дешевые или бесплатные api порекомендовали в качестве эмбедера и llm?
Я вот воюю с чем-то подобным.
Нет ни у кого примера/документации как подключить RAG в ollama или lm studio.
То есть, не когда запрос идёт в скрипт, там прогоняется запрос по RAG и передается в lm-ку.
А наоборот, запрос идёт в стандартный api ollama/lm studio, оттуда в раг и ответ чтобы приходил с сервиса.
(Пытаюсь документацию загрузить в раг и использовать как автокомплит в продуктах джетбрейнс)
Спасибо за статью! Было очень познавательно, узнал много нового!
Я делал LLM систему которая разбирала вордовские документы и пыталась из них собрать БД по жестким правилам...Самым фрустрирующим процессом был подбор промтов, т.к.:
Это не программирование, а чертово шаманство, немного переформулируешь фразу, и LLM совсем по другому работает. В каких-то случаях лучше справляется gemini, в каких-от openai.
Очень долго отлаживать промты, и нет гарантии, что при любом изменении в LLM и в исходных данных их результаты не поплывут, и не придется все отлаживать заново
Это ужасно скучно, и приходится зарываться в описание граничных случаев совсем "для даунов", когда пишешь "обрати внимание на то, что таблиц может быть больше одной..." и т.д., ну как вы описали с тысячами. Очень хотелось бы этот момент как-нибудь аутсорснуть, вроде кроме естественного интеллекта и настойчивости особых знаний это не требует
В итоге со всеми этими танцами с бубнами, с CoT и т.д. LLM все равно не дает 100% гарантии результата даже на одних и тех же данных (иногда как начнет вместо русского на английском шпарить). В итоге надо делать систему контроля этих глюков, делать 2-3 прохода и усреднять результат
Подскажите, сколько вы всего времени потратили на разработку системы?
Согласен, промпты - это трудоёмкая часть. Но зачастую мучения с ними - это лишь прокси проблемы, не связанной с самим RAGом как таковым.
Неважно, как работает вопросно-ответная система - дилеммы и edge кейсы остаются те же. На том же примере, "Является ли отсутствие доказательства - доказательством отсутствия?"
Не всегда допустимо пустить решение таких вопросов на самотёк.
На разработку системы я потратил 150-200 часов. Но только потому, что я отнёсся к процессу как к обучению. Одно только тестирование десятков парсеров чего стоит.
Так-то разработать что-то подобное, когда уже есть опыт - не так уж долго и сложно.
ну как вы описали с тысячами.
Замечу, этот момент вообще не очевиден для людей "не в теме", как и то, что цифра в скобках - это отрицательное значение.
В некоторых отчётах упоминание о том, что метрики приведены в тысячах, находится в начале секции на 40 страниц. И всё, больше нигде. И вот поди догадайся, надо ли домножать цифры на 1000. Есть, конечно эвристики, типа общих знаний о масштабе компании, что помогает интуитивно догадаться о порядке её доходов, но и это работает не всегда.
При создании валидационного сета натолкнулся на реальный случай, когда годовая выручка компании составила 214 долларов. Не тысяч, не миллионов. Лично перепроверил несколько раз, в т.ч. в других источниках, помимо отчёта.
Так что увы, для того, чтобы добрать несколько процентов точности из хвоста распределения, приходится учитывать подобные правила. Они применимы как к LLM, так и к "кожанным мешкам"
Это не программирование, а чертово шаманство, немного переформулируешь фразу, и LLM совсем по другому работает. В каких-то случаях лучше справляется gemini, в каких-от openai.
Ну теперь ещё DeepSeek добавился
Интересные проблемы при парсинге PDF, которые я обнаружил (но не успел решить):
ABBYY FineReader такие штуки ещё 20 лет назад понимал. Всяко должны уже появиться свободные решения. Или по требованиям нельзя пользоваться сторонними пакетами для парсинга?
Очень круто. Много идей мной апробированных и много новых. Но не понятно какой в итоге процент хороших ответов у модели. Может я пропустил.
Как RAG system design хорошая статья, но если заявляется SOTA не хватает описания системы метрик. В каких осях SoTA, как измеряли качество извлечения информации, как измеряли качество ризонинга, или все измерялось e2e, то тоже как?
Всегда есть типы ошибок, которые рассматриваются: ошибка поиска (в топ выдачи нет полезных подсказок), ошибка ризонинга (когда ллмка получила подсказки) и даже эта ошибка распадается на ошибку когда в топе была подсказка и модель не ответила, когда подсказки не было и не ответила (те работала из весов). А еще интересное, когда модель сама принимает решение ответить из весов несмотря на плохие подсказки. Вот этого не хватило.
Оценивался отдельно Retrieval и Generation. Больше инфы в канале у Рината и тут https://abdullin.com/erc/#r2
Чуть позже он выложит код скоринг системы.
Илья, спасибо за статью, крутая работа!
Корректировку relevance score производил взвешенным средним
vector_weight = 0.3, llm_weight = 0.7
Были другие эксперименты с весами корректировки - 50/50? Как были выбраны финальные коэффициенты?
Да, экспериментировал с другими, рассматривал RRF и прочие. Оценивал условно на глаз после вычитки результатов LLM скоринга (reasoning поле сопровождающее скор помогает в этом).
Сначала вообще думал использовать чисто результаты llm скоринга.
Развесовка исходя из доверия каждой системе. Т.е. similarity score векторного поиска может скорректировать LLM скор, но не сильно, т.к. последний гораздо качественнее
Это тот тип статей, который перечитаешь несколько раз, чтобы запомнить всё, огромное спасибо, +1 статье; +1 Вам!
Кстати, почему использовали Llama и Gpt от OpenAI, а не DeepSeek?
Спасибо)
почему использовали Llama и Gpt от OpenAI, а не DeepSeek?
Llama - потому что одна из номинаций была на открытые модели от IBM. Лама была одним из safe вариантов.
OpenAI - из-за их безумных лимитов. В некоторых пайплайнах у меня параллельно обрабатывалось по 800 запросов, из-за llm реранкинга
Илья, большое спасибо за проделанную работу и за то, что поделились с сообществом. Почерпнул много полезной информации об особенностях работы с llm.
Насколько я понял использовали только модели через апи? Потому что используя локальные модели гарантировать Structured Outputs даже у слабых моделей можно через такие библиотечки как outlines или lm-format-enforcer, у той же vllm они из коробки работают.
Очень интересно и доступно. До этой статьи думал, что все задачи связанные с ии, ллм - это что-то про математику и всякие библиотеки для обучения моделей. А это выглядит как backend задача по большей части
Отличная работа! Но хотелось бы меньше кастомизаций и большей универсальности (в реальную систему не только подобные таблицы будут подаваться скорее всего). Для нас сейчас оптимальный по соотношению затраты/качество является следующий вариант: Ключевой момент: parential retrievement. Маленькие чанки в идеале должны быть близки к размеру среднего запроса пользователя. На практике - абзац или ячейка таблицы. Ячейка таблицы как правило меньше среднего абзаца, потому ячейки больше попадают в топ, но это не баг, а фича, так как таблицы более сложный элемент. Большие чанки - абзац или таблица целиком или страница презентации. Да, таблицы парсятся в json, показало себя лучше, чем markdown. Все, такой подход даёт отличную итоговую точность, но, конечно, когда таблица большая, как в ваших примерах, он вылетает по лимиту токенов. Поэтому приходится усложнять. Во-первых, если таблица более двух страниц, то большой чанк тогда - пара страниц таблицы. В принципе достаточно только заголовки перенеси в каждую страницу. Далее, очень большие таблицы, как правило, с простой структурой. Объединения рандомных ячеек, когда, например, где то посередине три ячейки объединили в одну - такое в больших таблицах крайне редко. Поэтому совсем большие плоские таблицы просто конвертируем в pandas dataframe, а llm просим сделать запрос на фильтрацию датафрейма...
По поводу отображения некоторых символов в PDF, которые при копировании текстом выглядят как бессмысленный набор букв/символов:
Я с этим работал, и оказалось, что в этом виноваты специальные шрифты, которыми собственно эти символы сделаны (для отображения, например, спецсимволов обычным текстом), обычно такой шрифт зашивается внутрь pdf. Для них существуют таблицы соответствий кодов текста в код отображаемого символа (или наоборот, неважно). Часто такое случается в том числе из-за конвертации html -> pdf, но в html легче обнаружить конкретный шрифт и исправить текст.
Примеры таких шрифтов: Symbol, Webdings
О, спасибо за инфу! То есть побороть это можно только при помощи таблицы соответствий кодов? Её где-то нагуглить надо, или она вшита в метаинфу pdf?
В метаинфу, она, к сожалению, не зашита: я смог только их нагуглить. Вот соответствующие таблицы:
Webdings: https://www.alanwood.net/demos/webdings.html
Symbol: https://www.alanwood.net/demos/symbol.html (здесь таблицы отдельно по разным интервалам unicode, если вдруг кодировка не позволяет вмещать всё сразу)
1. Я очень далек от этой тематики, статья стала прекрасным ликбезом! Спасибо!
2. А еще мне со стороны кажется немного странным, что мы, люди, сначала
1) собираем данные в базах, потом
2) строим какие-то сводки метрик и оформляем их в виде красивого PDF-документа, а потом
3) парсим это чудовище в надежде
4) опять получить данные в виде пригодной для работы структуры (читай - обратно запихать в сводную базу).
Мне одному кажется, что цепочка (1)-(2)-(3)-(4) содержит какую-то внутреннюю избыточность, и что без промежуточных этапов (2), (3) было бы как-то проще??
З.Ы. Если что, я не LLM! См. аватарку ;-))
Согласен, цепочка избыточна. Но иначе никак, т.к. у нас нет доступа к базам данных компаний))
Я понимаю, что у некоторых конкретных людей его сейчас нет ;-)
Я переживаю за человечество в целом. У него-то доступ к ним есть?
Или... Или все идет к тому, что у человечества его тоже скоро не будет?! ;-))
Даже если бы был доступ к БД всех компаний - это бы не помогло, поскольку у них всех разная структура. Так что в некотором смысле "красивые pdf-документы" - это общедоступный, понятный всем формат представления данных )
Были ли попытки попробовать параллельно несколько LLM сервис использовать и в конце сравнивать результат?
Попробовать обогатить данные используя внешние источники или это было запрещено правилами?
Пытались валидировать конечный результат используя LLM и при подтверждении ошибки, завести на новый цикл с увеличенным набором данных и явным указанием на предыдущую ошибку?
Уважаемый Илья! Спасибо Вам большое!
Было бы интересно что-то вроде ablation study, как максимально упростить решение, минимально потерять в качестве. Разобраться сколько именно качества докидывают отдельные фичи
что если забить на шифр Цезары
на сколько влияет на скор сериализация таблиц
...
Как я победил в RAG Challenge: от нуля до SoTA за один конкурс