При плотной нагрузке счет за API легко превращается в постоянную и плохо прогнозируемую статью расходов, от которой уже сложно отмахнуться. В статье я покажу практичный компромисс: как развернуть собственную облачную LLM, которая укладывается в 16 ГБ видеопамяти, поддерживает инструменты и вызов функций, интегрируется с MCP-серверами и может использоваться как полноценный API-сервис для бэкенд-задач.

Привет, Хабр! На фоне ажиотажа вокруг нейросетей все чаще встает вполне приземленный вопрос — сколько стоит содержать собственную LLM.
Современные ИИ-агенты уровня Claude, ChatGPT и DeepSeek уже давно перестали быть «чатами для развлечения». Это сложные системы, которые перед тем как выдать ответ, тратят десятки тысяч токенов на внутренние рассуждения, вызывают внешние функции, взаимодействуют с MCP-серверами и даже работают напрямую с интерфейсом ОС.
В продакшене — особенно при использовании нескольких агентов, собственных инструментов и фоновых задач — потребление токенов растет лавинообразно. При плотной нагрузке счет за API легко превращается в постоянную и плохо прогнозируемую статью расходов, от которой уже сложно отмахнуться.
В статье я покажу практичный компромисс: как развернуть собственную облачную LLM, которая укладывается в 16 ГБ видеопамяти, поддерживает инструменты и вызов функций, интегрируется с MCP-серверами и может использоваться как полноценный API-сервис для бэкенд-задач.
Используйте навигацию, если не хотите читать целиком:Самый очевидный ответ — развернуть собственную нейросеть на сервере и использовать ее как облачный API.
Однако здесь нас ждет стоп-фактор. Большинство мощных open-source языковых моделей требуют десятки гигабайт видеопамяти. 24, 48, а иногда и 80 ГБ VRAM — а это уже совсем другой бюджет на инфраструктуру, который подходит далеко не всем. Вся архитектура будет максимально прагматичной и ориентированной на продакшен.
Из каких компонентов состоит решениеПрежде чем писать команды и поднимать сервер, нужно зафиксировать, что именно мы строим. Важно понимать: речь идет не о запуске «локального чата», а о сборке небольшой, но полноценной инфраструктуры.
В итоговом варианте решение представляет собой несколько логических компонентов. В основе лежит LLM-сервер, отдельный сервис, отвечающий исключительно за инференс модели: прием запросов, генерацию ответов, а также работу с инструментами и MCP.
MCP (Model Context Protocol) — открытый протокол, позволяющий подключать к агенту внешние сервисы как инструменты. Вместо того чтобы писать обертки для каждого API вручную, можно использовать готовые MCP-серверы.
Между моделью и внешним миром расположен инференс-движок — слой, отвечающий за производительность, управление видеопамятью и API. Именно на этом уровне используется vLLM, подробнее о нем чуть ниже.
Для корректного доступа к сервису извне применяется reverse proxy. Он отвечает за SSL, доменное имя и создает задел для будущего масштабирования.
Поверх этого располагается FastAPI-приложение — отдельный бэкенд-слой с прикладной логикой. Здесь сосредоточено управление входящими запросами, обработка вызовов инструментов, интеграция MCP-серверов, а также контроль доступа и ограничений.
Такое разделение позволяет воспринимать LLM как обычный бэкенд-сервис, а не как монолит, в который положили все подряд.
Какой стек будем использоватьВозьмем приземленный и знакомый большинству Python-разработчиков стек:
Linux-сервер с GPU;
инференс-движок для LLM, vLLM;
Nginx, FastAPI как основной бэкенд;
MCP-серверы и инструменты — в качестве внешних или встроенных компонентов.
Никаких специфичных ML-фреймворков или редких зависимостей — все легко поддерживается и масштабируется.
Почему именно vLLM, а не классический запуск через transformers?
Если вы когда-либо поднимали LLM локально через transformers, то знаете, что такой подход хорошо подходит для экспериментов, но плохо масштабируется в сервисном режиме.
Если к модели обратятся сразу несколько человек, видеопамять начнет тормозить и вам придется вручную прикручивать API и придумать, как не «уронить» сервер при высокой нагрузке.
vLLM создан как раз для таких задач. Он хорошо держит несколько одновременных запросов, а также API, совместимый с OpenAI-стилем. Он справляется со сложными функциями и позволяет засунуть серьезные модели даже в обычную видеокарту на 16 ГБ VRAM. Проще говоря, vLLM — это инференс-движок, заточенный под продакшен.
Подготовка инфраструктурыПереходим к практике. На этом этапе арендуем VPS с GPU и сразу привязываем к нему домен. Это позволит дальше не тратить время на настройку DNS.
Даже если вы никогда раньше не работали с VPS и доменами — ничего страшного. Повторяя шаги ниже, вы без проблем справитесь.
ДоменЧтобы наша система могла работать как полноценный «персональный ИИ-инстанс», нам необходимо открыть возможность отправки внешних запросов к нашему Qwen3.
При этом обращаться напрямую к IP-адресу с портом — не лучшая идея. Вместо этого мы будем использовать доменное имя с HTTPS. Без шифрования ваши промты и API-ключи будут лежать в сети в открытом виде, а современные браузеры и сервисы просто откажутся работать с «небезопасным» IP. Плюс, если сервер переедет, вам не придется переписывать конфиги во всех приложениях.
Шаги по регистрации домена:
Регистрируйте аккаунт в панели управления, если у вас его еще нет. Открывайте вкладку Продукты, далее Домены. Переходите в раздел регистрации доменных имен и нажимайте кнопку Зарегистрировать домен.

Проверьте доступность доменного имени, если имя свободно — нажимайте Оформить.

Заполните контактные данные администратора домена и завершите регистрацию. После этого доменное имя переходит в ваше распоряжение.

Далее переходите в раздел Доменные зоны и нажимайте Добавить зону.

Ожидайте, пока домен получит статус «Делегирован». Изменения вносятся в реестр за один рабочий час, но для полной работы DNS-серверов может потребоваться до 24 часов.

Этот статус означает, что мы можем полноценно управлять DNS-записями домена.
На этом этапе этих шагов более чем достаточно. К доменному имени мы еще вернемся позже — когда будем настраивать Nginx на VPS-сервере и привязывать домен к нашему vLLM-проекту, превращая его в полноценную точку входа для удаленных запросов.
VPS сервер с GPU 16 ГБВ рамках статьи я сознательно буду показывать запуск проекта на бюджетной конфигурации с GPU 16 ГБ. Этого более чем достаточно для демонстрации, тестирования и личного использования.
Если же вы планируете использовать модель в продакшене с высокой или средней нагрузкой, большим количеством одновременных запросов и длинным контекстом — в этом случае стоит сразу смотреть на более мощное железо. Но логика настройки при этом останется той же.
Сейчас нам нужно арендовать VPS-сервер с GPU, получить к нему доступ и подготовить его к дальнейшей настройке.
Я остановился на следующем варианте конфигурации облачного сервера:
процессор — четыре виртуальных ядра;
оперативная память — 32 ГБ;
накопитель — 100 ГБ SSD;
графический ускоритель — одна видеокарта NVIDIA Tesla T4 с 16 ГБ видеопамяти.
Это сбалансированная и доступная конфигурация, которая отлично подходит для запуска Qwen3-14B в квантованном виде и работы через vLLM.
Как по шагам создать свой VPSПереходим в в панель управления, открываем раздел Инфраструктура → Облачные серверы.

Кликаем на Создать сервер.

В качестве операционной системы выбираем Ubuntu 24.04. Она лучше всего адаптирована под работу с GPU, драйверами NVIDIA и современным ML-стеком (и идет с установленными драйверами на видеокарту).

Выбираем конфигурацию. Я возьму для тестов GPU с Tesla T4 (16 ГБ).

Добавим к стандартным 20 ГБ SSD диска еще 80 ГБ, чтобы хватило места для модели, кэша Hugging Face, а также для тяжелых зависимостей vLLM в виртуальном окружении.

Добавим SSH-ключ для входа на сервер без ввода пароля.
Создание SSH-ключа — инструкция для всех ОСИнструкция для Windows:
Для современных Windows 10/11 лучше всего использовать встроенный клиент:
# Встроенный OpenSSH (Win 10/11)
ssh-keygen -t ed25519 -C "ваш@email.com"
# Или через PowerShell
New-Item -ItemType Directory -Force ~/.ssh
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 -N ""Альтернатива: PuTTYgen (скачать с putty.org) → Generate → Save public/private key.
Инструкция для macOS / Linux:
Здесь все стандартно, используем терминал:
# Самый безопасный (рекомендую)
ssh-keygen -t ed25519 -C "ваш@email.com"
# Или RSA (совместимость со старыми системами)
ssh-keygen -t rsa -b 4096 -C "ваш@email.com"Где лежат ключи:
публичный (его мы копируем в панель облака): ~/.ssh/id_ed25519.pub;
приватный (это ваш пароль, его нельзя никому показывать): ~/.ssh/id_ed25519.
Как быстро скопировать ключ в буфер обмена:
# macOS
pbcopy < ~/.ssh/id_ed25519.pub
# Linux (xclip)
xclip -sel clip < ~/.ssh/id_ed25519.pub
# Windows PowerShell
Get-Content ~/.ssh/id_ed25519.pub | Set-ClipboardГотово. Теперь вставляем публичный ключ в панель управления облака.


На этом этапе сервер готов к работе.
Связываем доменное имя с VPS серверомЕсли на данном этапе у вас есть доменное имя и активирована доменная зона, то процесс связки доменного имени с сервером займет пару минут.
Переходим в Доменные зоны.

Проваливаемся внутрь записи и привязываем публичный IP-адрес сервера к домену, как указано ниже.

Оставляем имя группы пустым, если хотите, чтоб вызов нейросети шел по домену второго уровня.
Настройка VPS-сервераПеред запуском LLM-модели необходимо подготовить VPS-сервер: установить базовые зависимости, проверить драйверы NVIDIA и поставить окружение для запуска vLLM. Приведем сервер в рабочее состояние.
Подключение к серверуВвод пароля не требуется, так как мы на предыдущем этапе уже связали свою локальную машину с VPS сервером через публичный ключ.
Обновление системы и установка базовых зависимостейДля начала обновим пакеты и установим необходимый минимум:
sudo apt update && sudo apt install -y \
nginx \
certbot \
python3 \
python3-pip \
python3-venv \
python3-certbot-nginx
Что здесь важно:
Python 3 + venv — основа для запуска vLLM;
Nginx и certbot понадобятся позже для HTTPS и проксирования.
Мы закладываем инфраструктуру сразу, без необходимости возвращаться к этому этапу.
Драйверы NVIDIAЕсли вы выбирали выделенный сервер с Ubuntu 24 в панели управления Selectel, то необходимости в отдельной установке драйверов на видеокарту у вас не будет.
Убедимся, что драйверы установлены, командой: nvidia-smi.
Если команда выводит информацию о Tesla T4 — значит, драйвер установлен и видеокарта готова к работе.

Дополнительно установим CUDA Toolkit из репозитория Ubuntu/Debian. Нам это нужно для компиляции CUDA-кода, работы с GPU и выполнения операций на видеокарте.
apt install -y nvidia-cuda-toolkit
Облачная инфраструктура для ваших проектов
Виртуальные машины в Москве, Санкт-Петербурге и Новосибирске с оплатой по потреблению.
Создадим рабочую директорию под наш проект и разместим ее в домашнем каталоге:
cd ../home
mkdir vllm_qwen3
cd vllm_qwen3Дальше создаем виртуальное окружение Python и активируем его:
python3 -m venv .venv
source .venv/bin/activateИспользование виртуального окружения позволяет:
изолировать зависимости проекта;
избежать конфликтов с системными пакетами;
упростить дальнейшее сопровождение сервиса.
Устанавливаем инференс-движок vLLM: pip install vllm.
Запуск Qwen3 через vLLM на Tesla T4 Мы запускаем Qwen3-14B-AWQ на доступной Tesla T4 (16 ГБ VRAM) с 4-битной квантовкой AWQ и аккуратно подобранными лимитами памяти и контекста.
Цель — получить продакшн-совместимый OpenAI-API сервер и не прибегнуть к производительным A100/H100.
Генерация API-ключаДля защиты API потребуется токен, получим его командой: openssl rand -hex 32.
Токен будет выглядеть примерно так: c8a9f7d2e4b1a6c3f9d8e7b2a4c6f1d3e5b7a9c2f4d6e8b1a3c5f7d9e2b4a6c8
Этот ключ потребуется передавать в заголовке:
Authorization: Bearer ВАШ_КЛЮЧ
Команда запускаvllm serve Qwen/Qwen3-14B-AWQ \
--host 0.0.0.0 \
--port 8002 \
--gpu-memory-utilization 0.96 \
--max-model-len 8000 \
--max-num-seqs 1 \
--dtype half \
--enforce-eager \
--trust-remote-code \
--enable-prefix-caching \
--enable-chunked-prefill \
--quantization awq \
--served-model-name qwen3-14b \
--api-key "ВАШ_КЛЮЧ" \
--disable-log-requests \
--enable-auto-tool-choice \
--tool-call-parser hermes \
--chat-template-content-format string
Разбор параметров — что и за что отвечаетМодель Qwen/Qwen3-14B-AWQКак я уже говорил, используется уже квантованная версия модели в формате AWQ. На T4 это позволяет:
уместить 14B модель в 16 ГБ VRAM;
сохранить приемлемое качество;
получить хорошую скорость инференса.
--host 0.0.0.0 — сервис доступен извне (не только localhost);
--port 8002 — порт OpenAI-совместимого API.
--gpu-memory-utilization 0.96
vLLM может использовать до 96% VRAM. Позволяет максимально эффективно задействовать T4, не доводя до OOM.
--max-model-len 8000
Максимальный контекст — 8 000 токенов.
На T4 это практически верхняя безопасная граница при 4-битной модели. Больше — риск нехватки памяти при длинных диалогах.
--max-num-seqs 1
Одновременно обрабатывается один активный запрос. Это стабилизирует потребление памяти, исключает резкие скачки VRAM и подходит для личного сервера или low-load продакшена.
Если планируется многопользовательская нагрузка — параметр, как и мощность железа, нужно будет пересматривать.
--dtype half
Используется FP16 для вычислений (где это применимо). Оптимальный баланс скорости и стабильности для T4.
--enforce-eager
Принудительный eager-режим. На T4 это часто работает стабильнее, чем полностью компилируемый граф.
Оптимизации скорости--enable-prefix-caching
Кэширует общий префикс запроса и сильно ускоряет диалоги, повторяющиеся системные промты, агентные сценарии.
--enable-chunked-prefill
Разбивает длинный ввод на части при чтении запроса. Позволяет избежать пикового потребления памяти при больших промтах.
Безопасность и интеграция--api-key "..."
Ограничивает доступ к серверу. Без ключа запросы будут отклоняться.
--disable-log-requests
Не логирует тексты запросов в stdout. Важно для приватности и продакшн-развертываний.
Инструменты (Tool Calling)--enable-auto-tool-choice
Позволяет модели автоматически выбирать инструмент.
--tool-call-parser hermes
Используется Hermes-парсер для корректной обработки tool-calls.
Это важно, если планируется:
LangChain;
агентные сценарии;
вызов внешних функций.
--trust-remote-code
Разрешает загрузку кастомного кода модели с HuggingFace. Необходим для корректной работы Qwen.
--served-model-name qwen3-14b
Имя, которое будет отображаться в API. Именно его будут видеть клиенты OpenAI-формата.
--chat-template-content-format string
Формат передачи контента в шаблон чата. Обеспечивает совместимость с OpenAI-стилем сообщений.
Что происходит после запускаСкачивание модели происходит автоматически (8–9 ГБ, один раз), после чего ее загрузка в VRAM занимает около 20–40 секунд. Первый запрос может выполняться до 1–2 минут из-за нормального процесса компиляции графа. Однако все последующие ответы будут приходить практически мгновенно.
Не пугайтесь долгого первого старта, это стандартное поведение.

Что мы получили:
14B модель;
4-битная квантовка;
8 000 токенов контекста;
OpenAI-совместимый API;
Полная работа на одной Tesla T4.
Без A100, без 80 ГБ VRAM и без космического бюджета.
Теперь модель доступна по адресу:
http://SERVER_IP:8002
Быстрый тест APIКогда сервер поднялся, проверим, что все работает. Для этого необходимо открыть новый терминал и там выполнить вход на VPS сервер.
Если мы введем команду nvidia-smi, то увидим, что наша модель заняла практически весь размер видеопамяти:

Выполним простой запрос через curl:
curl http://localhost:8002/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer z64bf3f7f93601wZez6a621381axqfagzaaa0fd79c589aX2eaaadsr1a0cdd0491a2ea" \
-d '{
"model": "qwen3-14b",
"messages": [
{
"role": "user",
"content": "Привет! Кто тебя создал такого?"
}
],
"max_tokens": 256
}'
Сразу видим, что модель из коробки поддерживает режим Thinking. То есть кроме обычного ответа и доп данных, мы можем видеть процесс размышления модели. Бывает очень полезно в некоторых сценариях.
Если вы не хотите тратить время на получение размышлений, то можно легко эти самые размышления отключить.
Пример запроса:
curl http://localhost:8002/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer z64bf3f7f93601wZez6a621381axqfagzaaa0fd79c589aX2eaaadsr1a0cdd0491a2ea" \
-d '{
"model": "qwen3-14b",
"messages": [
{
"role": "user",
"content": "Привет! Кто ты?"
}
],
"max_tokens": 256,
"chat_template_kwargs": {
"enable_thinking": false
}
}'
Ответ получили значительно быстрее.
Запуск через systemdДля постоянной работы сервиса запускать его вручную — плохая идея. Поэтому сразу оформим все через systemd.
Создаем сервисный файл командой: sudo nano /etc/systemd/system/vllm-qwen3.service.
Пример конфигурации:
[Unit]
Description=vLLM Qwen3-14B Server
After=network.target
StartLimitIntervalSec=0
[Service]
Type=simple
User=root
WorkingDirectory=/home/vllm_qwen3
Environment="PATH=/home/vllm_qwen3/.venv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
Environment="CUDA_VISIBLE_DEVICES=0"
ExecStart=/home/vllm_qwen3/.venv/bin/python -m vllm.entrypoints.openai.api_server \
--model Qwen/Qwen3-14B-AWQ \
--host 0.0.0.0 \
--port 8002 \
--gpu-memory-utilization 0.96 \
--max-model-len 8000 \
--max-num-seqs 1 \
--dtype half \
--enforce-eager \
--trust-remote-code \
--enable-prefix-caching \
--enable-chunked-prefill \
--quantization awq \
--served-model-name qwen3-14b \
--api-key ВАШ_ТОКЕН\
--disable-log-requests \
--enable-auto-tool-choice \
--tool-call-parser hermes \
--chat-template-content-format string
Restart=always
RestartSec=10
StandardOutput=journal
StandardError=journal
SyslogIdentifier=vllm-qwen3
[Install]
WantedBy=multi-user.targetАктивируем сервис:# Перезагрузить systemd
sudo systemctl daemon-reload
# Включить автозапуск
sudo systemctl enable vllm-qwen3.service
# Запустить сервис
sudo systemctl start vllm-qwen3.service
# Проверить статус
sudo systemctl status vllm-qwen3.service
# Посмотреть логи
sudo journalctl -u vllm-qwen3.service -f
Теперь LLM будет автоматически подниматься вместе с сервером и переживать перезапуски.
Настраиваем Nginx и HTTPSПревратим наш локальный LLM-сервис в настоящую облачную нейросеть, к которой можно подключаться с любого места — точно так же, как к ChatGPT или DeepSeek.
На данный момент у нас уже должно быть доменное имя, к которому привязана А-запись на домен второго уровня с привязкой к IP-адресу нашего сервера.
Конфигурация NginxСоздадим конфигурационный файл:
nano /etc/nginx/sites-available/qwen3-vllm.ruСодержимое:
server {
listen 80;
server_name ВАШ ДОМЕН (в моем случае qwen3-vllm.ru);
# Важно для долгих ответов и стриминга
proxy_read_timeout 600s;
proxy_connect_timeout 600s;
proxy_send_timeout 600s;
# Для больших промтов
client_max_body_size 50M;
location / {
proxy_pass http://127.0.0.1:8002;
proxy_http_version 1.1;
# WebSocket для стриминга
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
# Отключаем буферизацию для SSE
proxy_buffering off;
proxy_cache off;
}
}Активация конфига и получение SSL сертификата:
# Активируем сайт
ln -s /etc/nginx/sites-available/qwen3-vllm.ru /etc/nginx/sites-enabled/
rm -f /etc/nginx/sites-enabled/default
# Проверяем конфиг
nginx -t
# Перезапускаем Nginx
systemctl restart nginx
Подключаем HTTPSУстанавливаем certbot (если еще не установлен):
sudo apt install -y certbot python3-certbot-nginx
Получаем SSL-сертификат
certbot --nginx -d ВАШ ДОМЕН --non-interactive --agree-tos --email your-email@example.com
Например:
certbot --nginx -d qwen3-vllm.ru --non-interactive --agree-tos --email ivanov_invan@gmail.com
Certbot автоматически включит HTTPS, настроит редирект и добавит автообновление сертификата.

Проверяем, что все работает
Открываем в браузере https://ВАШ_ДОМЕН/docs. В моем случае это: https://qwen3-vllm.ru/docs.

Так как vLLM использует FastAPI под капотом, вы сразу увидите Swagger-документацию. Это отличный знак — значит сервис полностью доступен извне.
На этом этапе у нас есть полностью рабочая облачная LLM с HTTPS-доступом и API, совместимым с OpenAI. Прежде чем двигаться дальше и добавлять прикладную бизнес-логику, имеет смысл проверить, как эта модель ведет себя в реальных сценариях.

ML Impact — про ML и AI без хайпа
Все кругом говорят про ML, но многие ли понимают его настоящую пользу для бизнеса? Мы запустили ресурс, который поможет во всем разобраться.
Все примеры ниже выполняются на локальном компьютере. GPU, Docker и сложная инфраструктура не требуются — мы работаем с LLM как с обычным внешним API.
Подготовка локального окруженияСоздадим отдельное виртуальное окружение для клиентского кода на своей локальной машине:
mkdir llm-client
cd llm-client
python3 -m venv .venv
source .venv/bin/activateУстановим минимальный набор зависимостей:
pip install langchain langchain-openai langgraph langchain-mcp-adapters pydantic-settings httpx
Или, если вы клонировали репозиторий: pip install -r requirements.txt.
КонфигурацияДалее начинается достаточно много примеров кода на Python. Для того, чтобы было проще ориентироваться по тексту далее, можете клонировать репозиторий, в котором находится полный исходник.
Для подключения к LLM нам нужны три параметра: токен, адрес сервера и название модели. Хранить их в коде — плохая практика, поэтому вынесем все в .env-файл:
CLIENT_TOKEN=ВАШ_ТОКЕН
CLIENT_BASE_URL=https://qwen3-vllm.ru
LLM_MODEL_NAME=qwen3-14bА считывать будем через pydantic-settings — это дает валидацию и типизацию из коробки: from pydantic_settings import BaseSettings, SettingsConfigDict.
class Settings(BaseSettings):
model_config = SettingsConfigDict(
env_file=".env",
env_file_encoding="utf-8",
case_sensitive=False,
)
client_token: str
client_base_url: str
llm_model_name: str
settings = Settings()Если забыть указать любую из переменных — приложение падает при старте с понятной ошибкой валидации, а не где-то посреди работы с None вместо токена.
Пример-1: чат-агентНачнем с минимального варианта — агент без инструментов, просто разговор с моделью. Это позволяет убедиться, что подключение работает, модель отвечает адекватно, а задержка приемлемая.
import asyncio
from langchain_openai import ChatOpenAI
from langchain.agents import create_agent
from config import settings
def create_model(
temperature: float = 0.7,
max_tokens: int = 1024,
enable_thinking: bool = False,
) -> ChatOpenAI:
base_url = settings.client_base_url.rstrip("/")
extra_body = None
if not enable_thinking:
extra_body = {
"chat_template_kwargs": {"enable_thinking": False}
}
return ChatOpenAI(
model=settings.llm_model_name,
api_key=settings.client_token,
base_url=f"{base_url}/v1",
temperature=temperature,
max_completion_tokens=max_tokens,
extra_body=extra_body,
)
async def main():
model = create_model()
agent = create_agent(
model=model,
tools=[],
system_prompt="Ты полезный ассистент. Отвечай кратко и по делу на русском языке.",
)
print("Простой агент запущен. Введите 'exit' для выхода.\n")
while True:
user_input = input("Вы: ")
if user_input.strip().lower() in ("exit", "quit", "выход"):
break
result = await agent.ainvoke(
{"messages": [{"role": "user", "content": user_input}]}
)
messages = result.get("messages", [])
for msg in reversed(messages):
if msg.type == "ai" and msg.content:
print(f"\nАссистент: {msg.content}\n")
break
if name == "__main__":
asyncio.run(main())Ключевой момент — ChatOpenAI из LangChain работает с любым OpenAI-совместимым API. Мы просто подставляем base_url нашего vLLM-сервера, и все подключение готово. Никаких специальных клиентов или SDK не нужно.
Параметр extra_body с enable_thinking: False отключает «режим размышления» у моделей, которые его поддерживают (например, QwQ). Для простого чата он не нужен, а ответы приходят быстрее.
Запускаем через команду: python -m example.simple_agent.
Пример-2: агент с инструментамиПростой чат — это хорошо, но настоящая сила агентов в том, что они могут использовать инструменты. Модель сама решает, когда и какой инструмент вызвать, на основе запроса пользователя.
Определим несколько инструментов через декоратор @tool:
from langchain_core.tools import tool
import httpx
from datetime import datetime, timezone, timedelta
@tool
def get_current_time() -> str:
"""Возвращает текущую дату и время по Москве (UTC+3)."""
moscow_tz = timezone(timedelta(hours=3))
now = datetime.now(moscow_tz)
return now.strftime("%d.%m.%Y %H:%M:%S (МСК)")
@tool
async def get_random_joke() -> str:
"""Возвращает случайный анекдот/шутку на английском языке."""
async with httpx.AsyncClient(timeout=10) as client:
resp = await client.get("https://official-joke-api.appspot.com/random_joke")
resp.raise_for_status()
data = resp.json()
return f"{data['setup']}\n— {data['punchline']}"
@tool
async def get_random_quote() -> str:
"""Возвращает случайную вдохновляющую цитату."""
async with httpx.AsyncClient(timeout=10) as client:
resp = await client.get("https://zenquotes.io/api/random")
resp.raise_for_status()
data = resp.json()[0]
return f'«{data["q"]}»\n— {data["a"]}'
@tool
async def get_random_fact() -> str:
"""Возвращает случайный интересный факт."""
async with httpx.AsyncClient(timeout=10) as client:
resp = await client.get(
"https://uselessfacts.jsph.pl/api/v2/facts/random?language=en"
)
resp.raise_for_status()
data = resp.json()
return data["text"]Обратите внимание: docstring каждого инструмента — это не просто документация для разработчика. Именно по этому описанию модель понимает, что делает инструмент и когда его стоит вызвать. Чем точнее описание, тем лучше модель выбирает нужный инструмент.
Теперь передаем инструменты агенту:
async def main():
model = create_model()
tools = [get_current_time, get_random_joke, get_random_quote, get_random_fact]
agent = create_agent(
model=model,
tools=tools,
system_prompt=(
"Ты полезный ассистент с доступом к инструментам:\n"
"- get_current_time — узнать текущее московское время\n"
"- get_random_joke — получить случайную шутку\n"
"- get_random_quote — получить случайную цитату\n"
"- get_random_fact — получить случайный интересный факт\n\n"
"Используй инструменты когда это уместно. "
"Данные от API приходят на английском — переводи их на русский в ответе."
),
)
tool_names = [t.name for t in tools]
print(f"Агент с инструментами запущен: {', '.join(tool_names)}")
print("Введите 'exit' для выхода.\n")
while True:
user_input = input("Вы: ")
if user_input.strip().lower() in ("exit", "quit", "выход"):
break
result = await agent.ainvoke(
{"messages": [{"role": "user", "content": user_input}]}
)
messages = result.get("messages", [])
for msg in messages:
if msg.type == "ai" and hasattr(msg, "tool_calls") and msg.tool_calls:
for tc in msg.tool_calls:
print(f" 🔧 Вызов: {tc['name']}({tc['args']})")
if msg.type == "tool":
print(f" 📎 Результат: {msg.content[:200]}")
for msg in reversed(messages):
if msg.type == "ai" and msg.content and not msg.tool_calls:
print(f"\nАссистент: {msg.content}\n")
breakЛогика процесса устроена так: LangChain через LangGraph строит цикл, «модель → инструмент → модель». Когда пользователь спрашивает «Который час?», модель не пытается угадать время — она возвращает вызов get_current_time(). LangGraph выполняет функцию, передает результат обратно модели, и та формирует финальный ответ.
Запуск: python -m example.agent_with_tools.
Попробуйте спросить: «Расскажи шутку и интересный факт» — модель вызовет оба инструмента и скомбинирует результаты в один ответ.
Пример-3: агент с MCP-серверамиВ этом примере мы подключаем два MCP-сервера:
fetch — загрузка и парсинг веб-страниц по URL;
filesystem — чтение, запись и навигация по файловой системе.
И комбинируем их с нашими кастомными инструментами из предыдущего примера.
from langchain_mcp_adapters.client import MultiServerMCPClient
MCP_SERVERS = {
"fetch": {
"command": "uvx",
"args": ["mcp-server-fetch"],
"transport": "stdio",
},
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/home/user"],
"transport": "stdio",
},
}MCP-серверы запускаются как дочерние процессы и общаются с клиентом по stdio. Библиотека langchain-mcp-adapters автоматически превращает все доступные операции MCP-сервера в LangChain-инструменты:
async def main():
mcp_client = MultiServerMCPClient(MCP_SERVERS)
mcp_tools = await mcp_client.get_tools()
custom_tools = [get_current_time, get_random_joke, get_random_quote, get_random_fact]
all_tools = mcp_tools + custom_tools
model = create_model()
agent = create_agent(
model=model,
tools=all_tools,
system_prompt=(
"Ты ассистент с доступом к инструментам.\n\n"
"MCP инструменты:\n"
"- fetch — загрузка и чтение веб-страниц по URL\n"
"- filesystem — чтение, запись, поиск файлов и навигация по каталогам\n\n"
"Кастомные инструменты:\n"
"- get_current_time — текущее московское время\n"
"- get_random_joke — случайная шутка\n"
"- get_random_quote — случайная цитата\n"
"- get_random_fact — случайный интересный факт\n\n"
"Отвечай на русском языке. Данные от API на английском — переводи."
),
)
…Запуск командой: python -m example.agent_with_mcp.
Теперь агент может, например, прочитать веб-страницу и пересказать ее содержание, или найти файл на диске и показать его содержимое — все в рамках одного диалога.
Попробуем с запросом: «прочитай эту статью https://ru.wikipedia.org/wiki/Qwen и сделай ее саммари с основными тезисами в файл summary.md».

ЗаключениеМы убедились, что LLM доступна по API, корректно отвечает на вопросы, умеет вызывать инструменты и работать с внешними сервисами через MCP. Все это — с локального компьютера, GPU и без сложной настройки.
Следующий логичный шаг — обернуть эту логику в полноценный бэкенд на FastAPI, чтобы агент стал доступен не только из терминала, но и через HTTP-эндпоинты для фронтенда или других сервисов, чем мы и займемся в следующей части.
Поделитесь в комментариях: используете ли вы квантованные модели в продакшене и, если да, какое семейство моделей (Qwen, Llama, Mistral) лучше всего показало себя в ваших задачах?
| # | Наименование новости | Тональность | Информативность | Дата публикации |
|---|---|---|---|---|
| 1 | Запускаем AI-ассистента на бесплатном CPU: Qwen2.5 + Gradio + Hugging Face Spaces | 0 | 17.1 | 07-02-2026 |
| 2 | MCP vs Thin MCP: где AI агенты теряют скорость | 0 | 9.91 | 03-04-2026 |
| 3 | vLLM vs LMDeploy vs Triton: обзор бэкендов для инференса LLM | 0 | 7 | 18-07-2026 |
| 4 | Как заставить LLM считать точно: генерация кода вместо генерации ответов | 0 | 11.55 | 28-03-2026 |
| 5 | Large-v3 на Ryzen 5500U: как я оцифровал архив диктофонных записей без GPU и облаков | 0 | 12.15 | 26-02-2026 |
| 6 | Нанимаем ChatGPT на работу или автоматизация бизнес-процессов | 0 | 9.63 | 19-02-2026 |
| 7 | Создание MCP‑серверов на FastMCP: 7 ошибок, которых стоит избегать | 0 | 10.33 | 15-05-2026 |
| 8 | Как я научил Claude заказывать продукты в Яндекс Лавке (и что для этого пришлось отреверсить) | 0 | 10.75 | 28-07-2026 |
| 9 | Как мы заставили vLLM «лениться» под нагрузкой и спасли Time-to-First-Token | 0 | 10.92 | 26-04-2026 |
| 10 | В чём реальная проблема ЛЛМ | -5 | 7 | 03-07-2026 |