Dify не подключается к модели: причины и решение
Ключ вставлен, провайдер сохранён, а приложение отвечает «модель недоступна» или падает на первом запуске. В ветке 1.x между Dify и провайдером стоят ещё два звена — демон плагинов и сам плагин-провайдер, — поэтому жалоба «dify не видит модель» одинаково звучит для пяти разных поломок. Разберём по слоям — с дословными текстами ошибок и командами, которые показывают, где порвалось.
Содержание
- Четыре слоя между Dify и моделью
- «Credentials validation failed»: что делает кнопка сохранения
- Провайдер настроен, а модели нет в списке приложения
- Ollama, vLLM и OpenAI-совместимый endpoint
- Ключ принят, а провайдер всё равно отказывает
- Всё работало и отвалилось: plugin_daemon, dify_plugin и SECRET_KEY
- Какой сервер под Dify брать в MAATRIX
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Четыре слоя между Dify и моделью
До версии 1.0 список провайдеров был вшит в бэкенд. Сейчас каждый провайдер — плагин, и цепочка длиннее: браузер → api → plugin_daemon → процесс плагина со своим окружением Python → запрос к API провайдера. Ломается любое звено, а в консоли выглядит одинаково.
Начинайте не с настроек, а с состояния стека и журнала демона:
cd /opt/dify/docker
docker compose ps --format 'table {{.Service}}\t{{.Status}}'
docker compose logs --tail 80 plugin_daemon
docker compose logs --tail 200 api | grep -iE 'plugin|credential|provider'
Если plugin_daemon не Up или ходит по кругу перезапусков, дальше по настройкам идти бессмысленно: проверить ключ физически нечем. Иначе ориентируйтесь по тексту ошибки — он указывает на слой.
| Что видно | Где рвётся | Куда смотреть |
|---|---|---|
Credentials validation failed | плагин → провайдер | ключ, base URL, регион сервера |
PluginInvokeError с InvokeConnectionError | плагин → сеть | DNS, адрес локальной модели, фаервол |
Ошибка со словом plugin daemon, 500 при сохранении | api → plugin_daemon | демон, переменные PLUGIN_* |
| Провайдер настроен, но модели нет в приложении | внутри api | рабочее пространство, тип модели |
403 unsupported_country_region_territory | провайдер | локация и IP сервера |
Деталь, экономящая часы: исходящий запрос делает не контейнер api, а процесс плагина внутри plugin_daemon. Сеть и ключи проверяйте изнутри того контейнера, который реально звонит наружу.
«Credentials validation failed»: что делает кнопка сохранения
Кнопка «Сохранить» — не запись в базу, а живой запрос: Dify передаёт ключ демону, тот запускает у плагина проверку учётных данных, плагин делает настоящий вызов к API. Текст ошибки почти всегда пришёл снаружи, и читать его надо с конца, из вложенного message:
[openai] Error: PluginInvokeError: {"args":{},"error_type":"CredentialsValidateFailedError",
"message":"Error code: 401 - {'error': {'message': 'Incorrect API key provided: sk-pr*****XYZ.
You can find your API key at https://platform.openai.com/account/api-keys',
'type': 'invalid_request_error', 'code': 'invalid_api_key'}}"}
Код внутри сообщения раскладывает причину: 401 — ключ неверный или обрезанный, 403 — доступ запрещён, чаще всего по региону, 404 — не найдена модель или неправильный base URL, 429 — квота либо лимит. Кавычки, $ или { в маскированном ключе — скопировали лишнее: копипаст из мессенджера приносит перенос строки и неразрывный пробел U+00A0. Сверьте длину: проектные ключи OpenAI sk-proj- заметно длиннее ста символов, ключ Anthropic sk-ant-api03- — около ста восьми.
Самая честная проверка — повторить запрос руками из того же контейнера, минуя Dify:
read -rs KEY # ключ не попадёт в history
docker compose exec -T -e K="$KEY" plugin_daemon python3 - <<'EOF'
import os, urllib.request, urllib.error
req = urllib.request.Request(
"https://api.openai.com/v1/models",
headers={"Authorization": "Bearer " + os.environ["K"]})
try:
print("OK", urllib.request.urlopen(req, timeout=15).status)
except urllib.error.HTTPError as e:
print("HTTP", e.code, e.read()[:400].decode())
except Exception as e:
print("NET", type(e).__name__, e)
EOF
Исходы читаются однозначно: OK 200 — ключ и сеть в порядке, причина внутри Dify; HTTP 401/403 — дословный вердикт провайдера; NET — контейнер не дошёл до сети, вопрос к DNS и фаерволу.
И главная развилка: валидация провайдера и вызов модели — разные запросы. Плагин при сохранении дёргает список моделей, приложение просит конкретную. Проектный ключ OpenAI видит /v1/models, но не имеет доступа к нужной модели: провайдер сохранится зелёным, а запуск вернёт 404 The model 'gpt-4o' does not exist or you do not have access to it.
Развернуть за пару минут
Готовый образ на VPS MAATRIX: NVMe, AMD EPYC, root-доступ. Локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Развернуть DifyПровайдер настроен, а модели нет в списке приложения
Здесь ключи ни при чём — модель просто не доезжает до выпадающего списка. Причин пять, каждая проверяется за минуту.
Не то рабочее пространство. Ключи привязаны к workspace, а не к аккаунту: коллега в собственном пространстве видит пустой список при полностью настроенном соседнем. Переключатель — в левом нижнем углу консоли. Что лежит в базе:
docker compose exec -T db psql -U postgres -d dify -c '\dt' | grep -i provider
docker compose exec -T db psql -U postgres -d dify \
-c "select tenant_id, provider_name, provider_type, is_valid from providers order by tenant_id;"
Несколько разных tenant_id — верный признак, что ключ введён не там.
Не тот тип модели. Плагин объявляет модели по типам: llm, text-embedding, rerank, speech2text, tts, moderation. Узел LLM показывает только llm, база знаний в режиме High Quality — только эмбеддинги. Отсюда классическое «модель есть, а база знаний не создаётся»: у подключённого провайдера эмбеддингов нет вовсе. Системные роли разобраны в материале про установку и настройку Dify на VPS — незаполненные роли оставляют приложения без модели по умолчанию.
Кастомный провайдер без каталога. У совместимого с OpenAI API провайдера готового списка нет: каждую модель добавляют вручную, имя — ровно такое, какого ждёт сервер, плюс четыре поля: тип, режим (Chat или Completion), Model context size, Upper bound for max tokens. Опечатка в имени даёт 404 на первом вызове, неверный режим — 404 на другом пути, пустой размер контекста — молча обрезанные промпты.
Модель не умеет того, что просит узел. Агентному узлу нужна поддержка function calling; без неё модель не появится в подборе инструментов или проигнорирует вызовы. Обходной путь — режим ReAct: работает на любых моделях, но многословнее.
Приложение помнит удалённую модель. Оно хранит связку «провайдер + имя». После обновления или переустановки плагина модель в редакторе подсвечивается красным, а запуск падает на model not found. Правится руками: открыть селектор, выбрать модель заново, сохранить — в каждом узле каждого воркфлоу.
Ollama, vLLM и OpenAI-совместимый endpoint
Локальные модели дают отдельный класс отказов с узнаваемым симптомом:
[ollama] Error: PluginInvokeError: {"args":{},"error_type":"InvokeConnectionError",
"message":"HTTPConnectionPool(host='localhost', port=11434): Max retries exceeded with url:
/api/chat (Caused by NewConnectionError('...: Connection refused'))"}
Адрес localhost внутри контейнера ведёт в сам контейнер. Правильный — http://host.docker.internal:11434, и работает он только с пробросом шлюза. Запрос уходит от plugin_daemon, значит, extra_hosts нужен ему. Правку кладите в docker-compose.override.yaml, чтобы её не стёр git pull:
services:
plugin_daemon:
extra_hosts:
- "host.docker.internal:host-gateway"
Ollama слушает только петлю. По умолчанию демон биндится на 127.0.0.1, и хост-гейтвей до него не достучится:
ss -lntp | grep 11434 # видите 127.0.0.1:11434 — вот и причина
sudo systemctl edit ollama # [Service] Environment="OLLAMA_HOST=0.0.0.0:11434"
sudo systemctl restart ollama
После этого порт торчит наружу — сразу закройте его для всех, кроме докерных подсетей:
sudo ufw allow from 172.16.0.0/12 to any port 11434 proto tcp
sudo ufw deny 11434/tcp
Модель не скачана или названа иначе. Имя в Dify обязано совпадать с тегом до символа, включая :8b или :latest; сверяйтесь с ollama list, иначе получите model 'llama3.1' not found, try pulling it first. Как поднять сам движок — в статье про локальный запуск LLM через Ollama.
Base URL для OpenAI-совместимых серверов. Dify дописывает путь сам, и это главный источник 404 при подключении vLLM, llama.cpp или шлюза. Правильная форма — http://host.docker.internal:8000/v1. Полный путь .../v1/chat/completions превращается в /v1/chat/completions/chat/completions, адрес без /v1 — в /chat/completions; оба дают 404, который легко принять за «не та модель». Сервер проверяйте отдельно: curl -s http://127.0.0.1:8000/v1/models | head -c 200. Нужны единые ключи с бюджетами на несколько провайдеров — ставьте между Dify и моделями шлюз, его грабли собраны в разборе, почему LiteLLM не видит API-ключи.
Честное ограничение: Dify рядом с локальной моделью на одной машине — сложение требований, а не экономия; расчёт по памяти — в последнем разделе.
Ключ принят, а провайдер всё равно отказывает
Бывает, что значение доехало идеально и сеть в порядке, а отказ приходит всё равно. Причины уже не в Dify.
География IP. С российского адреса зарубежные провайдеры отвечают отказом независимо от ключа:
Error code: 403 - {'error': {'code': 'unsupported_country_region_territory',
'message': 'Country, region, or territory not supported'}}
Gemini возвращает {"code": 400, "message": "User location is not supported for the API use.", "status": "FAILED_PRECONDITION"}, Anthropic — сухой 403 без подробностей. Перевыпуск ключа не поможет: смотрят на исходящий адрес. В то же самое упирается и маркетплейс плагинов — провайдера может не выйти даже установить. Сторонний HTTP-прокси спасает (обход гео-блокировок нейросетей), но это лишняя точка отказа и чужой узел, через который идут ваши ключи.
Квота против лимита. Ответ insufficient_quota с кодом 429 — пустой баланс, а не превышение скорости; настоящий рейт-лимит приходит как rate_limit_exceeded. Разница важна: встроенные повторы в узле LLM лечат второе и бесполезны против первого.
Область действия ключа. Проектные ключи OpenAI sk-proj- привязаны к проекту: модель, не включённая в его настройках, отдаёт 404, а не 401. У ключа с урезанными правами будет Missing scopes. Это не «Dify не видит ключ», а «ключ не тот».
Azure OpenAI требует другого. Кроме ключа нужны endpoint, api_version и имя деплоймента вместо имени модели. Подставили gpt-4o туда, где ждут имя вашего деплоя, — получите DeploymentNotFound, выглядящий как отсутствующая модель.
DNS и таймауты. Если контейнер не резолвит имена, отказ выглядит как проблема ключа: docker compose exec plugin_daemon sh -c 'getent hosts api.openai.com || echo NO-DNS'. А длинные ответы рвутся по своему потолку: вызов плагина ограничен PLUGIN_MAX_EXECUTION_TIMEOUT (по умолчанию 600 секунд), и упёршаяся в него генерация обрывается на середине без внятного текста.
Всё работало и отвалилось: plugin_daemon, dify_plugin и SECRET_KEY
Отдельный сценарий: вчера модели отвечали, сегодня провайдеров нет вовсе или все вызовы падают. Почти всегда это последствие обновления или переноса.
Демону нужна собственная база. Он ходит в Postgres не в dify, а в базу из переменной DB_PLUGIN_DATABASE (по умолчанию dify_plugin). На чистом томе она создаётся при инициализации, при обновлении со старой ветки на существующем томе — нет. Демон уходит в цикл перезапусков, и в журнале одна строка причины:
FATAL: database "dify_plugin" does not exist
Лечится одной командой, данные не страдают:
docker compose exec -T db psql -U postgres -c "CREATE DATABASE dify_plugin;"
docker compose restart plugin_daemon
Ключи между сервисами разъехались. PLUGIN_DAEMON_KEY со стороны api обязан совпадать с SERVER_KEY демона, а PLUGIN_DIFY_INNER_API_KEY обслуживает обратный канал по адресу PLUGIN_DIFY_INNER_API_URL (по умолчанию http://api:5001). Расхождение даёт отказы авторизации при каждом вызове модели, хотя ключ провайдера верный. Меняете значение — меняйте с обеих сторон и пересоздавайте контейнеры (docker compose down && docker compose up -d): restart окружение не перечитывает.
Установка провайдера падает по таймауту. Демон собирает для плагина отдельное окружение Python и тянет зависимости из pypi.org. На слабом процессоре или узком канале это не укладывается в PLUGIN_PYTHON_ENV_INIT_TIMEOUT — по умолчанию 120 секунд; поднимите до 300–600 и пересоздайте контейнер. Туда же смотрите при «плагин установился, но не работает»: окружения живут в PLUGIN_WORKING_PATH (/app/storage/cwd), весят немало, и забитый диск ломает их молча — df -h, du -sh volumes/plugin_daemon.
Потеряли SECRET_KEY. Ключи провайдеров хранятся в базе зашифрованными, корень цепочки — SECRET_KEY из docker/.env. Скопировали при обновлении .env.example поверх рабочего файла или перенесли базу без .env — расшифровать старые записи нельзя ничем, кроме прежнего значения: провайдер числится настроенным, а вызовы падают. Выхода два — вернуть старый SECRET_KEY либо удалить провайдера и ввести ключи заново. Проверить, что он есть: grep '^SECRET_KEY=' /opt/dify/docker/.env. Остальные поломки стека — в разборе частых ошибок Dify на сервере.
Какой сервер под Dify брать в MAATRIX
Большинство причин выше конфигурационные, но три упираются в железо и адрес: региональный 403, таймаут сборки окружения плагина и OOM, уносящий демон плагинов. Последнее в интерфейсе выглядит именно как «Dify не видит модель», хотя это нехватка памяти.
Честный минимум: 2 vCPU, 4 ГБ RAM, 40–50 ГБ NVMe. Документационный порог: Postgres, Redis, векторная база, фронтенд, api, worker и демон плагинов на одной машине. Работать будет, но каждый провайдер — ещё один процесс со своим окружением Python: пять плагинов на четырёх гигабайтах уже ощутимы, а всплеск при индексации выбивает самый жирный. Swap тут не опция, а обязательный элемент; плагинов держите минимум.
Комфортный вариант: 4 vCPU, 8 ГБ RAM, 80 ГБ NVMe. Десяток плагинов, параллельные вызовы и сборка зависимостей перестают мешать друг другу, а таймауты установки уходят сами. Локальную модель считайте отдельно: 8 ГБ на платформу плюс ~4,5 ГБ весов модели 7B в Q4 — уже 16 ГБ, и практичнее вынести инференс на вторую машину.
Локация — Великобритания, Лондон. Прямое следствие раздела про 403: с британского адреса OpenAI, Anthropic и Google отвечают штатно, маркетплейс плагинов открывается, а до пользователей в Европе и России ближе, чем через Атлантику. Соседство с GDPR-контуром — плюс, когда в базу знаний идут документы европейских контрагентов; Франция подходит по тем же причинам. США берут ради американского IP и чистой подсети. Россия оправдана в одном сценарии: данные обязаны оставаться в РФ по 152-ФЗ и модели российские — тогда за плагинами всё равно идти через прокси.
Заказ занимает несколько минут: выбираете локацию и конфигурацию, отмечаете Dify из каталога apps.maatrix.io — приложение разворачивается автоматически на Ubuntu или Debian, вручную ставить стек не нужно. Адрес консоли и стартовые доступы появятся в личном кабинете, в разделе «Доступ». Оплата — картой российского банка, по СБП, криптовалютой или токеном MAAT. Первым делом после входа сохраните SECRET_KEY из docker/.env в менеджер паролей: это единственное, что не восстановить, когда ключи вдруг перестанут расшифровываться.
Развернуть за пару минут
Готовый образ на VPS MAATRIX: NVMe, AMD EPYC, root-доступ. Локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Развернуть DifyОбсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Частые вопросы
Ключ проходит проверку, но приложение пишет, что модель недоступна. Почему?
Валидация дёргает список моделей, а приложение просит конкретную — это разные запросы. Строка The model ... does not exist or you do not have access to it в логах api означает права ключа на модель или опечатку в имени, а не проблему с ключом.
Перенёс Dify на другой сервер: провайдеры числятся настроенными, но ни один вызов не работает.
Почти наверняка база приехала без прежнего SECRET_KEY из docker/.env — ключи зашифрованы и не расшифровываются. Верните старое значение либо удалите провайдеров и введите ключи заново.
Ollama стоит на том же сервере, а Dify отвечает Connection refused.
Нужны два условия сразу: адрес провайдера http://host.docker.internal:11434 и проброс extra_hosts: - "host.docker.internal:host-gateway" у сервиса plugin_daemon. Плюс сам Ollama обязан слушать не петлю — Environment="OLLAMA_HOST=0.0.0.0:11434" в юните, а порт 11434 закрыт фаерволом для всех, кроме докерных подсетей.
Нужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.