Сделай Сам: ИИ-ассистент за пару дней на коленке для себя и бизнеса. Часть №1

Готовы за пару дней сконструировать собственного виртуального ИИ-помощника на базе документации компании, который будет отвечать на вопросы, помогать с ответами и легко дополняться? Я покажу, как это сделать!

Читающим примечания: есть интересный проект и нужна поддержка? Напишите @aashmig
Читающим примечания: есть интересный проект и нужна поддержка? Напишите @aashmig

Кому это будет интересно?

В первую очередь статья будет интересна разработчикам, которые начали погружаться в тему Natural Language Processing или которых захватил ChatGPT, Claude или Gemeni (про Сайгу, Орку, Мистраль и зоопарк других моделей мы поговорим немного позже) и они в поиске способов интегрировать LLM в бизнес или заказчикам. Так же будет интересно поиграться с результатом и начинающим разработчикам - от использования в чат-ботах до умного поиска на сайтах, группах и каналах.

Начнем с конца

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

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

Если же вы хотите получить готовый проект или исходные коды рабочего представленного проекта за разумную цену, то можете написать мне в телеграм @aashmig.

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

Сделай Сам: ИИ-ассистент за пару дней на коленке для себя и бизнеса. Часть №1
Сделай Сам: ИИ-ассистент за пару дней на коленке для себя и бизнеса. Часть №1
Сделай Сам: ИИ-ассистент за пару дней на коленке для себя и бизнеса. Часть №1
Сделай Сам: ИИ-ассистент за пару дней на коленке для себя и бизнеса. Часть №1

Ингредиенты для приготовления

Использовавшиеся мной в проекте выше:

  • NodeJS;
  • VueJS;
  • Vuetify;
  • RabbitMQ;
  • ElasticSearch;
  • MySQL 8;
  • Transformers.js;
  • Puppeteer;
  • Socket.IO;
  • ONNX Runtime;

То, что будем использовать сейчас:

  • NodeJS;
  • RabbitMQ;
  • ElasticSearch;
  • MySQL 8;
  • Transformers.js;
  • ONNX Runtime;

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

Теперь немного о каждом из используемых ингредиентов:

  • NodeJS: потому что мне она нравится. Будем делать базовый REST API для получения, добавления, удаления информации. В этой статье мы обойдёмся без авторизаций, регистраций, восстановлений паролей и другой связанной функциональщиной, которая отнимет у нас много времени;
  • RabbitMQ: работа с очередями. Удобный инструмент управления очередями и сообщениями. Используем для того, чтобы (а) не хранить их в памяти в каком-то глобальном объекте NodeJS; (б) не хранить в базе данных MySQL; (в) не писать свою логику обработки сообщений и все связанное с этим.
  • ElasticSearch: лексический и семантический поиск. Будем использовать в качестве главного компонента поиска текста по запросу, как по ключевым словам, так и по смыслу.
  • MySQL: база данных, не требует отдельного представления. Нужна будет нам для хранения истории диалогов с пользователями (предпочитаю такое хранить в реляционных БД по многим причинам, а не в ElasticSearch);
  • Transformers.js: библиотека от парней из Hugging Face для работы с моделями, токенайзерами и прочими около МЛ штуками. Она нам понадобится в момент добавления данных в ElasticSearch и в момент обработки пользовательского запроса.
  • ONNX Runtime: использовать напрямую не будем, но без неё не сможем запустить @cointegrated/rubert-tiny2. ONNX Runtime позволяет запускать модельки под большим количеством платформ, например, под NodeJS или даже в браузере (привет WASM и WebGPU!).

Теперь пора подняться на пару уровней выше и понять, как все эти компоненты будут между собой взаимодействовать:

  • Администратор платформы публикует новые документы или статью во внутренней wiki;
  • Где-то внутри Wiki отправляет запрос к ИИ-ассистенту на добавление новой информации (REST API);
  • ИИ-ассистент полученный блок текста разбивает, очищает, векторизует и сохраняет в ElasticSearch;
  • Пользователь открывает некий интерфейс UI в виде чата или текстового поля и вводит туда свой запрос, нажимает кнопку Отправить или Получить ответ;
  • Где-то внутри отправляется запрос к ИИ-ассистенту с запросом пользователя;
  • Запрос пользователя очищается, векторизуется и отправляется в ElasticSearch для смешанного поиска - лексического (по ключевым словам, словосочетаниям, фразам) и семантического (по смыслу), результат поиска - набор отрывков из статей для последующей подачи LLM на вход;
  • LLM получает данные из базы знаний и с учетом заранее настроенного промпта и истории диалога с пользователем генерирует ответ (сообщение), которое мы потом и возвращаем пользователю;

Шаг №1: выбираем ОС

Долгими были мои мучения при работе с CentOS 7-8, а когда коллеги из Oracle обрадовали новостью о прекращении поддержки и развития, то пришлось выдохнуть и начать присматриваться к какому-то другому дистрибутиву для работы.

Выбор пал на Ubuntu 22 по чистой случайности и подписи "Machine Learning" + LTS. За рекламу мне Selectel не платит, а мог бы 💁

Сделай Сам: ИИ-ассистент за пару дней на коленке для себя и бизнеса. Часть №1

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

На тест и демо-проект нам будет достаточно 1-2 vCPU и 4+ GB RAM. Можем взять SSD на 15 GB и этого тоже должно хватить на первые тестовые запуски и проверки. Если планируете запускать проект в массы, то обратите внимание, что Elastic и RabbitMQ очень любят кушать память и её нужно будет увеличить, а так же изменить ряд настроек по-умолчанию для Elastic с её прожорливой JVM.

ОС поставили. Рекомендую выполнить все стандартные шаги для обновлений:

apt update apt upgrade

С первым шагом закончили.

Шаг №2: настройка и установка Nginx

Nginx - потрясающий инструмент. Использовал у себя в качестве proxy, а сейчас его поставим и настроим на тот случай, если захотите раздавать во вне API проекта.

Устанавливаем Nginx:

sudo apt update sudo apt install nginx

Чтобы Nginx заработал корректно и с портами не было проблем стоит воспользоваться новой утилитой в Ubuntu - ufw.

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

sudo ufw app list

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

Output Available applications: Nginx Full Nginx HTTP Nginx HTTPS OpenSSH

Что они значат:

  • Nginx Full: открыть 80 и 443 порты;
  • Nginx HTTP: открыть только 80 порт;
  • Nginx HTTPS: открыть только 443 порт;

Нам нужен первый вариант - это с учетом того, что сервис будем вешать на какой-то домен и на него же потом ставить SSL сертификат через Lets Encrypt или любой другой сервис.

sudo ufw allow 'Nginx Full'

Проверяем статус:

sudo ufw status

И получаем примерно такой вывод:

Status: active To Action From -- ------ ---- Nginx HTTPS ALLOW Anywhere 22/tcp ALLOW Anywhere 22 ALLOW Anywhere Nginx Full ALLOW Anywhere Nginx HTTPS (v6) ALLOW Anywhere (v6) 22/tcp (v6) ALLOW Anywhere (v6) 22 (v6) ALLOW Anywhere (v6) Nginx Full (v6) ALLOW Anywhere (v6)

Проверим статус Nginx:

systemctl status nginx

Вывод примерно такой:

Output ● nginx.service - A high performance web server and a reverse proxy server Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled) Active: active (running) since Fri 2022-03-01 16:08:19 UTC; 3 days ago Docs: man:nginx(8) Main PID: 2369 (nginx) Tasks: 2 (limit: 1153) Memory: 3.5M CGroup: /system.slice/nginx.service ├─2369 nginx: master process /usr/sbin/nginx -g daemon on; master_process on; └─2380 nginx: worker process

Nginx работает и настроен из коробки.

Теперь найдём конфигурационный файл в `/etc/nginx/nginx.conf` и приведём его к вот такому виду (за исключением всего, что касается SSL - этот дополнительный код сгенерировал cert-bot при установке и настройке SSL-сертификата от Lets Encrypt):

server { server_name ai2me.ru; root /var/www/ai2me.ru/frontend/dist; index index.html index.htm index.nginx-debian.html; location / { try_files $uri $uri/ /index.html; } listen 443 ssl; # managed by Certbot ssl_certificate /etc/letsencrypt/live/ai2me.ru/fullchain.pem; # managed by Certbot ssl_certificate_key /etc/letsencrypt/live/ai2me.ru/privkey.pem; # managed by Certbot include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot location /socket.io/ { proxy_pass http://localhost:3333; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; proxy_set_header X-Forwarded-For $remote_addr; } } server { if ($host = ai2me.ru) { return 301 https://$host$request_uri; } # managed by Certbot listen 80; server_name ai2me.ru; return 404; # managed by Certbot }

Можем закинуть в нашу root-директорию index.html файл для проверки и открыть http://[наш IP адрес]. Если страница открывается - отлично, всё сделано правильно. Если страница не открывается - перепроверяем настройки, пути, код ошибки.

Шаг №3: установка и настройка NodeJS v20

Оптимальный вариант производить установку NodeJS через nvm (node version manager) - позволит удобно управлять версиями используемой node, удалять, переустанавливать.

Устанавливаем nvm:

https://www.digitalocean.com/community/tutorials/how-to-install-node-js-on-ubuntu-20-04

Применяем:

source ~/.bashrc

Проверим список доступных версий:

nvm list-remote

И установим нужную нам:

nvm install v20.0.0

Чтобы убедиться, что установка прошла корректно и мы установили 20 версию:

nvm list

Если всё прошло без ошибок, то установленную версию сделаем версией по-умолчанию:

nvm use v20.0.0

Шаг №4: установка и настройка RabbitMQ

В этот раз идём на официальный сайт RabbitMQ и находим вот этот раздел со способами установки RabbitMQ - Installing on Debian and Ubuntu. Нас интересует подраздел Cloudsmith Quick Start Script.

Продублирую его полностью ниже:

#!/bin/sh sudo apt-get install curl gnupg apt-transport-https -y ## Team RabbitMQ's main signing key curl -1sLf "https://keys.openpgp.org/vks/v1/by-fingerprint/0A9AF2115F4687BD29803A206B73A36E6026DFCA" | sudo gpg --dearmor | sudo tee /usr/share/keyrings/com.rabbitmq.team.gpg > /dev/null ## Community mirror of Cloudsmith: modern Erlang repository curl -1sLf https://github.com/rabbitmq/signing-keys/releases/download/3.0/cloudsmith.rabbitmq-erlang.E495BB49CC4BBE5B.key | sudo gpg --dearmor | sudo tee /usr/share/keyrings/rabbitmq.E495BB49CC4BBE5B.gpg > /dev/null ## Community mirror of Cloudsmith: RabbitMQ repository curl -1sLf https://github.com/rabbitmq/signing-keys/releases/download/3.0/cloudsmith.rabbitmq-server.9F4587F226208342.key | sudo gpg --dearmor | sudo tee /usr/share/keyrings/rabbitmq.9F4587F226208342.gpg > /dev/null ## Add apt repositories maintained by Team RabbitMQ sudo tee /etc/apt/sources.list.d/rabbitmq.list <<EOF ## Provides modern Erlang/OTP releases ## deb [signed-by=/usr/share/keyrings/rabbitmq.E495BB49CC4BBE5B.gpg] https://ppa1.novemberain.com/rabbitmq/rabbitmq-erlang/deb/ubuntu jammy main deb-src [signed-by=/usr/share/keyrings/rabbitmq.E495BB49CC4BBE5B.gpg] https://ppa1.novemberain.com/rabbitmq/rabbitmq-erlang/deb/ubuntu jammy main # another mirror for redundancy deb [signed-by=/usr/share/keyrings/rabbitmq.E495BB49CC4BBE5B.gpg] https://ppa2.novemberain.com/rabbitmq/rabbitmq-erlang/deb/ubuntu jammy main deb-src [signed-by=/usr/share/keyrings/rabbitmq.E495BB49CC4BBE5B.gpg] https://ppa2.novemberain.com/rabbitmq/rabbitmq-erlang/deb/ubuntu jammy main ## Provides RabbitMQ ## deb [signed-by=/usr/share/keyrings/rabbitmq.9F4587F226208342.gpg] https://ppa1.novemberain.com/rabbitmq/rabbitmq-server/deb/ubuntu jammy main deb-src [signed-by=/usr/share/keyrings/rabbitmq.9F4587F226208342.gpg] https://ppa1.novemberain.com/rabbitmq/rabbitmq-server/deb/ubuntu jammy main # another mirror for redundancy deb [signed-by=/usr/share/keyrings/rabbitmq.9F4587F226208342.gpg] https://ppa2.novemberain.com/rabbitmq/rabbitmq-server/deb/ubuntu jammy main deb-src [signed-by=/usr/share/keyrings/rabbitmq.9F4587F226208342.gpg] https://ppa2.novemberain.com/rabbitmq/rabbitmq-server/deb/ubuntu jammy main EOF ## Update package indices sudo apt-get update -y ## Install Erlang packages sudo apt-get install -y erlang-base \ erlang-asn1 erlang-crypto erlang-eldap erlang-ftp erlang-inets \ erlang-mnesia erlang-os-mon erlang-parsetools erlang-public-key \ erlang-runtime-tools erlang-snmp erlang-ssl \ erlang-syntax-tools erlang-tftp erlang-tools erlang-xmerl ## Install rabbitmq-server and its dependencies sudo apt-get install rabbitmq-server -y --fix-missing

Его необходимо сохранить в какой-то *.sh скрипт и запустить на выполнение. После установки проверим статус сервера командой:

systemctl status rabbitmq-server

И в ответе будет что-то подобное:

rabbitmq-server.service - RabbitMQ broker Loaded: loaded (/lib/systemd/system/rabbitmq-server.service; enabled; vendor preset: enabled) Active: active (running) since Mon 2023-12-11 06:49:10 UTC; 4h 31min ago Main PID: 833 (beam.smp) Tasks: 25 (limit: 4606) Memory: 120.0M CPU: 1min 34.472s CGroup: /system.slice/rabbitmq-server.service ├─ 833 /usr/lib/erlang/erts-14.1.1/bin/beam.smp -W w -MBas ageffcbf -MHas ageffcbf -MBlmbcs 512 -MHlmbcs 512 -MMmcs 30 -pc unicode -P 1048576 -t 5000000 -stbt db -zdbbl 128000 -sbwt none -sbwtdcp> ├─ 888 erl_child_setup 32768 ├─1032 /usr/lib/erlang/erts-14.1.1/bin/epmd -daemon ├─1106 /usr/lib/erlang/erts-14.1.1/bin/inet_gethost 4 ├─1107 /usr/lib/erlang/erts-14.1.1/bin/inet_gethost 4 └─1526 /bin/sh -s rabbit_disk_monitor

Сервер успешно запущен и работает.

Ссылка по-умолчанию для подключения к серверу:

amqp://127.0.0.1:5672

Шаг №5: установка и настройка ElasticSearch

Если мы в РФ и наивно решим скачать ElasticSearch с официального сайта без VPN или proxy, то нас ждёт разочарование:

Сделай Сам: ИИ-ассистент за пару дней на коленке для себя и бизнеса. Часть №1

Добрые ребята (ссылки, к сожалению, не помню) скачали все версии и выложили на своём сайте, а я делюсь с вами ссылкой на Яндекс.Диске - ElasticSearch 8.11.2.deb пакет.

Установка из deb пакета оказалась идеальным вариантом, если учитывать тот факт, что все другие способы были заблокированы.

Спасибо ElasticSearch за то, что доступ к документации оставили без proxy или vpn.

Установка ElasticSearch из deb пакета:

dpkg -i elasticsearch-8.11.2-amd64.deb

Ссылка по-умолчанию для подключения к серверу:

http://localhost:9200

Для проверки корректной установки можно выполнить две команды:

systemctl status elasticsearch

или воспользоваться curl и отправить запрос на адрес подключения:

curl http://localhost:9200

Получив примерно такой ответ:

{ "name" : "corinne", "cluster_name" : "elasticsearch", "cluster_uuid" : "_-Ujfp1QQBejHJJ6aOka9Q", "version" : { "number" : "8.11.1", "build_flavor" : "default", "build_type" : "deb", "build_hash" : "6f9ff581fbcde658e6f69d6ce03050f060d1fd0c", "build_date" : "2023-11-11T10:05:59.421038163Z", "build_snapshot" : false, "lucene_version" : "9.8.0", "minimum_wire_compatibility_version" : "7.17.0", "minimum_index_compatibility_version" : "7.0.0" }, "tagline" : "You Know, for Search" }

Шаг №6: установка и настройка MySQL 8

Установка MySQL 8 никаких трудностей не составляет:

sudo apt install mysql-server

Проверяем статус:

sudo systemctl start mysql.service

После установки необходимо произвести конфигурацию:

sudo mysql_secure_installation

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

В этой части я опущу создание выделенного пользователя с ограниченным набором прав - для нашего примера это не критично.

Шаг №7: устанавливаем всё для NodeJS

На этом шаге наша с вами задача подготовить окружение NodeJS таким образом, чтобы мы могли обрабатывать запросы, выполнять над ними действия, подключаться к RabbitMQ и ElasticSearch, вычислять эмбеддинги и прочее.

Приведу свой package.json файл:

{ "name": "speakup_web", "version": "1.0.0", "description": "Speakup.business", "main": "index.js", "type": "module", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "migrate-list": "migrate list", "local-migrate-up": "ENV=local migrate up", "prod-migrate-up": "ENV=prod migrate up" }, "keywords": [], "author": "Andrew Shmig", "license": "ISC", "dependencies": { "@elastic/elasticsearch": "^8.10.0", "@xenova/transformers": "^2.9.0", "ajv": "^8.12.0", "ajv-formats": "^2.1.1", "amqplib": "^0.10.3", "bcrypt": "^5.0.1", "cors": "^2.8.5", "dotenv": "^16.3.1", "express": "^4.18.2", "install": "^0.13.0", "migrate": "^1.8.0", "moment": "^2.29.4", "mysql2": "^3.3.1", "node-cron": "^3.0.2", "node-fetch": "^3.3.2", "nodemailer": "^6.9.2", "npm": "^9.7.2", "pino": "^8.15.0", "pino-pretty": "^10.2.0", "puppeteer": "^21.5.2", "randomstring": "^1.2.3", "socket.io": "^4.6.1" } }

Некоторая часть из этого списка нам не нужна будет, оставляем только то, что пригодится для этого демо-проекта. Результат будет таким:

{ "name": "speakup_web", "version": "1.0.0", "description": "Speakup.business", "main": "index.js", "type": "module", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "migrate-list": "migrate list", "local-migrate-up": "ENV=local migrate up", "prod-migrate-up": "ENV=prod migrate up" }, "keywords": [], "author": "Andrew Shmig", "license": "ISC", "dependencies": { "@elastic/elasticsearch": "^8.10.0", "@xenova/transformers": "^2.9.0", "amqplib": "^0.10.3", "express": "^4.18.2", "mysql2": "^3.3.1", "npm": "^9.7.2", } }

Выполняем команду установки в директории, которой находится package.json:

npm i

После установки в этой же директории появятся node_modules и package-lock.json

🙌 Примечание: если вы знаете, что такое PM2, то можете его установить и настроить через файл ecosystem.conf для запуска приложения. Если не знаете, то можете поискать в Google или спросить ChatGPT.

Конец первой части.

Во второй части мы с вами:

  • Напишем несколько API методов для работы с данными - сохранение, удаление, поиск;
  • Погрузимся в механизм подготовки больших данных (текстов) для оптимизации последующего лексического и семантического поиска - очистка, chunking, эмбеддинги;
  • Научимся портировать модели и конвертировать их в ONNX формат;
  • Протестируем модель @cointegrated/rubert-tiny2 на тестовых данных;
  • Научимся сохранять контекст диалога и получим первый ответ от LLM по нашим данным из базы знаний.

Если подобные серии статей вам интересны, то обязательно ставьте лайк и подписывайтесь на мой блог на vc.ru

Возможно у вас есть идея или задача в бизнесе, которую, как вам кажется, может решить ИИ-консультант / ИИ-ассистент / ИИ-всезнайка и вы хотите такое решение видеть у себя - напишите мне в телеграм @aashmig и мы обсудим подробности реализации и условия.

Берегите себя и свои модели 🫶

55
9 комментариев
Комментарий удалён модератором

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

1
Ответить

Очень интересная статья/информация . С нетерпением ожидаю вторую часть повествования об ИИ в деле. Автору в карму плюс! Подписался с удовольствием :+₽

2
Ответить

Благодарю за обратную связь ☺️ Поищу время на публикацию второй части с конкретной реализацией, может даже и на гитхаб код выложу сразу.

1
Ответить

Первая часть статьи - просто шикарная! Автор молодец

1
Ответить

Благодарю! Подписывайтесь, чтобы вторую часть не пропустить. 🤝

1
Ответить

Андрей, спасибо за первую часть ! Заинтригован, жду вторую ! И еще идея, а что если к LLM подключить возможность управлять чем-либо, скрипты например запускать, страницы подгугливать .. Короче каких-нибудь агентов, которые бы могли расширять ее возможности. Возможно такое уже есть, но я просто не знаю

1
Ответить