Felo API PlatformFelo API Platform

Расходы

Держите расходы на модели предсказуемыми при росте нагрузки

Пропускайте каждую задачу через один OpenAI-compatible endpoint, направляйте её в самую дешёвую модель, которая справится, и записывайте расход токенов из каждого ответа.

Время20 минутУровеньСреднийОбновлено2026-10-29
Для когоПлатформенные командыВладельцы API-продуктовИнженерные руководители

Скопировать промпт

Замените поля в квадратных скобках и вставьте в Claude Code, Codex или любой AI с доступом к терминалу. Он установит навык Felo, спросит перед списанием кредитов и выполнит процесс.

Проверь наши расходы на модели и предложи план маршрутизации для этих задач: [список задач или функций].

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

Подготовь:
1. Таблицу задача -> рекомендуемая модель.
2. Какие задачи можно опустить на уровень ниже и какой риск для качества.
3. План логирования использования по задачам и функциям.
4. Что измерять перед изменением продакшена.

Правила:
- Читай актуальные ID моделей и цены из живого каталога; никогда не цитируй тариф по памяти.
- Не меняй конфигурацию продакшена и не отправляй реальный трафик.
- Спрашивай перед расходом кредитов на тестовые вызовы.
- Держи план отката и лимит расходов по каждой функции.
- Запиши план в ./routing-plan.md и кратко изложи его в чате.

В копию также входят шаги установки и правила безопасности.

Что получится

Пример вывода одного запуска. Не живая генерация.

Пример плана маршрутизации (фрагмент)
ЗадачаСейчасПредложениеРиск
Классифицировать тикетсильная модельбыстрая модельнизкий
Составить ответсильная модельсильная модельнет
Суммировать changelogсильная модельбыстрая модельсредний

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

Реальные вызовы

Для разработчиков: тот же процесс в виде кода в порядке выполнения.

Показать реальные вызовы API
  1. Все задачи через один endpoint

    Используйте единый OpenAI-compatible endpoint и ключ, чтобы не держать SDK для каждого провайдера.

    routing.ts
    const BASE_URL = "https://openapi.felo.ai/api/v1";
    const headers = {
      Authorization: `Bearer ${process.env.FELO_API_KEY}`,
      "Content-Type": "application/json",
    };
    
    type Completion = {
      choices: { message: { content: string } }[];
      usage: { prompt_tokens: number; completion_tokens: number; total_tokens: number };
    };
    
    async function chat(model: string, prompt: string): Promise<Completion> {
      const res = await fetch(`${BASE_URL}/chat/completions`, {
        method: "POST",
        headers,
        body: JSON.stringify({ model, messages: [{ role: "user", content: prompt }] }),
      });
      if (!res.ok) throw new Error(`${res.status}: ${await res.text()}`);
      return res.json() as Promise<Completion>;
    }
    
    const summary = await chat(
      "claude-haiku-5-5",
      "Summarize this changelog in three bullets: …",
    );
    console.log(summary.choices[0].message.content);

    Пример вывода

    {
      "choices": [{ "message": { "content": "• …" } }],
      "usage": { "prompt_tokens": 812, "completion_tokens": 96, "total_tokens": 908 }
    }
  2. Маршрутизируйте модель по задаче

    Выбирайте быструю или сильную модель по сложности задачи и сначала запишите текущую базу.

    routing.ts
    type TaskKind = "classify" | "extract" | "summarize" | "draft" | "review";
    
    const MODEL_ROUTES: Record<TaskKind, string> = {
      classify: "claude-haiku-5-5",
      extract: "claude-haiku-5-5",
      summarize: "claude-haiku-5-5",
      draft: "claude-sonnet-5-5",
      review: "claude-sonnet-5-5",
    };
    
    export async function route(kind: TaskKind, prompt: string) {
      const model = MODEL_ROUTES[kind];
      const result = await chat(model, prompt);
      return {
        model,
        text: result.choices[0].message.content,
        usage: result.usage,
      };
    }

    Пример вывода

    {
      "model": "claude-haiku-5-5",
      "text": "• …",
      "usage": { "prompt_tokens": 812, "completion_tokens": 96, "total_tokens": 908 }
    }
  3. Читайте и записывайте использование

    Берите usage из каждого ответа и записывайте токены и задержку по функциям.

    routing.ts
    type UsageRecord = {
      model: string;
      kind: TaskKind;
      promptTokens: number;
      completionTokens: number;
      totalTokens: number;
    };
    
    const usageLog: UsageRecord[] = [];
    
    function logUsage(kind: TaskKind, model: string, usage: Completion["usage"]) {
      const entry: UsageRecord = {
        model,
        kind,
        promptTokens: usage.prompt_tokens,
        completionTokens: usage.completion_tokens,
        totalTokens: usage.total_tokens,
      };
      usageLog.push(entry);
      console.log(JSON.stringify(entry)); // ship this line to your metrics store
      return entry;
    }
    
    export function tokensByModel() {
      return usageLog.reduce<Record<string, number>>((totals, entry) => {
        totals[entry.model] = (totals[entry.model] ?? 0) + entry.totalTokens;
        return totals;
      }, {});
    }
    
    const result = await route("summarize", "Summarize this changelog in three bullets: …");
    logUsage("summarize", result.model, result.usage);
    console.log(tokensByModel());

    Пример вывода

    {"model":"claude-haiku-5-5","kind":"summarize","promptTokens":812,"completionTokens":96,"totalTokens":908}
    { "claude-haiku-5-5": 18234, "claude-sonnet-5-5": 4201 }
  4. Один ключ для всех провайдеров

    Вызывайте модели из каталога одним ключом Felo и упростите управление провайдерами.

    routing.ts
    async function chatOnChannel(model: string, prompt: string, channel?: string) {
      const res = await fetch(`${BASE_URL}/chat/completions`, {
        method: "POST",
        headers: {
          ...headers,
          ...(channel ? { "X-Felo-Channel": channel } : {}),
        },
        body: JSON.stringify({ model, messages: [{ role: "user", content: prompt }] }),
      });
      if (!res.ok) throw new Error(`${res.status}: ${await res.text()}`);
      return res.json() as Promise<Completion>;
    }
    
    // Leave `channel` undefined for the default supplier.
    export function routePinned(kind: TaskKind, prompt: string, channel?: string) {
      return chatOnChannel(MODEL_ROUTES[kind], prompt, channel);
    }
  5. Цены — из живого каталога

    Не фиксируйте тарифы; читайте текущие цены из каталога моделей и страницы цен.

    routing.ts
    type Catalog = {
      data: { id: string; owned_by: string; model_kind: string }[];
    };
    
    export async function chatModelIds() {
      const res = await fetch(
        `${BASE_URL}/models?exclude_video_and_decisions=true`,
        { headers },
      );
      if (!res.ok) throw new Error(`${res.status}: ${await res.text()}`);
      const catalog = (await res.json()) as Catalog;
      return catalog.data
        .filter((model) => model.model_kind === "chat")
        .map((model) => model.id);
    }
    
    // Price `tokensByModel()` against https://openapi.felo.ai/pricing and
    // https://openapi.felo.ai/models. Keep the links, not the rates, in your code.

    Пример вывода

    ["claude-haiku-5-5", "claude-sonnet-5-5"]

Что входит

  • Единый endpoint и ключ
  • Выбор быстрой или сильной модели по задаче
  • Лог токенов из каждого ответа
  • Цены из живого каталога, а не из кода

Чего не делает

  • Не гарантирует снижение счёта
  • Не переключает продакшен-трафик автоматически
  • ID моделей и цены меняются; всегда читайте живой каталог
  • Не оценивает качество за вас; нужны свои примеры
  • Не заменяет биллинг или систему наблюдаемости

Вопросы

Счёт уменьшится?

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

Он сам вызывает модели?

Только если вы одобрите тестовые вызовы. По умолчанию он читает каталог и пишет рекомендации, не трогая продакшен-трафик.

Как понять, какая модель дешевле?

Читайте живой каталог моделей и страницу цен; процесс не фиксирует тарифы, потому что они меняются.

Можно закрепить провайдера?

Да, когда задержка важнее цены. Закрепление — выбор, а не стратегия повторов; fallback добавляйте сами.

Что логировать?

Для каждого вызова: задача, функция, модель, prompt token, completion token, общие токены и задержка. Затем агрегируйте по функциям и ставьте бюджет.

Сколько стоит обзор?

Чтение каталога не тратит вызовы модели. Тестовые вызовы оплачиваются по факту использования; промпт просит одобрение до вызова.

Связанные процессы

Адаптируйте под себя

Тот же рецепт, подстроенный под ваш реальный процесс.

Сначала только логирование

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

Бюджет по функциям

Задайте месячный лимит на функцию и предупреждайте или деградируйте при превышении.

Закрепление провайдера ради задержки

Когда задержка важнее цены, закрепите провайдера и добавьте свой fallback.

Справочные страницы этого рецепта и куда двигаться дальше.