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 に書き、チャットで要約してください。

コピー内容にはインストール手順と安全ルールも含まれます。

完成するもの

実行時の出力例です。リアルタイム生成ではありません。

ルーティング計画の例(抜粋)
タスク現在提案リスク
チケット分類強いモデル速いモデル低
返信下書き強いモデル強いモデルなし
変更履歴の要約強いモデル速いモデル中

変更する前に: 1週間、タスクごとの利用を記録し、無作為に選んだ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 を読み、機能ごとに token とレイテンシを記録します。

    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. 1つのキーですべてのプロバイダーを扱う

    同じ 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、合計 token、レイテンシを記録します。機能別に集計してから予算を設定します。

1回のレビュー費用は?

カタログ読み取りはモデル呼び出しを発生させません。テスト呼び出しは従量制で、プロンプトは呼び出し前に確認を求めます。

関連ワークフロー

自分の形に変える

同じレシピを、実際の進め方に合わせて調整します。

まず記録だけ行う

本番前に1週間使用量を記録してからダウングレードを判断します。

機能ごとに予算を設定する

各機能に月次上限を設定し、超過時に警告または縮退します。

レイテンシ優先でプロバイダー固定

レイテンシが価格より重要な場合、プロバイダーを固定し独自の fallback を加えます。

このレシピの背景にあるリファレンスと、次に見るべきページ。