Есть отечественный файрвол (NGFW). У этого файрвола есть документация для пользователей powered by GitBook, на русском языке. В этой документации работает простой поиск — только по словам и словосочетаниям. И это плохо, потому что нет ответов на вопросы:

  • Какие алгоритмы шифрования ipsec поддерживаются у вас?

  • Как заблокировать ютуб?

  • Как настроить DMZ?

Хочется, чтобы поиск был "умным" и чтобы пользователи могли обращаться с подобными вопросами именно к поиску, а не к инженерам тех. поддержки. AI или ML внутри — не важно, как это называть. Но на простые вопросы из списка выше поиск должен отвечать.

Я решил эту задачу (Retrieval Question Answering), используя OpenAI API. Казалось бы, уже опубликованы сотни похожих инструкций, как это сделать. Но под катом будет не инструкция, а рассказ про сложности, которые пришлось решить на пути от идеи до запуска поиска: как прикинуть бюджет, быстро собрать прототип с сохранением всех ответов и оценок обратной связи, организовать альфа- и бета-тестирование, позвать асессоров и разметить собранный датасет, подвести итоги проекта и наметить следующие шаги.

Постановка задачи

Итак, уточняем задачу.

  1. Есть документация по продукту, внутри — база документов в формате markdown.

  2. Нужно по этой документации сделать "умный" поиск (далее — GPT поиск или бот).

  3. В ответах мы хотим увидеть и ссылки на источники. Как окажется позже, наличие правильно подобранных ссылок на источники даже при ответе плохого качества — нравится пользователям поиска.

Те, кто знакомы с большими языковыми моделями (LLM), знают, что эта задача называется Retrieval QA.

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

Предварительные изыскания

Перед тем, как браться за задачу, проверим, а можно ли её вообще не делать?

Что было сделано на первых шагах (пишу во множественном числе, потому что мне помогали коллеги):

  1. Для начала мы собрали статистику поиска по документации продукта и ещё раз убедились, что поиск нужно делать. Вопросы, которые задавали пользователи продукта, в большинстве случаев оставались без ответов (см. три вопроса во вступительной части).

  2. Разобрались с GitBook, нельзя ли подключить плагин поиска Algolia или подобный? Нет, в июне 2023 года это сделать было нельзя. Были лишь планы разрешить сторонним разработчикам создавать свои собственные плагины, но без указания сроков.

  3. На тот момент у GitBook был доступен "умный" AI поиск — Lens (сегодня он по умолчанию включен). Мы включили его для теста, но оказалось, что с русским языком он не работает. Выглядело это так себе: задаёшь вопрос на русском языке, а получаешь ответ на английском. Да ещё и качество в сравнении с привычными чат-ботами chat.openai.com и perplexity.ai неудовлетворительное.

  4. Сначала попробовали сделать "умный" поиск локальным — скачать к себе языковую модель, локально задавать ей вопросы и получать ответы. Наиболее подходящей моделью тогда оказалась Dolly. Запустили прототип, на русском языке сравнили качество ответов модели с привычными чат-ботами, не понравилось.

Jupyter блокнот для знакомства с LLM Dolly
Jupyter блокнот для знакомства с LLM Dolly
  1. Всё, что мы смогли до сих пор сделать, по качеству ответов сильно уступало чат-боту ChatGPT. Похоже, пришло время протестировать OpenAI API.

Разработка прототипа "умного" поиска

Шаг 1. Быстро решить задачу Retrieval QA.

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

Пример построен с применением фреймворка для работы с языковыми моделями — LangChain, в качестве языковой модели используется модель GPT 3.5 Turbo от компании OpenAI. Код не буду повторять, расскажу лишь про неочевидные детали:

  1. Для работы с OpenAI API понадобится API-ключ, который можно получить после регистрации на https://openai.com/ (доступ из России блокируется, помогает VPN).

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

  3. Начать можно с пробной версии, а дальше уже привязать карту (не российскую, помогает поисковая выдача по запросу: "Оплата иностранных сервисов, подписок и товаров").

Итак, цепочка RetrievalQAWithSourcesChain работает, я получаю ответы на вопросы по базе документов. При выставленном параметре "температура" в ноль (так я прошу модель в качестве источников использовать только предъявленную базу документов) качество ответов вполне устраивает, ответы заметно лучше по сравнению с Dolly и GitBook Lens.

Теперь всё это нужно упаковать в сервис для пользователей.

Шаг 2. Прикинуть бюджет.

Но сначала прикидываю бюджет. Точнее, выбираю между GPT-3.5 Turbo и GPT-4. Тариф на входящие токены для модели GPT-3.5 Turbo — $0.001 за тысячу токенов, в то время как у GPT-4 — $0.03. Тариф на исходящие токены для GPT-3.5 Turbo — $0.002, а у GPT-4 — $0.06.

Выходит, что вопросы и ответы у модели GPT-4 дороже в ~30 раз. Пока выбираю модель GPT-3.5 Turbo.

Первые эксперименты показали, что с учётом всех комиссий один вопрос к модели стоит ~1 российский рубль. Сразу же для защиты от непорядочных бета-тестеров выставляю порог расходов в личном кабинете OpenAI. Если начнут ддосить — сервис просто перестанет давать ответы.

Пока это всего лишь прототип для проверки гипотезы, поэтому на следующих шагах быстро собираю финальное решение.

Шаг 3. Быстро сделать фронтенд.

Фронтенд будет обращаться к бекенду с вопросами пользователей. Для быстрого старта подойдёт Twitter Bootstrap 5.

Шаг 4. Быстро сделать бекенд.

Выбираю FastAPI. Не зря он fast, отлично подходит для решаемой задачи.

Шаг 5. Подключить к модели полную документацию продукта.

Шаг 6. Сохранить все вопросы и ответы.

Для разбора ответов и улучшения сервиса будем сохранять все вопросы пользователей, полученные моделью ответы, источники, ошибки. В самом продукте активно используется ClickHouse, поэтому эти данные складываю туда же.

Шаг 7. Арендовать сервер, где будет работать поиск.

Поскольку к OpenAI API нельзя обращаться напрямую из России, выбираю дата-центр за пределами.

Шаг 8. Выбрать доменное имя.

Шаг 9. Подключить сертификаты LE.

И проверить, что всё работает и нет предупреждений безопасности, которые могут отпугнуть будущих пользователей поиска.

Шаг 10. Запустить альфа-тестирование.

Устраиваем альфа-тестирование нового поиска среди сотрудников компании. Обрабатываем шквал скриншотов с замечаниями и предложениями, даже находим ошибки в исходной документации, исправляем. Стало понятно, что перед бета-тестированием нужно добавить обратную связь.

Вспоминаем Алексея Лысенкова — бессменного ведущего передачи "Сам себе режиссер". Он рассказывал, что когда команда редакторов просматривает присланные видеоролики, то первые комментарии — они самые живые и смешные, но в эфир попасть не могут, потому что не пройдут цензуру. Чувствуем себя примерно так же, особенно разбирая вопрос про коз.

Лог первых вопросов и ответов модели
Лог первых вопросов и ответов модели

Шаг 11. Доработать поиск по результатам альфа-тестирования.

Список доработок:

  1. Замечаем, что иногда модель отвечает на английском языке. Исправляю это уточнением промпта.

  2. Обнаруживаем недокументированные коды ошибок модели OpenAI, корректно обрабатываю их.

  3. Набираем примеры разметки источников. Иногда они дописываются в текст ответа, иногда — в структуру данных “источники”. Иногда используется HTML разметка, иногда нет.

  4. Делаю источники кликабельными, удобно же.

  5. Добавляю возможность для каждого ответа выставить оценку: "Плохо" (-1), "Нормально" (0), "Хорошо" (+1). Учу бекенд принимать оценки и сохранять в ClickHouse.

Шаг 12. Запустить бета-тестирование.

Публикуем новость о запуске поиска в официальных каналах компании-разработчика файрвола, запускаем бета-тестирование.

Шаг 13. Оценить результаты тестирования.

Набираем за несколько дней более 300 запросов и уходим обрабатывать ответы. По каждому запросу просим наших дорогих асессоров (сотрудников компании-разработчика файрвола, которые в совершенстве владеют документацией) разметить выборку. Проверить каждый ответ и выставить свою оценку: -1, 0, 1. Также просим прикрепить комментарий, чтобы знать, что можно улучшить.

Разметка асессорами собранного датасета с вопросами и ответами
Разметка асессорами собранного датасета с вопросами и ответами

Подведение итогов

Для оценки качества поиска я выбрал простой подход — Human Evaluation. По размеченной пользователями и асессорами выборке составил таблицу:

Статистика

От пользователей

От асессоров

Всего запросов (с 22.09 по 02.10)

336

336

Количество отрицательных оценок

18

122

Количество нейтральных оценок

7

63

Количество положительных оценок

18

139

Без оценок

293

12

Асессорам мы доверяем больше, чем пользователям. Поэтому смотрим на самый правый столбец.

Положительных оценок больше отрицательных. Но это ещё не значит, что GPT поиск работает хорошо. Среди ответов с положительной оценкой асессоров много "плохих" вопросов, не относящихся к теме, вроде: "Как настроить велосипед". Поэтому вместе с асессорами обсуждаем детали.

Что работает хорошо:

  • Если вопрос подробно сформулирован и про это есть конкретно в документации, то GPT поиск генерирует хорошие ответы. Иногда даже добавляет то, чего может не хватать в документации для понимания.

  • Бот приемлемо хорошо умеет собирать ответ из нескольких блоков с разных страниц документации. Опять же, если вопрос подробно сформулирован и части ответов есть в документации.

  • В подавляющем большинстве случаев бот находит корректные источники в документации. Уже в этом есть польза, даже если сам ответ плохого качества.

  • Всё, что мы пробовали до GPT-3.5 Turbo (Dolly, GitBook Lens), по качеству на голову ниже.

  • Однозначно, такой поиск работает лучше поиска по умолчанию в GitBook.

Что работает плохо:

  • Бот плохо отвечает на вопросы, которые не освещены в документации. За исключением общих и/или энциклопедических вопросов ("Что такое DNS?").

  • Модель может фантазировать.

  • Редко, но модель может ошибаться в источниках.

  • Модель может давать неполные ответы.

  • Модель может давать по большей части верные ответы, но добавлять и неподходящие блоки.

  • Иногда ответ генерируется на данных из файлов changelog старых версий.

Финальный вывод: GPT поиск по документации файрвола работает лучше других поисков, почти всегда даёт правильные источники, генерирует ответ хорошего качества при условии конкретного и подробного вопроса, который описан в документации.

От идеи до запуска GPT поиска прошло около 3 месяцев, ещё месяц ушёл на подведение итогов. Опыт внедрения современных технологий искусственного интеллекта считаем успешным, пора задуматься о стратегии развития AI/ML в компании.

Что делать дальше:

  • Ответить на вопрос: "Если модель сгенерирует неправдоподобный/ложный ответ, будет ли это безопасно для пользователя?"

  • Научить бота не отвечать матом.

  • Научить бота распознавать версию файрвола в вопросе и генерировать ответ по документации нужной версии.

  • Разобраться, как максимально ускорить сервис. Сейчас отвечает достаточно медленно (и Сэм Альтман признаёт это).

  • Перенести поиск в общую инфраструктуру компании.

  • Добавить фильтрацию чувствительных данных, которые могут появиться в ответе.

  • Попробовать GPT-4, GigaChat API, Yi-34B и что там ещё.

Короткие итоги от меня лично. Теперь я согласен с Chip Huyen: "It’s easy to make something cool with LLMs, but very hard to make something production-ready with them." (Building LLM applications for production)

GPT поиск доступен для всех желающих по ссылке: https://gpt-docs.ideco.ru/

Скриншот умного поиска
Скриншот умного поиска

Вместе со мной над проектом работали:

  • @socketpair — идейный вдохновитель

  • @fisher85 — научный руководитель

  • дорогие асессоры Анастасия и Владислав

Комментарии (23)


  1. kolabaister
    03.12.2023 16:45

    Интересная идея, но вот ответы по моему бесполезны. Пара полезных слов и много воды. Единственное ценное - ссылки, но ведь их можно и простым индексированием выдавать.
    Вы оценивали CSI?


    1. imf1ne Автор
      03.12.2023 16:45
      +1

      1. Чтобы понять, полезные ответы или бесполезные, мы привлекли на помощь асессоров. Вместе разметили ответы поиска и оценили его качество. Совместный вывод сделали такой: польза есть и в самих ответах, табличка в посте это подтверждает.

      2. Да, согласен, ссылки можно выдавать индексированием. Но ссылки — это точно не единственная польза. Польза есть и в ответах.

      3. CSI явно не оценивали. Неявно — по оценкам от пользователей можно сделать первые выводы. Количество положительных оценок совпадает с количеством отрицательных оценок, но пока это статистически незначимые числа. Продолжаем набирать статистику.


  1. mtop
    03.12.2023 16:45

    а как подобную штуку реализовать?
    https://www.highcharts.com/chat/gpt/


    1. imf1ne Автор
      03.12.2023 16:45
      +1

      Всё-таки этот вопрос лучше задать разработчикам Highcharts GPT.

      Но кое-что можно и прикинуть самим. В блоге у них есть подсказка — модель отвечает только по версиям до 2021 года. Значит, они даже не дополняют "контекст" вопроса свежими примерами использования своей библиотеки. Выглядит так, что этот поиск работает следующим образом: к промпту пользователя "Create a donut chart of the world's top 5 car manufacturers. Use dark mode." они дописывают в конце что-то вроде: "Use Highcharts JS library". Я задал такой вопрос модели ChatGPT, ответ по содержанию совпадает с ответом Highcharts GPT.


      1. mtop
        03.12.2023 16:45

        Ну и с другой стороны их система не отвечает на вопросы за пределами вопросов Highcharts , но с удовольствием расскажет как это юзать


        1. yrub
          03.12.2023 16:45

          есть instruct модели, которые пишут четко что в промпте одним ответом, а большая часть промпта будет системная, которую вы не видете. в ней будет написано что-то типа "напиши js код используя следующие функции.." ну и там будет перечень функций с описанием. есть путь посложнее - дообучение. месяца 3 это есть в chatgpt, дообучить не дорого стоит.

          ЗЫ: при желании наверно можно заставить написать не код, надо эксперементировать


      1. mtop
        03.12.2023 16:45

        Перечитал ваш ответ.... согласен с версией


    1. flyoz
      03.12.2023 16:45

      Легко, вам нужен интерпретатор кода.


  1. talraaash
    03.12.2023 16:45
    +1

    Если пользователь по ключевому слову в простом поиске "dmz" или "ipsec" не может найти ответа на свой вопрос по этой теме, то проблема в самой документации.

    Асессорам мы доверяем больше, чем пользователям. Поэтому смотрим на самый правый столбец.

    А почему? На мой вкус реальный отзыв от пользователя системы актуальнее для понимания решает ли эта система поставленную задачу. Нежели несколько деформированное восприятие человека цель которого не решить проблему с помощью инструмента, а протестировать инструмент.


    1. imf1ne Автор
      03.12.2023 16:45

      Не соглашусь с первым тезисом. Если пользователь по ключевому слову "ipsec" не может найти ответа на свой вопрос, то могут быть разные тому причины, например:

      1. В документации про это нет. Согласен, это проблема документации.

      2. Пользователь получает много ссылок на страницы, где упоминается "ipsec". И ему сложно обработать такой объем информации в ответе. В этом случае документация "не виновата". И поможет тут "умный" поиск, если пользователь более подробно сформулирует свой запрос.

      К вопросу, почему мы больше доверяем асессорам. Важно заметить: речь не про "отзыв от пользователя". Речь про оценку пользователя, насколько хороший ответ в поиске он получил. Пользователь не всегда обладает знаниями, чтобы корректно оценить качество ответа, особенно сложного и объёмного ответа. Асессор лучше знает предмет и корректнее сможет оценить качество ответа.


      1. talraaash
        03.12.2023 16:45

        1. Пользователь получает много ссылок на страницы, где упоминается "ipsec". И ему сложно обработать такой объем информации в ответе. В этом случае документация "не виновата". И поможет тут "умный" поиск, если пользователь более подробно сформулирует свой запрос.

        Для этого используют не один ключ в поиске) Я понимаю, что "гугление" - забытая техника древних, но не до такой же степени. И мы снова упремся в то насколько хорошо написана документация, охватывает ли она весь функционал софта и т.п.. Перевод тех документации в "упрощенный человеко читаемый формат" с помощью нейронки - хорошая задача для разминки. Но для реальных юзкейсов сомнительно... человек не знающий что такое DMZ не будет у нейронки спрашивать советов по его настройке, а знакомый со значением термина довольно легко найдет нужный раздел в документации. А абстрактные кейсы "Как заблокировать сайт Х" решаются хорошим FAQ или рекапом текста документаци, тут как раз может помочь нейронка сократить время на подсвечивание основных сценариев использования и функций софта.

         Речь про оценку пользователя, насколько хороший ответ в поиске он получил. Пользователь не всегда обладает знаниями, чтобы корректно оценить качество ответа

        Но задача пользователя не решена или решена отсюда и оценка пользователя по качеству ответа. И это важнейший критерий качества ответа, нет?


  1. Mike_666
    03.12.2023 16:45

    Называйте меня пароноиком, но таки интеграция помошника на базе OpenAI API в справочную систему для ПО обеспечения безопасности ориентированного на рынок РФ в текущей геополитической ситуации напрашивается на ачивки:

    • Утечка сведений об особенностях конкретных инсталяций этого самого ПО (через вопросы пользователей с конкретными настройками)

    • Первая успешная атака вида 'автоматизация приёмов социальной инженерии для создания заведомо уязвимых конфигураций посредством llm'


    1. imf1ne Автор
      03.12.2023 16:45

      Да, всё верно. И в задачах на будущее у нас много подобных вопросов. Вообще, безопасен ли ложный ответ модели? Фильтрация чувствительных данных в ответе. Защита от состязательных атак (ваш пример атаки отравления — абсолютно реальный).


  1. Nabusteam
    03.12.2023 16:45
    +2

    Как для хаброуровня ждал какой то код с описанием. По факту только два слова langchain и retrievalqa.


    1. imf1ne Автор
      03.12.2023 16:45
      +1

      Рабочий код подобного примера со всеми пояснениями опубликован в оригинальной работе, на которую я ссылаюсь в посте: https://www.reaminated.com/run-chatgpt-style-questions-over-your-own-files-using-the-openai-api-and-langchain


  1. Ol0lO
    03.12.2023 16:45

    Все это реализовано в flowiseai


    1. imf1ne Автор
      03.12.2023 16:45

      Спасибо, отличный пример, изящная реализация цепочки RetrievalQA, не был знаком с этим инструментом.


    1. yrub
      03.12.2023 16:45

      это реализовано уже и в chatgpt, называется gptx.


  1. dimnsk
    03.12.2023 16:45

    промпт покажите?

    text_splitter = CharacterTextSplitter(chunk_size=512 , chunk_overlap=0)
    это все варианты разделения?


  1. thunderspb
    03.12.2023 16:45

    А llama index не пробовали?


    1. imf1ne Автор
      03.12.2023 16:45

      Не работал с таким инструментом


      1. thunderspb
        03.12.2023 16:45

        Посмотрите, оно как раз для аггрегации внутренней документации, причём из разных источников, типа пдф, док и много чего другого. Индексирует и отправляет в чатгпт. Идея крутая, но я, как далёкий человек от мл/ии, примерно заставил это работать и оно хорошие ответы выдает, но обрезанные. Скорее всего, чтото подтюнить надо :)


  1. AlexanderAnisimov
    03.12.2023 16:45

    Хотелось бы узнать ваше мнение по поводу (потенциальной) возможности применения этого инструмента https://habr.com/ru/articles/778414/ к вашей задаче. Я имею ввиду прикрепить вашу базу документов к ассистенту и потом разговаривать с этим ассистентом.