Последнее обновление: 2026-06-20
Cloudflare AI Gateway — прокси-слой между Smarty и LLM-провайдерами (OpenAI, Anthropic, Google).
Применяется только в cloud/SaaS профиле поставки. Regulated-клиенты (клиники, госсектор, air-gapped) получают on-prem стек (vLLM/SGLang + Langfuse) — данные не покидают периметр.
| Функция | Описание |
|---|---|
| Semantic cache | Повторные запросы с близким смыслом → ответ из кэша без LLM-вызова |
| Model routing | Правила: GPT-4o-mini для tool-loop/FAQ, GPT-4o для сложных задач |
| Spend Limits | Бюджет на workspace/проект; превышение → отклонение, не неограниченные расходы |
| Rate limiting | Защита от runaway agent loop (R2 — cost guardrails) |
| Observability | Логи всех запросов, latency, cost, ошибки в Cloudflare dashboard |
| Fallback | Автоматический fallback на резервного провайдера при 5xx |
Unit-экономика (почему критично): ~$0.12 → ~$0.02 на диалог через routing (дешёвая модель для tool-loop/FAQ) + semantic cache. Обязательно до prod-масштаба.
Cloud / SaaS On-prem / Air-gapped
┌─────────────────────┐ ┌─────────────────────┐
│ smarty_custom │ │ smarty_custom │
│ endpoint → │ │ endpoint → │
│ CF AI Gateway │ │ vLLM / Ollama │
│ ↓ │ │ (локально) │
│ OpenAI / Anthropic │ │ │
└─────────────────────┘ └─────────────────────┘
Шов — один: провайдер smarty_custom + поле customProviderEndpoint в настройках бота.
Один и тот же код, две реализации по профилю поставки.
Cloudflare нельзя ставить в data-path regulated-клиентов — данные пациентов, госсектор, air-gapped enterprise. Для них — self-hosted стек без исключений.
https://gateway.ai.cloudflare.com/v1/{ACCOUNT_ID}/{GATEWAY_ID}/{PROVIDER}/...
Примеры:
# OpenAI через Gateway
https://gateway.ai.cloudflare.com/v1/50fdb59b7724b696fd809ca810e34278/default/openai/chat/completions
# Anthropic через Gateway
https://gateway.ai.cloudflare.com/v1/50fdb59b7724b696fd809ca810e34278/default/anthropic/v1/messages
# Google через Gateway
https://gateway.ai.cloudflare.com/v1/50fdb59b7724b696fd809ca810e34278/default/google-ai-studio/v1/models/{model}:generateContent
# Cloudflare AI Gateway
CLOUDFLARE_ACCOUNT_ID=50fdb59b7724b696fd809ca810e34278
CLOUDFLARE_AI_GATEWAY_ID=default
CLOUDFLARE_API_TOKEN=<токен из Cloudflare Dashboard, не коммитить>
# LLM провайдеры (значения остаются теми же — Gateway прозрачен)
AI_PROVIDER_OPENAI_KEY=sk-...
AI_PROVIDER_ANTHROPIC_KEY=sk-ant-...
CLOUDFLARE_API_TOKEN — секрет, хранить в .env / vault, не коммитить.
Настройка в интерфейсе Smarty, на уровне конкретного бота:
| Поле | Значение |
|---|---|
| Провайдер | smarty_custom |
| Endpoint URL | https://gateway.ai.cloudflare.com/v1/{ACCOUNT_ID}/{GATEWAY_ID}/openai |
| Модель | gpt-4o-mini (tool-loop / FAQ) или gpt-4o (сложные задачи) |
| Authorization | Bearer <CLOUDFLARE_API_TOKEN> (через поле apiToken или customProviderHeaders) |
| openaiCompatMode | true (режим по умолчанию, полная поддержка tools/tool_choice) |
Код в smarty_custom.js прозрачно проксирует запрос на указанный endpoint, добавляет:
Authorization: Bearer <apiToken> (если не задан явно в customProviderHeaders)X-API-Key: <customConnectionToken> — per-bot service token для обратной трассировкиSSRF-защита: validateURL() из lib/utils/ssrfGuard.js блокирует приватные адреса до передачи запроса. Gateway — публичный URL, проходит без проблем.
const { createOpenAI } = require('@ai-sdk/openai');
const { generateText } = require('ai');
const ACCOUNT_ID = process.env.CLOUDFLARE_ACCOUNT_ID;
const GATEWAY_ID = process.env.CLOUDFLARE_AI_GATEWAY_ID || 'default';
const openai = createOpenAI({
apiKey: process.env.CLOUDFLARE_API_TOKEN,
baseURL: `https://gateway.ai.cloudflare.com/v1/${ACCOUNT_ID}/${GATEWAY_ID}/openai`
});
const { text } = await generateText({
model: openai('gpt-4o-mini'),
prompt: '...',
maxTokens: 500
});
Флаг SMARTY_AI_SDK=true переключает стандартные провайдеры (openai/anthropic/google/deepseek)
на Vercel AI SDK через aiSdkAdapter.js. Для этого достаточно изменить baseURL в config/default.js:
// config/default.js — ai.providers.openai
openai: {
apiKey: process.env.AI_PROVIDER_OPENAI_KEY || '',
baseURL: process.env.AI_PROVIDER_OPENAI_BASE_URL
|| `https://gateway.ai.cloudflare.com/v1/${process.env.CLOUDFLARE_ACCOUNT_ID}/${process.env.CLOUDFLARE_AI_GATEWAY_ID || 'default'}/openai`
}
Gateway кэширует ответы по хэшу запроса. При семантически похожих запросах (cosine similarity > порог) возвращает кэшированный ответ — без вызова LLM.
Запрос 1 (cache miss): ~800ms, стоимость = цена токенов
Запрос 2 (cache hit): ~50ms, стоимость = $0
Полезно для:
Не включать кэш для запросов с персональными данными (ФИО, медкарты, финансы).
В Cloudflare Dashboard → AI Gateway → Settings → Spend Limits:
Per-workspace budget: $X / месяц (или суточный лимит)
На превышении: HTTP 429 → agentLoop получает error, останавливается
Kill-switch: Отключить gateway целиком через Dashboard или API
Альтернатива для on-prem — самостоятельная реализация budget-check в agentLoop.js
(перед каждым LLM-вызовом проверять счётчик в Redis).
Gateway пишет в Cloudflare Logpush:
Для коррелирования с backend-трассами добавляйте cf-aig-log-id из response headers
в metadata Langfuse trace:
// В startTrace() langfuseClient.js — уже включает otelTraceId
// Дополнительно передавать cf-aig-log-id из headers ответа smarty_custom
Скрипт smarty-dialog/lib/employeeBots/providers/test-cf-caching.js проверяет:
CLOUDFLARE_API_TOKEN=... AI_PROVIDER_OPENAI_KEY=... node smarty-dialog/lib/employeeBots/providers/test-cf-caching.js
| Ограничение | Комментарий |
|---|---|
| Только cloud-профиль | Regulated-клиенты → on-prem стек без исключений |
| Не для data-path с ПДн | Данные проходят через Cloudflare — нарушает требования GDPR/152-ФЗ для ряда клиентов |
| Cache может вернуть устаревший ответ | Для динамичного контента — отключать кэш заголовком cf-skip-cache: true |
| Gateway overhead ~30-50ms | На cache miss добавляет latency; на cache hit экономит 700+ ms |
| Spend Limits — конфиг, не код | Устанавливаются в Dashboard, не в репозитории |