Ayarlar

Dil

Tek Bir API Key ile AI Chatbot Oluşturun: Sıfırdan Üretime 30 Dakikada

T
TokenLab
·26 Şubat 2026·11 dk okuma·Güncellendi 14 Temmuz 2026·1435 görüntüleme
#sohbet botu#eğitim#python#fastapi#akış
Tek Bir API Key ile AI Chatbot Oluşturun: Sıfırdan Üretime 30 Dakikada

Bu eğitimde; FastAPI, SSE streaming, konuşma belleği ve model değiştirme özelliklerine sahip, küçük ancak üretime hazır bir chatbot hizmeti oluşturacağız. Buradaki amaç bir oyuncak demo yapmak değil; gerçek bir ürün arayüzünün arkasına koyabileceğiniz ve her model değiştirdiğinizde entegrasyonunuzu yeniden yazmak zorunda kalmadan güvenle yineleyebileceğiniz bir backend geliştirmektir.

Eğer OpenAI uyumlu bir SDK'yı halihazırda TokenLab'e yönlendirdiyseniz, bu makale kaldığınız yerden devam eder. Henüz base URL değişikliğini yapmadıysanız, önce geçiş kılavuzunu okuyun. Ana endişeniz yük altında istek şekillendirme ve backoff ise, bu kılavuzu AI API hız sınırlama kılavuzu ile birlikte kullanın.

Önemli Çıkarımlar

  • Üretime hazır bir chatbot altı parçaya ihtiyaç duyar: bir senkron endpoint, bir streaming endpoint, sunucu tarafında konuşma durumu, bir model izin listesi (allowlist), gerçek hata yönetimi ve net bir depolama yükseltme yolu.
  • Streaming, bellek veya araç çağrılarını eklemeden önce; anahtarınızı, base URL'nizi ve yönlendirmenizi küçük bir sohbet endpoint'i ile test edin.
  • SSE streaming, çoğu sohbet ürününü kapsar ve websocket'lere göre daha az operasyonel yük getirir.
  • Modelleri serbest metin alanı yerine bir backend izin listesi aracılığıyla sunun, böylece frontend rastgele veya kullanımdan kaldırılmış model kimlikleri isteyemez.
  • Model kullanılabilirliği ve dizilimleri sık değişir. İzin listenizi üretime kilitlemeden önce TokenLab'in model dizinini (2026-07-07 tarihinde gözlemlenmiştir) kontrol edin.

Ne İnşa Ediyoruz?

Tamamlanmış hizmet altı hareketli parçaya sahiptir:

  1. Duman testleri için senkron bir /chat endpoint'i.
  2. Gerçek kullanıcı arayüzü için streaming destekli bir /chat/stream endpoint'i.
  3. conversation_id ile anahtarlanmış konuşma durumu.
  4. Frontend'in rastgele kimlikler istemesini engelleyen bir model izin listesi.
  5. İlk 429 hatasında çökmeyen bir hata yönetimi.
  6. Bellek içi prototipten Redis veya PostgreSQL'e geçiş için net bir yol.

Bu, bir destek botunu, dahili bir asistanı veya gömülü bir sohbet widget'ının ilk sürümünü çalıştırmak için yeterlidir.

Minimum Yığını Kurun

pip install fastapi uvicorn openai pydantic redis

İlk aşamada redis'i atlayabilirsiniz, ancak import işlemini şimdiden yapmak, daha sonraki yükseltmeyi bir refactoring yerine basit bir işleme dönüştürür.

Adım 1: Küçük ve Basit Bir Sohbet Endpoint'i ile Başlayın

Chatbot çalışmalarında kaybolmanın en hızlı yolu; temel istek yolu kararlı hale gelmeden websocket'ler, araç kullanımı ve ajan düzenlemeleri ile başlamaktır. Anahtarınızın, base URL'nizin ve model yönlendirmenizin çalıştığını kanıtlayan tek bir küçük endpoint ile başlayın.

from fastapi import FastAPI
from openai import OpenAI
from pydantic import BaseModel

app = FastAPI()

client = OpenAI(
    api_key="sk-tokenlab-xxx",
    base_url="https://api.tokenlab.sh/v1"
)

class ChatRequest(BaseModel):
    message: str
    model: str = "deepseek-v4-flash"
    conversation_id: str | None = None

@app.post("/chat")
async def chat(req: ChatRequest):
    response = client.chat.completions.create(
        model=req.model,
        messages=[{"role": "user", "content": req.message}]
    )
    return {"reply": response.choices[0].message.content}

Bir duman testi çalıştırın. Eğer bu başarısız olursa, üzerine inşa etmeye devam etmeyin.

Adım 2: Streaming Ekleyin, Çünkü Kullanıcılar Gecikmeyi Ölçmeden Önce Hissederler

Çoğu chatbot ürünü, model yavaş olduğu için değil, yanıtın tamamı gelene kadar kullanıcı arayüzü boş kaldığı için yavaş hissedilir. SSE, çoğu sohbet ürünü için yeterlidir ve websocket'lere göre daha düşük operasyonel yüke sahiptir.

from fastapi.responses import StreamingResponse

@app.post("/chat/stream")
async def chat_stream(req: ChatRequest):
    def generate():
        stream = client.chat.completions.create(
            model=req.model,
            messages=[{"role": "user", "content": req.message}],
            stream=True
        )
        for chunk in stream:
            delta = chunk.choices[0].delta
            if delta.content:
                yield f"data: {delta.content}\n\n"
        yield "data: [DONE]\n\n"

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

Frontend tarafında, standart bir fetch okuyucusu hala yeterlidir:

async function sendMessage(payload) {
  const response = await fetch('/chat/stream', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(payload),
  });

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

  while (true) {
    const { done, value } = await reader.read();
    if (done) break;
    const chunk = decoder.decode(value, { stream: true });
    console.log(chunk);
  }
}

Eğer ürününüz zaten standart HTTP üzerinden bir tarayıcı istemcisi çalıştırıyorsa, SSE mimariyi bir websocket katmanından daha basit tutar.

Adım 3: Konuşma Durumunu İstek Gövdesinden Çıkarın

İlk chatbot demosu genellikle tüm transkripti tarayıcıda tutar ve her adımda yeniden gönderir. Bu, prototipler için işe yarar. Ancak yeniden denemelere, devam ettirilebilir oturumlara veya sunucu tarafı araçlara ihtiyacınız olduğunda hızla karmaşıklaşır.

Bellek içi bir depo başlangıç için iyidir:

from collections import defaultdict
import uuid

conversations: dict[str, list] = defaultdict(list)
SYSTEM_PROMPT = "You are a helpful assistant. Be concise and direct."

def build_messages(conv_id: str, user_msg: str) -> list:
    messages = [{"role": "system", "content": SYSTEM_PROMPT}]
    history = conversations[conv_id][-20:]
    messages.extend(history)
    messages.append({"role": "user", "content": user_msg})
    conversations[conv_id].append({"role": "user", "content": user_msg})
    return messages

Redis'e yükseltme yolu, mantıksal değişikliklerden ziyade çoğunlukla depolama tesisatıdır:

import json
import redis

redis_client = redis.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))

Konuşmaların TTL'ye, devam ettirilebilirliğe veya çoklu örnek dağıtımına ihtiyacı olduğunda Redis'e başvurun. Transkriptin kendisi daha sonra sorgulamanız, denetlemeniz veya raporlamanız gereken ürün verisi olduğunda PostgreSQL'e başvurun.

Adım 4: Hataları Sadece İstisna Değil, Ürün Davranışı Olarak Görün

Chatbot'unuz müşteri odaklıysa, hata yolu da en az mutlu yol kadar önemlidir. Kullanıcı, hatanın hız sınırlamasından, tükenmiş bir bakiyeden veya yukarı akıştaki bir model kesintisinden kaynaklanıp kaynaklanmadığını önemsemez. Kullanıcı arayüzünün donup donmadığını önemser.

from openai import APIConnectionError, APIError, RateLimitError

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

    def generate():
        full_response = []
        try:
            stream = client.chat.completions.create(
                model=req.model,
                messages=messages,
                stream=True
            )
            for chunk in stream:
                delta = chunk.choices[0].delta
                if delta.content:
                    full_response.append(delta.content)
                    yield f"data: {delta.content}\n\n"
        except RateLimitError:
            yield "data: [error: rate limited, please retry shortly]\n\n"
        except APIConnectionError:
            yield "data: [error: connection issue, please retry]\n\n"
        except APIError:
            yield "data: [error: something went wrong on our end]\n\n"
        finally:
            if full_response:
                conversations[conv_id].append(
                    {"role": "assistant", "content": "".join(full_response)}
                )
        yield "data: [DONE]\n\n"

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

Adım 5: Frontend'in Hangi Modelleri İsteyebileceğini Kilitleyin

Frontend'in rastgele bir model dizisini doğrudan API'ye geçirmesine asla izin vermeyin. Serbest bir metin alanı; kullanımdan kaldırılmış modeller, yazım hataları veya asla sunmayı amaçlamadığınız modeller için istek davetiyesi çıkarır. Bunun yerine bir backend izin listesi üzerinden yönlendirin.

ALLOWED_MODELS = {
    "default": "deepseek-v4-flash",
    "flagship": "gpt-5.5",
    "balanced": "claude-sonnet-5",
}

class ChatRequest(BaseModel):
    message: str
    tier: str = "default"
    conversation_id: str | None = None

@app.post("/chat/stream")
async def chat_stream(req: ChatRequest):
    model = ALLOWED_MODELS.get(req.tier, ALLOWED_MODELS["default"])
    # streaming mantığının geri kalanı, istemci tarafından sağlanan ham dize yerine `model` değişkenini kullanır

Bu, bir sağlayıcı bir modeli kullanımdan kaldırdığında, frontend koduna dokunmadan veya bir istemci güncellemesi yayınlamadan modelleri değiştirebileceğiniz tek bir yer sağlar.

Adım 6: Sadece Mutlu Yolu Değil, Üretimin Geri Kalanını Yönetin

Bir chatbot backend'i, temel sohbet çağrısı akıllandığında değil, çevresindeki kenar durumlar ele alındığında üretime hazır kabul edilir.

Kontrol listesi kısadır:

  • Frontend hatalarını backend günlüklerine bağlayabilmek için istek kimlikleri (request IDs) ekleyin.
  • Kullanıcı başına eşzamanlılığı ve istek boyutunu sınırlayın.
  • Uzun geçmişleri token bütçenizi patlatmadan önce kırpın.
  • Modeli, gecikmeyi, girdi boyutunu ve bitiş nedenini günlüğe kaydedin.
  • Kullanıcı tarafından görülebilen hata mesajlarını dahili hata detaylarından ayırın.
  • İlk gerçek kesintiden önce yedeğin çalıştığından emin olmak için alternatif bir modeli test edin.

Geçmiş kırpma basit kalabilir:

def trim_history(messages: list, max_tokens: int = 8000) -> list:
    system = messages[0]
    history = messages[1:]
    total_chars = len(system["content"])
    trimmed = []

    for msg in reversed(history):
        msg_chars = len(msg["content"])
        if total_chars + msg_chars > max_tokens * 4:
            break
        trimmed.insert(0, msg)
        total_chars += msg_chars

    return [system] + trimmed

Amaç token-mükemmel muhasebe değildir. Amaç, bağlam patlamalarını faturanıza veya gecikmenize yansımadan önce durdurmaktır.

Demodan Ürüne

Bu backend kararlı hale geldiğinde, bir sonraki yükseltme nadiren "daha fazla AI" olur. Genellikle sıkıcı altyapı işleridir:

  • Bir kullanıcının diğerinin konuşmasını okuyamaması için kimlik doğrulama.
  • Oturumların dağıtımlardan sağ çıkması için kalıcılık.
  • Gürültülü bir kullanıcının kotanızı yakamaması için hız sınırlama.
  • Chatbot müşteri odaklıysa faturalandırma veya kullanım ilişkilendirme.
  • Konuşmaların uzun vadeli belleğe ihtiyacı varsa arka plan özetleme.

Birleşik bir ağ geçidi (gateway) bunların çoğunda yardımcı olur. Base URL geçişi arkanızda kaldığında, model değişiklikleri bir platform yeniden yazımı olmaktan çıkar ve bir yapılandırma düzenlemesine dönüşür.

Duman Testi

uvicorn main:app --reload --port 8000

curl -N -X POST http://localhost:8000/chat/stream \
  -H "Content-Type: application/json" \
  -d '{"message": "Hello!", "model": "deepseek-v4-flash"}'

Eğer bir turu stream edebiliyor, bir konuşmayı koruyabiliyor ve zorunlu bir hatada temiz bir hata döndürebiliyorsanız, doğru temele sahipsiniz demektir.

Maliyet Tahmini

TokenLab'de bir API anahtarı oluşturun, OpenAI SDK'nızı https://api.tokenlab.sh/v1 adresine yönlendirin; sağlayıcılar arasında ayrı hesaplar yönetmek zorunda kalmadan chatbot'unuzun ilk üretim sürümünü yayınlayabilirsiniz.

Model Tipik Katman Notlar
DeepSeek V4 Flash Hızlı / varsayılan Yüksek hacimli, düşük gecikmeli turlar için iyi bir varsayılan
GPT-5.5 Amiral gemisi Daha güçlü muhakeme gerektiren turlar için kullanın
Claude Sonnet 5 Dengeli Kodlama ve inceleme tarzı yanıtlar için güçlü bir seçim
Gemini 3.5 Flash Bütçe / hızlı alt Yüksek hacimli yönlendirme için düşük maliyetli, hızlı alternatif

Tam token başına fiyatlandırma sağlayıcılar arasında sık değişir ve burada sabit rakamlar olarak verilmemiştir. Bütçe yapmadan önce güncel oranları model dizininden (2026-07-07 tarihinde gözlemlenmiştir) kontrol edin. Uygulamada, çoğu konuşmayı DeepSeek V4 Flash veya Gemini 3.5 Flash gibi hızlı/varsayılan bir katmana yönlendirmek ve GPT-5.5 veya Claude Sonnet 5'i ihtiyaç duyulan turlar için ayırmak, çoğu uygulamayı düşük bir aylık faturada tutar, ancak bir bütçeye taahhüt etmeden önce hesabınız için gerçek milyon token başına oranları onaylayın.

SSS

AI chatbot oluşturmak için websocket'lere ihtiyacım var mı? Hayır. Adım 2'de gösterilen SSE streaming, sohbet ürünlerinin büyük çoğunluğunu kapsar. Websocket'ler, canlı işbirliği veya sunucu tarafından başlatılan olaylar gibi istek/yanıt dışında çift yönlü push ihtiyacınız olduğunda gerçek değer katar. Standart bir sohbet arayüzü için SSE'yi dağıtmak, hata ayıklamak ve ölçeklendirmek daha basittir.

Hangi modeli varsayılan yapacağımı nasıl bilirim? Varsayılan katman için DeepSeek V4 Flash veya Gemini 3.5 Flash gibi hızlı, düşük maliyetli bir modelle başlayın ve Adım 5'te gösterilen izin listesinin arkasına Claude Sonnet 5 veya GPT-5.5 ile dengeli veya muhakeme katmanı ekleyin. Yeni modeller çıktığı ve eskileri kontrolünüz dışındaki bir takvimle kullanımdan kaldırıldığı için güncel seçenekler için model dizinini (2026-07-07 tarihinde gözlemlenmiştir) kontrol edin.

Bir chatbot demodan gerçek trafiğe geçtiğinde ilk ne bozulur? Neredeyse her zaman mutlu yol değil, hata yolu. Sınırsız yeniden denemeler, eksik kullanıcı başına eşzamanlılık sınırları ve sınırsız konuşma geçmişi, bir chatbot backend'inin gerçek yük altında çökmesinin en yaygın üç nedenidir. Yukarıdaki 4. ve 6. adımlar bu üçünü de doğrudan ele alır.


API anahtarınızla başlayın: tokenlab.sh, tek bir endpoint üzerinden 300'den fazla model sunar. İnşa etmeye başlamanız için 1$ ücretsiz kredi.

Kaynaklar

Fiyat 2026-07-07 tarihinde gözlendi

Paylaş:

İlgili modeller

Son herkese açık modeller

Bu rehberdeki modellerle geliştirin

Fiyatları karşılaştırın, rotaları test edin ve araştırmayı çalışan bir API çağrısına dönüştürün.