От страха к успеху: история появления ИИ-помощника в системе «АФИДА». chromadb.. chromadb. llm.. chromadb. llm. qwen.. chromadb. llm. qwen. rag.. chromadb. llm. qwen. rag. Блог компании Газпром ЦПС.. chromadb. llm. qwen. rag. Блог компании Газпром ЦПС. Интеграция AI.. chromadb. llm. qwen. rag. Блог компании Газпром ЦПС. Интеграция AI. искусственный интеллект.. chromadb. llm. qwen. rag. Блог компании Газпром ЦПС. Интеграция AI. искусственный интеллект. Корпоративные решения.

На связи снова Всеволод Зайковский, заместитель руководителя проекта в «Газпром ЦПС».

В прошлый раз я рассказывал, как мы научили нашу систему «АФИДА» распознавать и раскладывать по полочкам тысячи строительных актов с помощью компьютерного зрения. Хаос был побежден, документы оцифрованы, лежали в нужных папках, и их даже можно было найти. Казалось бы — живи и радуйся, но аппетит приходит во время еды. Мы поняли, что система «видит» текст, и задали логичный вопрос: «А можно просто спросить у нее, какую марку бетона использовали для заливки фундамента, и она ответит?». Подумали и решили, что можно.

Тогда нам казалось, что прикрутить LLM к нашему архиву, чтобы она работала как умный поисковик, очень просто. Но все оказалось не так радужно. Первая версия нашего «строительного  чат-бота» галлюцинировала так, что путала проектную документацию с дизайном, а ответы генерировались по три минуты.

Это история о том, как мы прошли путь от игрушечного чат-бота до полноценной RAG-системы в закрытом контуре. Расскажу, как мы запускали нейросети на CPU, почему в нашем сравнительном тесте победил Qwen, и как мы оценивали качество ответов в Excel, когда поняли, что стандартные бенчмарки нам не подходят. Статья будет полезна архитекторам, ML-инженерам, и руководителям, которые ищут рабочие on-premise решения. Если вы тоже пытаетесь внедрить LLM в энтерпрайз без бюджета и видеокарт — этот кейс для вас.

Как продать идею руководству

Для того чтобы продать идею внедрения LLM, вам нужно показать пример на полуреальных данных. Иначе никакие уговоры не сработают (по крайней мере, у меня не сработали).

Я начал с того, что смотрел на крупные релизы 24-го года (в апреле вышла Llama, в октябре вышел Claude), ходил к руководителям и говорил: “Давайте внедрять LLM, это здорово, это круто”. Но мои “давайте” – не работали. И на новогодних каникулах решил действовать более решительно.

Я сел, придумал в голове объект строительства, взял формы документов из интернета и сделал синтетику. Взял общедоступного чат-бота (на тот момент я использовал Алису) и собрал небольшой «ручной» конвейер, чтобы показать, как из документов можно получить хороший результат. Наделал скриншотов с информацией, которую выдала модель, и выложил в рабочий чат.

Путь прототипа "на коленке"

Путь прототипа “на коленке”

Это заинтересовало руководство, началась дискуссия. Мы начали обсуждать, как это можно сделать, и мне дали добро на выделение ресурсов.

Сама команда была не против — ребята и так были заряжены поиграться с новой технологией. Но была проблема с железом, которая наверняка есть у многих. Нам не хотелось ждать, пока кто-то выделит GPU. Мы взяли то, что было под рукой — невостребованный ноутбук Lenovo ThinkPad на складе.

Простое решение для первых экспериментов

Простое решение для первых экспериментов

И начали работать на обычном процессоре (CPU). Это долго, но почему бы и нет? И вот тут мы допустили классическую ошибку — о ней дальше.

Первая итерация: чат-бот, который не взлетел

Не нужно внедрять LLM только ради того, чтобы «внедрять LLM». Но поначалу мы решили сделать именно так.

Мы собрались командой и обсудили все возможные решения. Определились, что будем делать обычного чат-бота. Разговор был примерно следующим:

— Вот есть же ChatGPT, там пользователи пишут вопросы и получают ответы.

— Отлично.

— Давайте сделаем тоже самое?

— Окей.

Сказано — сделано. Мы нарисовали обычное модальное окошко на фронте, в дизайне основного приложения. По бэкенду развернули Ollama и обращались к ней просто по API. Ничего сверхсложного: поднимается веб-сервер вместе с LLM, вы обращаетесь к эндпоинту, отправляете вопрос, вам прилетает ответ.

Маленькая победа на большом пути

Маленькая победа на большом пути

И все получилось, в целом. Бот запустился, работал, мы его показал.

Но после того, как его показали, мы поняли, что результат-то на самом деле не очень. А если честно – то совсем плохой. Наш энтузиазм значительно упал 😥.

Во-первых, на тот момент у нас все еще не было GPU, и ответы мы ждали долго, по две-три минуты.

Во-вторых, качество ответов, конечно же, было весьма и весьма скромное. У нас был строительный бот – у него в системном промте было зашито, что он строитель. Но не тут-то было. Я спрашиваю: “Что такое ПСД?” (хочу ответ “приемо-сдаточная документация”). А в ответ получаю что-то про дизайн (Place Setting Design).

Но оказалось, что победой это назвать сложно

Но оказалось, что победой это назвать сложно

Видимо, в весах модели дизайн и строительство — это где-то рядышком. Такое качество, конечно, никого не устраивало. И дело не столько в качестве. Мы работаем с инженерами, строителями, а им нужна какая-то четкая база, основа. Если дается ответ на вопрос, то нужно предоставить и релевантные источники, иначе они не доверяют им. Инженеры вполне обоснованно предполагают, что модель что-то придумала. А значит, с этой информацией идти дальше (например, к руководству) – нельзя.

Инженеру нужен проверяемый ответ со ссылкой на источник. Желательно, чтобы источник был с синей подписью и печатью.

Мы поняли, что нужно пересобраться и взять опору на реальные документы, которые и так есть у нас в системе.

Вторая итерация: делаем «по уму» (RAG)

Нужен был RAG (Retrieval Augmented Generation), и его можно реализовать по-разному. Команда начала думать, как его сделать применительно к нашей системе, и остановился на архитектуре, которую сейчас опишу.

Мы исходили из следующих предположений:

  1. У заказчика, так же как у нас, может не быть GPU. Поэтому решили сделать эту опцию отключаемой. Приложение в целом работает и без всякого чат-бота, оно должно приносить ценность, даже если GPU нет.

  2. Пользователи будут чаще задавать вопросы по имеющимся в системе документам, чем загружать новые документы (например, по завершенным объектам строительства новые документы вообще не загружаются. А потребность найти по ним информацию есть всегда). Поэтому нет смысла обновлений базы данных в real-time. Разумная задержка допустима. Но при этом документы всё-таки будут добавляться. А значит векторизация новых данных должна происходить автоматически, в фоновом режиме.

  3. У нас не было большого опыта в синхронизации баз данных. Чтобы не изобретать велосипеды, мы вынесли нужные таблицы из основного монолита в микросервис ИИ-помощника через WAL (Write-Ahead Logging) репликацию PostgreSQL. Это позволило отвязать нагрузку LLM от основной системы: если помощник «задумается», основная «АФИДА» не ляжет. Подняли ChromaDB, потому что модель общается с векторами, а не с голым текстом. Саму LLM поднимали через Ollama, которая крутилась в отдельном docker-контейнере.

Архитектурная схема второй итерации была чуточку сложнее

Архитектурная схема второй итерации была чуточку сложнее

На векторизации я хотел бы остановиться чуть-чуть поподробнее. Тем, кто RAG еще не реализовывал, будет интересно понять, как это работает. Я на схеме нарисовал два потока данных: синий поток — это поток эмбеддингов, и черный поток — это поток работы с вопросами пользователя.

Они работают параллельно, и чтобы реализовать постоянно работающий RAG в типовом варианте, вам нужно реализовать оба этих потока:

  1. Синий поток (индексация документов). Сначала по API получаем новый текст — пользователь загрузил документ, он распознался. Затем делим его на чанки (chunks) — кусочки текста. Чанк отправляется в модель-эмбеддер (Embedder). Это «малая» большая языковая модель, которая берет текст и делает из него число. И это число — эмбеддинг — складывается в ChromaDB и там хранится. Этот поток работает постоянно: документ загрузился — эмбеддинг добавился.

  2. Черный поток (работа с вопросами). Пользователь задает вопрос, например: «Дай мне объемы работ по бетону». Этот вопрос тоже векторизируется, превращается в число. Затем сопоставляется с теми числами, которые есть в ChromaDB, с релевантными кусочками текста. Эти релевантные кусочки объединяются с вопросом пользователя, и уже этот объединенный вопрос летит во вторую модель — большую языковую модель (LLM). И уже на выходе нее мы получаем ответ, который показываем пользователю.

Эмбеддинг туда, эмбеддинг сюда. Раз-раз — и готово!

Эмбеддинг туда, эмбеддинг сюда. Раз-раз — и готово!

Такое, конечно, мы реализовывали подольше. На все у нас ушло порядка трех месяцев, а не месяц, как на обычного чат-бота. И после того, как мы показали хоть какой-то результат (с чат-ботом), у наконец-то у нас появилась GPU.

На итог, что получили?

Во-первых, мы полностью контролируем источники данных. Решаем вопрос информационной безопасности: работаем не с данными, на которых кто-то обучил модель, а с документами в нашем контуре. Знаем, откуда пользователь зашел, и пробрасываем только те документы, к которым у него и так есть доступ. Просто так получить ответ на вопрос про «заработную плату директора» – нельзя. Но если ты находишься в каталоге с документами про заработную плату всех сотрудников – то можно. А вот кому давать доступ к какому каталогу – решается обычным распределением доступов через панель администратора системы. И LLM эту схему никак нарушить не сможет.

Результат работы после второй итерации

Результат работы после второй итерации

Во-вторых, модель объединяет несколько документов сразу. В классическом поиске вам нужно прокликать десять документов, которые вам показала поисковая выдача. А здесь – модель их быстро посмотрит сама.

И третье, что понравилось нашим заказчикам больше всего — это кликабельные ссылки на источник. Если ты контролируешь источник, ты можешь дать пользователю ссылку. Он нажмет, увидит глазами превью PDF-ки и поймет, откуда взята информация. Ему уже не надо думать: галлюцинировала модель или нет, потому что интерфейс системы даёт возможность в режиме этого же окна за секунду проверить источник. Это полностью снимает вопрос доверия к LLM.

Все заработало, я выдохнул. Но возник финальный вопрос: а всё ли хорошо мы сделали? И вообще, на самом деле, в работе LLM — что такое хорошо, а что такое плохо?

Выбор модели: как впихнуть невпихуемое

Этим вопросом я задался после того, как мы с командой начали безудержно экспериментировать.

Разработчики приходили ко мне с горящими глазами: «Там вышла новая моделька! У Яндекса, у Т-Банка, Qwen новый релизнул. Давайте попробуем, интересно». Мы заливали новые веса на наш закрытый сервер и смотрели.

Мы веди для себя небольшую таблицу:

  • модель;

  • размер модели = влезают ли веса в видеокарту (на тот момент у нас было ограничение по VRAM — половина от Tesla L40, т.е. около 24 Гб);

  • адекватное ли время ответа;

  • пишет ли она хорошо на русском языке (для локальных моделей это проблема, так как некоторые, особенно раньше, подмешивали в ответ и китайский, французский).

И был пятый, самый субъективный критерий — «Качество» (хорошо ответила или плохо).

Таблица "для себя", в которую заносили данные для выбора LLM

Таблица “для себя”, в которую заносили данные для выбора LLM

На тот момент мы остановились на Qwen 2.5 7b. Она хорошо понимала русский, влезала в нашу память и давала вменяемую скорость. Llama 3.2 3b оказалась слишком неинформационной для наших задач, а более крупные модели просто не могли запустить локально с нужной скоростью.

Где теряется качество в RAG?

Но выбрав модель, мы поняли, что качество ответа зависит далеко не только от нее. Как говорят на крутых ML-конференциях, система с LLM под капотом — это не про возможность выполнения задачи, а про вероятность выполнения задачи. И эта вероятность — всегда не 100%.

Была нарисована схема «где мы можем облажаться» (спойлер: везде).

Если поделить 100% потерь на количество мест, где они могут произойти - то на LLM придётся всего 13%

Если поделить 100% потерь на количество мест, где они могут произойти – то на LLM придётся всего 13%

Смотрите, где качество может «просесть»:

  • Загрузка: загрузили не ту PDF-ку, или OCR криво распознал таблицу (поехали строки).

  • Чанкинг: мысль разорвало пополам: начало предложения в одном чанке, конец — в другом.

  • Эмбеддер: модель не чувствует нюансов. Для нее «бетон» и «цемент» могут быть одним и тем же, а для строителя — нет.

  • Поиск (Retrieval): система нашла пять релевантных кусков, а мы решили подавать в LLM только четыре. А самый важный ответ был в пятом.

  • Промт пользователя: строители — не промт-инженеры. Они могут в окно чата просто написать слово «Бетон» (без дополнительных пояснений). Или использовать ненормативную лексику (я это не проверял, но риски есть всегда). Причём плохой промт портит качество два раза – сначала на основе плохого промта находятся плохие чанки, а потом этот же плохой промт вместе с плохими чанками прокидывается на вход LLM.

  • Ранжирование (Reranking): подали в модель чанки в неправильном порядке, “закопав” самый нужный где-то посередине.

  • Отображение ответа: пользователь прочитал текст и расстроился — он хотел ответ больше (или меньше). Он хотел нумерованный или маркированный список. Он был бы в восторге от mermaid-схемы. Даже если ответ в целом верный — плохо оформленный ответ будет восприниматься хуже (а хорошо оформленный — лучше).

Делаем свой бенчмарк «на коленке»

Возник вопрос: как это измерить? Бенчмарки, которые есть на рынке (MMLU и прочие), содержат олимпиадные задачи по математике или биологии. Я не уверен, что наши инженеры на работе решают олимпиадные задачки по биологии. Нам нужно проверять знание ГОСТов и СНиПов.

Если LLM – это вероятностная история, и мы хотим использовать её для решения конкретной бизнес-задачи, то мы должны оценивать результат от LLM в виде вероятности выполнения конкретной бизнес-задачи.

Подкрепление этой мысли я нашёл в кейсе коллег про Робота Макса на «Госуслугах» — там тоже ушли от «абстрактной» оценки модели к проверке качества ответов на своих данных.

Так как команда у нас небольшая, мы решили сделать свой бенчмарк просто в Excel.

Не MMLU конечно, но для нас — подошло

Не MMLU конечно, но для нас — подошло

Механика простая:

  1. взяли наши реальные документы;

  2. экспертно написали по ним вопросы и «эталонные ответы»;

  3. наша тестировщица (у нее, кстати, лингвистическое образование) прогнала вопросы через систему и выписала ответы.

Оценивали так:

  • 1 балл — хорошо.

  • 0.5 балла — средненько, но источники указаны верно.

  • 0 баллов — плохо.

Складываем, делим на количество вопросов, получаем число. Все прозрачно! А с этим числом — работаем дальше. Смотрим на схему потерь в RAG-системе, пробуем «подкрутить» какой-либо из этапов, и затем отслеживаем изменение метрики.

Если бы мы сделали такой бенчмарк сразу, то сэкономили бы, наверное, месяц разработки, исключив хаотичные эксперименты.

Что я понял за 4 месяца

В целом кейс по внедрению LLM я оцениваю как успешный. Мы не только попробовали новую технологию, но и добились вменяемого результата. Это направление планируем развивать дальше: повышать качество ответа, внедрять LLM для извлечения сущностей и проверки документации.

Резюмируя наш путь «от страха к успеху», хочу поделиться тремя главными выводами:

  • Фокусируйтесь на бизнес-задаче, а не на технологии. Не делайте LLM ради LLM. Игнорируйте хайп. Ваш ИИ должен решать конкретную проблему (в нашем случае — поиск информации в документах), а не рассказывать анекдоты про стройку.

  • Продукт с «LLM под капотом» не должен делать ставку только на ИИ. Иногда простые «хаки» в интерфейсе могут снять проблемные вопросы, например, подозрение на галлюцинации.

  • Создайте бенчмарк «для себя» в начале проекта. Это сэкономит вам не только время на пустые эксперименты, но и нервы — и свои, и команды!

Спасибо, что дочитали! Буду рад ответить на вопросы в комментариях. Рассказывайте, как вы внедряете нейросети в свои рабочие процессы. Особенно если вы — производственная или строительная компания!

И пожалуйста, напишите нам на afida@gazpromcps.ru, если вы хотите сократить время на поиск нужных документов в десятки раз, снизить риски ошибок из-за устаревших версий и автоматизировать обработку больших архивов с помощью ИИ!

Автор: 4lk4st

Источник

Rambler's Top100