В 2024 году не иметь доступа к генеративным ИИ вроде ChatGPT или YandexGPT — моветон. Эту проблему мы решили еще в прошлом году, когда разработали чат-бота для Telegram, который работает без танцев с бубном. А по ходу еще написали API для работы наших внутренних сервисов со сторонними LLM. О том, как шел ход разработки, рассказал Артем Нуртдинов, технический директор «Технократии».

Дисклеймер: эту заметку подготовила редакция «Технократии». Чтобы не пропустить анонс новых материалов подпишитесь на «Голос Технократии» — мы регулярно рассказываем о новостях про AI, LLM и RAG, а также делимся полезными мастридами и актуальными событиями.

Сначала было слово. И слово это — бот

История началась с довольно простой и понятной задачи: дать доступ сотрудникам компании к ChatGPT..

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

Завести пару учеток и шэрить доступы между всеми сотрудниками? Тоже не вариант — тогда можно легко запутаться в чатах и тратить время на поиск переписки по своему вопросу.

Самым логичным и понятным для всех вариантом стал чат-бот в Telegram, который бы работал без подключения дополнительных средств маскировки трафика. А также это удобно для всех сотрудников компании — вся рабочая переписка у нас агрегирована в Telegram. Решено — пишем чат-бота!

Важно отметить, что документация OpenAI написана на качественном уровне и поднять своего бота для Telegram не проблема. Я сгенерировал API-ключ и принялся писать бота. Базовые функции для общения с ChatGPT были написаны довольно быстро (в интернете хватает гайдов, как это сделать. Пример).

Но вообще, помимо сложностей с регистрацией, OpenAI в какой-то момент заблокировали возможность вызовов API из серверов, которые находятся на территории РФ. Поэтому мы перенесли бота на сервер во Франции.

Первая микросложность ждала меня на моменте с правами доступа: нужно было сделать так, чтобы ботом могли пользоваться только сотрудники Технократии, а не все мимокрокодилы из поиска Telegram. Эту проблему я решил довольно простым путем: сделал форму заявки на использование чат-бота, которую отправил в общий чатик-флудилку.

В заявке сотрудник указывал свое ФИО, алиас в Telegram, должность и задачи, которые сотрудник планировал решать с помощью бота. Чем подробнее сотрудник описывает сферу своих задач, тем качественнее ChatGPT будет генерировать ответы.

Сноска для пытливых читателей: да, я понимаю что это решение довольно сложно масштабировать, и в будущем рассматриваю вариант забирать эти данные из нашей HRM-системы Youl.

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

Дальше бот забирает информацию о сотруднике из БД и передает все атрибуты пользователя в LLM в виде системного промпт-запроса, который пользователь не видит. Системный промпт выглядит примерно так:

«Ты являешься Telegram-ботом с искусственным интеллектом. Сейчас ты находишься в Telegram-переписке. Твой собеседник указал о себе следующее: <информация из базы данных>»

С помощью этого системного промпта LLM получает дополнительный контекст, с помощью которого формируется более качественный ответ.

Второй момент, который я учел на старте — ограничение на количество используемых токенов. Во-первых, у языковых моделей есть свое контекстное окно. Если его превысить, то LLM будет работать хуже, а в некоторых случаях галлюцинировать. Например, контекстное окно у OpenAI сейчас составляет 128 тысяч токенов.

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

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

Если забивать на контекст и общаться с нейросетью на разные темы, то со временем будет снижаться качество генерируемых ответов. Чтобы качество не падало, я внедрил два решения. Первое: при достижении определенного числа токенов, чат-бот будет откидывать самые ранние сообщения. В целом, на стороне LLM делают примерно также (а еще суммаризируют ответы и формулируют их в более сжатом виде), но я перестраховался и добавил функцию отбрасывания предыдущего контекста. 

Второе решение более радикальное: добавил в чат-бота команду /clear_context, которая стирает всю историю переписки с ботом. Если выбрать эту команду, то общение с ботом начнется с чистого листа, в нашем случае с отправки системного промтпа. 

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

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

Также с ботом в чате флудилке можно пообщаться, если тегнуть его через @ или при помощи обычного reply, но само собой никто для серьезных задач этим не пользуется.

Нужно подружить LLM с внутренними продуктами, или как родился LLMBox 

Конечно, ChatGPT — классный инструмент и один из лидеров рынка, но нам было интересно попробовать другие LLM. В моменте мы с командой решили, что быстрее и проще всего будет подключить к боту отечественный YandexGPT.

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

Итак, у нас есть амбиции развивать направление с нейросетями, но каждый раз проделывать одни и те же манипуляции для обмена данными с LLM не круто. Поэтому родилась идея разработать инструмент, который был бы ретранслятором данных между нашими сервисами и различными LLM. Так и родилась идея написания LLMBox — API для обмена данными с LLM.

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

Тело запроса состоит из трех полей:

messages — Список сообщений с указанием ролей и содержимого. Включает всю историю переписки.

assistant — Выбор ассистента ИИ для генерации ответа. Возможные значения: chat_gpt, yandex_gpt (регистр значения не учитывается).

source — Источник запроса. Возможные значения соответствуют нашим внутренним сервисам (чат-бот, «Статусер» или Youl). 

Вот пример POST-запроса, который включает system-сообщение, для поддержания контекста при разговоре о функциях банковского приложения:

POST /generate-ai-response

{

  "messages": [

    {"role": "system", "content": "Вы ИИ-ассистент, отвечаете на вопросы о банковском приложении."},

    {"role": "user", "content": "Привет, ИИ!"},

    {"role": "assistant", "content": "Привет! Чем могу помочь?"},

    {"role": "user", "content": "Можешь рассказать, как перевести деньги?"},

    {"role": "assistant", "content": "Конечно! В разделе 'Переводы' выберите получателя и введите сумму."},

    {"role": "user", "content": "Есть ли комиссии за переводы?"}

  ],

  "assistant": "yandex_gpt",

  "source": "technokratos_gpt_bot"

}

Ответ, в свою очередь, состоит из двух полей:

assistant_message — Сгенерированный ответ от ассистента.

usage — Информация о количестве использованных токенов.

А вот пример ответа, который будет возвращать LLM в LLMBox:

{

  "assistant_message": "В зависимости от вашего тарифного плана, переводы могут быть бесплатными или с небольшой комиссией. Пожалуйста, проверьте раздел 'Тарифы' для более точной информации.",

  "usage": {

    "prompt_tokens": 60,

    "completion_tokens": 20,

    "total_tokens": 80

  }

}

В общем, получился универсальный инструмент для общения внутренних сервисов с языковыми моделями. С его помощью не нужно каждый раз реализовывать интеграцию c API разных LLM, так как эту часть работы забирает на себя LLMBox.

Планы по развитию сервиса

LLMBox пока что маленький, но у меня на него большие планы, а именно:

  • Интеграция с HRM-системой Youl: сейчас мы работаем над тем, чтобы индивидуальные планы развития сотрудников генерировались при помощи ИИ. 

  • Дополнительные LLM: пока что в качестве внешних языковых моделей сервисы обращаются к ChatGPT и YandexGPT. Но хочется добавить больше опций для генерации контента и возможность обращатсья к GigaChat. 

  • Поднять локальную LLM: конечно, облачные LLM это здорово, но если LLMBox оборачивать в решение для коммерческих задач, то нужно будет разворачивать локальную языковую модель. Например, LLaMA или LaMDA, которые бы работали только во внутреннем контуре компании.

  • Добавить RAG и векторую базу данных: с помощью RAG можно повысить качество ответов LLM, но чтобы он работал корректно нужны сервера с графическими ускорителями, что-то вроде A100 от Nvidia. 

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


  1. famer
    22.11.2024 11:57

    «Все дело в том, что LLM не обладает собственной памятью.»

    Так ли? При общении через веб, вполне себе помнит историю


  1. poro_ku
    22.11.2024 11:57

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

    Но вообще это всё плохая затея, у телеграма есть очень неприятные ограничения с которыми трудно бороться, нельзя например так просто взять и отправить сообщение в котором больше 4к символов, его придется резать с учетом маркдауна. Нельзя вставить картинки посреди текста итп.

    Маркдаун это вообще отдельная песня, конвертер маркдауна от ллм в телеграм это как святой грааль, нереально сделать полностью правильно. Ллм его генерирует по разному и не всегда корректно, а телеграм к такому не готов.