Pilih Auto, TokenLab Verified, atau Official untuk setiap permintaan, dengan harga yang ditampilkan di awal.Lihat yang baru

Membangun Chatbot AI dengan Satu API Key: Dari Nol hingga Produksi dalam 30 Menit

·19 September 2026·15 menit baca·Diperbarui 2 Oktober 2026·2789 tampilan
#chatbot#tutorial#python#fastapi#streaming
Membangun Chatbot AI dengan Satu API Key: Dari Nol hingga Produksi dalam 30 Menit

Anda dapat membangun AI chatbot yang melakukan streaming satu balasan dalam satu sore. Menjaganya tetap hidup setelah 429 pertama adalah pekerjaan yang sebenarnya. Kami membangun layanan FastAPI kecil dengan streaming SSE, memori percakapan sisi server, dan daftar izinkan (allowlist) model, semuanya di balik satu kunci TokenLab. Tujuannya adalah backend yang dapat Anda letakkan di balik antarmuka produk nyata dan mengubah model tanpa menulis ulang integrasi. Jika Anda belum melakukan penukaran base URL, baca panduan migrasi terlebih dahulu. Jika kekhawatiran utama Anda adalah backoff di bawah beban, pasangkan panduan ini dengan panduan pembatasan laju AI API.

Poin Penting

  • Chatbot yang siap produksi membutuhkan enam bagian: endpoint sinkron, endpoint streaming, status percakapan sisi server, daftar izinkan model, penanganan error nyata, dan jalur peningkatan penyimpanan.
  • Muat kunci dari TOKENLAB_API_KEY di setiap proses dan simpan di server. Dokumentasi autentikasi (diamati 2026-10-03) menyatakan jangan pernah mengekspos kunci dalam kode sisi klien atau melakukan commit pada kunci tersebut.
  • GET /v1/models bersifat publik, jadi respons yang berhasil tidak membuktikan kunci Anda berfungsi. Buktikan dengan satu permintaan chat nyata (Quickstart, diamati 2026-10-03).
  • SSE mencakup sebagian besar produk chat. Perlakukan stream yang mati setelah output tiba sebagai tidak lengkap, bukan sebagai jawaban selesai.
  • Daftar izinkan dalam panduan ini memetakan tier ke deepseek-v4-flash, gpt-5.5, claude-sonnet-5, dan gemini-3.5-flash. Masing-masing mencantumkan openai_chat_completions sebagai format yang diterima (diamati 2026-10-03).
  • Sebagai perkiraan dari harga di bawah, satu giliran dengan 2.000 token input dan 500 token output menelan biaya sekitar $0,0006 hingga $0,0075, tergantung pada modelnya.

Membangun AI Chatbot: Pengaturan dan Layanan Inti

Layanan yang sudah jadi memiliki enam bagian yang bergerak:

  1. Endpoint /chat sinkron untuk pengujian smoke test.
  2. Endpoint /chat/stream streaming untuk UI nyata.
  3. Status percakapan yang dikunci oleh conversation_id.
  4. Daftar izinkan model, sehingga frontend tidak dapat meminta ID arbitrer.
  5. Penanganan error yang tidak runtuh pada 429 pertama.
  6. Jalur dari prototipe dalam memori ke Redis atau PostgreSQL.

Itu sudah cukup untuk bot dukungan, asisten internal, atau versi pertama dari widget chat tertanam. Setiap blok kode di bawah ini ditambahkan ke satu file, main.py, dalam urutan yang ditampilkan.

Langkah 1: Atur kunci dan instal stack

Buat kunci di bawah API Keys di workspace Anda. Nilai lengkapnya hanya ditampilkan sekali, dan awalan dalam daftar kunci tidak dapat mengautentikasi permintaan. Semua kunci TokenLab dimulai dengan sk-. Periksa saldo Anda di Billing juga, karena permintaan pertama ditagih sesuai harga model saat ini (Quickstart, diamati 2026-10-03).

Simpan kunci dalam variabel lingkungan, jangan pernah di sumber. Prompt di bawah ini menjaganya agar tidak masuk ke baris perintah dan riwayat shell, dan hanya berlaku untuk terminal saat ini serta proses turunannya. Gunakan pengelola rahasia untuk aplikasi yang dideploy. Quickstart juga memiliki versi PowerShell.

printf 'TokenLab API key: '
read -r -s TOKENLAB_API_KEY
printf '\n'
export TOKENLAB_API_KEY
pip install fastapi uvicorn openai pydantic

Anda tidak memerlukan SDK khusus TokenLab. SDK OpenAI resmi berfungsi setelah Anda mengubah kunci dan base URL (panduan SDK, diamati 2026-10-03).

Langkah 2: Tentukan skema, daftar izinkan, dan memori

Kita mulai dengan bagian yang dibagikan. Skema permintaan menggunakan tier, bukan string model mentah, dan setiap contoh curl nanti dalam panduan ini mengirimkan bidang yang sama.

Demo chatbot pertama biasanya menyimpan transkrip di browser dan mengirimnya kembali setiap giliran. Misalnya, itu berfungsi untuk prototipe. Hal ini menjadi berantakan setelah Anda memerlukan percobaan ulang, sesi yang dapat dilanjutkan, atau alat sisi server. Jadi server memiliki riwayat sejak awal.

import json
import logging
import os
import time
import uuid
from collections import defaultdict

from fastapi import FastAPI, HTTPException
from fastapi.responses import StreamingResponse
from openai import APIConnectionError, APIStatusError, OpenAI, RateLimitError
from pydantic import BaseModel, Field

log = logging.getLogger("chatbot")
app = FastAPI()

client = OpenAI(
    api_key=os.environ["TOKENLAB_API_KEY"],
    base_url="https://api.tokenlab.sh/v1",
    timeout=30.0,
    max_retries=0,
)

ALLOWED_MODELS = {
    "default": "deepseek-v4-flash",
    "flagship": "gpt-5.5",
    "balanced": "claude-sonnet-5",
    "budget": "gemini-3.5-flash",
}
SYSTEM_PROMPT = "You are a helpful assistant. Be concise and direct."
MAX_HISTORY = 20          # pesan disimpan per percakapan (pilihan Anda)
MAX_REPLY_TOKENS = 1000   # batas output per giliran (pilihan Anda)

class ChatRequest(BaseModel):
    message: str = Field(min_length=1, max_length=4000)
    tier: str = "default"
    conversation_id: str | None = None

def resolve_model(tier: str) -> str:
    model = ALLOWED_MODELS.get(tier)
    if model is None:
        raise HTTPException(status_code=400, detail=f"unknown tier: {tier}")
    return model

conversations: dict[str, list[dict]] = defaultdict(list)

def build_messages(conv_id: str, user_msg: str) -> list[dict]:
    history = conversations[conv_id][-MAX_HISTORY:]
    return [
        {"role": "system", "content": SYSTEM_PROMPT},
        *history,
        {"role": "user", "content": user_msg},
    ]

def remember(conv_id: str, user_msg: str, reply: str) -> None:
    conversations[conv_id].append({"role": "user", "content": user_msg})
    conversations[conv_id].append({"role": "assistant", "content": reply})

Klien menetapkan max_retries=0 dan timeout 30 detik, sesuai dengan Quickstart. Kami membuat keputusan percobaan ulang sendiri, karena percobaan ulang SDK buta pada giliran yang di-stream dapat mengulangi biaya.

Langkah 3: Petakan error dan tambahkan endpoint sinkron

Kami menyimpan satu fungsi kecil yang mengubah pengecualian SDK apa pun menjadi kode status dan pesan yang aman bagi pengguna. Detailnya masuk ke log Anda, bukan ke pengguna.

def describe_error(exc: Exception) -> tuple[int, str]:
    if isinstance(exc, RateLimitError):  # periksa dulu: ini adalah subkelas dari APIStatusError
        return 429, "The assistant is busy. Please retry shortly."
    if isinstance(exc, APIConnectionError):
        return 502, "Connection problem. Please retry."
    if isinstance(exc, APIStatusError):
        log.error("upstream status=%s code=%s", exc.status_code, exc.code)
        if exc.status_code in (401, 402, 403):  # kunci, saldo, atau izin: masalah operator
            return 503, "The assistant is unavailable right now."
        if exc.status_code in (400, 404):  # bidang buruk atau ID model: bug kami
            return 500, "Something went wrong on our side."
        return 502, "The assistant is unavailable right now."
    return 500, "Something went wrong."

def retry_delay(exc: RateLimitError) -> float:
    try:
        return min(float(exc.response.headers.get("retry-after", "2")), 10.0)
    except ValueError:
        return 2.0

def create_with_one_retry(**kwargs):
    try:
        return client.chat.completions.create(**kwargs)
    except RateLimitError as exc:
        time.sleep(retry_delay(exc))
        return client.chat.completions.create(**kwargs)

@app.post("/chat")
def chat(req: ChatRequest):
    model = resolve_model(req.tier)
    conv_id = req.conversation_id or str(uuid.uuid4())
    messages = build_messages(conv_id, req.message)
    try:
        response = create_with_one_retry(
            model=model, messages=messages, max_tokens=MAX_REPLY_TOKENS
        )
    except (APIConnectionError, APIStatusError) as exc:
        status, message = describe_error(exc)
        raise HTTPException(status_code=status, detail=message)
    reply = response.choices[0].message.content or ""
    log.info("model=%s usage=%s", model, response.usage)
    remember(conv_id, req.message, reply)
    return {"conversation_id": conv_id, "reply": reply}

Jalankan satu permintaan sebelum membangun apa pun. Jika ini gagal, jangan terus membangun di atasnya.

Stream Balasan dan Jaga AI Chatbot Tetap Responsif

Sebagian besar produk chatbot terasa lambat bukan karena modelnya lambat, tetapi karena UI tetap kosong sampai respons penuh mendarat. Kami menambahkan SSE karena mencakup sebagian besar produk chat dan membawa beban operasional yang lebih sedikit daripada websocket. Jika produk Anda sudah menjalankan klien browser melalui HTTP biasa, SSE menjaga arsitektur tetap lebih sederhana.

Langkah 4: Tambahkan endpoint streaming

Dokumentasi streaming (panduan Streaming, diamati 2026-10-03) menjaga streaming Chat Completions tetap valid untuk framework yang sudah mengharapkan potongan SSE dari /v1/chat/completions. Kami tetap pada jalur itu karena keempat model yang diizinkan menerimanya. Kami mengenkode setiap event sebagai JSON, sehingga baris baru di dalam balasan tidak dapat merusak framing.

def sse(payload: dict) -> str:
    return f"data: {json.dumps(payload)}\n\n"

@app.post("/chat/stream")
def chat_stream(req: ChatRequest):
    model = resolve_model(req.tier)
    conv_id = req.conversation_id or str(uuid.uuid4())
    messages = build_messages(conv_id, req.message)

    def generate():
        parts: list[str] = []
        finish_reason = None
        try:
            with client.chat.completions.create(
                model=model,
                messages=messages,
                max_tokens=MAX_REPLY_TOKENS,
                stream=True,
                stream_options={"include_usage": True},
            ) as stream:
                for chunk in stream:
                    if chunk.usage:
                        log.info("model=%s usage=%s", model, chunk.usage)
                    if not chunk.choices:
                        continue
                    choice = chunk.choices[0]
                    if choice.delta.content:
                        parts.append(choice.delta.content)
                        yield sse({"delta": choice.delta.content})
                    if choice.finish_reason:
                        finish_reason = choice.finish_reason
        except (APIConnectionError, APIStatusError) as exc:
            _, message = describe_error(exc)
            yield sse({"error": message})
            return
        if finish_reason != "stop":
            yield sse({"error": f"Reply incomplete ({finish_reason})."})
            return
        remember(conv_id, req.message, "".join(parts))
        yield sse({"done": True, "conversation_id": conv_id})

    return StreamingResponse(generate(), media_type="text/event-stream")

Dua detail penting di sini. Pertama, include_usage: true menambahkan penggunaan token ke potongan stream, dan potongan penggunaan akhir tidak memiliki choices, jadi loop melewatinya. Kedua, kami menyimpan giliran hanya ketika finish_reason adalah stop. Penyelesaian length berarti batas token memotong balasan, dan dokumentasi mencantumkan keduanya sebagai kondisi akhir yang normal.

Karena error muncul di dalam generator, status HTTP sudah 200 saat kegagalan terjadi. Klien harus membaca event error. Blok with menutup stream upstream saat generator keluar. Dokumentasi menyarankan untuk membatalkan upstream saat pengguna berhenti atau terputus, jadi uji apakah server ASGI Anda benar-benar menghentikan generator saat terputus.

Langkah 5: Baca stream di browser

Browser harus memanggil backend Anda sendiri yang terautentikasi dan tidak pernah memanggil TokenLab secara langsung. Parse berdasarkan batas event, karena satu potongan jaringan belum tentu satu event SSE yang lengkap.

async function sendMessage(payload, onDelta) {
  const response = await fetch('/chat/stream', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(payload), // { message, tier, conversation_id }
  });
  if (!response.ok || !response.body) throw new Error(`HTTP ${response.status}`);

  const reader = response.body.getReader();
  const decoder = new TextDecoder();
  let buffer = '';

  while (true) {
    const { done, value } = await reader.read();
    if (done) break;
    buffer += decoder.decode(value, { stream: true });
    const events = buffer.split('\n\n');
    buffer = events.pop();
    for (const raw of events) {
      if (!raw.startsWith('data: ')) continue;
      const event = JSON.parse(raw.slice(6));
      if (event.error) throw new Error(event.error);
      if (event.delta) onDelta(event.delta);
    }
  }
}

Tingkatkan memori ke Redis saat Anda membutuhkannya

Kamus dalam memori baik untuk satu proses. Gunakan Redis saat percakapan memerlukan TTL, kemampuan untuk dilanjutkan, atau beberapa instance. Gunakan PostgreSQL saat transkrip adalah data produk yang harus Anda kueri, audit, atau laporkan. Perubahan Redis adalah pemipaan penyimpanan, bukan logika. Jalankan pip install redis, lalu buat build_messages dan remember membaca serta menulis melalui helper ini.

import redis

redis_client = redis.Redis(
    host=os.environ.get("REDIS_HOST", "127.0.0.1"), port=6379, decode_responses=True
)

def load_history(conv_id: str) -> list:
    raw = redis_client.get(f"chat:{conv_id}")
    return json.loads(raw) if raw else []

def save_history(conv_id: str, history: list) -> None:
    redis_client.setex(f"chat:{conv_id}", 60 * 60 * 24, json.dumps(history))

Tangani Error Saat Anda Membangun AI Chatbot untuk Produksi

Pengguna yang berhadapan dengan pelanggan tidak peduli apakah kegagalan berasal dari pembatasan laju, saldo kosong, atau pemadaman upstream. Mereka peduli apakah UI membeku. Bayangkan widget dukungan yang stream-nya mati setelah empat puluh kata. Dokumentasi TokenLab mengatakan stream yang terputus setelah output tiba bukanlah respons lengkap, dan mengulanginya dapat menghasilkan output yang berbeda dan biaya kedua (Tangani error API, diamati 2026-10-03). Itulah mengapa Langkah 4 tidak pernah menyimpan giliran yang belum selesai.

Langkah 6: Terapkan aturan percobaan ulang

Tangani error berdasarkan status HTTP dan code, bukan berdasarkan message yang dapat dibaca manusia, yang dapat berubah tanpa pemberitahuan. Tabel ini menggabungkan dokumentasi dengan apa yang dilakukan layanan kami.

Status Arti (per dokumentasi) Apa yang dilakukan layanan ini
400 Bidang, ID model, atau input tidak valid Kembalikan 500, catat, jangan pernah coba lagi
401 Kunci hilang, tidak valid, kedaluwarsa, atau dicabut Kembalikan 503, peringatkan operator
402 Saldo atau batas API-key terlalu rendah (insufficient_balance, quota_exceeded) Kembalikan 503, peringatkan operator
403 Kunci tidak dapat menggunakan model ini Kembalikan 503, periksa daftar model kunci
404 Sumber daya atau model tidak ditemukan Kembalikan 500, periksa ID terhadap /v1/models
429 Batas permintaan tercapai Tunggu Retry-After, coba lagi sekali (hanya sinkron)
500–504 Layanan tidak tersedia atau kegagalan jaringan Coba lagi hanya jika retryable adalah true; hormati retry_after

Dua peringatan dari dokumentasi. 503 all_channels_failed tidak selalu berarti pemadaman sementara. Jika retryable adalah false, jangan ulangi permintaan yang sama, dan periksa GET /v1/models sebelum memilih model lain. Selain itu, Chat Completions dan Responses menggunakan objek error gaya OpenAI, tetapi Anthropic Messages dan Gemini menyimpan format mereka sendiri. Layanan kami memanggil Chat Completions pada setiap model yang diizinkan, jadi satu parser berfungsi. Jika Anda memindahkan tier ke format asli, Anda memerlukan parser kedua.

Simpan ID Permintaan dari header respons dengan endpoint, model, waktu, dan ID pengguna atau pekerjaan Anda sendiri. Dokumentasi tidak menyebutkan header di halaman yang kami gunakan, jadi konfirmasikan terhadap jalur pemecahan masalah sebelum Anda menghubungkan log Anda.

Sisa daftar periksa produksi singkat:

  • Tambahkan ID permintaan Anda sendiri agar Anda dapat menghubungkan kegagalan frontend ke log backend.
  • Batasi konkurensi per pengguna dan ukuran permintaan. max_length=4000 pada message adalah titik awal yang harus Anda sesuaikan.
  • Batasi riwayat berdasarkan jumlah pesan, seperti yang dilakukan MAX_HISTORY. Dokumentasi penagihan mengatakan tokenisasi berbeda berdasarkan model, bahasa, dan input media, jadi rumus jumlah karakter bukanlah perkiraan penagihan yang andal.
  • Catat model, latensi, penggunaan, dan alasan penyelesaian pada setiap giliran.
  • Jaga agar pesan yang terlihat pengguna tetap terpisah dari detail error internal.
  • Kirim satu giliran pengujian ke tier alternatif, sehingga Anda tahu fallback berfungsi sebelum pemadaman nyata pertama.

Pilih Model dan Perkirakan Biaya untuk AI Chatbot Anda

Jangan pernah biarkan frontend meneruskan string model arbitrer ke API. Bidang teks bebas mengundang kesalahan ketik, model yang sudah pensiun, dan model yang tidak pernah Anda maksudkan untuk diekspos. Peta ALLOWED_MODELS memberi Anda satu tempat untuk menukar model saat penyedia menghentikan satu model, tanpa pembaruan klien. ID model yang tidak dikenal mengembalikan model_not_found, dan dokumentasi mengarahkan Anda ke /v1/models untuk ID saat ini. Periksa direktori model sebelum Anda mengunci daftar izinkan.

Harga saat ini per 1 juta token

Ini adalah harga TokenLab dalam USD dari entri API langsung setiap model, diamati 2026-10-03. Harga terakhir diperbarui 2026-10-02T16:53:30.068Z. Keempat model menunjukkan tahap siklus hidup active.

Tier ID Model Input / 1M Output / 1M Cache read / 1M Sumber
default deepseek-v4-flash (off-peak) $0.15 $0.60 $0.003 model API
default deepseek-v4-flash (peak) $0.30 $1.20 $0.006 model API
flagship gpt-5.5 $1.50 $9.00 $0.15 model API
balanced claude-sonnet-5 $0.90 $4.50 $0.09 model API
budget gemini-3.5-flash $0.75 $4.50 $0.075 model API

Untuk deepseek-v4-flash, entri mencantumkan jendela puncak pada hari kerja, tidak termasuk hari libur nasional Tiongkok. Off-peak mencakup akhir pekan dan hari libur tersebut. claude-sonnet-5 juga mencantumkan harga tulis cache sebesar $1,125 per 1 juta token.

Satu permintaan yang berhasil

Asumsikan satu giliran dengan 2.000 token input dan 500 token output. Ukuran itu adalah asumsi kami, bukan pengukuran. Untuk gpt-5.5:

  • Input: 2.000 × $1,50 / 1.000.000 = $0,0030
  • Output: 500 × $9,00 / 1.000.000 = $0,0045
  • Total: $0,0075 per giliran (perkiraan, tidak ada cache hit)

Menggunakan aritmatika yang sama, kita mendapatkan perkiraan ini: deepseek-v4-flash menelan biaya $0,0006 saat off-peak dan $0,0012 saat peak, claude-sonnet-5 menelan biaya $0,00405, dan gemini-3.5-flash menelan biaya $0,00375. Selama 1.000 giliran tersebut, itu kira-kira $7,50 pada gpt-5.5 dibandingkan $0,60 hingga $1,20 pada deepseek-v4-flash. Giliran nyata tumbuh seiring akumulasi riwayat, jadi baca usage dari respons atau potongan stream akhir daripada mempercayai ukuran ini.

Dalam praktiknya, kami merutekan sebagian besar percakapan ke tier default dan mencadangkan gpt-5.5 atau claude-sonnet-5 untuk giliran yang membutuhkannya. Dokumentasi penagihan memperingatkan bahwa harga terendah per token tidak selalu merupakan biaya terendah per tugas yang diselesaikan. Jalankan prompt yang sama melalui dua tier dan bandingkan biaya akhir di Usage.

Dua pemeriksaan sebelum Anda mengirim. Dokumentasi penagihan mengatakan jangan melakukan hard-code pada tabel harga yang disalin, jadi baca GET /v1/models/:model/pricing jika aplikasi Anda menampilkan biaya (Penagihan dan harga, diamati 2026-10-03). Selain itu, entri deepseek-v4-flash mencantumkan json-mode, prompt-cache, dan tool-use tetapi tidak vision. Jika chatbot Anda menerima gambar, rutekan giliran tersebut ke tier yang entri-nya mencantumkan vision.

Smoke Test dan Kirim AI Chatbot Anda

Langkah 7: Jalankan dari ujung ke ujung

Jalankan server di terminal di mana TOKENLAB_API_KEY diekspor. Payload curl menggunakan bidang message, tier, dan conversation_id yang sama dengan ChatRequest.

uvicorn main:app --reload --port 8000
# 1. Endpoint sinkron: harapkan balasan singkat dan conversation_id
curl -X POST http://localhost:8000/chat \
  -H "Content-Type: application/json" \
  -d '{"message": "Reply only with OK.", "tier": "default"}'

# 2. Streaming: harapkan baris data: {"delta": ...}, lalu {"done": true, ...}
curl -N -X POST http://localhost:8000/chat/stream \
  -H "Content-Type: application/json" \
  -d '{"message": "Hello!", "tier": "default"}'

# 3. Memori: gunakan kembali conversation_id yang dikembalikan di atas
curl -X POST http://localhost:8000/chat \
  -H "Content-Type: application/json" \
  -d '{"message": "What did I just say?", "tier": "default", "conversation_id": "PASTE_ID_FROM_STEP_1"}'

# 4. Kegagalan paksa: harapkan HTTP 400 dan "unknown tier: nope"
curl -i -X POST http://localhost:8000/chat \
  -H "Content-Type: application/json" \
  -d '{"message": "Hello!", "tier": "nope"}'

Untuk memaksa kegagalan upstream, mulai ulang server dengan TOKENLAB_API_KEY yang salah. Klien Anda harus mendapatkan pesan 503 yang bersih, dan log Anda harus menunjukkan 401 upstream dengan invalid_api_key. Kemudian buka Requests untuk mengonfirmasi model, status, dan penggunaan panggilan yang berhasil. Jika Anda dapat melakukan stream satu giliran, mempertahankan satu percakapan, dan mengembalikan error yang bersih pada kegagalan paksa, Anda memiliki fondasi yang tepat.

Setelah itu, peningkatan berikutnya adalah infrastruktur yang membosankan daripada AI tambahan:

  • Autentikasi, sehingga satu pengguna tidak dapat membaca percakapan pengguna lain.
  • Persistensi, sehingga sesi bertahan setelah deploy.
  • Pembatasan laju per pengguna, sehingga satu pengguna yang berisik tidak dapat menghabiskan kuota Anda.
  • Atribusi penggunaan, jika chatbot berhadapan dengan pelanggan.
  • Ringkasan latar belakang, jika percakapan memerlukan memori jangka panjang.

Setelah migrasi base URL selesai, perubahan model hanyalah pengeditan konfigurasi ke ALLOWED_MODELS.

FAQ

Apakah saya memerlukan websocket untuk membangun AI chatbot?

Tidak. SSE, yang ditunjukkan di Langkah 4, mencakup sebagian besar produk chat. Websocket memberikan nilai saat Anda memerlukan push dua arah di luar permintaan dan respons, seperti kolaborasi langsung atau event yang dimulai server. Untuk UI chat standar, SSE lebih sederhana untuk dideploy dan di-debug.

Model mana yang harus digunakan chatbot saya secara default?

Mulai dengan tier harga rendah seperti deepseek-v4-flash dan tambahkan claude-sonnet-5 atau gpt-5.5 di balik daftar izinkan untuk giliran yang lebih sulit. Harga di atas, diamati 2026-10-03, menunjukkan kesenjangannya. Kemudian uji prompt Anda sendiri pada dua tier dan bandingkan biaya akhir di Usage. Periksa direktori model sebelum Anda berkomitmen, karena jajaran berubah.

Mengapa chatbot saya mengembalikan 402 atau 429?

402 berarti saldo akun atau batas penggunaan kunci itu sendiri terlalu rendah. Kodenya adalah insufficient_balance dan quota_exceeded, dan mengulangi permintaan tidak akan membantu. 429 berarti Anda mencapai batas permintaan, jadi tunggu Retry-After lalu coba lagi. Endpoint sinkron kami mencoba lagi sekali dan endpoint streaming melaporkan error ke klien.

Bisakah browser memanggil TokenLab secara langsung?

Tidak dengan aman. Dokumentasi Autentikasi mengatakan jangan pernah mengekspos kunci API dalam kode sisi klien. Simpan kunci di lingkungan server dan buat browser memanggil backend Anda sendiri yang terautentikasi, seperti yang dilakukan sampel frontend.


Buat kunci API di tokenlab.sh, tambahkan dana, dan jalankan smoke test di atas.

Sumber

Harga diamati pada 2026-10-03

Model terkait

Model yang baru dirilis

Bangun dengan model dalam panduan ini

Bandingkan harga, uji rute, dan ubah riset menjadi panggilan API yang berjalan.