Как сделать свой AnythingGPT, отвечающий на вопросы так, как вам это необходимо (Python, OpenAI Embeddings, ChatGPT API) |
||
МЕНЮ Главная страница Поиск Регистрация на сайте Помощь проекту Архив новостей ТЕМЫ Новости ИИ Голосовой помощник Разработка ИИГородские сумасшедшие ИИ в медицине ИИ проекты Искусственные нейросети Искусственный интеллект Слежка за людьми Угроза ИИ ИИ теория Внедрение ИИКомпьютерные науки Машинное обуч. (Ошибки) Машинное обучение Машинный перевод Нейронные сети начинающим Психология ИИ Реализация ИИ Реализация нейросетей Создание беспилотных авто Трезво про ИИ Философия ИИ Big data Работа разума и сознаниеМодель мозгаРобототехника, БПЛАТрансгуманизмОбработка текстаТеория эволюцииДополненная реальностьЖелезоКиберугрозыНаучный мирИТ индустрияРазработка ПОТеория информацииМатематикаЦифровая экономика
Генетические алгоритмы Капсульные нейросети Основы нейронных сетей Распознавание лиц Распознавание образов Распознавание речи Творчество ИИ Техническое зрение Чат-боты Авторизация |
2023-07-30 12:50 теория программирования, реализация искусственного интеллекта Всем привет! Недавно я на практике применил одно интересное решение, которое давно хотел попробовать, и теперь готов рассказать, как своими руками такое можно сделать для любой другой аналогичной задачи. Речь пойдет о создании своей кастомизированной версии ChatGPT, которая отвечает на вопросы, учитывая большую базу знаний, которая по длине не ограничивается размером промта (то есть вы бы не смогли просто добавить всю информацию перед каждым вопросом к ChatGPT). Для этого будем использовать контекстные эмбеддинги от OpenAI (для действительно качественного поиска релеватных вопросов из базы знаний) и сам СhatGPT API (для оборачивания ответов в натуральный человеческие ответы). При этом, также предполагается, что ассистент может отвечать не только на прямо указанные в Q&A вопросы, но и на такие вопросы, на которые смог бы отвечать человек, который ознакомился с Q&A. Кому интересно научиться делать простых ботов, отвечающих по большой базе знаний, добро пожаловать под кат. Сразу скажу, что существуют некоторые проекты библиотек, которые пытаются решить эту задачу в виде фреймворка, например, LangChain, и я тоже пробовал ее использовать, но как и любой фреймворк, находящийся на достаточно ранней стадии развития, в некоторых случаях он скорее ограничивает, чем упрощает жизнь. В частности, с самого начала решения данной задачи я понимал, что именно хочу сделать с данными и понимал, как сделать это своими руками (в том числе контекстный поиск, задание правильного контекста в промте, комбинирование источников информации), но настроить фреймворк делать именно это у меня никак не получалось с приемлемым качеством, а отлаживать фреймворк уже казалось оверкилл для этой задачи. В общем я сделал свой бойлерплейт код и оказался доволен таким подходом. Задача Немного опишу задачу, которую решал я, при этом вы можете использовать тот же самый код в своих задачах, заменив источники данных и промты на подходящие вам, при этом у вас останется полный контроль над логикой работы бота. При написании кода я часто использую ChatGPT ( В частности, при разработке сабграфов стандарта The Graph (это наиболее популярный способ построения ETL для выгрузки индексированных данных смарт-контрактов из EVM-совместимых блокчейнов, почитать подробнее можно в моей предыдущей статье), сами библиотеки претерпели уже несколько ломающих совместимость изменений, что "старые" ответы от ChatGPT уже не помогают и надо идти искать правильные ответы в лучшем случае в скудной документации, а в худшем в дискорде разработчиков, что мягко говоря не очень удобно ( Вторая часть проблемы состоит в том, что каждый раз нужно задавать очень правильно контекст разговора, потому что ChatGPT все время уводит в сторону от тематики именно по сабграфам, то в GraphQL, то в SQL, то в высшую математику (The graph, subgraphs и тд супер не уникальные термины с кучей разных толкований и тематик). Поэтому недолго пострадав от общения с ChatGPT на тему исправления ошибок в коде сабграфов, я решил сделать своего SubgraphGPT бота, который будет всегда в правильном контексте и пытаться отвечать, учитывая базу знаний и сообщений разработчиков. PS. Я работаю продакт-менеджером в компании-провайдере Web3-инфраструктуры chainstack.com[ссылка удалена модератором] и отвечаю за развитие сервиса хостинга этих самых сабграфов, поэтому мне довольно много приходится с ними работать, помогая пользователям разобраться с этой относительно новой технологией. Верхнеуровневое решение В итоге для решения этой задачи, я решил использовать два источника: 1) Вручную составленная база вопросов и ответов, отобранных в полуслепом режиме (часто я брал название темы из документации в качестве вопроса, а весь абзац наполнения в качестве ответа) 2) Выгруженные сообщения из дискорда за последние 2 года (как раз чтобы покрыть недостающий период с конца 2021 года) Далее для каждого источника использовались разные подходы для составления запроса к ChatGPT API, в частности:
Кроме того, если не задать тему в явном виде, то наличие фрагментов Q&A и чатов может привести к двусмысленности в ответах, которые могут выглядеть, например, следующим образом: То есть, он понимает, что вопрос был отвязан от контекста, и принят был также отвязанным от контекста. Далее ему было сказано, что можно использовать такие данные, и он суммаризирует это: 1) Вообще-то ответ может быть такой ... 2) А если учесть контекст, то вот такой ... Чтобы избежать этого, мы вводим понятие topic, который задается явно и вставляется в начале промта в виде:
Кроме того, в последнем предложении, я также добавляю это:
В итоге, полный промт (за исключением части, полученной из чатов) выглядит следующий образом:
Ответ на запрос выше с таким полу-авто-сгенерированным промтом на входе уже выглядит правильно: В данном случае бот сразу отвечает в правильном ключе и добавляет еще релевантной информации, что ответ выглядит не так скудно, как в Q&A (напомню, что в точности этот вопрос встречается в списке вопросов-ответов), а с разумными пояснениями, отчасти снимающими следующие вопросы. Исходные коды Сразу скажу, что в конце будет ссылка на репозиторий, так что бота можно будет запустить как есть, подменив "topic" на свой, файл с базой знаний Q&A - на свои, и подложив свои API ключи для OpenAI и телеграм-бота. Так что в описании здесь, я не претендую на полное соответствие исходников гитхабу, скорее на освещение основных аспектов кода. 1 - Подготовка виртуального окружения Создадим новое виртуальное окружение и установим зависимости из requirements.txt: 2 - База знаний, собираемая вручную Как было описано выше, предполагается наличие списка вопросов-ответов, в данном случае в формате эксель-файла следующего вида: При этом, для поиска наиболее близкого вопроса к заданному, нам необходимо добавить к каждой строке этого файла эмбеддинг вопроса (многомерный вектор в пространстве состояний). Для этого воспользуемся файлом add_embeddings.py. Скрипт состоит из нескольких простых частей. Импорт библиотек и считывание аргументов командной строки: Далее считывание файла в pandas dataframe и фильтрация вопросов по наличию вопросительного знака. Этот фрагмент кода общий как для обработки базы знаний, так и сырого потока сообщений из дискорда, поэтому предполагая, что вопросы часто дублируются, я решил оставить такой простой способ грубой фильтрации не-вопросов. И последнее - функция для формирования эмбеддинга, путем вызова API модели text-embedding-ada-002, пару повторных запросов, тк API периодически перегружен и может ответить ошибкой, и применение этой фукнции к каждой строке датафрейма: В итоге этот скрипт можно вызвать следующей командой: задав OpenAI API ключ, файл с базой знаний и имя колонки, в которой находится текст вопроса. Итоговый созданный файл subgraphs_faq._question_embed.csv содержит помимо колонок "Question" и "Answer" еще и колонку "ada_embedding". 3 - Сбор данных из дискорда (опционально) Если вас интересует простой бот, отвечающий соотвественно вручную собранной базе знаний и только, можете пропустить этот и следующий разделы. Тем не менее, приведу кратко здесь примеры кода для сбора данных как из дискорд-канала, так и из телеграм-группы. Файл discord-channel-data-collection.py состоит из двух частей. Первая - импорт библиотек и инициализация аргументов из командной строки: Вторая - функция получения данных из канала и сохранения их в pandas датафрейм, а также ее вызов с заданными параметрами: Из полезного тут есть деталь, которую каждый раз я днем с огнем не могу сыскать в интернете - это получения ключа авторизации. Если channel_id можно получить из URL ссылки на дискорд канал, открытой в браузере (последнее длинное число в ссылке), то authorization_key можно найти только начав писать какое-то сообщение в необходимом канале, после чего через инструменты разработчика найти событие с названием "typing" в секции Network и вытащить параметр из header'a. Получив эти параметры, сбор всех сообщений из канала можно запустить следующей командой (подставив свои значения): 4 - Сбор данных из телеграма Так как я часто выкачиваю разные данные из чатиков/каналов из телеграма, то решил также привести код и для этого, формирующий похожий по формату (совместимый в смысле работы скрипта add_embeddings.py csv файл). Итак скрипт telegram-group-data-collection.py выглядит следующим образом. Импорт библиотек и инициализация аргументов из командной строки: Как вы можете заметить, нельзя просто скачать из все сообщения из чата, не авторизовавшись от себя как от первого лица. То есть вам придется помимо создания app через https://my.telegram.org/apps (получения APP_ID и APP_HASH), еще использовать номер и пароль, чтобы создать экземляр класса TelegramClient библиотеки Telethon. Помимо этого вам понадобится публичный group_name телеграм-чата и указание в явном виде количества последних выгружаемых сообщений. В целом, я много раз делал такую процедуру с любым количеством выгружаемых сообщений и ни разу не получал временных или постоянных банов от Telegram API, в отличие от случая, когда вы слишком часто отправляете сообщения с одного аккаунта. Вторая часть скрипта содержит саму функцию выгрузки сообщений и ее запуск (с необходимыми фильтрациями для избежания критических ошибок, останавливающих сбор на полпути): В итоге этот скрипт можно запустить следующей командой (замените значения на свои): 5 - Скрипт телеграм-бота, который уже отвечает на вопросы Чаще всего я оборачиваю свои пет-проекты в телеграм ботов, так как это требует минимум усилий для запуска при этом сразу показывает потенциал. В данном случае я поступил также. Сразу скажу, что код бота не содержит всех корнер-кейсов, которые я использую в продакшен версии бота SubgraphGPT, т.к. в нем довольно много унаследованной логики из другого моего пет-проекта, напротив я оставил минимум основного кода, который должно быть легко модифицировать под свои нужды. Скрипт telegram-bot.py состоит из нескольких частей. Сначала как и прежде происходит импорт библиотек и инициализация аргументов из командной строки: Обратите внимание, что в данном случае также понадобится OpenAI API ключ, так как для того, чтобы найти наиболее похожий на только что введенный пользователей вопрос из базы знаний необходимо сначала получить эмбеддинг этого вопроса, вызвав API как мы это делали для самой базы знаний. Кроме того, нам понадобятся:
Далее идет загрузка файла с базой знаний и инициализация эмбеддингов вопросов Для запроса к ChatGPT API, также зная, что иногда он отвечает ошибкой, будучи перегруженным, я использую функцию с авто-повтором запроса при ошибке: По рекомендации OpenAI перед пересчетом текста в эмбеддинг необходимо заменить новые строки на пробелы: Для поиска наиболее близких вопросов считаем косинусное расстояние между двумя эмбеддингами вопросов, взятое прямо из библиотеки openai: Получив список наиболее близких к заданному пар вопрос-ответ, можно собрать их в один текст, разметив так, чтобы ChatGPT недвусмысленно определил, что есть что: После чего, уже нужно собрать описанные в самом начале статьи "куски" промта воедино: В данном случае я исключил часть, использующую сообщения из дискорда, но логику можно проследить при условии chat_prompt != None. Помимо прочего нам понадобится функция, разбивающая полученный ответ от ChatGPT API на сообщения телеграма (не более 4096 символов): Бот запускается вполне обычной последовательностью шагов, с заданием двух функций, срабатывающих по нажатию команды /start и по приему личного сообщения от пользователя: Код для ответа на /start очевиден: А для ответа на сообщение в свободной форме, не совсем. Во-первых, чтобы избежать блокирования потоков от разных пользователей, сразу "разведем" их по независимым процессам через threading. Далее вся логика работы будет происходить внутри функции long_running_task. Я намеренно обернул основные фрагменты в try/except, чтобы при модифицировании кода бота было легко сразу локализовать ошибку.
Так как при замене базы знаний и топика на свои, могут возникнуть какие-то ошибки, например, из-за форматирования, то выдается человеко-читаемая ошибка. Далее запрос отправляется на ChatGPT API с лидирующим системным сообщением, которое уже зарекомендовало себя "You are a helpful assistant.", а результат отработки делится на несколько сообщений при необходимости и пересылается пользователю. На этом часть с кодом завершена. Прототип Сейчас прототип такого бота доступен в ограниченном формате по ссылке. Так как API платное, можно делать до 3 запросов в сутки, но не думаю, что это кого-то ограничит, так как самое интересное это не специализированный по узкой тематике бот, а сам код проекта AnythingGPT, который доступен на гитхабе (не откажусь от звездочек) с короткой инструкцией, как сделать своего бота, решающего вашу задачу с вашей базой знаний из этого примера. Буду рад ответить на вопросы. Источник: habr.com Комментарии: |
|