Felo API PlatformFelo API Platform

ต้นทุน

รักษาต้นทุนโมเดลให้คาดการณ์ได้เมื่อการใช้งานเติบโต

ส่งทุกงานผ่าน endpoint เดียวที่เข้ากันได้กับ OpenAI กำหนดเส้นทางไปโมเดลที่ถูกที่สุดที่ทำงานได้ และบันทึกการใช้โทเคนที่ทุกคำตอบคืนมา

เวลา20 นาทีระดับระดับกลางอัปเดต2026-10-29
สำหรับใครทีมแพลตฟอร์มเจ้าของผลิตภัณฑ์ APIผู้นำวิศวกรรม

คัดลอกพรอมป์ต์

แทนช่องในวงเล็บเหลี่ยมแล้ววางใน Claude Code, Codex หรือ AI ที่เข้าถึงเทอร์มินัล ระบบจะติดตั้งสกิล Felo ถามก่อนใช้เครดิต และรันเวิร์กโฟลว์

ตรวจสอบค่าใช้จ่ายโมเดลของเราและเสนอแผนการกำหนดเส้นทางสำหรับงานเหล่านี้: [รายการงานหรือฟีเจอร์]

ข้อจำกัด: งบรายเดือน [จำนวน] เป้าหมาย latency [เป้าหมาย] ระดับคุณภาพ [ระดับ]
อ่านแค็ตตาล็อกโมเดลสดก่อนแนะนำสิ่งใด

สร้าง:
1. ตารางงาน -> โมเดลที่แนะนำ
2. งานใดลดระดับได้หนึ่งขั้น และความเสี่ยงด้านคุณภาพ
3. แผนบันทึกการใช้งานตามงานและฟีเจอร์
4. สิ่งที่ต้องวัดก่อนเปลี่ยนโปรดักชัน

กฎ:
- อ่าน ID และราคาโมเดลปัจจุบันจากแค็ตตาล็อกสด ห้ามอ้างราคาจากความจำ
- ห้ามเปลี่ยนการตั้งค่าโปรดักชันหรือส่งทราฟฟิกจริง
- ถามก่อนใช้เครดิตในการเรียกทดสอบ
- เก็บแผน rollback และเพดานการใช้จ่ายต่อฟีเจอร์
- เขียนแผนลง ./routing-plan.md และสรุปในแชท

สำเนายังรวมขั้นตอนติดตั้งและกฎความปลอดภัย

สิ่งที่คุณได้รับ

ตัวอย่างผลลัพธ์จากการรันหนึ่งครั้ง ไม่ใช่การสร้างสด

ตัวอย่างแผนเส้นทาง (ตัดตอน)
งานปัจจุบันเสนอความเสี่ยง
จำแนกตั๋วโมเดลแรงโมเดลเร็วต่ำ
ร่างคำตอบโมเดลแรงโมเดลแรงไม่มี
สรุป changelogโมเดลแรงโมเดลเร็วกลาง

ก่อนเปลี่ยนอะไร: บันทึกการใช้งานต่องานหนึ่งสัปดาห์ และเปรียบเทียบคุณภาพใน 50 ตัวอย่างผลลัพธ์

การเรียกที่แน่นอน

สำหรับนักพัฒนา: เวิร์กโฟลว์เดียวกันในรูปโค้ดตามลำดับการทำงาน

แสดงการเรียก API จริง
  1. ทุกงานผ่าน endpoint เดียว

    ใช้ endpoint เดียวที่เข้ากันได้กับ OpenAI และคีย์เดียว ไม่มี 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 และราคาเปลี่ยน ต้องอ่านแคตตาล็อกสดเสมอ
  • ไม่ประเมินคุณภาพแทนคุณ ต้องมีตัวอย่างของคุณ
  • ไม่แทนที่ระบบเรียกเก็บเงินหรือ observability

คำถาม

ใบแจ้งหนี้จะลดไหม?

บอกว่างานใดลดระดับได้ แต่การประหยัดจริงหลังเทียบตัวอย่างและบันทึกการใช้แล้วเท่านั้น

เรียกโมเดลอัตโนมัติไหม?

เฉพาะเมื่อคุณอนุมัติการเรียกทดสอบ ค่าเริ่มต้นอ่านแคตตาล็อกและเขียนข้อเสนอโดยไม่แตะทราฟฟิกโปรดักชัน

รู้ได้อย่างไรว่าโมเดลใดถูกกว่า?

อ่านแคตตาล็อกโมเดลสดและหน้าค่าบริการ เวิร์กโฟลว์ไม่ตรึงราคาเพราะเปลี่ยน

ตรึงผู้ให้บริการได้ไหม?

ได้เมื่อความหน่วงสำคัญกว่าราคา การตรึงเป็นการเลือก ไม่ใช่กลยุทธ์ retry ให้เพิ่ม fallback ของคุณ

ควรบันทึกอะไร?

ต่อการเรียก: งาน ฟีเจอร์ โมเดล prompt token, completion token, รวม และความหน่วง รวมตามฟีเจอร์ก่อนตั้งงบ

การทบทวนหนึ่งครั้งมีค่าใช้จ่ายเท่าไร?

อ่านแคตตาล็อกไม่สร้างการเรียกโมเดล การเรียกทดสอบคิดตามการใช้งาน พรอมป์ต์ขออนุมัติก่อน

เวิร์กโฟลว์ที่เกี่ยวข้อง

ปรับให้เป็นของคุณ

สูตรเดิม ปรับตามวิธีที่คุณส่งมอบจริง

บันทึกก่อนเท่านั้น

ก่อนโปรดักชัน บันทึกการใช้งานหนึ่งสัปดาห์แล้วตัดสินใจลดระดับ

งบต่อฟีเจอร์

ตั้งวงเงินรายเดือนต่อฟีเจอร์และเตือนหรือลดระดับเมื่อเกิน

ตรึงผู้ให้บริการเพื่อความหน่วง

เมื่อความหน่วงสำคัญกว่าราคา ตรึงผู้ให้บริการและเพิ่ม fallback

หน้าเอกสารอ้างอิงเบื้องหลังสูตรนี้และก้าวต่อไป