Umut ABALI
← Projelere dön

Multimodal Agentic Chatbot

Kaynak gösteren, dokümana dayalı Türkçe soru-cevap için local-first bir chatbot. Görsel, PDF ve ses girişini de destekliyor.

Problem

Sohbet modelleri, yüklenen dokümanlarda cevap olmasa bile çoğu zaman kendinden emin yanıt veriyor. Hedef, kaynak gösteren, bağlam yetmediğinde cevap vermeyi reddeden ve görsel, ses ile canlı soruları da karşılayan, Türkçe ağırlıklı bir doküman soru-cevap sistemiydi.

Sistemin ayrıca lokal çalışması gerekiyordu (README, Metal destekli Apple Silicon veya NVIDIA GPU öneriyor). Proje bir bitirme tezi prototipi olarak başladı.

Mimari

Multimodal Agentic Chatbot mimari diyagramıChainlit UItext · image · PDF · voice (faster-whisper)Routerkeyword + LLM route decisionVisionimage understandingRewriter → RetrieverQdrant hybrid · bge-m3Direct responsechat · math · codeWeb searchTavily + quality gateRerankerbge-reranker-baseGraceful refusalinsufficient contextGraderdense gate + reason codesGeneratorcitations · token budgetllama.cppGemma-4-E4B · n_ctx from /propsedge-ttsspoken answerLangSmithsanitized traces
src/agent/graph.py, src/agent/nodes/, src/rag/ ve README'deki rota tablosundan çıkarıldı.
  • Altı rotalı bir LangGraph grafı: rag, web, direct, vision, vision_rag ve vision_search.
  • rag rotası rewriter → retriever → grader → generator. Retrieval hibrit (Qdrant'ta bge-m3 ile dense + sparse) ve bge-reranker-base ile yeniden sıralanıyor.
  • Üç bölgeli bir dense kapısı (pass / soft / weak) ve grader gerekçe kodları (sufficient, partial, insufficient_context, needs_live_data, irrelevant) cevaplama, web araması ve reddetme arasında karar veriyor.
  • Üretim, llama.cpp'nin OpenAI uyumlu sunucusuyla yapılıyor. Uygulama gerçek bağlam boyutunu /props'tan okuyor ve ayarlanan ile bildirilen n_ctx'ten küçük olanı kullanıyor.
  • Chainlit thread'leri ve LangGraph checkpoint'leri SQLite'ta saklanıyor. Böylece bir konuşma aynı thread id ile kaldığı yerden devam edebiliyor.

Tasarım kararları

Tahmin etmek yerine reddetmek

Dense kapısı ve grader bağlamın yetersiz olduğunu söylerse bot serbest üretim yerine nazik bir ret dönüyor. Zayıf Tavily sonuçları (çok kısa snippet'ler, tarihi bilinmeyen ve başlığı genel sonuçlar) boş sayılıyor.

Ödünleşim: Uydurma cevaplar azalıyor, ama retrieval kaçırdığında cevaplanabilir bazı sorular da reddediliyor.

Gerçek çalışma zamanına göre token bütçesi

Bağlam; son geçmiş, getirilen chunk'lar, beklenen çıktı bütçesi ve bir güvenlik payından oluşturuluyor. Token'lar tiktoken cl100k_base ile sayılıyor. Mümkünse n_ctx llama.cpp /props'tan alınıyor.

Ödünleşim: cl100k_base Gemma'nın tokenizer'ı olmadığı için sayımlar yaklaşık. Yine de Türkçe metinde karakter tahmininden daha isabetli.

Bağlama duyarlı semantik cache

Cevaplar Qdrant'ta cache'leniyor. Anahtar; kaynak filtresi, oturumda yüklenen dosyalar, retrieval stratejisi, hafıza hash'i ve prompt sürümünü içeriyor. Kısa, fallback veya yarım kalmış cevaplar hiç cache'lenmiyor.

Ödünleşim: Tekrarlanan sorular LLM'e gitmiyor, ama anahtara eklenen her bileşen isabet oranını düşürüyor.

Varsayılan olarak yalnızca lokal modeller

LLM (llama.cpp üzerinde Gemma-4-E4B GGUF), embedding, reranker ve ses modelleri makinede çalışıyor. Dışarı çıkan tek şeyler Tavily web araması ve isteğe bağlı LangSmith izleri. İzler de temizlenerek gönderiliyor.

Ödünleşim: Gizli ve ücretsiz çalışıyor, ama lokal GPU belleği ve hızıyla sınırlı.

Teknolojiler

PythonLangGraphChainlitllama.cpp (Gemma-4-E4B GGUF)QdrantBAAI/bge-m3BAAI/bge-reranker-basefaster-whisperedge-ttsTavilySQLiteLangSmithMCP

Sırada ne var

  • Türkçe grounding benchmark'ı yayınlamak: cevaplanabilir ve cevaplanamaz sorularda atıf doğruluğu ve reddetme isabeti.
  • Bütçeleme için cl100k_base yaklaşımı yerine Gemma'nın kendi tokenizer'ını kullanmak.
  • tests/manual altındaki manuel senaryoları otomatik regresyon değerlendirmelerine çevirmek.

Sonuçlar

Grounding: atıf doğruluğu ve sadakatBenchmark yakında
Reddetme isabeti / duyarlılığı (precision / recall)Benchmark yakında
Gecikme: ilk token süresi ve token/snBenchmark yakında

Notlar