Где это находится
/admin/settings/ai. Для просмотра нужно settings.read, для изменений —
settings.write, что на практике означает владельца. Каждое изменение
записывается в журнал аудита вместе с исполнителем и причиной, которую собрала
панель.
Три адаптера
У строки провайдера есть вид (kind), и вид решает, какую форму запроса говорит Omniflow. Их три, и они намеренно тонкие: каждый сопоставляет запрос с точкой входа этого провайдера и разбирает ответ обратно. Редактирование чувствительных данных, бюджеты, повторы и ограничения принадлежат шлюзу, а не адаптеру.
Три свойства общие для всех трёх, и их стоит знать до того, как что-то
диагностировать:
- Сообщение об ошибке от провайдера никогда не передаётся дальше. Ответ не из
диапазона 2xx превращается в
HTTP <статус>и ничего больше, потому что текст ошибки провайдера может вернуть промпт, а в промпте содержимое клиента, которому нечего делать в браузере оператора. Подробности уходят в лог. - Тело ответа ограничено 4 МиБ, а запрос истекает через 60 секунд. Точка входа, которая передаёт данные без конца, должна упасть, а не исчерпать память.
- Задача без лимита токенов получает 1024. Функция, которой не задали потолок, должна отвечать коротко, а не дорого; повышение потолка — осознанное действие на уровне функции.
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, сохраните, затем включите Одобрен к использованию на карточке
провайдера. Задача, направленная на провайдера без включённой строки,
отклоняется, а не переключается на другого.
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. - Модель называется у функции, а не у провайдера, и это должно быть имя, которое публикует ваш сервер, а не имя у облачного вендора.
Маршрутизация функции к модели
Карточка Функции перечисляет каждую функцию, которая может быть у установки. Каждая выключена, пока вы её не включите и не выберете провайдера и модель, а функцию, включённую без обоих, нельзя сохранить: включённая функция, которая упала бы при первом же вызове, выглядит как ошибка, а не как незаполненная настройка.
У каждой функции свои настройки, потому что сводка обращения и суждение о том,
совершает ли кто-то мошенничество, — это не один и тот же риск и они не должны
делить конфигурацию:
Хранение задаётся по функциям, потому что материал разный: черновик маркетинга —
это собственный текст оператора, а сводка обращения — чья-то жалоба. Промпты по
умолчанию не хранятся, ответы хранятся.
Потолки и кого они останавливают
Бюджеты у функции ограничивают эту функцию. Карточка Лимиты использования ограничивает людей, а это другой вопрос: «установка израсходовала бюджет» и «один оператор зациклил копилот» требуют разных ответов, и останавливать нужно только во втором случае. У лимита есть область, окно в секундах и любая комбинация числа запросов, числа токенов и потолка стоимости в минорных единицах:
Когда подходит несколько лимитов, оператору сообщают о самом узком, потому что
средство различается: ожидание не поможет с лимитом, который назвал вас лично.
Неизмеримый счётчик отказывает в закрытую сторону. Тратить в счёт бюджета,
который никто не может измерить, — это способ узнать свой лимит из счёта.
Чтение состояния на экране
Карточка Расходы и производительность показывает запросы, токены, среднюю и 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, его списки разрешений и ограничения исходящих соединений.
Настройки установки
Остальные экраны конфигурации и то, как запечатываются секреты.