Я сделал небольшой клиент для Wolfram Language, который умеет вызывать OpenAI API и другие API, которые на него похожи. Сам активно пользуюсь им и хочу рассказать о том, как легко создать ассистента на основе OpenAI API и добавить в него свои собственные плагины.
Зачем я это делаю?
Во-первых, я не так часто вижу на Хабре утилитарные статьи, где рассказывается о том, как использовать нейросеть с примерами кода. И особенно мало таких статей, где речь идет про конкретные плагины. Чаще всего мы видим здесь рекламу, ссылочки на телеграм и восхваление очередных достижений нейросете-строения.
Во-вторых, у Wolfram Language есть фантастически крутой блокнотный пользовательский интерфейс. Речь конечно же про Mathematica и про наш родной отечественный WLJS Notebook. Формат интерактивного блокнота как нельзя лучше подходит для работы с чат-ботами, LLM и нейросетями.
В-третьих, в пакете AILink есть киллер-фича WL из коробки, которая доступна всем пользователям Wolfram Language — это Cloud Evaluate. С его помощью вам не потребуется VPN для обхода блокировки по региону со стороны OpenAI. То есть AILink в Wolfram Language работает в РФ без использования прокси!
В-четвертых, я как фанат Wolfram Language просто в очередной раз хочу про него рассказать.
Подготовка
Будем считать, что среда выполнения когда уже установлена, но если нет, то всегда можно получить бесплатное ядро Wolfram Engine с регистрацией, но без смс. Там очень простые инструкции, нужно всего-то зарегистрировать учетную запись и нажать кнопку «получить лицензию».
Установить ядро на Windows можно так:
winget install WolframEngine
На MacOS так:
brew cask install wolfram-engine
На Linux можно только скачать файл-установщик по ссылке, но зато можно в одну строчку получить образ для docker:
docker pull wolframresearch/wolframengine
После выполнения шагов выше и получения лицензии создадим где-нибудь директорию LLMBot, а в ней новый файл llmbot.nb:
Затем откроем файл при помощи Mathematica и приступим к написанию кода.
Импорт зависимостей
Первое, что мы добавим в наш скрипт — это установка и импорт зависимостей. Нам понадобится несколько пакетов из Paclet Repository:
(*function like apt update*) Map[PacletSiteUpdate] @ PacletSites[]; (*install paclets*) PacletInstall["KirillBelov/Internal"]; PacletInstall["KirillBelov/Objects"]; PacletInstall["KirillBelov/AILink"]; (*paclets importing*) Get["KirillBelov`AILink`"];
После чего пользователю станут доступны функции из пакета AILink:
-
AIModels[] — список моделей OpenAI
-
AIImageGenerate[«prompt»] — создает картинку в DALL-E
-
AISpeech[«text»] — превращает текст в аудио в TTS
-
AITranscription — преобразует звук в текст в Whisper
-
AIChatObject[<>] — представление объекта чата в языке
-
AIChatComplete[chat, message] — дополнение чата в GPT
-
AIChatCompleteAync[chat, message, callback] — асинхронное дополнение
Для того чтобы ими всеми пользоваться необходимо задать ключ для доступа к API. Сделать это можно выполнив команду:
(*set api key*) SystemCredential["OPENAI_API_KEY"] = "your openai api key";
Готово! Проверить что все работает можно добавим в скрипт вот такую строчку:
(*print models*) AIModels[]
Если все примерно как на скриншоте — то можно продолжать. Следующим шагом проверим, что работают другие функции:
Текст в голос
Можно передать в качестве аргументов скрипта текстовую строку и OpenAI модель TTS создаст для него аудио файл:
hiAudio = AISpeech["Привет!"] Export["hi.mp3", hiAudio]
В качестве опциональных аргументов функция AISpeech[] принимает имя голоса. с помощью которого нужно озвучить текст. Доступные голоса можно посмотреть в документации OpenAI. Вот как будут отличаться разные голоса:
hiAlloy = AISpeech["Привет Хабр!", "Voice" -> "alloy"] hiNova = AISpeech["Привет Хабр!", "Voice" -> "nova"] AudioPlot[{hiAlloy, hiNova}]
Голос в текст
Все тоже самое можно проделать и в обратную сторону:
AITranscription[hiAlloy] AITranscription[hiNova]
Генерация изображений
Последней доп-функцией в обзоре будет генерация изображений. Все очень просто:
AIImageGenerate["wolf and ram in the village"]
Чат с LLM
Теперь перейдем к главной части статьи! Чат бот! Чтобы создать пустой объект чата используем функцию:
chat = AIChatObject[]
Отправим первое сообщение в OpenAI. После выполнения запроса оно сохранится в чат и чат же вернется как результат выполнения функции:
AIChatComplete[chat, "Привет!"]; chat["Messages"]
Ну и дальше вызывая функцию AIChatComplete можно продолжать общаться с LLM. Но это слишком просто!
Плагины-функции
У функции AIChatComplete есть несколько важных опций:
-
«Model» — позволяет указать конкретную модель. По умолчанию «gpt-4o»
-
«Temperature» — позволяет указать температуру — не все модели ее поддерживают
-
«Tools» — позволяет использовать функции-плагины, опять же не все модели их поддерживают
Можно передать как в функцию дополнения так и в качестве параметров конструктора чата:
chat = AIChatObject["Tools" -> {tool1, tool2}]; AIChatComplete[chat, "Model" -> "gpt-4o"];
С выбором модели все еще более менее понятно.
-
«gpt-3.5-turbo» — быстрая и не самая умная
-
«gpt-4o» — умнее и медленнее
-
«o1-preview» — умеет рассуждать и тулы не поддерживает
Но что передавать в качестве tool1, tool2, …? Это должны быть функции! Функции, которые создаются с некоторыми ограничениями, но очень простыми:
-
Они возвращают в качестве ответа строку
-
Они имеют описание в usage
-
Типы аргументов явно указаны и могут быть String, Real или Integer
Создадим очень простую такую функцию:
time::usage = "time[] returns current time in string format."; time[] := DateString[]
Создадим еще функцию с параметрами. Например получение текущей температуры в указанном населенном пункте. Для того чтобы узнать температуру я буду использовать WeatherAPI.
В процессе написания статьи я зарегистрировался там и посмотрел как выполняется запрос в документации. На Wolfram Language это будет вот так:
SystemCredential["WEATHERAPI_KEY"] = "<api key>"; wheather::usage = "wheather[lat, lon] returns info about current wheathe for specific geo coordinates. Result is JSON object with coordinates, text description, temperature, wind speed and etc."; wheather[lat_Real, lon_Real] := Module[{ endpoint = "http://api.weatherapi.com/v1/current.json", apiKey = SystemCredential["WEATHERAPI_KEY"], request, response }, request = URLBuild[endpoint, { "q" -> StringTemplate["``,``"][lat, lon], "key" -> apiKey }]; response = URLRead[request]; response["Body"] ]
Плюс еще одна функция мне потребуется для определения координат населенного пункта по названию. Ее я сделаю с использованием Wolfram Alpha:
geoPosition::usage = "geoPosition[city] geo position of the specific city. city parameter - name of the city only in English."; geoPosition[city_String] := StringTemplate["lat = ``, lon = ``"] @@ First @ WolframAlpha[city <> " GeoPosition", "WolframResult"]
Теперь я просто добавлю эти функции в список функций LLM и посмотрю что получится:
Чтобы информация поместилась в окне блокнота я многое удалил, но если коротко. то произошло следующее:
-
Пользователь спросил у ГПТ текущую погоду в Саратове
-
ГПТ вернул сообщение, где попросил вызвать функцию geoPosition[«Saratov»]
-
Функция отправила в ГПТ координаты
-
ГПТ снова вернул вызов функции и параметры — теперь weather[lat, lon]
-
Функция отправила в ГПТ информацию о погоде
-
ГПТ вернул пользователю отформатированный читаемый текст.
-
Да, пока я пишу эту статью в Саратове и правда около 6-7 градусов и моросит дождь — вот он на фото ниже
Чат-бот знает теперь три функции, с помощью которых он может получить доступ к внешнему миру. Но они довольно узконаправленные: время. координаты и погода. Но что если дать боту более общий инструмент для общения с миром? Например, поиск в интернете? На самом деле сделать это довольно легко! Пусть с первого раза реализация будет не лучшей и не оптимальной, но я потратил на это буквально несколько минут. Сначала я вспомнил, что DuckDuckGo невозбранно дает использовать свой поиск, а потом посмотрел какие там есть варианты и нашел что там есть поиск lite. И вот как выглядит инструмент поиска в сети:
duckDuckGoSearch::usage = "duckDuckGoSearch[query] call DuckDuckGo search engine. .."; duckDuckGoSearch[query_String] := Module[{url = "https://lite.duckduckgo.com/lite/", request, response, responseBody}, request = HTTPRequest[url, <| Method -> "POST", "Body" -> { "q" -> query }, "ContentType" -> "application/x-www-form-urlencoded" |> ]; response = URLRead[request]; responseBody = response["Body"]; ImportString[ExportString[responseBody, "String"], "HTML"] <> "\nhttps://duckduckgo.com?" <> URLQueryEncode[{"q" -> query}] ];
Ну и опять попробуем что получится:
AIChatComplete[ "Try to search in the web what the last Donald Trump speech", "Tools" -> {time, geoPosition, wheather, duckDuckGoSearch}, "Model" -> "gpt-4o" ]["Messages"][[-1, "content"]]
Хм… там есть ссылки. А что есть просто взять и научить читать LLM страницы по ссылкам! Это очень просто и лежит на поверхности. Просто добавим urlRead!
urlRead::usage = "urlRead[url] read text from html page with address == url. Use this function when you need to get data from the specific address or site in the internet. result is a imple text."; urlRead[url_String] := ImportString[URLRead[url]["Body"], "HTML"];
А теперь попросим LLM прочитать подробнее что написано в статье по первой ссылке!
Да, это вполне реальная статья: https://time.com/7026339/donald-trump-speech-app-comment-public-reaction-kamala-harris-campaign/, а не сгенерированный URL, который просто похож на настоящий.
В принципе, продолжать добавлять плагины можно еще очень долго и можно реализовать самые смелые и интересные идеи. Кроме показанных примеров я так же делал для себя:
-
Поиск по локальным файлам в директории
-
Составление кратного описание большого файла чтобы иметь «каталог»
-
Сделать свой CoPilot
-
Дать доступ к ядру и возможность создавать и редактировать ячейки блокнота
-
Выполнять код
-
Использовать другие полезные сервисы — курсы валют, интернет магазины, новости и др.
-
Добавить в групповой чат и дать доступ ко всем сообщениям и поиску по ним
-
и т.д.
Вывод
То, что сделано на коленке в рамках статьи — я очень часто вижу в виде товара, но нечасто в виде реализации. Самые разные инфлюэнсеры, криптовалютные эксперты и тарологи рассказывают о новой невероятной нейросети с самыми крутыми возможностями — главное купить подписку именно на их телеграм. Может быть я не там смотрю и нужно идти не в магазин, а на завод. Но в любом случае я хотел поделиться своими лучшими практиками по программному использованию OpenAI API и созданию плагинов для него. Всем спасибо за внимание!
ссылка на оригинал статьи https://habr.com/ru/articles/851304/
Добавить комментарий