All Case Studies
AI / Automation2025Fullstack Developer & AI Engineer

AI WhatsApp Bot

Multi-tenant AI assistant with RAG

Hono v4TypeScriptPostgreSQL + pgvectorDrizzle ORMOpenAI (GPT-4o / 4o-mini)React 18ZustandWAHA (WhatsApp HTTP API)pnpm monorepo

Problem

Businesses lose customers because they can’t respond to WhatsApp messages instantly 24/7. Traditional chatbots rely on rigid decision trees that break on unexpected input. We needed a system that:

  • Understands natural language intent in Bahasa Indonesia
  • Retrieves product/service info from database (not hardcoded)
  • Respects guardrails (no off-topic, no hallucinated prices)
  • Scales across multiple tenants with isolated data

Solution

A multi-tenant WhatsApp AI platform with RAG (Retrieval-Augmented Generation):

  1. Pipeline: WAHA webhook → Message processor → AI intent classifier → Tool execution → Response → WAHA send
  2. RAG: Product descriptions chunked → embedded via OpenAI → stored in pgvector → semantic search at query time
  3. Guardrails: Function-calling tools with strict schemas validate every AI arguments before execution
  4. Multi-tenant: Each organization gets isolated customers, conversations, and AI context via JWT auth

Architecture

WhatsApp → WAHA webhook → Hono pipeline
  → Customer lookup (LID + phone format)
  → Intent detection (keyword + AI fallback)
  → Tool execution (DB query, RAG search, etc.)
  → Response formatting
  → WAHA sendMessage

Key Tech Decisions

Keyword bypass for deterministic queries

gemini-3-flash often returned hallucinated text instead of calling tool functions, even with explicit “WAJIB panggil tool X” system prompts. For product queries, keyword-based bypass detects intent via regex, directly queries the database, formats the response, then sends via WAHA. Skip AI entirely for deterministic queries, saving 2-3s response time.

pgvector over Pinecone

Used PostgreSQL pgvector for embeddings instead of a separate vector database. Keeps the stack simpler (single DB), avoids vendor lock-in, and pgvector’s performance is sufficient for our scale. The embedding pipeline chunks product descriptions into ~512-token segments with 128-token overlap for context continuity.

Hono onError over try/catch middleware

Hono v4 routes errors bypass app.use('*', tryCatchMiddleware) because compose.js catches errors at the dispatch level. Route errors go directly to app.onError. Using middleware try/catch for route errors is useless — must use app.onError() instead.

Metrics

Metric Value
API Routes 40+
Database Tables 15+
AI Models 3 (classifier + RAG embedder + function-calling)
Response Time (keyword) < 1s
Response Time (AI) 3-5s