Расходы
Держите расходы на модели предсказуемыми при росте нагрузки
Пропускайте каждую задачу через один OpenAI-compatible endpoint, направляйте её в самую дешёвую модель, которая справится, и записывайте расход токенов из каждого ответа.
Скопировать промпт
Замените поля в квадратных скобках и вставьте в Claude Code, Codex или любой AI с доступом к терминалу. Он установит навык Felo, спросит перед списанием кредитов и выполнит процесс.
Проверь наши расходы на модели и предложи план маршрутизации для этих задач: [список задач или функций]. Ограничения: месячный бюджет [сумма], цель по задержке [цель], планка качества [планка]. Прочитай живой каталог моделей, прежде чем что-либо рекомендовать. Подготовь: 1. Таблицу задача -> рекомендуемая модель. 2. Какие задачи можно опустить на уровень ниже и какой риск для качества. 3. План логирования использования по задачам и функциям. 4. Что измерять перед изменением продакшена. Правила: - Читай актуальные ID моделей и цены из живого каталога; никогда не цитируй тариф по памяти. - Не меняй конфигурацию продакшена и не отправляй реальный трафик. - Спрашивай перед расходом кредитов на тестовые вызовы. - Держи план отката и лимит расходов по каждой функции. - Запиши план в ./routing-plan.md и кратко изложи его в чате.
В копию также входят шаги установки и правила безопасности.
Что получится
Пример вывода одного запуска. Не живая генерация.
| Задача | Сейчас | Предложение | Риск |
|---|---|---|---|
| Классифицировать тикет | сильная модель | быстрая модель | низкий |
| Составить ответ | сильная модель | сильная модель | нет |
| Суммировать changelog | сильная модель | быстрая модель | средний |
Перед любыми изменениями: неделю логируйте использование по задачам и сравните качество на 50 выборочных выходах.
Реальные вызовы
Для разработчиков: тот же процесс в виде кода в порядке выполнения.
Показать реальные вызовы API
Все задачи через один 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 } }Маршрутизируйте модель по задаче
Выбирайте быструю или сильную модель по сложности задачи и сначала запишите текущую базу.
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 } }Читайте и записывайте использование
Берите 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 }Один ключ для всех провайдеров
Вызывайте модели из каталога одним ключом 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); }Цены — из живого каталога
Не фиксируйте тарифы; читайте текущие цены из каталога моделей и страницы цен.
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, общие токены и задержка. Затем агрегируйте по функциям и ставьте бюджет.
Сколько стоит обзор?
Чтение каталога не тратит вызовы модели. Тестовые вызовы оплачиваются по факту использования; промпт просит одобрение до вызова.
Связанные процессы
Отвечайте на вопросы поддержки по своей документации
Создайте LiveDoc, загрузите справочный центр и внутренний runbook, найдите фрагменты, отвечающие на тикет, и позвольте модели отвечать только по этим доказательствам.
Открыть рабочий процессИсследованияПревратите один вопрос в исследовательский бриф с источниками
Спросите веб, сохраните страницы, на которых основан ответ, как Markdown, добавьте мнения практиков из X и оставьте доказательства в LiveDoc, который можно будет искать позже.
Открыть рабочий процессОфисПревратите исследовательскую страницу в презентацию
Извлеките страницу, сохраните её как контекст LiveDoc, затем дайте PPT Task API собрать deck и опрашивайте задачу до готовой ссылки.
Открыть рабочий процессАдаптируйте под себя
Тот же рецепт, подстроенный под ваш реальный процесс.
Сначала только логирование
Перед продакшеном запишите неделю использования и только потом решайте о понижении.
Бюджет по функциям
Задайте месячный лимит на функцию и предупреждайте или деградируйте при превышении.
Закрепление провайдера ради задержки
Когда задержка важнее цены, закрепите провайдера и добавьте свой fallback.
Продолжить
Справочные страницы этого рецепта и куда двигаться дальше.