Bu mimari doküman, kurumsal diyalog ortamlarında (WhatsApp, Instagram, Web Chat, Form) kullanıcıları karşılayan; Claude 4.5 ve GPT-4o tabanlı; **Haystack 2.x** ile retrieval ve pipeline orkestrasyonu yapan; **Qdrant** ile çoklu indeksli semantik hafıza yöneten; gerektiğinde canlı temsilciye bağlam özetiyle devreden (Handoff) üretim seviyesi bir **AI Danışman Altyapısının teknik tasarımını** tanımlar.
Sistem sadece soru yanıtlayan pasif bir chatbot değildir. **"Satış"** kelimesinden agresif bir pazarlama anlaşılmamalıdır. Sistem kullanıcının ihtiyacını doğru adımlarla netleştirir (Qualification):
Sistem her kullanıcıya aynı şekilde yaklaşmaz. İki temel diyalog modu vardır:
Bir kullanıcı sisteme ilk kez mesaj attığında geçmişe dair hiçbir bilgi yoktur (Kullanıcı kim, ne istiyor, bütçesi ne — bilinmiyor). Standart chatbotlar bu aşamada bir FAQ döküp kullanıcıyı kaybettirir. Bizim Cold Start yaklaşımımız eşzamanlı 3 şey yapar:
Kullanıcı: "Rhinoplasty (Burun Estetiği) hakkında bilgi alabilir miyim?"
❌ Yanlış Yaklaşım: "Rinoplasti burun şeklini düzelten ameliyattır. İyileşme süreci 2 haftadır." (Kullanıcı okur ve gider)
✅ Doğru Yaklaşım: "Elbette yardımcı olabilirim. Rinoplasti hem estetik görünümü iyileştirmek hem de nefes alma sorunlarını çözmek için yapılıyor. Size daha net yönlendirme yapabilmem için sizi en çok rahatsız eden konu estetik mi yoksa nefes alma mı?"
Diyalog ilerledikçe veya kullanıcının veritabanında geçmiş kayıtları varsa sistem bu moda geçer. `patient_summary` ve `patient_memory_tr` aktif kullanılır. Kullanıcı her defasında kendini tekrar tanıtmak zorunda kalmaz; dönüşüm oranı ciddi oranda artar.
Projede kullanılan her bir teknoloji bileşeni, somut testler ve mimari gerekçeler doğrultusunda seçilmiştir:
| Bileşen | Seçilen Teknoloji | Gerekçe / Neden Bu Teknoloji Seçildi? |
|---|---|---|
| Primary LLM | Claude 4.5 Sonnet / Haiku | İnstruksiyon takibi, Prompt Caching desteği ve medikal bağlam sadakatinde sektör lideri. |
| RAG Framework | Haystack 2.x | Modüler pipeline yapısı, retriever/reranker bileşenlerinin kolay entegrasyonu ve kod netliği. |
| Embedding Model | Voyage-4 (`voyage-large-4`) | 1024-dim. Türkçe ve çok dilli medikal metin aramasında OpenAI `text-embedding-3-large`'a kıyasla daha yüksek hassasiyet. |
| Vector DB | Qdrant | Dense + Sparse hibrit arama yeteneği, gelişmiş metadata filtreleme ve Haystack ile yerel uyum. |
| Transactional DB | PostgreSQL | ACID garantisi, kanonik gerçeklik kaynağı (Canonical truth). Tüm ham mesajlar burada tutulur. |
| Distributed Cache/Lock | Redis | SETNX ile Idempotency kilidi, conversation lease yönetimi ve FAQ fast-path cache altyapısı. |
| Task Queue | Celery + Redis | Asenkron hafıza güncellemeleri, ağır medya işleme (STT/OCR) ve CRM handoff kuyruğu. |
| Reranker | BGE-M3 (Transformers) | Çok dilli cross-encoder reranking. Qdrant'tan gelen 10 adayı 4'e düşürerek bağlamı %60 sadeleştirir. |
PostgreSQL ilişkisel bütünlük ve ACID doğruluk için; Qdrant semantik vektör araması için; Redis ise anlık distributed kilit ve geçici state koordinasyonu için optimize edilmiştir. Bu üç iş yükünü tek DB'ye sıkıştırmak ya arama kalitesini ya da sistem dayanıklılığını düşürür.
Sistem, tüm verileri tek bir vektör havuzuna atmak yerine **4 Ayrı Qdrant Koleksiyonu** altında izole eder:
| Koleksiyon | İçerik & Amaç | Chunking Yöntemi | Metadata Filtreleri |
|---|---|---|---|
faq_tr |
Canonical Sık Sorulan Sorular. | Split yok (1 FAQ = 1 Document) | `faq_id`, `intent`, `topic`, `version` |
knowledge_tr |
Hizmet detayları, klinik SOP'ler. | Heading-Aware (300-450 Token) | `doc_id`, `doc_type`, `topic`, `page` |
policy_tr |
Fiyat, KVKK, medikal sınır politikaları. | Section-First (250-350 Token) | `policy_id`, `priority`, `valid_from`, `valid_to` |
patient_memory_tr |
Hastanın geçmiş diyalog hafızası. | Segment Summary Chunking | `patient_id`, `stage`, `importance_score` |
Kullanıcının aynı anda birkaç sorusu olduğunda, `RetrievalPlanner` sorguları birleştirir. Qdrant'tan dönen sonuçlar tek bir **Shared BGE-M3 Reranker** instance'ından geçirilerek en alakalı **Top-4** dokümana düşürülür.
Qdrant sorgu yükü **%70-80 azalır.** LLM'e giden prompt boyutu küçüldüğü için token maliyeti düşer ve yanıt süresi ~2.5 saniye kazanır.
Gelen mesaj LLM'e gitmeden önce `core/classifier.py` içindeki **Zero-Shot DeBERTa-v3** katmanından geçer:
from haystack.components.routers import TransformersZeroShotTextRouter
LABELS = [
"greeting", "price_question", "service_discovery",
"photo_related", "contact_request", "safety_abuse"
]
# Model: MoritzLaurer/deberta-v3-base-zeroshot-v1.1-all-33
_router = TransformersZeroShotTextRouter(labels=LABELS)
Model hiç ön eğitim gerektirmeden cümlenin niyetini anlar (`price_question`, `greeting` vb.). Tehlikeli mesajlar anında elenir.
Mesaj içerisindeki uzmanlık alanı ve tedavi (Saç Ekimi, Rinoplasti, Zirkonyum vb.) tespit edilerek diyalog durumu kilitlenir.
Selamlama, teşekkür, emoji veya kısa onaylar RAG/LLM hattını meşgul etmeden hafif yanıt veya sessizlik kararı verilerek sonlandırılır.
Ham diyalog geçmişinin tamamını prompt'a yığmak maliyetli ve gürültülüdür. Sistem **3-Katmanlı Hafıza** kullanır:
PostgreSQL `messages` tablosunda saklanır. Ham haldeki tüm diyalogdur; kanonik gerçeklik kaynağıdır.
`patient_summary` tablosunda tutulan aktif kullanıcı özetidir (Yaş, İlgi Alanı, Şehir, Durum).
`patient_memory_tr` koleksiyonunda saklanan semantik hafıza segmentleridir. On-demand sorgulanır.
| Sinyal / Olay | Puan Değişimi | Açıklama |
|---|---|---|
| `medical_risk_question` / `refund_concern` | +0.25 | Yüksek medikal risk veya finansal talep |
| `patient_status` değişimi | +0.25 | Aday durumunun `qualified` olması |
| `existing_patient` tespiti | +0.20 | Kayıtlı hasta etkileşimi |
| `selamlaşma` / `teşekkür` / `emoji` | -0.15 ile -0.20 | Önemsiz diyalog (Vektör store'a yazılmaz) |
• Score ≥ 0.50: `structured_and_embedded` (Hem DB'ye yazılır hem Qdrant'a embed edilir).
• 0.25 ≤ Score < 0.50: `structured_only` (Yalnızca DB özetine yazılır).
• Score < 0.25: `raw_only` (Vektör veritabanı kirletilmez).
Sistem, uluslararası hasta portföyüne (Türkçe, İngilizce, Almanca, Fransızca, İspanyolca, Arapça, Rusça, Romence vb.) kesintisiz yanıt vermek adına 4-Aşamalı Dinamik Çoklu Dil Mimarisi kullanır:
`core/classifier.py` içindeki detect_language() ve get_lang_confidence() fonksiyonları langdetect kütüphanesini kullanarak gelen mesajın dilini milisaniyeler içinde yüksek güven skorlamasıyla tespit eder.
Kullanıcının dili ConversationState.detected_language değişkeninde saklanır. Hasta diyalog ortasında dil değiştirse dahi (`tr` ➔ `en` ➔ `ro` vb.) state otomatik olarak güncellenir ve diyalog yeni dilde devam eder.
`core/i18n.py` modülü; Handoff (Canlıya Devir) ve Short-Circuit mesajlarında LLM beklemeden 7 farklı dilde (`tr`, `en`, `de`, `fr`, `es`, `ar`, `ru`) 0ms latanslı anadilde hazır şablon yanıt verir.
`core/lang_guard.py` modülündeki is_language_mismatch() fonksiyonu, LLM yanıt ürettikten sonra çalışır. Cevabın dili beklenen hastanın diliyle uyuşmuyorsa (Örn: Hasta Romence sordu ama model Türkçe ürettiyse) yanıt anında yakalanır ve düzeltme hattına sokulur.
// core/i18n.py - Sözlük Tabanlı Çoklu Dil Sözlüğü
HANDOFF_MESSAGES = {
"tr": "Uzman sağlık danışmanımız size en kısa sürede dönüş yapacak...",
"en": "I've forwarded your question to our specialist team. They'll get back to you shortly.",
"de": "Ich habe Ihre Anfrage an unser Fachteam weitergeleitet...",
"ro": "Am transmis întrebarea dvs. echipei noastre de specialiști..."
}
// core/lang_guard.py - Üretim Sonrası Dil Doğrulayıcı
def is_language_mismatch(reply_text: str, expected_lang: str) -> bool:
if not reply_text or len(reply_text) < 40:
return False
detected = detect(reply_text).lower()
return detected != expected_lang.lower().split("-")[0]
Anthropic **Prompt Caching** teknolojisi kullanılarak sabit sistem komutları ve çıktı sözleşmesi cache'lenir:
// SYSTEM PROMPT (CACHEABLE PREFIX - Ephemeral Cache)
Role: AI Danışman / Satış Uzmanı (Enterprise Platform)
Ton: Güven verici, profesyonel, kısa ve yönlendirici.
Kurallar: Bilmediğini uydurma. Medikal kesinlik iddiası verme.
// OUTPUT CONTRACT (CACHEABLE PREFIX)
JSON formatında dönüş yap:
{
"reply_text": "string",
"decision": "reply | handoff | noop",
"confidence": 0.95,
"labels": ["romanian", "dental_implant"],
"reason": "string"
}
// USER PROMPT (DYNAMIC BLOCK)
{
"patient_context": { ... },
"retrieved_docs": [ ... ],
"user_message": "Fiyatlar ne kadar?"
}
Model cevabında şüpheli bir fiyat veya medikal iddia tespit edilirse, ikincil bir doğrulama çağrısı (`claude-haiku`) yapılarak yanıt kurumsal dokümanlarla karşılaştırılır. Doğrulanamayan yanıtlar anında **`handoff` (insan temsilciye devir)** durumuna geçirilir.
WhatsApp gibi kanallar ağ gecikmelerinde aynı mesajı tekrar teslim edebilir. Çift kilit koruması uygulanır:
| Seviye | Tetikleyici Koşul | Sistem Davranışı |
|---|---|---|
| Seviye 1 (Partial Outage) | Claude API Error Rate > %5 veya Latency > 15s | Semantic Cache ve FAQ Fast-Path devreye girer. LLM çağrısı atlanır. |
| Seviye 2 (Full Outage) | Circuit Breaker Open State | Tüm yeni diyaloglar otomatik mesaj ile canlı temsilci kuyruğuna alınır. |
| Seviye 3 (Cascading Failure) | Hem Claude hem Qdrant erişilemez | İn-memory FAQ cache çalışır, tüm karmaşık vakalar temsilciye devredilir. |
Sisteminizde canlı olarak çalışan **Gerçek Sorumluluk Akışı ve WAPIM Aktarım Mantığı** aşağıda birebir kodlandığı şekliyle açıklanmıştır:
ai_owned): Mesaj geldiğinde AI niyeti tespit eder, RAG veritabanını sorgular ve Claude 4.5 ile yanıt üretir.decision == "handoff" (hasta eksik bilgileri tamamladı veya canlı temsilci istedi) veya Chatwoot UI üzerinden temsilci atandı (assignee != null).ai_handoff etiketi basılır.private: true) eklenir.send_to_wapim_task.delay() Celery görevi tetiklenir. Konuşmadaki tüm geçmiş mesajlar normalize edilerek WAPIM REST API (/api/v1/dash/conversations/chatwoot) uç noktasına iletilir.ai_muted): Konuşmada ai_handoff etiketi veya temsilci ataması bulunduğu sürece hasta yeni mesaj atarsa:
if "ai_handoff" in labels:
forward_to_wapim_task.delay(msg_data, conv_data)
return {"status": "forwarded_to_wapim"}
AI **tamamen sessiz kalır**, yeni hiçbir yanıt üretmez ve gelen mesajı doğrudan WAPIM'e iletir.
ai_handoff etiketini silmesi veya atanmış temsilciyi kaldırması durumunda AI tekrar yanıt vermeye başlar.{
"patient_id": "pat_456",
"chatwoot_conversation_id": 1042,
"current_stage": "qualification_completed",
"intent": "dental_implant_pricing",
"summary": "Hasta Adriana (28). Fotoğraflar alındı, alerji durumu yok. Gelecek ay İstanbul'a gelmeyi planlıyor.",
"messages": [ ... /* Normalize edilmiş tüm müşteri ve AI diyalog geçmişi */ ... ]
}
| Faz | Hedef & Kapsam | Başarı Kriteri |
|---|---|---|
| Faz 1 | Temel Yanıt & Webhook Entegrasyonu (FastAPI, Redis, Claude) | Uçtan uca mesaj alım ve gönderim kararlılığı. |
| Faz 2 | Kurumsal Bilgiye Dayalı Retrieval (Haystack 2.x, Qdrant, Voyage-4) | Hallucination oranının %1'in altına düşmesi. |
| Faz 3 | Sınıflandırma, Kural Kontrolleri ve Handoff (DeBERTa-v3, RBAC) | Riskli vakaların %100 oranında temsilciye devri. |
| Faz 4 | Hafıza ve Konuşma Sürekliliği (Structured & Episodic Memory) | Kullanıcı geçmişine dayalı tutarlı diyalog akışı. |
| Faz 5 | Dayanıklılık, HA/DR & Operasyonel Olgunluk (Circuit Breaker, Tracing) | 99.9% Sistem erişilebilirliği ve maliyet kontrolü. |