В заметке расскажу как на python сделать простого чат бота для телеграм на базе последней версии llm модели llama-3.
Предположим у нас уже установлен python и CUDA (если хотите использовать gpu для ускорения). Для взаимодействия с моделью на python есть несколько вариантов, чтобы не усложнять будем использовать библиотеку llama.cpp и квантованную модель в формате GGUF. Обратите внимание, нужна Instruct версия.
Подготовка
В телеграм с помощью @BotFather
создайте нового бота и получите токен.
Скачайте с huggingface.co модель, как вариант отсюда https://huggingface.co/bartowski/Meta-Llama-3-8B-Instruct-GGUF/tree/main
, либо можно найти подходящую по запросу llama-3 8b gguf
.
В каталоге с проектом создаем виртуальное окружения для python и активируем его:
python -m venv venv
. venv/bin/activate
Устанавливаем библиотеку для работы с моделью:
pip install llama-cpp-python
Устанавливаем telebot для создания телеграм бота
pip install telebot python-dotenv
Работа с моделью
Давайте проверим как в принципе взаимодействовать с моделью из python.
Инициализируем модель:
from llama_cpp import Llama
llm = Llama(
model_path="./models/Meta-Llama-3-8B-Instruct-Q4_K_M.gguf",
chat_format="llama-3",
# n_gpu_layers=-1, # для использования GPU
# seed=1337, # установить конкретный seed
# n_ctx=8192, # установить размер контекста
)
Попробуем получить какой-нибудь вывод от модели:
messages = [
{ "role": "system", "content": "Ты полезный ИИ помощник." },
{ "role": "user", "content": "Привет! Ты кто?" },
]
output = llm.create_chat_completion(messages)
print(output)
Получаем на выходе:
{
'id': 'chatcmpl-24b5cdf3-945d-41b2-ad30-d4d24226a4e4',
object': 'chat.completion',
'created': 1714558400,
'model': './models/Meta-Llama-3-8B-Instruct-Q4_K_M.gguf',
'choices': [
{
'index': 0,
'message': {
'role': 'assistant',
'content': 'Привет! Я - LLaMA, искусственный интеллект, созданный Meta AI.
Моя задача - помочь людям в их повседневной жизни, ответить на вопросы, дать советы и просто пообщаться.
Я могу генерировать текст, отвечать на вопросы, переводить языки и многое другое! Как я могу помочь вам сегодня?'
},
'logprobs': None,
'finish_reason': 'stop'
}],
'usage': {
'prompt_tokens': 33,
'completion_tokens': 88,
'total_tokens': 121
}
}
Модель работает, можно идти дальше.
Телеграм бот
Теперь сделаем простого бота который будет получать сообщения от пользователя и отправлять ему ответ:
from llama_cpp import Llama
import telebot
from telebot.types import Message
from dotenv import load_dotenv
load_dotenv()
TG_TOKEN = os.getenv("TG_TOKEN")
bot = telebot.TeleBot(TG_TOKEN)
@bot.message_handler(commands=["start", "help"])
def send_welcome(message: Message):
bot.send_message(message.chat.id, "Я ИИ бот на базе llama-3.")
# Сделаем простую историю общения. Инициализируем ее системным сообщением.
messages = [ { "role": "system", "content": "Ты полезный ИИ помощник." } ]
# создаем обработчик текстовых сообщений
@bot.message_handler(func=lambda message: True)
def message_handler(message: Message):
chat_id = message.chat.id
# добавляем в историю сообщение пользователя
messages.append({"role": "user", "content": message.text})
# получаем ответ от модели
out = llm.create_chat_completion(messages)
# из объекта получаем текст сообщения
reply = out["choices"][0]["message"]["content"]
# отправляем текст от ИИ в чат пользователю
bot.send_message(chat_id, reply)
# сохраняем ответ ИИ в историю
messages.append({"role": "assistant", "content": reply})
print("bot is ready")
bot.infinity_polling() # запускаем пулинг
Создаём .env
файл с переменной TG_TOKEN
с токеном бота, запускаем скрипт и идем в телеграм к боту проверять:
Немного улучшим бота
Чат работает, но тут есть как минимум три проблемы:
- Общая история сообщений для всех пользователей
- Не учитывается длинна контекста. Для стандартной llama-3 модели размер контекста 8K токенов
Немного перепишем бота и сделаем наивное отсечение истории с глубиной в 30 сообщений. Столько последних сообщений бот будет “помнить”.
import datetime
import os
import telebot
from dotenv import load_dotenv
from llama_cpp import Llama
from telebot.types import Message
load_dotenv()
TG_TOKEN = os.getenv("TG_TOKEN")
bot = telebot.TeleBot(TG_TOKEN)
@bot.message_handler(commands=["start", "help"])
def send_welcome(message: Message):
bot.send_message(message.chat.id, "Я ИИ бот на базе llama-3.")
llm = Llama(
model_path="./models/Meta-Llama-3-8B-Instruct-Q4_K_M.gguf",
chat_format="llama-3",
verbose=False,
)
# словарь для хранения историй сообщений
user_message_history = {}
@bot.message_handler(content_types=["text"])
def message_handler(message: Message):
chat_id = message.chat.id
user_id = message.from_user.id
# Получаем историю сообщений текущего пользователя
user_history = user_message_history.get(user_id, [])
user_history.append({"role": "user", "content": message.text})
# Добавим в контест текущую дату и время
current_date_time = datetime.datetime.now().strftime("%d %B %Y, %H:%M MSK")
messages = [ { "role": "system", "content": f"Ты полезный ИИ помощник.\nТекущая дата: {current_date_time}" } ]
for msg in user_history:
messages.append(msg)
# Симулируем что бот печатает ответ
bot.send_chat_action(chat_id, "typing")
# Получаем ответ от модели
out = llm.create_chat_completion(messages)
reply = out["choices"][0]["message"]["content"]
# Добавляем ответ бота в историю пользователя
user_history.append({"role": "assistant", "content": reply})
# Сохраняем усеченную историю
user_message_history[user_id] = user_history[-30:]
# Отправляем ответ пользователю
bot.send_message(chat_id, reply)
print("bot is ready")
bot.infinity_polling() # запускаем пулинг
Проверим работу контекста и памяти:
Бот смог понять из системного сообщения какая сейчас дата и смог вспомнить о чем я его спрашивал.
Обратите внимание, это proof of concept, бот не для продакшена и в зависимости от ваших ресурсов сможет обработать ограниченное число одновременных (параллельных) запросов. Для чего-то более жизнеспособного можно например организовать очередь сообщений (queue, redis, rabbitqm…) для их последовательной обработки.