Все проекты

AI-шлюз

pacod-gw

Один шлюз перед всеми моделями — с ключами, ценами, квотами и учётом использования, которые вашим приложениям не нужно держать у себя.

pacod-gw стоит между вашими приложениями и LLM-провайдерами. Ядро на Rust проксирует или транслирует каждый вызов, не допускает ключи провайдеров в ваши приложения, следит за квотами, рассчитывает стоимость каждого запроса и передаёт данные об использовании в аналитику на ClickHouse — и всё это управляется из консоли на SvelteKit.

  • Apache-2.0
  • Версия 0.1.0
  • Предварительная

Возможности

  • Proxy или managed

    Проксируйте API провайдера байт в байт или доверьте шлюзу разрешение шаблонов, слияние параметров и трансляцию между диалектами.

  • Много диалектов, один контракт

    OpenAI, Anthropic, Gemini и собственный диалект; проверено вживую на DeepSeek и GLM, а Kimi и Ollama эмулируются mock-провайдером.

  • Ключи остаются в шлюзе

    Хранимые учётные данные провайдеров и ключи шлюза для каждого рабочего пространства. Приложения никогда не видят ключ провайдера.

  • Квоты и лимиты

    Лимиты на токены и запросы для организации, рабочего пространства и ключа применяются до того, как вызов покинет шлюз.

  • Стоимость каждого вызова

    Журнал использования со стоимостью прямо в ответе, так что команды сразу видят, во что обошёлся каждый запрос.

  • Аналитика на ClickHouse

    События поступают в отдельный сервис аналитики с отчётами и задачами по расписанию; для эксплуатации — Prometheus, Grafana и OpenTelemetry.

  • Маршрутизация и намерения

    Схемы и правила маршрутизации, а также плагин определения намерений с движками LLM, Jev и cascade, чтобы выбрать подходящую модель для каждого запроса.

  • Режим Lite

    Та же плоскость данных в одном контейнере — без базы данных и консоли — с настройкой через один файл .env и журналированием каждого вызова.

Место в экосистеме

Люди и сервисыLLM-провайдерыAPpacod-apCMpacod-cmsKBpacod-kbGWpacod-gwIDpacod-id
Люди и сервисыLLM-провайдерыAPpacod-apCMpacod-cmsKBpacod-kbGWpacod-gwIDpacod-id
Схема: как связаны проекты pacod Вызовы LLM Нажмите на проект, чтобы увидеть, с чем он связан.

Зачем нужен шлюз

Каждый продукт, работающий с языковой моделью, в итоге заново реализует одно и то же: хранение ключей провайдеров, трансляцию между API, подсчёт токенов, соблюдение лимитов и объяснение счёта. pacod-gw забирает всё это из приложения. Приложение обращается к одной конечной точке с ключом шлюза; шлюз решает, какая модель обслужит вызов, сколько он может стоить и кто за него платит.

Первая цель конкретна: заменить LiteLLM-прокси перед приложением, изменив только его базовый URL и ключ.

Два режима, одно ядро

Ядро — это один бинарный файл на Rust с двумя слушателями: плоскостью данных для приложений и API управления для консоли и скриптов. Режим выбирается префиксом URL и разрешается для каждого ключа.

  • Режим proxy (/proxy/{provider}/…) передаёт собственный API провайдера байт в байт и добавляет аутентификацию, лимиты и учёт. Шаблон при этом всё равно может задать модель и её параметры.
  • Режим managed обслуживает /v1/chat/completions от OpenAI, /v1/messages от Anthropic, generateContent от Gemini и собственный /gw/v1/chat, а также эмбеддинги и синтез речи.

В режиме managed маршрут определяют диалект вызывающей стороны и провайдер модели:

Вызывающая сторона говорит Модель находится у Что происходит
Диалект OpenAI OpenAI-совместимого провайдера (OpenAI, DeepSeek, GLM, Kimi, Ollama, …) Байты вызывающей стороны правятся точечно; стоимость добавляется в usage.
Диалект Anthropic Anthropic Диалог доходит до Anthropic в том виде, в каком был отправлен; стоимость возвращается в заголовке.
Любая другая пара и собственный интерфейс любого провайдера Трансляция через нейтральную модель и обратно, поэтому вызов может переключиться на резервную модель и через границу диалектов.

Один вызов, шаг за шагом

  1. Аутентификация. Ключ ищется по HMAC в снимке конфигурации в памяти.
  2. Чтение. Сканер находит модель и флаги потоковой передачи, не разбирая всё тело; плагины рабочего пространства видят диалог.
  3. Разрешение. Шаблон (@name или x-gw-template) или идентификатор разрешённой модели определяет модель и её параметры.
  4. Допуск. Ограничение одновременных вызовов ключа и каждый применимый лимит должны быть соблюдены.
  5. Отправка. Сохранённые учётные данные провайдера заменяют ключ шлюза. В режиме managed ответ 429, 5xx или потерянное соединение повторяются или передаются следующей модели, прежде чем вызывающая сторона получит хоть один байт.
  6. Передача и расчёт. Ответ возвращается потоком, а отвод читает использование из копии; затем обновляются стоимость и счётчики, а событие использования уходит в спул на диске.

Ответ содержит x-gw-request-id, x-gw-delay-ms (время, добавленное самим шлюзом), x-gw-model-served и, для вызовов managed без потоковой передачи, x-gw-cost.

Конфигурация хранится в PostgreSQL, но путь запроса её не ждёт: изменение подменяет снимок примерно за две секунды, а если какое-то хранилище недоступно, трафик продолжает идти на последнем снимке.

Организации, рабочие пространства и ключи

Организация — это клиент или крупное подразделение. Рабочее пространство — одно приложение, проект, среда или команда; ему принадлежат его ключи, шаблоны, лимиты, настройки и использование. Два правила покрывают любое ограничение: списки разрешений пересекаются, а числовые пределы берут минимум.

Ключи провайдеров принадлежат инсталляции, организации или рабочему пространству, и вызов использует ближайший: собственный ключ рабочего пространства, затем ключ его организации, затем общий ключ инсталляции. Ключ, который шлюз уже хранит, можно передать вниз организации или рабочему пространству, не вводя его заново; секрет никогда не покидает шлюз.

Роли описаны в одном файле, authz/gw.yaml, из которого генерируются проверки и ядра, и консоли:

Роль Что охватывает
Администратор платформы Провайдеры, учётные данные, модели, цены, организации, люди
Администратор организации Её настройки, рабочие пространства, участники и выданные модели
Администратор рабочего пространства Шаблоны, ключи, лимиты, настройки и режим аудита одного рабочего пространства
Аудитор Читает конфигурацию, использование и записи режима аудита
Наблюдатель Читает конфигурацию и использование; без секретов и записей режима аудита

Вызовы несут атрибуцию — end_user, session_id, trace_id, объявленные теги, agent_id, task, complexity, — которую используют отчёты, лимиты и маршрутизация. Пользователи входят в консоль с локальными учётными записями или, при PGW_AUTH=oidc, через pacod-id.

Лимиты и стоимость

Лимит применяется к организации, рабочему пространству, ключу или конечному пользователю. Он считает токены, запросы или расходы за минуту, час, день, неделю, месяц или за всё время и либо отклоняет вызовы (429, 402), либо только считает и сообщает. Приложения могут узнать состояние квоты пользователя через GET /gw/v1/quota. Счётчики объединяются между инстансами через PostgreSQL примерно раз в секунду, поэтому лимит может быть превышен примерно на секунду трафика.

Каждый вызов оценивается при завершении по версионированной цене, которая учитывает чтение и запись кеша, рассуждения, пакетные варианты, ступени по размеру входа и внепиковые окна. Цены по умолчанию нет: модель можно активировать только с ценой или с явной пометкой «бесплатно». Обнаружение моделей по умолчанию раз в день запрашивает у каждого провайдера список его моделей и предлагает те, которых в шлюзе нет; модель, добавленная из предложения, остаётся черновиком, пока у неё нет цены. Трекер цен по расписанию читает прайс-лист LiteLLM или страницу цен провайдера и применяет изменения в пределах заданной границы либо предлагает их на утверждение. Пока у него нет источников, консоль предлагает список LiteLLM для OpenAI, Anthropic, Gemini, DeepSeek и z.ai.

Маршрутизация и намерения

Шаблон может содержать пул моделей с уровнями, весами и приоритетами. Без дополнительной настройки обслуживает первая модель, а следующая подхватывает при 429, 5xx или потере соединения. Схема маршрутизации добавляет правила по тому, что сообщает вызывающая сторона (complexity, task, теги, размер входа или выражение CEL), и алгоритмы: по приоритету, взвешенный, round robin, наименьшая задержка и самый дешёвый, с необязательной привязкой к сессии, чтобы кеши промптов оставались «тёплыми». Предохранитель (circuit breaker) отодвигает сбоящую модель, а каждый ответ называет в x-gw-route правило, по которому он был направлен.

Плагин намерений отвечает на вопрос «для чего этот вызов?» по каталогу, который пишет организация или рабочее пространство, с помощью LLM, движка Jev или каскада из обоих. Его вердикт может заблокировать вызов, направить его, учесть в лимитах по намерению или пометить для проверки; сначала он может работать в теневом режиме и никогда не меняет диалог.

Новый каталог начинается со встроенного шаблона starter с намерениями универсального ассистента и правилами, которые помечают и блокируют. Новая привязка начинается с шаблона, который шлюз заполняет для своей области: теневой режим, этот каталог и самая дешёвая выданная модель, которая отвечает по JSON-схеме, или Jev, если такой нет. Панели пробы и оценки в консоли запускают движки на примерах текстов, сначала на демонстрационных данных, подготовленных для каталога, чтобы сравнить движки до того, как привязка начнёт применять решения. См. руководство по маршрутизации и концепцию плагинов.

Наблюдаемость и аудит

События использования приходят в сервис аналитики пакетами из спула каждого инстанса; доставка выполняется как минимум один раз, а ClickHouse удаляет дубликаты. Сервис строит отчёты по использованию, ошибкам, задержке шлюза, рейтингам и конечным пользователям, с экспортом в CSV, и выполняет задачи по расписанию. Консоль обращается к нему только через ядро, которое проверяет роль вызывающего и принудительно задаёт область видимости.

Prometheus, дашборды Grafana, правила Alertmanager и трейсы OpenTelemetry покрывают эксплуатацию; консоль показывает текущие показатели, состояние провайдеров и открытые оповещения.

Режим аудита сохраняет полные вызовы для отладки: запрос, каждую попытку к провайдеру и ответы. По умолчанию он выключен, организация может его потребовать или запретить, учётные данные удаляются до сохранения, а записи по умолчанию истекают через 14 дней.

Модель безопасности

  • Ключи провайдеров запечатываются по отдельности с AES-256-GCM под ключом шифрования ключей, который берётся из окружения или файла, но никогда из базы данных. API показывает только отпечаток.
  • Ключи шлюза (pgw_…) содержат 32 случайных байта, хранятся как HMAC-SHA256 с pepper и показываются один раз.
  • Разделение арендаторов. Рабочее пространство определяется ключом, а не запросом, и ядро ограничивает отчёты тем, что разрешают роли вызывающего.
  • Исходящие соединения к провайдерам и источникам цен проверяются после разрешения имён: частные и link-local адреса отклоняются, если оператор явно их не открыл.
  • Промпты не попадают в логи, метрики и трейсы, которые содержат только метаданные; тела сохраняются только в режиме аудита.

Модель угроз перечисляет и то, что остаётся открытым: например, порт метрик не требует аутентификации и несёт метки арендаторов, а в общей сети любой контейнер pacod может обратиться к API управления, которое тогда защищено только собственной аутентификацией.

Развёртывание и эксплуатация

Ядро работает в роли all или разделяется на инстансы gateway и один инстанс admin. Инстансы делят один PostgreSQL и больше ничего.

Схема Файлы
Одно ядро deploy/docker-compose.yml с docker-compose.standalone.yml
Несколько шлюзов на одном хосте плюс docker-compose.scale.yml
Шлюзы на других машинах docker-compose.hub.yml централизованно, deploy/node/ на каждой машине
Kubernetes deploy/helm/pacod-gw
Минимальный шлюз deploy/lite/docker-compose.yml

Как и все проекты pacod, шлюз подключается к общей Docker-сети pacod-net, где у каждого сервиса своё имя: ядро называется pacod-gw, остальные сервисы — gw-*. docker-compose.yml содержит собственные сервисы шлюза; docker-compose.standalone.yml добавляет его копии общих компонентов: PostgreSQL, pacod-id, Caddy и мониторинг. pacod-demo запускает шлюз вместе с остальными проектами pacod на demo.pacod.io. pacod-demo загружает только первый файл и запускает каждый общий компонент один раз; ClickHouse остаётся у шлюза.

Caddy завершает TLS и направляет каждый вызов на готовый шлюз с наименьшим числом вызовов в работе. Ранбук описывает секреты, резервное копирование и восстановление, ротацию ключей, обновления и устранение неполадок; встроенный тестер запускает тест-кейсы и нагрузочные тесты из консоли.

pacod-gw-lite сохраняет трансляцию, потоковую передачу, повторы и переключение на резервные модели, с лимитами на ключ в памяти и одной строкой лога на каждый вызов с его стоимостью. Его клиенты делят ключи провайдеров и не отделены друг от друга на стороне провайдера. В общей сети минимальный шлюз тоже называется pacod-gw, поэтому на одном хосте работает либо он, либо полный шлюз (подробнее).

Что проверено

  • OpenAI, Anthropic, Gemini, DeepSeek и GLM проверены живыми вызовами; Kimi, Ollama, xAI и Vertex AI — только по их документации и на имитирующем провайдере.
  • Проектная цель — 10 000 одновременных потоков в режиме proxy и 5 000 в режиме managed на инстанс (2 CPU, 1 GB) — пока не подтверждена нагрузочным тестом.
  • Пока не опробованы: сертификаты Let's Encrypt, хост на Linux, обновление между релизами и Helm-чарт в реальном кластере.
  • Не входят в первый релиз: управление MCP и инструментами, контентные ограничители и кеширование ответов.

Страница об архитектуре показывает, как устроен код и где он отличается от концепции дизайна.

Технологии

Языки
  • Rust
  • TypeScript
  • Python
Технологии
  • Rust
  • PostgreSQL
  • ClickHouse
  • SvelteKit
  • Caddy
  • Docker
  • Helm
  • Prometheus
  • OpenTelemetry

Быстрый старт

Полный стек с mock-провайдером
make test-servicesmake verifymake dev-upmake smoke-mockopen http://localhost:13000
Минимальный шлюз
make lite-dev-upmake lite-smoke

Работает с

  • pacod-id

    С PGW_AUTH=oidc пользователи входят в консоль через pacod-id; роли и рабочие пространства берутся из его ленты авторизации.

  • pacod-ap

    Каждый вызов LLM от агента проходит через шлюз, который управляет моделями, ценами, ключами и учётом использования.

  • pacod-cms

    AI-перевод в студии обращается к шлюзу, поэтому CMS никогда не хранит ключ провайдера.

  • pacod-kb

    Необязательный проход очистки через LLM в базе знаний маршрутизируется, тарифицируется и атрибутируется шлюзом.

Лицензия

Apache-2.0