- BrainTools - https://www.braintools.ru -
Каждый раз, когда кто-то говорит про запуск LLM, возникает вопрос: “А где взять GPU?” Облачные GPU стоят денег, локальные видеокарты стоят ещё больших денег, а бесплатные GPU-тиры исчезают быстрее, чем появляются.
Но что если можно запустить полноценного AI-ассистента вообще без GPU? На обычном CPU. Бесплатно. С хорошей поддержкой русского языка. И развернуть его за 15-20 минут.
Эта статья адресована начинающим специалистам в области машинного обучения [1] и data science. Если вы только знакомитесь с экосистемой ML-инструментов, здесь вы найдёте подробное введение в два замечательных инструмента: Gradio для создания веб-интерфейсов к ML-моделям и Hugging Face Spaces для бесплатного хостинга демо-приложений. Никаких глубоких знаний веб-разработки не требуется — только базовый Python.
Звучит слишком хорошо, чтобы быть правдой, но это работает. В этой статье:
Разворачивается модель Qwen2.5-3B-Instruct на бесплатном CPU-тире Hugging Face Spaces
Создаётся веб-интерфейс чата с помощью Gradio
Генерируется публичная ссылка, которой можно поделиться с кем угодно
Разбирается каждая строчка кода, чтобы было понятно, что происходит под капотом
Всё, что нужно: Python, аккаунт на Hugging Face и 15-20 минут времени.
|
Тема |
Содержание |
|---|---|
|
Что создаётся |
AI-ассистент с веб-интерфейсом чата |
|
Модель |
Qwen2.5-3B-Instruct (квантизация Q4_K_M) |
|
Технологии |
Gradio + llama-cpp-python + Hugging Face Spaces |
|
Требования |
Python 3.10+, аккаунт на Hugging Face |
|
Время |
~15-20 минут |
|
Стоимость |
Бесплатно |
|
Результат |
Публичная ссылка на работающего чат-бота |
Gradio — это open-source Python-библиотека для создания веб-интерфейсов к машинному обучению. Звучит сухо, но на практике это означает: вы можете превратить любую Python-функцию в полноценное веб-приложение за несколько строк кода. Без HTML. Без CSS. Без JavaScript. Просто Python.
Установка:
pip install gradio
Создайте файл app.py:
import gradio as gr
def greet(name):
return f"Привет, {name}!"
demo = gr.Interface(fn=greet, inputs="text", outputs="text")
demo.launch()
Запуск:
python app.py
Четыре строки кода — и у вас есть веб-страница с текстовым полем, кнопкой и областью вывода. После запуска браузер откроется на http://127.0.0.1:7860 с готовым интерфейсом.
Gradio предлагает три способа создания интерфейсов, от простого к сложному:
gr.Interface — самый простой вариант. Одна функция, входы, выходы. Идеально для быстрых демо: классификация изображений, генерация текста, предсказания модели.
gr.ChatInterface — специализированный интерфейс для чат-ботов. Из коробки получаете историю сообщений, поле ввода, примеры запросов. Именно его мы используем в этом проекте.
gr.Blocks — полный контроль над layout. Можно создавать сложные интерфейсы с несколькими колонками, табами, условной логикой [3]. Требует больше кода, но даёт больше гибкости.
В Gradio более 40 готовых компонентов. Самые популярные:
|
Компонент |
Назначение |
|---|---|
|
|
Текстовый ввод/вывод |
|
|
Загрузка и отображение изображений |
|
|
Работа с аудиофайлами |
|
|
Видео-контент |
|
|
Чат с историей сообщений |
|
|
Ползунок для числовых значений |
|
|
Выпадающий список |
|
|
Загрузка файлов |
|
|
Таблицы данных |
|
|
Графики (matplotlib, plotly) |
Компоненты можно комбинировать в любых сочетаниях. Хотите загрузить изображение и получить текстовое описание? inputs=gr.Image(), outputs=gr.Textbox(). Хотите голосовой ввод с текстовым ответом? inputs=gr.Audio(), outputs=gr.Textbox().
Оба инструмента решают похожую задачу, но есть важные отличия:
Для чат-ботов Gradio удобнее. gr.ChatInterface — это готовое решение для conversational AI. В Streamlit придётся собирать чат вручную из st.chat_message и управлять состоянием через st.session_state.
Интеграция с Hugging Face. Gradio создан той же командой, что и Hugging Face Hub. Деплой на Spaces работает бесшовно, а модели с Hub подключаются в одну строку.
Share-ссылки. Запустите demo.launch(share=True), и Gradio создаст публичную ссылку, которая работает 72 часа. Удобно для быстрых демонстраций без деплоя.
API из коробки. Каждое Gradio-приложение автоматически получает REST API. Можно вызывать вашу модель программно, не только через веб-интерфейс.
Gradio использует FastAPI для бэкенда и Svelte для фронтенда. При запуске demo.launch() поднимается локальный веб-сервер, который обрабатывает запросы и вызывает вашу Python-функцию.
Когда вы деплоите на Hugging Face Spaces, происходит то же самое — только сервер работает в облаке, а не на вашей машине.
Hugging Face Spaces — это платформа для хостинга ML-демо приложений. Более миллиона приложений уже развёрнуто на Spaces: от простых классификаторов до сложных мультимодальных систем.
Главная ценность Spaces — низкий порог входа. Вы загружаете код, платформа сама собирает окружение, устанавливает зависимости и запускает приложение. Никаких Docker-файлов, никаких конфигов nginx, никакого SSH на сервер.
Под капотом Spaces — это Git-репозиторий с автоматическим CI/CD:
Вы создаёте Space и выбираете SDK (Gradio, Streamlit или Docker)
Загружаете код через веб-интерфейс или git push
Spaces автоматически читает requirements.txt и устанавливает зависимости
Запускается app.py (или указанный вами файл)
Приложение становится доступно по публичной ссылке
Каждый push запускает пересборку. Изменили код — через минуту изменения в продакшене.
Gradio — основной SDK для ML-демо. Лучшая интеграция с экосистемой Hugging Face.
Streamlit — альтернатива для тех, кто уже знаком со Streamlit. Полная поддержка всех фич.
Docker — для сложных приложений, которым нужен полный контроль над окружением. Можно запускать что угодно: Flask, FastAPI, Node.js, даже статические сайты.
Spaces предлагает бесплатный тир и несколько платных опций:
|
Тип |
CPU |
RAM |
GPU |
Цена |
|---|---|---|---|---|
|
CPU Basic |
2 vCPU |
16 GB |
– |
Бесплатно |
|
CPU Upgrade |
8 vCPU |
32 GB |
– |
$0.03/час |
|
Nvidia T4 small |
4 vCPU |
15 GB |
16 GB |
$0.40/час |
|
Nvidia T4 medium |
8 vCPU |
30 GB |
16 GB |
$0.60/час |
|
Nvidia L4 |
8 vCPU |
30 GB |
24 GB |
$0.80/час |
|
Nvidia L40S |
8 vCPU |
62 GB |
48 GB |
$1.80/час |
|
Nvidia A10G small |
4 vCPU |
15 GB |
24 GB |
$1.00/час |
|
Nvidia A100 large |
12 vCPU |
142 GB |
80 GB |
$2.50/час |
Для CPU-инференса квантизированных моделей бесплатного тира более чем достаточно. 16 GB RAM хватает для моделей до 7B параметров в Q4-квантизации.
Отдельно стоит упомянуть ZeroGPU — экспериментальную фичу, которая динамически выделяет GPU только на время инференса. Для пользователей с PRO-подпиской ($9/месяц) предоставляется бесплатная квота GPU-времени, остальные получают ограниченный доступ с очередью. Под капотом — Nvidia A100, одни из самых мощных GPU на рынке.
ZeroGPU отлично подходит для демо, где GPU нужен редко: пользователь загрузил картинку, модель обработала за 2 секунды, GPU освободился.
Бесплатные Spaces имеют несколько ограничений, о которых важно знать:
Холодный старт. После 5-15 минут бездействия Space “засыпает”. Следующий запрос его “разбудит”, но это займёт 1-3 минуты. Модель загружается заново, кэш очищается.
Непостоянный диск. Всё, что вы записываете на диск (кроме кэша моделей), теряется при перезапуске. Не храните важные данные локально.
Общие ресурсы. Бесплатные Spaces работают на shared-инфраструктуре. В моменты пиковой нагрузки производительность может падать.
Нет гарантий uptime. Это бесплатный сервис. Для production-нагрузок нужен платный тир или собственная инфраструктура.
Никогда не хардкодьте API-ключи и токены в коде. Spaces поддерживает два типа переменных окружения:
Variables — для несекретных данных (имена моделей, конфигурация). Видны в настройках, копируются при дублировании Space.
Secrets — для API-ключей и токенов. Скрыты после сохранения, не копируются при дублировании.
Доступ из кода стандартный:
import os
api_key = os.getenv("MY_API_KEY")
Spaces тесно интегрированы с остальной экосистемой Hugging Face:
Модели с Hub загружаются через huggingface_hub без дополнительной авторизации
Можно указать связанные модели и датасеты в README — они появятся в UI
Spaces можно встраивать в карточки моделей и датасетов
ArXiv-интеграция: демо появляются на страницах научных статей
Это создаёт замкнутую экосистему: модель на Hub, датасет на Hub, демо на Spaces — всё связано и доступно в одном месте.
Давайте сразу разберёмся с главным вопросом: как вообще можно запускать LLM на CPU?
Когда OpenAI выпустила GPT-3, для его запуска требовалось несколько сотен гигабайт видеопамяти. Модели меньшего размера тоже требовали GPU — это казалось аксиомой. Но потом появились две технологии, которые всё изменили.
Первая технология — квантизация. Идея простая: вместо того чтобы хранить веса модели в формате float16 (16 бит на каждое число), они сжимаются до 4 бит. Это как JPEG для нейросетей — качество немного падает, но размер уменьшается в 4 раза.
Почему это работает? Оказывается, большинство весов в нейросети близки к нулю или к небольшим значениям. Высокая точность для их хранения не требуется. А те веса, которые действительно важны, можно хранить с более высокой точностью — это называется смешанная квантизация.
На практике разница между оригинальной моделью и её квантизированной версией почти незаметна в обычных диалогах. Вы не отличите ответы Q4-модели от FP16-оригинала без специальных тестов.
Вторая технология — это библиотека llama.cpp. Её создал Георги Герганов (Georgi Gerganov), и она совершила маленькую революцию в мире LLM.
llama.cpp написана на чистом C++ без зависимости от CUDA или других GPU-фреймворков. Она использует:
SIMD-инструкции процессора (AVX, AVX2) для параллельных вычислений
Оптимизированное управление памятью [4]
Эффективную работу с квантизированными весами
Результат: модель, которая на PyTorch требует 16 GB видеопамяти, на llama.cpp работает в 2 GB оперативки. И работает быстро — не в реальном времени, но достаточно для интерактивного использования.
Через Python-обёртку llama-cpp-python вся эта магия доступна как обычная библиотека.
Для хостинга используем Hugging Face Spaces — платформу, подробно описанную выше. Бесплатный CPU-тир (2 vCPU, 16 GB RAM) идеально подходит для нашей задачи: 16 гигабайт — более чем достаточно для квантизированной 3-миллиардной модели.
Выбор модели для CPU-инференса — это всегда компромисс. С одной стороны, хочется модель поумнее. С другой — она должна влезть в 16 GB RAM и генерировать ответы за разумное время.
На момент написания статьи для CPU-инференса популярны несколько семейств моделей:
Llama 3.2 — отличные модели от Meta, но версия 3B плохо работает с русским языком. Для англоязычных проектов — отличный выбор.
Phi-3 — компактные модели от Microsoft. Phi-3 Mini (3.8B) показывает впечатляющие результаты на бенчмарках, но тоже слабо поддерживает русский.
Qwen2.5 — модели от Alibaba. Qwen2.5-3B-Instruct официально поддерживает 29+ языков, включая русский. И это не просто “поддерживает” — модель реально хорошо генерирует текст на русском.
Gemma 2 — модели от Google. Gemma 2 2B неплохо работает, но 3B версии нет.
После тестирования выбор пал на Qwen2.5-3B-Instruct по следующим причинам:
Размер: 3 миллиарда параметров — оптимальный баланс для CPU. Квантизированная версия Q4_K_M занимает около 2.1 GB.
Качество: Qwen2.5 показывает отличные результаты на бенчмарках, часто обходя модели аналогичного и даже большего размера.
Многоязычность: Официально поддерживает 29+ языков, включая русский, английский, китайский, французский и другие. Это критично для русскоязычных пользователей.
Контекст: Поддержка до 32K токенов на входе и до 8K токенов на генерацию — можно вести длинные диалоги без потери контекста.
Instruct-тюнинг: Модель уже обучена следовать инструкциям и вести диалог. Не нужно изобретать свой формат промптов.
Модель доступна на Hugging Face: Qwen/Qwen2.5-3B-Instruct-GGUF [5]
В репозитории GGUF-версии модели есть несколько вариантов квантизации:
|
Вариант |
Размер |
Качество |
Скорость |
|---|---|---|---|
|
Q2_K |
~1.2 GB |
Низкое |
Быстро |
|
Q3_K_M |
~1.6 GB |
Приемлемое |
Быстро |
|
Q4_K_M |
~2.1 GB |
Хорошее |
Средне |
|
Q5_K_M |
~2.5 GB |
Очень хорошее |
Медленнее |
|
Q8_0 |
~3.5 GB |
Почти оригинал |
Медленно |
Рекомендуемый вариант — Q4_K_M, это золотая середина. “K” означает k-quant — метод квантизации с переменной точностью, где более важные слои (attention, первые и последние) сжимаются меньше. “M” означает Medium — средний размер файла (есть также варианты S — Small и L — Large). Это даёт лучшее соотношение качества к размеру, чем простая Q4 квантизация.
Если у вас есть лишние гигабайты памяти, можно попробовать Q5_K_M. Если памяти впритык — Q3_K_M всё ещё даёт приемлемое качество.
Проект состоит из трёх файлов:
my-ai-assistant/
├── README.md # Конфигурация Space
├── app.py # Основной код приложения
└── requirements.txt # Зависимости
https://huggingface.co/Luigi/llama-cpp-python-wheels-hf-spaces-free-cpu/resolve/main/llama_cpp_python-0.3.22-cp310-cp310-linux_x86_64.whl
gradio>=6.0.0
huggingface-hub>=0.20.0
Обратите внимание [6] на первую строку — это прямая ссылка на prebuilt wheel для llama-cpp-python. Почему нельзя просто написать pip install llama-cpp-python?
Проблема в том, что llama-cpp-python — это не чистый Python-пакет. Внутри него лежит вся библиотека llama.cpp, написанная на C++. При установке через pip происходит компиляция этого C++ кода, а для этого нужен компилятор (gcc/clang) и заголовочные файлы.
На Hugging Face Spaces ничего этого нет — там минимальный Docker-контейнер без средств разработки. Установка из PyPI падает с ошибкой [7] вроде:
error: command 'gcc' failed: No such file or directory
Решение — использовать prebuilt wheel. Это архив с уже скомпилированным кодом, который просто распаковывается при установке.
Как получить ссылку на wheel:
Откройте репозиторий Luigi с wheel-файлами [8]
Найдите файл для Python 3.10 и Linux x86_64 (например, llama_cpp_python-0.3.22-cp310-cp310-linux_x86_64.whl)
Нажмите на файл, затем скопируйте прямую ссылку — она будет вида https://huggingface.co/Luigi/.../resolve/main/имя_файла.whl
Вставьте эту ссылку первой строкой в requirements.txt
Расшифровка имени файла: cp310 означает CPython 3.10, linux_x86_64 — платформа.
Важно: wheel-файлы от Luigi собраны для Python 3.10. По умолчанию HF Spaces может использовать более новую версию Python, поэтому необходимо явно указать версию в конфигурации Space — иначе получите ошибку is not a supported wheel on this platform.
Спасибо пользователю Luigi за поддержку этого репозитория — он регулярно обновляет wheel-файлы под новые версии llama-cpp-python.
---
title: Qwen Chat
emoji: 🤖
colorFrom: blue
colorTo: purple
sdk: gradio
sdk_version: 6.5.1
app_file: app.py
python_version: "3.10"
pinned: false
---
Этот файл — конфигурация вашего Space. Hugging Face читает YAML-блок между --- и применяет настройки:
title — название, отображается в интерфейсе
emoji — иконка Space
sdk: gradio — указывает, что это Gradio-приложение
sdk_version — версия Gradio (опционально, но рекомендуется для воспроизводимости)
app_file — точка входа, по умолчанию app.py
python_version: "3.10" — критически важно для совместимости с wheel-файлами Luigi
Без указания python_version Space может запуститься на Python 3.11+ и установка wheel упадёт с ошибкой.
Теперь самое интересное — код приложения. Полный код приведён в конце статьи в разделе Полный код для копирования [9], а здесь разберём его по частям.
Давайте разберём каждую часть кода подробнее.
MODEL_REPO = "Qwen/Qwen2.5-3B-Instruct-GGUF"
MODEL_FILE = "qwen2.5-3b-instruct-q4_k_m.gguf"
Все параметры вынесены в константы в начале файла. Это не просто “хороший стиль” — это практично. Захотите попробовать другую модель? Поменяйте две строки. Нужно настроить температуру? Одна строка. Не нужно искать магические числа по всему коду.
MODEL_REPO — это идентификатор репозитория на Hugging Face в формате owner/repo-name. MODEL_FILE — имя конкретного файла для скачивания.
model_path = hf_hub_download(
repo_id=MODEL_REPO,
filename=MODEL_FILE,
)
Функция hf_hub_download из библиотеки huggingface_hub делает несколько вещей:
Проверяет, есть ли файл в локальном кэше
Если нет — скачивает его с Hugging Face Hub
Возвращает локальный путь к файлу
При первом запуске это займёт 2-3 минуты (файл ~2.1 GB). При последующих запусках модель берётся из кэша мгновенно. Кэш хранится в ~/.cache/huggingface/hub/.
llm = Llama(
model_path=model_path,
n_ctx=CONTEXT_SIZE,
n_threads=2,
verbose=False,
)
Создаём объект модели. Важные параметры:
n_ctx — размер контекста в токенах. Это сколько текста модель может “помнить” за один вызов. Системный промпт + история диалога + текущее сообщение + ответ — всё должно влезть в этот лимит.
n_threads=2 — количество CPU-потоков для инференса. На бесплатном тире HF Spaces ровно 2 vCPU, больше ставить бессмысленно.
verbose=False — отключаем дебаг-вывод. С verbose=True модель печатает кучу информации о загрузке, что засоряет логи.
def chat(message: str, history: list) -> str:
Это сердце приложения. Gradio вызывает эту функцию каждый раз, когда пользователь отправляет сообщение. Она получает текущее сообщение и всю историю диалога.
В Gradio 6.x история приходит в OpenAI-style формате:
[
{"role": "user", "content": [{"type": "text", "text": "Привет"}]},
{"role": "assistant", "content": [{"type": "text", "text": "Здравствуйте!"}]}
]
Обратите внимание: content — это список блоков контента, а не просто строка. Это позволяет передавать мультимодальный контент (текст + изображения). Для текстовых сообщений нужно извлечь текст из блоков.
Функция:
Формирует список сообщений в формате OpenAI Chat API (role/content)
Добавляет системный промпт в начало
Извлекает текст из structured content и добавляет историю диалога
Добавляет текущее сообщение пользователя
Вызывает модель через create_chat_completion
Извлекает и возвращает текст ответа
demo = gr.ChatInterface(
fn=chat,
title="AI-ассистент на Qwen2.5-3B",
...
)
Используем gr.ChatInterface — специализированный компонент для чат-ботов, описанный в разделе “Что такое Gradio”. Достаточно передать функцию chat, указать заголовок и примеры — Gradio сделает остальное.
|
Параметр |
Значение |
Описание |
|---|---|---|
|
|
4096 |
Размер контекста. Больше = длиннее диалоги, но больше памяти |
|
|
1024 |
Максимальная длина ответа |
|
|
0.7 |
Креативность. 0.1 — строго по делу, 0.9 — фантазирует |
|
|
0.9 |
Nucleus sampling. Обычно не трогают |
|
|
1.1 |
Штраф за повторения [10]. Помогает избежать зацикливания |
|
|
10 |
Лимит сообщений в истории. Предотвращает переполнение контекста |
Системный промпт — это инструкция, которая задаёт поведение [11] модели. В данном примере он простой:
SYSTEM_PROMPT = """You are a helpful AI assistant. Respond in Russian
if the user writes in Russian. Be concise and to the point."""
Почему системные промпты лучше писать на английском?
Большинство современных LLM (GPT, Claude, Llama, Gemini) обучались преимущественно на английских текстах. Это означает:
Лучшее понимание инструкций. Модель точнее интерпретирует команды на английском — меньше двусмысленностей и ошибок в следовании указаниям.
Экономия токенов. Английский текст обычно занимает меньше токенов, чем эквивалентный русский. Системный промпт передаётся в каждом запросе, поэтому экономия накапливается.
Консистентность поведения [12]. На английском модель ведёт себя более предсказуемо — особенно важно для сложных инструкций с условиями и ограничениями.
При этом модель отлично понимает, что отвечать нужно на русском — достаточно явно указать это в промпте (“Respond in Russian”).
Хороший системный промпт:
Определяет роль и экспертизу модели
Задаёт формат и стиль ответов
Указывает, как вести себя в неоднозначных ситуациях
Ограничивает область ответов (если нужно)
Ниже приведены готовые конфигурации для типичных сценариев. Достаточно заменить SYSTEM_PROMPT в коде на один из вариантов.
Ассистент для разработчиков: отвечает на вопросы о коде, помогает с отладкой, предлагает улучшения.
SYSTEM_PROMPT = """You are an experienced senior developer with 10+ years of experience.
Your tasks:
- Answer technical programming questions
- Conduct code reviews: find bugs, suggest improvements
- Explain complex concepts in simple terms
- Provide code examples with comments
Rules:
- If a question is ambiguous, ask for context
- If you see a potential security issue, warn about it
- If you're unsure of an answer, say so honestly
- Respond in the same language the user writes in"""
Примеры использования:
“Проверь этот код на баги: [код]”
“Как оптимизировать этот SQL-запрос?”
“Объясни разницу между async/await и промисами”
Ассистент для авторов: помогает улучшать тексты, исправляет ошибки, предлагает формулировки.
SYSTEM_PROMPT = """You are a professional editor and copywriter.
Your tasks:
- Fix grammatical and stylistic errors
- Improve text structure
- Suggest more precise and concise wording
- Adapt text for the target audience
Rules:
- Preserve the author's voice and style
- Explain why you suggest changes
- Offer multiple options when possible
- Don't change the meaning without explicit request
- Respond in the same language as the input text"""
Примеры использования:
“Отредактируй этот абзац: [текст]”
“Сделай этот текст более формальным”
“Сократи до 100 слов, сохранив суть”
Ассистент для ответов на типовые вопросы в рамках заданной темы.
SYSTEM_PROMPT = """You are a customer support assistant for TechCorp.
Your knowledge base includes information about:
- Company products and their features
- Pricing and plans
- Technical requirements
- Common issues and their solutions
Rules:
- Only answer questions related to company products
- If a question is outside your knowledge base, politely direct to a live agent
- Provide specific step-by-step instructions
- For technical issues, ask for product version and OS
- Respond in the same language the user writes in"""
Примеры использования:
“Как сбросить пароль?”
“Какие системные требования у продукта X?”
“Не работает функция Y, что делать?”
Ассистент для практики иностранного языка.
SYSTEM_PROMPT = """You are an English language teacher.
Your tasks:
- Conduct dialogue in English, adapting complexity to the learner's level
- Correct errors in user messages
- Explain grammar rules
- Suggest new words and expressions related to the conversation topic
Rules:
- After each user message, point out errors (if any)
- Suggest the correct version of the phrase
- Use real-life examples
- If the user writes in Russian, gently steer the conversation to English"""
Примеры использования:
“Let’s practice talking about travel”
“Explain the difference between ‘make’ and ‘do'”
“Correct my sentence: I goed to store yesterday”
Прежде чем публиковать приложение на Hugging Face Spaces, рекомендуется протестировать его локально. Это позволит убедиться, что всё работает корректно, и упростит отладку.
# Создание виртуального окружения
python -m venv venv
# Активация (Linux/macOS)
source venv/bin/activate
# Активация (Windows)
venvScriptsactivate
Для локального запуска llama-cpp-python устанавливается иначе, чем на HF Spaces. Локально пакет компилируется из исходников, поэтому нужен компилятор C++.
Linux (Ubuntu/Debian):
sudo apt-get update
sudo apt-get install build-essential
pip install llama-cpp-python gradio huggingface-hub
macOS:
xcode-select --install # если ещё не установлен
pip install llama-cpp-python gradio huggingface-hub
Windows:
Требуется Visual Studio Build Tools с компонентом “C++ build tools”.
pip install llama-cpp-python gradio huggingface-hub
Если компиляция не удаётся, можно использовать prebuilt wheels из репозитория [13].
После установки зависимостей создайте файл app.py и запустите:
python app.py
После запуска в консоли появится сообщение:
Running on local URL: http://127.0.0.1:7860
Откройте эту ссылку в браузере. Появится интерфейс чата, в котором можно протестировать работу модели.
При первом запуске модель загружается из Hugging Face Hub (~2.1 GB), это занимает 2-3 минуты в зависимости от скорости интернета. Последующие запуски используют закэшированную модель и стартуют быстрее.
|
Аспект |
Локально |
HF Spaces |
|---|---|---|
|
Установка llama-cpp-python |
Компиляция из исходников |
Prebuilt wheel |
|
requirements.txt |
Стандартные пакеты |
URL на wheel-файл |
|
Производительность |
Зависит от железа |
2 vCPU, 16 GB RAM |
|
Доступ |
Только локально |
Публичная ссылка |
Для локального тестирования requirements.txt может выглядеть проще:
llama-cpp-python
gradio>=6.0.0
huggingface-hub>=0.20.0
Но для деплоя на HF Spaces используется версия с prebuilt wheel.
Остался последний шаг — публикация. Весь процесс занимает 5 минут.
Зайдите на huggingface.co [14] и войдите в аккаунт
Нажмите на аватар → New Space
Заполните форму:
Owner: ваш username
Space name: например, qwen-assistant
License: выберите любую (MIT, Apache 2.0)
SDK: Gradio
Hardware: CPU basic (Free)
Нажмите Create Space
Есть два способа:
Через веб-интерфейс (проще):
На странице Space нажмите “Files” → “Add file” → “Upload files”
Загрузите README.md, app.py и requirements.txt
Нажмите Commit
Через Git (для тех, кто любит командную строку):
git clone https://huggingface.co/spaces/YOUR_USERNAME/qwen-assistant
cd qwen-assistant
# Скопируйте README.md, app.py и requirements.txt в эту папку
git add .
git commit -m "Initial commit"
git push
После загрузки файлов Space автоматически начнёт сборку. Это можно наблюдать во вкладке “Logs”.
Что происходит:
Building — установка зависимостей из requirements.txt (~1-2 минуты)
Running — запуск app.py
Загрузка модели из Hugging Face Hub (~2-3 минуты при первом запуске)
Инициализация Llama
Запуск Gradio-сервера
Общее время первого запуска: 3-5 минут. После этого Space готов к работе.
В логах вы увидите примерно такое:
Загрузка модели...
Модель загружена: /root/.cache/huggingface/hub/.../qwen2.5-3b-instruct-q4_k_m.gguf
Модель инициализирована
Running on local URL: http://127.0.0.1:7860
Когда появится строка “Running on local URL”, Space готов. Можете открыть его по публичной ссылке вида https://huggingface.co/spaces/YOUR_USERNAME/qwen-assistant.
|
Ошибка |
Причина |
Решение |
|---|---|---|
|
|
Несовместимая версия Python |
Добавьте |
|
|
Неправильный wheel-файл |
Проверьте URL в requirements.txt |
|
|
Модель слишком большая |
Используйте меньшую модель или квантизацию |
|
|
Опечатка в имени файла модели |
Проверьте |
|
Space “Building” бесконечно |
Ошибка в коде |
Смотрите логи во вкладке Logs |
|
Очень медленная генерация |
Первый запуск |
Подождите, модель кэшируется |
Важный нюанс: бесплатные Spaces “засыпают” после нескольких минут бездействия (обычно 5-15 минут без запросов). При следующем обращении происходит холодный старт — Space просыпается, и модель загружается заново.
Это занимает 2-3 минуты. Первый пользователь после простоя видит спиннер и ждёт.
Есть несколько способов борьбы с этим:
Keep-alive пинги. Простой скрипт, который каждые 5 минут делает запрос к вашему Space. Можно запустить на бесплатном сервере (GitHub Actions, бесплатный VPS) или даже локально.
Платный тир. CPU Upgrade стоит 22/месяц при 24/7), но Space не засыпает и работает постоянно.
Смириться. Для личного использования холодный старт — не проблема. Вы знаете, что нужно подождать пару минут.
Несколько вещей, о которых стоит помнить:
Модель не идеальна. Qwen2.5-3B — это маленькая модель. Она может ошибаться, галлюцинировать, давать неправильные ответы. Не используйте её для критически важных решений без проверки.
Нет фильтрации контента. В отличие от ChatGPT, у локальной модели нет встроенных guardrails. Она может генерировать нежелательный контент, если пользователь попросит. Для публичного сервиса стоит добавить фильтрацию.
Логи видны вам. Все запросы к вашему Space логируются. Если вы делаете публичный сервис, предупредите пользователей о сборе данных.
Диск не persistent. Всё, что Space записывает на диск (кроме кэша моделей), теряется при перезапуске. Не храните важные данные локально.
Поговорим о скорости. CPU — это не GPU, и чудес ждать не стоит.
|
Платформа |
CPU |
Скорость |
Короткий ответ (50 токенов) |
Средний ответ (200 токенов) |
|---|---|---|---|---|
|
HF Spaces Free |
2 vCPU |
3-7 токен/с |
8-17 сек |
30-70 сек |
|
MacBook M1/M2 |
8 cores |
12-18 токен/с |
3-5 сек |
12-18 сек |
|
Intel i7 (12th gen) |
12 cores |
8-12 токен/с |
5-7 сек |
18-25 сек |
|
AMD Ryzen 7 5800X |
8 cores |
10-14 токен/с |
4-5 сек |
15-20 сек |
Примечание: значения приблизительные и зависят от загрузки системы, температуры и других факторов.
На бесплатном тире HF Spaces (2 vCPU) Qwen2.5-3B-Q4_K_M генерирует примерно 3-7 токенов в секунду. Это значит:
Короткий ответ (50 токенов) — 8-17 секунд
Средний ответ (200 токенов) — 30-70 секунд
Длинный ответ (500 токенов) — 70-170 секунд
Для интерактивного чата это терпимо. Для production-нагрузки с множеством пользователей — нет.
Уменьшить max_tokens. Если вам не нужны длинные ответы, ограничьте их. max_tokens=256 вместо max_tokens=1024 сократит время ожидания в 4 раза.
Использовать streaming. Вместо ожидания полного ответа можно выводить токены по мере генерации. Пользователь видит, что что-то происходит, и не уходит. Для этого нужно немного изменить код:
def chat(message: str, history: list):
messages = [{"role": "system", "content": SYSTEM_PROMPT}]
# Gradio 6.x: извлекаем текст из structured content
for msg in history:
content = msg["content"]
if isinstance(content, list):
text = "".join(
block.get("text", "") for block in content
if block.get("type") == "text"
)
else:
text = content
messages.append({"role": msg["role"], "content": text})
messages.append({"role": "user", "content": message})
response = llm.create_chat_completion(
messages=messages,
stream=True, # Включаем streaming
)
partial_message = ""
for chunk in response:
delta = chunk["choices"][0]["delta"]
if "content" in delta:
partial_message += delta["content"]
yield partial_message # Возвращаем частичный ответ
И в Gradio-интерфейсе ничего менять не нужно — ChatInterface автоматически поддерживает генераторы.
Перейти на платный тир. CPU Upgrade ($0.03/час) даёт 8 vCPU и 32 GB RAM. Это увеличит скорость примерно вдвое и позволит использовать модели побольше.
Использовать GPU-тир. Если скорость критична, ZeroGPU на HF Spaces даёт ~30-50 токенов в секунду. PRO-подписчики получают бесплатную квоту GPU-времени, для остальных доступ ограничен.
Ниже приведён полный код проекта, готовый для копирования и использования.
---
title: Qwen Chat
emoji: 🤖
colorFrom: blue
colorTo: purple
sdk: gradio
sdk_version: 6.5.1
app_file: app.py
python_version: "3.10"
pinned: false
---
https://huggingface.co/Luigi/llama-cpp-python-wheels-hf-spaces-free-cpu/resolve/main/llama_cpp_python-0.3.22-cp310-cp310-linux_x86_64.whl
gradio>=6.0.0
huggingface-hub>=0.20.0
import gradio as gr
from llama_cpp import Llama
from huggingface_hub import hf_hub_download
import traceback
# =============================================================================
# КОНФИГУРАЦИЯ
# =============================================================================
MODEL_REPO = "Qwen/Qwen2.5-3B-Instruct-GGUF"
MODEL_FILE = "qwen2.5-3b-instruct-q4_k_m.gguf"
CONTEXT_SIZE = 4096
MAX_TOKENS = 1024
TEMPERATURE = 0.7
TOP_P = 0.9
REPEAT_PENALTY = 1.1
MAX_HISTORY = 10 # Максимум сообщений в истории
SYSTEM_PROMPT = """You are a helpful AI assistant. Respond in Russian
if the user writes in Russian. Be concise and to the point."""
# =============================================================================
# ЗАГРУЗКА МОДЕЛИ
# =============================================================================
try:
print("Загрузка модели...")
print("Это займёт 2-3 минуты при первом запуске...")
model_path = hf_hub_download(
repo_id=MODEL_REPO,
filename=MODEL_FILE,
)
print(f"[OK] Модель загружена: {model_path}")
print("Инициализация модели...")
llm = Llama(
model_path=model_path,
n_ctx=CONTEXT_SIZE,
n_threads=2,
verbose=False,
)
print("[OK] Модель готова к работе!")
except Exception as e:
print(f"[ERROR] Ошибка при загрузке модели: {e}")
traceback.print_exc()
raise
# =============================================================================
# ФУНКЦИЯ ЧАТА
# =============================================================================
def chat(message: str, history: list) -> str:
try:
messages = [{"role": "system", "content": SYSTEM_PROMPT}]
# Ограничиваем историю последними N сообщениями
recent_history = history[-MAX_HISTORY:] if len(history) > MAX_HISTORY else history
# Gradio 6.x: история в OpenAI-style формате
for msg in recent_history:
role = msg["role"]
content = msg["content"]
if isinstance(content, list):
text = "".join(
block.get("text", "") for block in content
if block.get("type") == "text"
)
else:
text = content
messages.append({"role": role, "content": text})
messages.append({"role": "user", "content": message})
response = llm.create_chat_completion(
messages=messages,
max_tokens=MAX_TOKENS,
temperature=TEMPERATURE,
top_p=TOP_P,
repeat_penalty=REPEAT_PENALTY,
stream=False,
)
return response["choices"][0]["message"]["content"]
except Exception as e:
print(f"[ERROR] Произошла ошибка: {str(e)}")
traceback.print_exc()
return "Извините, произошла ошибка. Попробуйте переформулировать вопрос."
# =============================================================================
# GRADIO ИНТЕРФЕЙС
# =============================================================================
demo = gr.ChatInterface(
fn=chat,
title="AI-ассистент на Qwen2.5-3B",
description="Бесплатный AI-ассистент, работающий на CPU. Поддерживает русский язык.",
examples=[
"Привет! Расскажи о себе.",
"Напиши короткое стихотворение о программировании.",
"Объясни, что такое машинное обучение, простыми словами.",
],
)
if __name__ == "__main__":
demo.launch()
Создайте папку проекта и поместите в неё все три файла (README.md, app.py, requirements.txt)
Для деплоя на HF Spaces: загрузите файлы в новый Space (SDK: Gradio, Hardware: CPU basic)
Для локального запуска: установите зависимости через pip install llama-cpp-python gradio huggingface-hub и выполните python app.py
Вот что получилось:
Модель: Qwen2.5-3B-Instruct (Q4_K_M квантизация)
Интерфейс: Gradio ChatInterface
Хостинг: Hugging Face Spaces (бесплатный CPU)
Языки: Русский, английский и ещё 27+
Код: ~70 строк Python
Весь проект состоит из трёх файлов и разворачивается за 15-20 минут. Никаких GPU, никаких платежей, никакой сложной инфраструктуры.
|
Параметр |
Значение |
|---|---|
|
Модель |
Qwen2.5-3B-Instruct-GGUF |
|
Квантизация |
Q4_K_M (~2.1 GB) |
|
Контекст |
4096 токенов |
|
Скорость |
~3-7 токенов/сек |
|
Стоимость |
Бесплатно |
|
Время деплоя |
~5 минут (первый запуск) |
Бесплатный CPU-тир идеален для:
Личных проектов и экспериментов
Демонстраций и прототипов
Обучения и изучения LLM
Небольших внутренних инструментов
Не подходит для:
Production с высокой нагрузкой
Приложений, где критична скорость отклика
Множества одновременных пользователей
Если хочется развить проект, вот несколько направлений:
RAG (Retrieval-Augmented Generation) — добавить поиск по вашим документам. Модель будет отвечать на вопросы, используя информацию из ваших файлов. Это превращает простого чат-бота в ассистента по документации.
Function calling — научить бота вызывать внешние API. Например, искать в интернете, проверять погоду, управлять умным домом. Qwen2.5 поддерживает function calling из коробки.
Qwen2.5-7B — перейти на бОльшую модель. 7B-версия умнее, квантизированная Q4_K_M занимает ~4.5 GB. Технически влезает в 16 GB, но для комфортной работы с длинным контекстом лучше иметь 32 GB — платный тир или свой сервер.
Кастомный системный промпт — настроить личность бота под вашу задачу. Можно сделать его экспертом в конкретной области, дать ему имя и характер.
Gradio Blocks — если ChatInterface слишком простой, можно использовать gr.Blocks для создания более сложного UI с дополнительными контролами.
Можно ли использовать в production?
Бесплатный CPU-тир не подходит для production с высокой нагрузкой. Основные ограничения: низкая скорость генерации (3-7 токенов/сек), засыпание Space после простоя, отсутствие гарантий доступности. Для production рекомендуется CPU Upgrade ($0.03/час за 8 vCPU, 32 GB RAM) или собственный сервер.
Как использовать другую модель?
Достаточно изменить две константы в начале файла:
MODEL_REPO — репозиторий на Hugging Face (например, "TheBloke/Llama-2-7B-Chat-GGUF")
MODEL_FILE — имя GGUF-файла из репозитория
Убедитесь, что модель влезает в 16 GB RAM (для Q4-квантизации это модели до ~7B параметров).
Почему Space засыпает и как с этим бороться?
Бесплатные Spaces засыпают после 5-15 минут бездействия для экономии ресурсов. Варианты решения:
Keep-alive пинги через GitHub Actions или cron-задачу
CPU Upgrade (22/мес при 24/7) — Space работает постоянно
Принять как данность для личных проектов
Можно ли запустить на Windows/Mac локально?
Да. Установка llama-cpp-python требует компиляции C++ кода, но для большинства платформ есть готовые wheels.
Вариант 1: CPU-версия (рекомендуется для начала)
pip install llama-cpp-python gradio huggingface-hub
На стандартных платформах (Windows x64, macOS, Linux x86_64) pip автоматически скачает prebuilt wheel.
Вариант 2: С GPU-ускорением
macOS (Metal): CMAKE_ARGS="-DLLAMA_METAL=on" pip install llama-cpp-python
Windows/Linux (CUDA): используйте wheels из jllllll/llama-cpp-python-cuBLAS-wheels [15]
Вариант 3: Сборка из исходников
Если prebuilt wheel недоступен, установите компилятор:
Windows: Visual Studio Build Tools
macOS: xcode-select --install
Linux: sudo apt install build-essential
Затем: pip install llama-cpp-python --no-binary llama-cpp-python.
Как добавить RAG (поиск по документам)?
Базовый RAG требует:
Библиотеку для эмбеддингов (например, sentence-transformers)
Векторную базу данных (например, chromadb или faiss)
Логику поиска релевантных фрагментов и добавления их в контекст
Это тема для отдельной статьи, но Qwen2.5 хорошо работает с RAG благодаря поддержке длинного контекста.
Сколько пользователей может обслуживать бесплатный тир?
Реалистично — 1-2 одновременных пользователя. Генерация ответа занимает 10-60 секунд, в это время другие запросы ждут в очереди. Для множества пользователей нужен платный тир или несколько Space с балансировкой.
Как увеличить скорость генерации?
Уменьшить max_tokens (256 вместо 1024)
Использовать более агрессивную квантизацию (Q3_K_M вместо Q4_K_M)
Перейти на платный CPU-тир (8 vCPU даёт ~2x ускорение)
Использовать GPU-тир (T4 даёт ~5-10x ускорение)
Включить streaming для лучшего UX (пользователь видит ответ по мере генерации)
Qwen2.5-3B-Instruct-GGUF [5] — модель на Hugging Face
llama-cpp-python wheels [16] — prebuilt wheels для HF Spaces
Gradio Documentation [17] — документация Gradio
Hugging Face Spaces [18] — документация по Spaces
llama.cpp [19] — исходники llama.cpp
Автор: Rummar
Источник [20]
Сайт-источник BrainTools: https://www.braintools.ru
Путь до страницы источника: https://www.braintools.ru/article/25260
URLs in this post:
[1] обучения: http://www.braintools.ru/article/5125
[2] Image: https://sourcecraft.dev/
[3] логикой: http://www.braintools.ru/article/7640
[4] памятью: http://www.braintools.ru/article/4140
[5] Qwen/Qwen2.5-3B-Instruct-GGUF: https://huggingface.co/Qwen/Qwen2.5-3B-Instruct-GGUF
[6] внимание: http://www.braintools.ru/article/7595
[7] ошибкой: http://www.braintools.ru/article/4192
[8] репозиторий Luigi с wheel-файлами: https://huggingface.co/Luigi/llama-cpp-python-wheels-hf-spaces-free-cpu/tree/main
[9] Полный код для копирования: #%D0%BF%D0%BE%D0%BB%D0%BD%D1%8B%D0%B9-%D0%BA%D0%BE%D0%B4-%D0%B4%D0%BB%D1%8F-%D0%BA%D0%BE%D0%BF%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F
[10] повторения: http://www.braintools.ru/article/4012
[11] поведение: http://www.braintools.ru/article/9372
[12] поведения: http://www.braintools.ru/article/5593
[13] репозитория: https://github.com/abetlen/llama-cpp-python/releases
[14] huggingface.co: https://huggingface.co
[15] jllllll/llama-cpp-python-cuBLAS-wheels: https://github.com/jllllll/llama-cpp-python-cuBLAS-wheels
[16] llama-cpp-python wheels: https://huggingface.co/Luigi/llama-cpp-python-wheels-hf-spaces-free-cpu
[17] Gradio Documentation: https://www.gradio.app/docs/
[18] Hugging Face Spaces: https://huggingface.co/docs/hub/spaces-overview
[19] llama.cpp: https://github.com/ggerganov/llama.cpp
[20] Источник: https://habr.com/ru/articles/993312/?utm_campaign=993312&utm_source=habrahabr&utm_medium=rss
Нажмите здесь для печати.