Skip to main content
Всё, что связано с AI в Omniflow, начинается с провайдера, которого владелец зарегистрировал и одобрил. Эта страница о том, как устроен реестр: три адаптера, поля на экране, как направить его на модель, работающую на вашем железе, как функция маршрутизируется к модели и получает потолок и что означает каждое состояние на экране. Решения, стоящие за конструкцией, — почему никто не обращается к провайдеру напрямую, почему одобрение является строкой в базе и почему модель никогда не действует сама, — описаны в Приватности AI и шлюзе и записи 0006. Здесь — механика.
В этой сборке провайдера не вызывает ни одна функция. Реестр, запечатывание учётных данных, маршрутизация по функциям, бюджеты и отчёт об использовании настоящие — именно через них провайдер и будет использоваться. Шлюз и пакеты функций реализованы и покрыты модульными тестами, но ни один процесс их не подключает: на /v1/panel нет ни одной точки входа AI, и ни один экран вне этих настроек её не вызывает. Зарегистрированный сегодня провайдер — это конфигурация, ожидающая поверхностей, и его регистрация никуда ничего не отправляет.

Где это находится

/admin/settings/ai. Для просмотра нужно settings.read, для изменений — settings.write, что на практике означает владельца. Каждое изменение записывается в журнал аудита вместе с исполнителем и причиной, которую собрала панель.

Три адаптера

У строки провайдера есть вид (kind), и вид решает, какую форму запроса говорит Omniflow. Их три, и они намеренно тонкие: каждый сопоставляет запрос с точкой входа этого провайдера и разбирает ответ обратно. Редактирование чувствительных данных, бюджеты, повторы и ограничения принадлежат шлюзу, а не адаптеру. Три свойства общие для всех трёх, и их стоит знать до того, как что-то диагностировать:
  • Сообщение об ошибке от провайдера никогда не передаётся дальше. Ответ не из диапазона 2xx превращается в HTTP <статус> и ничего больше, потому что текст ошибки провайдера может вернуть промпт, а в промпте содержимое клиента, которому нечего делать в браузере оператора. Подробности уходят в лог.
  • Тело ответа ограничено 4 МиБ, а запрос истекает через 60 секунд. Точка входа, которая передаёт данные без конца, должна упасть, а не исчерпать память.
  • Задача без лимита токенов получает 1024. Функция, которой не задали потолок, должна отвечать коротко, а не дорого; повышение потолка — осознанное действие на уровне функции.
Адаптер Anthropic фиксирует anthropic-version: 2023-06-01 вместо слежения за последней версией, потому что провайдер, меняющий форму ответа под работающей установкой, — это отказ, который никто не разворачивал.
Точка входа Gemini принимает ключ API в параметре запроса; это устройство того API, а не выбор, сделанный здесь. Поэтому ключ попадает в логи запросов на стороне провайдера. Если для вашей установки это важно, выбирайте один из двух других видов.

Регистрация провайдера

1

Откройте реестр

Перейдите на /admin/settings/ai. Карточка Провайдеры перечисляет зарегистрированное; на свежей установке она сообщает, что провайдер не настроен и поэтому каждая функция AI недоступна.
2

Заполните идентичность

Идентификатор — это стабильный слаг, который будет называть функция: строчные буквы, цифры, - и _, от 2 до 41 символа. Он никогда не показывается клиенту и не меняется, поэтому выбирайте долговечный (openai-main, local-llama). Название — то, что читают операторы.
3

Выберите вид и базовый URL

Выберите openai_compatible, anthropic или gemini. Оставьте Базовый URL пустым, чтобы использовать значение по умолчанию для этого вида из таблицы выше, или задайте его, чтобы обратиться к другой точке входа: региональному хосту, собственному шлюзу или локальной модели.
4

Запишите, что провайдер делает с вашими данными

Нулевое хранение и Может обучаться на ваших данных — это ваши ответы, взятые из условий самого провайдера. Omniflow не может их проверить и не пытается. Они показаны на карточке над переключателем, который отправил бы данные провайдеру, и порождают предупреждения у каждой функции, направленной на него.
5

Добавьте ключ и одобрите

Новый провайдер создаётся выключенным, что бы вы ещё ни задали. Вставьте ключ API, сохраните, затем включите Одобрен к использованию на карточке провайдера. Задача, направленная на провайдера без включённой строки, отклоняется, а не переключается на другого.
Ключ API доступен только на запись, от начала и до конца. Он запечатывается APP_DATA_ENCRYPTION_KEY до того, как попадёт в базу, привязывается к слагу провайдера, поэтому шифротекст, перенесённый в другую строку, не откроется, и никогда не возвращается через API. Поэтому поле всегда пустое при загрузке экрана, а пустое поле сохраняет текущий ключ — заменяют его кнопкой Заменить ключ. Пустое поле сохраняет ключ, только пока провайдер указывает туда, для чего ключ вводили. Сохранение, меняющее вид или базовый URL без нового ключа, отклоняется с 422 secret_required, а слой хранения сам удаляет сохранённый ключ у перенаправленного провайдера. Иначе любой, кому можно править адрес, направил бы его на свой сервер и получил ключ при следующем запросе, так и не имея возможности его прочитать.

Подключение локальной модели

Отдельного адаптера для локальной модели нет, и в этом смысл: всё, что реализует форму OpenAI /chat/completions, регистрируется как openai_compatible со своим базовым URL. Ollama, vLLM, LM Studio, сервер llama.cpp и большинство самостоятельно размещённых шлюзов это умеют.
  • Задайте Базовый URL как корень совместимой с OpenAI точки входа сервера, включая префикс пути, если он есть. Адаптер добавляет /chat/completions ровно к тому, что вы указали, а завершающий слеш отбрасывается.
  • Поле ключа API обязательно, даже если ваш сервер его игнорирует, потому что провайдер без ключа не может быть построен. Для сервера без аутентификации укажите любое непустое значение-заглушку.
  • Обращайтесь к серверу по имени, которое разрешает контейнер API. localhost внутри контейнера — это сам контейнер, а не хост: используйте имя сервиса Compose для модели в том же стеке или адрес хоста в локальной сети.
  • Задайте API APP_AI_ALLOW_PRIVATE_NETWORK=true. По умолчанию базовый URL обязан быть HTTPS к публичному адресу: запрос несёт ключ API провайдера, а введённый оператором адрес внутри сети развёртывания превратил бы адаптер в способ туда достучаться. Имя сервиса Compose или адрес в локальной сети разрешается в частный адрес и отклоняется — при сохранении, если это IP-адрес или обычный HTTP, и при подключении, после разрешения имени, если это имя хоста. Разрешение задаётся переменной окружения, а не переключателем в панели, чтобы решал тот, кто запускает процесс, а не тот, у кого есть settings.write.
  • Модель называется у функции, а не у провайдера, и это должно быть имя, которое публикует ваш сервер, а не имя у облачного вендора.
При включённом APP_AI_ALLOW_PRIVATE_NETWORK любой AI-провайдер может обращаться к частной сети API, а не только локальный: любой, у кого есть settings.write, сможет направить провайдера на внутренний адрес. Включайте его только там, где это приемлемо. Без него каждое соединение адаптера, включая открытое перенаправлением, проверяется после разрешения имени и отклоняется, если адрес не публичный.

Маршрутизация функции к модели

Карточка Функции перечисляет каждую функцию, которая может быть у установки. Каждая выключена, пока вы её не включите и не выберете провайдера и модель, а функцию, включённую без обоих, нельзя сохранить: включённая функция, которая упала бы при первом же вызове, выглядит как ошибка, а не как незаполненная настройка. У каждой функции свои настройки, потому что сводка обращения и суждение о том, совершает ли кто-то мошенничество, — это не один и тот же риск и они не должны делить конфигурацию: Хранение задаётся по функциям, потому что материал разный: черновик маркетинга — это собственный текст оператора, а сводка обращения — чья-то жалоба. Промпты по умолчанию не хранятся, ответы хранятся.

Потолки и кого они останавливают

Бюджеты у функции ограничивают эту функцию. Карточка Лимиты использования ограничивает людей, а это другой вопрос: «установка израсходовала бюджет» и «один оператор зациклил копилот» требуют разных ответов, и останавливать нужно только во втором случае. У лимита есть область, окно в секундах и любая комбинация числа запросов, числа токенов и потолка стоимости в минорных единицах: Когда подходит несколько лимитов, оператору сообщают о самом узком, потому что средство различается: ожидание не поможет с лимитом, который назвал вас лично. Неизмеримый счётчик отказывает в закрытую сторону. Тратить в счёт бюджета, который никто не может измерить, — это способ узнать свой лимит из счёта.

Чтение состояния на экране

Карточка Расходы и производительность показывает запросы, токены, среднюю и p95 задержку, отказы и оценочную стоимость по функциям и моделям за окно, которое печатается рядом с числами. Содержимое промптов и ответов в этом отчёте не хранится, поэтому в нём его и нет. У каждой функции показаны применимые к ней предупреждения, и каждое из них — факт, а не мнение:

Проверка провайдера

Проверить подключение выполняет один настоящий запрос. Кнопка распечатывает сохранённый ключ, отправляет собственный промпт Omniflow — Reply with the single word OK — с потолком в шестнадцать токенов вывода и записывает результат в строку провайдера. Именно этот результат экран покажет при следующей загрузке, поэтому вердикт не может разойтись сам с собой после обновления страницы. Это настоящее завершение, а не проверка доступности, потому что отказывают они по-разному и на вопрос отвечает только первое. Адрес, который резолвится, и ключ, который провайдер принимает, — разные факты, и проверка, доказывающая только первое, сообщила бы об отозванном ключе как об исправном. Оставьте Модель для проверки пустой — и проверка возьмёт ту модель, которую на этого провайдера уже указывает какая-нибудь функция: именно эту конфигурацию и стоит доказывать. У провайдера, на которого пока никто не указывает, выводить модель неоткуда, и запрос отклоняется, а не угадывается.
Проверять провайдера, которого вы ещё не включили, можно — и работа идёт именно в таком порядке: вставить ключ, проверить его, затем одобрить. Всё, что способно отправить клиентские данные, по-прежнему требует Одобрен к использованию.
Три детали сделаны намеренно:
  • Нужно settings.write, а не settings.read. Проверка распечатывает запечатанный ключ и тратит ваши деньги. Ни того, ни другого не должно мочь чтение экрана настроек.
  • Есть ограничение частоты — тридцать проверок в час на оператора: щедро для цикла «вставил — проверил — исправил» и мало настолько, что зациклившийся повтор не потратит бюджет за вечер.
  • Проверка, которую не удалось выполнить, ничего не сохраняет. Нет ключа, нет модели, незарегистрированный слаг — каждый случай отклоняется, а сохранённый результат остаётся прежним, потому что запись отказа утверждала бы, что попытка была. Проверка, которая выполнилась и не прошла, сохраняется — с категорией, а не словами провайдера: сообщение провайдера может вернуть промпт, а транспортная ошибка цитирует адрес, по которому шёл запрос. Ни один адаптер не кладёт ключ в URL — ключ Gemini передаётся в заголовке x-goog-api-key, — а из транспортных ошибок URL вырезается до того, как их что-либо запишет в лог.
Каждая проверка попадает в журнал аудита как ai.provider.tested, рядом с записью ai.provider.saved о предшествовавшей замене ключа. В строке хранится только последний результат, а спрашивают обычно так: «не работало, кто-то поменял ключ, потом заработало».

Разбор неполадок

Смежное

Приватность AI и шлюз

Что удаляется до отправки и что AI никогда не позволено делать.

Управление AI и оценка качества

Включение по функциям, инвентаризация потоков данных, хранение и пороги оценки.

Подключения MCP

Регистрация сервера MCP, его списки разрешений и ограничения исходящих соединений.

Настройки установки

Остальные экраны конфигурации и то, как запечатываются секреты.