MAATRIX / Блог / Open WebUI медленно отвечает: причины и решение

Open WebUI медленно отвечает: причины и решение

Open WebUI медленно отвечает: причины и решение

MAATRIX

Вы отправляете «Привет», курсор мигает секунд десять, текст ползёт по слову, а после последней точки интерфейс ещё не отпускает. Обидно то, что Open WebUI тормозит обычно не там, где на него думают: заметная часть времени уходит на фоновые вызовы модели, о которых пользователь не знает. Ниже — как разложить эти секунды и какие из них вернуть настройками.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →

Разложите задержку на четыре куска — иначе почините не то

«Медленно» — не диагноз. У связки Open WebUI + Ollama четыре места, где теряется время: загрузка модели в память (load_duration), обработка переписки (prompt_eval_duration), генерация (eval_duration) и хвост после ответа — служебные запросы самого Open WebUI. Первые три числа Ollama отдаёт сама:

curl -s http://127.0.0.1:11434/api/chat -d '{"model":"qwen2.5:7b","stream":false,
  "messages":[{"role":"user","content":"Перечисли три планеты"}]}' | python3 -c '
import sys, json; d = json.load(sys.stdin)
for k in ("load_duration","prompt_eval_duration","eval_duration","total_duration"):
    print(k.ljust(22), round(d[k] / 1e9, 2), "c")
print("tok/s", round(d["eval_count"] / (d["eval_duration"] / 1e9), 1))
'

Замер на стенде 4 vCPU без GPU, 8 ГБ RAM, Ubuntu 24.04, qwen2.5:7b-instruct-q4_K_M:

load_duration          6.41 c
prompt_eval_duration   3.24 c
eval_duration         22.13 c
total_duration        31.79 c
tok/s 5.6

Пользователь жаловался на «сорок секунд». Недостающие восемь-девять Ollama не показывает: это отдельные запросы, которые Open WebUI шлёт сам после того, как ответ дописан.

Пауза перед первым словом: модель выгрузилась из памяти

Ollama держит модель в RAM пять минут после последнего запроса, потом её освобождает. Отошли на обед — следующий вопрос упирается в повторное чтение гигабайт весов с диска. Проверка одной командой:

$ ollama ps
NAME              ID              SIZE      PROCESSOR    UNTIL
qwen2.5:7b        845dbda0ea48    6.2 GB    100% CPU     4 minutes from now

Пустой вывод — модели в памяти нет, ваши 5–7 секунд ушли на это. Правим окружение через sudo systemctl edit ollama.service:

[Service]
Environment="OLLAMA_KEEP_ALIVE=24h"
Environment="OLLAMA_NUM_PARALLEL=1"

Дальше sudo systemctl daemon-reload && sudo systemctl restart ollama; значение -1 держит модель вечно. Прогреть её после рестарта — пустым промптом:

curl -s http://127.0.0.1:11434/api/generate -d '{"model":"qwen2.5:7b","keep_alive":-1}'

OLLAMA_NUM_PARALLEL здесь не случайно: свежие версии Ollama сами решают, сколько слотов открыть, и при достаточной памяти берут четыре. Каждый слот получает свою копию KV-кэша — при контексте 8192 токена резервируется не 8192, а 32768. На 8 ГБ это разница между «модель влезла» и «модель уехала в своп».

Честная оговорка: 24h навсегда занимает 6–7 ГБ под 7B-модель. Живёт на машине что-то ещё — вы перенесли проблему на соседа: на 8 ГБ компромисс 1h.

Развернуть за пару минут

Готовый образ на VPS MAATRIX: NVMe, AMD EPYC, root-доступ. Локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Развернуть Open WebUI

Хвост после ответа: Open WebUI дёргает модель ещё три раза

Самая частая причина, о которой не пишут. После каждого сообщения Open WebUI шлёт модели служебные запросы: заголовок чата, теги, варианты продолжения, а при включённой базе знаний — переписанный поисковый. На GPU незаметно, на CPU каждый вызов — ещё один полный проход модели. В логах они начинаются характерно:

docker logs --tail 200 open-webui 2>&1 | grep -c "### Task:"

На одном сообщении мы поймали четыре обращения к модели вместо одного. Замер от последней точки ответа до момента, когда индикатор погас: было 11,4 с, стало 1,2 с. Выключается в Admin Panel → Settings → Interface или переменными:

ENABLE_TITLE_GENERATION=False
ENABLE_TAGS_GENERATION=False
ENABLE_FOLLOW_UP_GENERATION=False
ENABLE_AUTOCOMPLETE_GENERATION=False
ENABLE_RETRIEVAL_QUERY_GENERATION=False

Особенно вреден ENABLE_AUTOCOMPLETE_GENERATION: автодополнение стучится к модели, пока вы набираете текст, — сервер занят подсказкой ровно в момент, когда вы жмёте Enter.

Выключать всё подряд не обязательно: заголовки чатов полезны, просто их не должна писать семимиллиардная модель. В том же разделе есть пункт Task Model — поставьте туда llama3.2:1b. На стенде она даёт около 34 tok/s против 5,6 у 7B: заголовок пишется за полсекунды вместо шести. Для внешних провайдеров то же делает TASK_MODEL_EXTERNAL.

Ловушка, на которую наступают все: правка переменной может не примениться — при первом запуске часть настроек копируется в таблицу config внутри базы, и приоритет у неё. Меняйте в админке либо ставьте ENABLE_PERSISTENT_CONFIG=False; подробнее — в разборе частых ошибок.

Чем длиннее переписка, тем медленнее ответ

Классическая жалоба: «утром летало, к вечеру невыносимо, а я ничего не менял». Менялась длина чата: модель не помнит предыдущие реплики, поэтому Open WebUI при каждом сообщении отправляет всю историю целиком, и сервер перечитывает её заново.

Арифметика со стенда: промпт обрабатывается примерно на 48 tok/s. Пустой чат — 155 токенов, 3,2 секунды. Сороковое сообщение в том же чате — 5800 токенов, то есть две минуты только на чтение переписки. Сравните prompt_eval_count в новом чате и в проблемном: разница в десятки раз — диагноз поставлен.

  • Не тащить один чат месяцами. Новая тема — новый чат: самое дешёвое решение и самое игнорируемое.
  • Проверить размер контекста. По умолчанию Ollama даёт 4096 токенов (OLLAMA_CONTEXT_LENGTH). Когда переписка перерастает окно, начало обрезается, кэш обработанного промпта перестаёт переиспользоваться и каждое сообщение считается с нуля — тот самый момент, когда чат резко проваливается по скорости.
  • Не задирать контекст вслепую. Поле Context Length лежит в Settings → General → Advanced Parameters, и 32768 «чтобы наверняка» — плохая идея: KV-кэш займёт лишние гигабайты, а prompt eval станет дольше. Для CPU-сервера 8192 — разумный потолок. Сжатие кэша (OLLAMA_FLASH_ATTENTION=1 плюс OLLAMA_KV_CACHE_TYPE=q8_0) помогает на видеокарте, на чистом CPU выигрыш околонулевой.

Если и после правок генерация не радует, вы упёрлись не в Open WebUI, а в железо и квантование — это отдельный разбор, почему Ollama медленно генерирует токены.

Тормозит сам интерфейс: RAG, эмбеддинги и разбухшая база

Бывает наоборот: генерация быстрая, а интерфейс вялый — чаты открываются с задержкой, список моделей думает. Виноват бэкенд.

Первое — память. Контейнер в простое держит 600–900 МБ, но при обращении к базе знаний подгружает модель эмбеддингов (sentence-transformers/all-MiniLM-L6-v2) и вырастает до 1,2–1,5 ГБ:

$ docker stats --no-stream open-webui
CONTAINER ID   NAME         CPU %   MEM USAGE / LIMIT     MEM %
7f3a91c4e802   open-webui   1.87%   1.412GiB / 7.75GiB    18.22%

Если сумма «Open WebUI + модель в Ollama» подошла к объёму RAM, начинается своп — конец скорости. Проверка: vmstat 1 5, ненулевые si и so в установившемся режиме означают, что веса ездят на диск. Настройками не лечится — только память или модель поменьше.

Разгрузить бэкенд можно, отдав эмбеддинги в Ollama: RAG_EMBEDDING_ENGINE=ollama и RAG_EMBEDDING_MODEL=nomic-embed-text экономят 400–600 МБ, но индексация начинает конкурировать за процессор с генерацией. Осторожнее и с галочкой Hybrid Search: она подтягивает реранкер весом больше двух гигабайт.

Второе — база. SQLite спокойно живёт при паре сотен чатов и подтормаживает на паре тысяч, особенно в сайдбаре; удалённые чаты место не отдают:

docker stop open-webui
sqlite3 /var/lib/docker/volumes/open-webui/_data/webui.db "VACUUM;"
docker start open-webui

На базе в 180 МБ это вернуло 60 МБ и заметно оживило сайдбар. Если пользователей больше десятка и в логах мелькает database is locked, пора на PostgreSQL через DATABASE_URL. Честно: штатного переноса из SQLite в Postgres нет, решать надо на старте.

Секунды, которые съедает не сервер, а маршрут

Осталась категория задержек, где вычислений нет вовсе. Сравните один запрос с сервера и из дома:

curl -s -o /dev/null -w 'ttfb=%{time_starttransfer} total=%{time_total}\n' \
  -H "Authorization: Bearer sk-ВАШ_КЛЮЧ" -H "Content-Type: application/json" \
  -X POST https://ai.example.com/api/chat/completions \
  -d '{"model":"qwen2.5:7b","messages":[{"role":"user","content":"тест"}],"stream":true}'

Ключ берётся в Settings → Account → API Keys. Разница в ttfb в пределах пинга — норма, разница в секунды — одна из трёх ловушек ниже.

Мёртвый апстрим в списке моделей. Обновляя список, Open WebUI опрашивает всех провайдеров сразу. Коннектор OpenAI включён по умолчанию, и если сервер до api.openai.com не достучится, каждое открытие выпадающего списка ждёт таймаута:

ERROR [open_webui.routers.openai] Connection error: Cannot connect to host api.openai.com:443
ssl:default [Connect call failed ('104.18.7.192', 443)]

Не пользуетесь внешними API — ENABLE_OPENAI_API=False. Пользуетесь — уберите лишние адреса из OPENAI_API_BASE_URLS и подтяните AIOHTTP_CLIENT_TIMEOUT (по умолчанию 300 секунд, для списка моделей абсурдно много). В свежих сборках есть отдельный AIOHTTP_CLIENT_TIMEOUT_MODEL_LIST; версию покажет curl -s http://127.0.0.1:3000/api/version.

Проверка обновлений и загрузка с Hugging Face. На старте Open WebUI идёт на GitHub за номером версии, а при первом использовании RAG тянет эмбеддинги с huggingface.co. Недоступны эти адреса — старт зависает на минуты. Лечится связкой ENABLE_VERSION_UPDATE_CHECK=False и OFFLINE_MODE=1, но тогда модель надо положить заранее.

Соседи по гипервизору. Если на хосте пересдана мощность, такты уходят чужим виртуалкам. Показывает steal time: sudo apt install -y sysstat && mpstat -P ALL 1 3. Колонка %steal устойчиво выше 5 — вы платите за ядра, которых у вас нет; настройками не чинится.

И отдельно: ответ, приходящий целиком через полминуты вместо потока по словам, — это буферизация в reverse proxy, лечится proxy_buffering off; в nginx. Подробнее — в статье Open WebUI не видит Ollama.

Какой сервер под быстрый Open WebUI брать в MAATRIX

Сам Open WebUI — лёгкое веб-приложение, ему хватает двух ядер; тяжёлым становится то, что считает модели.

СценарийvCPURAMNVMeЧто по скорости
Интерфейс к внешним API (OpenAI, свой LiteLLM)24 ГБ40 ГБСкорость провайдера, сервер не при чём
Локальная модель до 8B на CPU4–816 ГБ100 ГБ5–8 tok/s, хватает одному
Команда, RAG, PostgreSQL рядом832 ГБ200 ГБСтолько же, но держит параллель

Минимум, на котором это честно работает — 2 vCPU, 4 ГБ, 40 ГБ NVMe, и только если модели считаются не здесь. Отвечать будет так же быстро, как провайдер: для большинства это самый разумный вариант.

Комфортный вариант под локальный инференс — 8 vCPU и 16 ГБ. Почему не 8 ГБ: 7B в Q4 занимает 6,2 ГБ, плюс полтора гигабайта контейнера, плюс KV-кэш — на восьми вы живёте на грани свопа, а своп на инференсе это не «чуть медленнее», а «в десять раз медленнее». Диск с запасом: три-четыре модели с индексом съедают 80 ГБ. И прямо: на процессоре без видеокарты быстро не будет никогда. 5–8 токенов в секунду — скорость медленно печатающего человека: личному помощнику хватит, десяти пользователям нужен GPU-сервер.

Локация — Великобритания (Лондон). Пинг в интерактивном интерфейсе ощущается на каждом клике: из Москвы до Лондона 45–60 мс против 110–130 мс до Нью-Йорка. Второй аргумент важнее первого — с британского адреса нормально открываются api.openai.com, huggingface.co и ghcr.io, то есть не будет ни зависших списков моделей, ни минутного старта. Франция равноценна для пользователей в ЕС, Нью-Йорк берут под сервисы с проверкой на американский адрес, а российская локация оправдана, когда все модели локальные и 152-ФЗ важнее задержек.

Оплата — картами российских банков, по СБП, криптовалютой или токеном MAAT; зарубежная карта для сервера в Лондоне не нужна. Связка Ollama и Open WebUI ставится из каталога приложений, дальше вы правите окружение под себя. Сомневаетесь — опишите сценарий: сколько человек и какие модели.

Развернуть за пару минут

Готовый образ на VPS MAATRIX: NVMe, AMD EPYC, root-доступ. Локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Развернуть Open WebUI

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →

Частые вопросы

Почему первый вопрос за день идёт 30 секунд, а следующие быстро?

Ollama выгружает модель через 5 минут простоя, и первый запрос заново читает гигабайты весов с диска. Пустой ollama ps подтверждает диагноз, лечится OLLAMA_KEEP_ALIVE=24h и прогревом через curl.

Ответ дописан, а интерфейс ещё крутится — нормально?

Нет, это фоновые вызовы модели: заголовок чата, теги, варианты продолжения. Выключите лишнее в Admin Panel → Settings → Interface или поставьте в Task Model llama3.2:1b — у нас хвост сократился с 11,4 до 1,2 секунды.

Старый чат отвечает медленнее нового — почему?

Вся переписка уходит модели заново при каждом сообщении, и время обработки промпта растёт вместе с ней. Сравните prompt_eval_count в новом и проблемном чате: разница в десятки раз значит, что дешевле начать новый.

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.