İçeriğe geç

Şu anda: Steady Control'de yapay zekâ izleme sistemleri kuruyorum

Daniil Dushin

Hotel AI Concierge

Misafirlere otelin kendi bilgileriyle dört dilde cevap veren, geri kalan her şeyi resepsiyona ileten bir Telegram konsiyerji.

Rol
Kişisel proje — tasarım, kod, testler
Yıl
2026
Kategori
Yapay zekâ · Botlar
Teknolojiler
Python 3.12, aiogram 3, Anthropic API, OpenAI API
Hotel AI Concierge kapak görseli — dört dilde sohbet balonları

Sorun

Resepsiyon bütün gün aynı soruları cevaplar: kahvaltı saatleri, Wi-Fi şifresi, havuzun ne zaman açıldığı, transferin nasıl ayarlandığı. Türkiye'deki bir tatil otelinde misafirler bu soruları Rusça, İngilizce, Türkçe ve Almanca sorar; personel ise bu dillerin hepsini konuşmaz.

Basit bir sohbet botu burada risklidir. Çıkış saatini veya bir fiyatı uyduran bir yapay zekâ resepsiyonda gerçek sorunlar yaratır ve misafir botu değil oteli suçlar.

Çözüm

Sadece otelin yazdığı bilgilere göre cevap veren, geri kalan her şeyi bir insana soran bir Telegram botu:

  • Bilgi tabanı, otelin düzenlediği tek bir Markdown dosyasıdır. /reload değişiklikleri yeniden başlatmadan uygular; bozuk bir dosya gelirse eski sürüm kullanılmaya devam eder.
  • Dil modeli (ayarlarda seçilen Claude veya OpenAI) found_in_knowledge_base alanı olan yapılandırılmış JSON döndürür; böylece "bunu biliyor muyum?" sorusu modelin cümlesinden tahmin edilmez, evet ya da hayır olur.
  • Bilinmeyen sorular İngilizce çevirisiyle birlikte personelin Telegram grubuna gider. Personel sadece "Yanıtla"ya basar; bot cevabı misafirin diline çevirir ve aslını altında gösterir.
  • Misafirin dili yapay zekâ olmadan belirlenir: alfabe, ı ş ğ veya ä ß gibi harfler ve sık kullanılan kelimeler. "ok" gibi kısa mesajlar sohbetin dilini korur.
  • Her hata bir insanla sonuçlanır: çalışmayan API, modelin reddi veya yarım kalan cevap personele gider; personel grubuna ulaşılamazsa misafire resepsiyona sormasını söyler.

Demo

Remotion ile hazırlanmış tanıtım videosu.

Ekran görüntüleri

Bir misafirin Rusça Wi-Fi sorup cevap aldığı, ardından doğum günü pastası sorduğu ve sorunun resepsiyona gittiği sohbet
Çevrimdışı demodaki gerçek sohbet (python -m app.demo), tanıtım videosunda sohbet olarak gösteriliyor.

Teknolojiler

  • Python 3.12
  • aiogram 3
  • Anthropic API
  • OpenAI API
  • SQLite
  • pytest
  • Docker

Vektör araması yerine bilgi tabanının tamamı prompt'a girer: bir otelin SSS'si birkaç bin token'dır, arama sadece yeni bir hata kaynağı eklerdi. Bu prompt misafirden misafire değişmediği için Anthropic onu önbelleğe alır ve tekrarlanan istekler daha ucuza gelir. Çevrimdışı sahte bir model, tüm akışın API anahtarı olmadan çalışmasını sağlar.

Öne çıkan kod

Ana karar Telegram'dan bağımsızdır; bu yüzden bot, terminal demosu ve testler aynı kodu çalıştırır:

python
async def handle_guest_message(self, guest: Guest, text: str) -> GuestReply:
    language = await self.guest_language(guest, text)
    history = format_history(
        await self._repo.recent_messages(guest.chat_id, self._settings.history_messages)
    )
    await self._repo.upsert_guest(guest.chat_id, guest.name, guest.username, language)
    await self._repo.log(guest.chat_id, Role.GUEST, Kind.QUESTION, text, language)

    result: ConciergeAnswer | None = None
    try:
        result = await self._llm.answer(text, language, self._knowledge.text, history)
    except LLMError as exc:
        logger.warning("LLM failed, escalating to staff: %s", exc)

    if result and result.found_in_knowledge_base and result.answer.strip():
        answer = result.answer.strip()
        await self._repo.log(guest.chat_id, Role.BOT, Kind.ANSWER, answer, language)
        return GuestReply(language, answer)

    # Not in the knowledge base, or the AI is unavailable: never guess, ask a human.
    reason = "not in the knowledge base" if result else "AI assistant unavailable"
    question_en = result.question_in_english if result else text
    escalation_id = await self._repo.create_escalation(
        guest.chat_id, language, text, question_en, reason
    )
    ...

Bulduğum ve düzelttiğim hata

Misafir komutları yapay zekâya ve resepsiyona soru olarak gidiyordu

Ne bozuldu

Hiçbir şey çökmedi ve test geçti. Yönetici komutu /reload için uçtan uca test yazarken, bu komutu bir misafir gönderdiğinde ne olduğunu takip ettim. Bot bir yapay zekâ çağrısı için para ödüyor, bilgi tabanında bir şey bulamıyor ve "/reload" mesajını personel grubuna misafir sorusu olarak gönderiyordu. Aynısı /help ve diğer tüm komutlar için de geçerliydi.

Asıl neden

aiogram işleyicileri kayıt sırasına göre kontrol eder ve filtreleri uyan ilk işleyiciyi kullanır. Sadece yöneticiler için olan işleyici misafiri doğru şekilde atlıyordu; böylece mesaj, her metni soru sayan son işleyiciye düşüyordu.

Çözüm

Son işleyiciden önce, özel sohbetlerdeki komutlar için bir işleyici eklendi; bu işleyici karşılama metnini gösteriyor. Test artık iki tarafı da kontrol ediyor: misafir karşılama metnini aldı ve personel grubuna hiçbir şey gitmedi. Ders: sadece "kötü şey olmadı" diye kontrol eden bir test yanlış sebeple geçebilir.

Önce
router.message.register(on_staff_reply, IsStaffChat(), F.reply_to_message, F.text)
router.message.register(on_guest_text, private, F.text)
router.message.register(on_guest_other, private)
Sonra
router.message.register(on_staff_reply, IsStaffChat(), F.reply_to_message, F.text)
# /help or a command the guest may not use: show the welcome text, do not ask the LLM.
router.message.register(cmd_start, private, F.text.startswith("/"))
router.message.register(on_guest_text, private, F.text)
router.message.register(on_guest_other, private)

Sonuç

  • 68 otomatik test; aralarında sahte bir Telegram bağlantısıyla aiogram dağıtıcısından geçen bir çalıştırma ve Claude ile OpenAI istemcilerinin sahte bir HTTP sunucusuna karşı testleri var.
  • Çevrimdışı demo dört misafire dört dilde cevap veriyor, beşinci soruyu personele gönderiyor ve personelin cevabını geri iletiyor.
  • Demo modunda hiçbir API anahtarı olmadan çalışır.