Back to Projects

ChromaDB RAG Chatbot

B2B FMCG Semantic Search & Intent Classification

Role

AI Engineer

Timeline

2024 — 2025

Languages
Python
Tools & Frameworks
ChromaDB Docker sentence-transformers ClickHouse OpenAI SDK
Methodologies
RAG Semantic Search Intent Classification Vector Embeddings

TL;DR — Understands How Indonesians Actually Talk About Products

A Dockerized RAG chatbot for a B2B FMCG e-commerce platform that resolves colloquial Indonesian product names keyword search can't ("indomie kuning" → "Indomie Mi Instan Rasa Kaldu Ayam"), classifies 35+ customer intent types, and answers FAQs — all from a single semantic pipeline with no hardcoded keyword or alias tables. Ships as one docker-compose up.

  "mie goreng bungkusan merah"          ← colloquial query
            │  embed + parallel semantic search
   ┌────────┼─────────────────┐
   ▼        ▼                 ▼
 PRODUCTS  FAQs            INTENTS
 (aliases) (ClickHouse)   (35+ types)
   └────────┴───── best match ──────────▶  correct SKU + Indonesian reply
                  (no keyword tables)

The Problem

In Indonesian B2B commerce, customers refer to products by colloquial names, brand abbreviations, or regional terms. Standard keyword search fails completely — "indomie kuning" or "mie soto" won't match the official catalog entry. The platform also needed to handle 35+ distinct customer intent types (cart operations to profile inquiries) and answer FAQs without maintaining brittle lookup tables.

The Approach — One Unified RAG Pipeline

A three-collection ChromaDB setup with semantic embeddings (sentence-transformers all-MiniLM-L6-v2) resolves queries across three knowledge domains in parallel:

  • Product collection — each product embedded with its official name, colloquial aliases, pack size, and description, enabling fuzzy matching regardless of naming variation.
  • FAQ collection — sourced from ClickHouse and indexed into ChromaDB, handling paraphrase and spelling variation.
  • Intent collection — 35 intent types embedded as concrete example phrases, classifying the customer's action before routing to the LLM.

A single UnifiedRetriever searches all three and returns the best match by relevance_score = 1.0 - cosine_distance; the UnifiedRAGOrchestrator builds targeted LLM context and generates the Indonesian-language response.

Architecture

  User Query (Indonesian / colloquial)
          │
  ┌───────▼───────────────────────────────┐
  │  UnifiedRetriever                     │
  │  Embedding → parallel ChromaDB search │
  └───┬───────────────┬───────────────┬───┘
      ▼               ▼               ▼
  [Products]      [FAQs]         [Intents]
  colloquial      ClickHouse     35 types
  name mapping    sourced
      │               │               │
      └───────┬───────┴───────────────┘
              │  best match by relevance_score
              ▼
  ┌───────────────────────────────────────┐
  │  UnifiedRAGOrchestrator               │
  │  LLM context build + response         │
  │  Function calling: check_inventory()  │
  └───────────────────────────────────────┘
              │
              ▼
  Response + Order Tracking (JSON)

Key Features

  • Colloquial name resolution: Products are indexed with semicolon-separated colloquial alias lists. A query for "mie goreng bungkusan merah" correctly resolves to the official product via semantic similarity, with no explicit alias lookup table.
  • LLM function calling for inventory: When a product query includes a quantity, the orchestrator enables a check_inventory(sku, requested_quantity) function call. The LLM invokes it automatically, and the result is captured by OrderTracker and persisted to JSON — simulating an order capture flow.
  • ClickHouse FAQ integration: FAQ data is fetched from a ClickHouse database at index time and stored in ChromaDB, decoupling the vector search from live database queries during runtime.
  • Docker-first deployment: The entire system runs inside a single Docker container. Indexing scripts are run as one-time setup commands inside the container, with ChromaDB persisted to a mounted volume. No Python installation required on the host server.
  • Windows compatibility: All scripts include UTF-8 reconfiguration for Windows console output, and dependency versions are pinned to avoid onnxruntime DLL issues specific to Windows + torch 2.8.0.

Technical Challenges

The primary compatibility challenge was ChromaDB version locking. ChromaDB 1.3.4 causes segmentation faults on Windows when paired with torch 2.8.0 — the version required for sentence-transformers 2.7.0. The fix was to pin chromadb==0.5.0 and document the constraint explicitly. Similarly, onnxruntime was removed from requirements.txt entirely (Docker uses PyTorch backend; Windows developers install 1.16.3 locally), preventing DLL load failures in the Docker image.

Intent classification required careful data design: the intent collection indexes not just intent names but concrete example customer phrases, so the embedding captures linguistic variation rather than just categorical labels. This keeps the system adaptable — adding a new intent requires only adding example phrases to data/intent.txt and re-indexing.

Impact

  • Established the semantic retrieval baseline for the platform's chatbot — covering product search, FAQ, and intent classification in a single unified pipeline.
  • 35+ intent types classified with no hardcoded keyword matching, using only semantic similarity against example phrases.
  • Dockerized deployment makes the system reproducible across environments with a single docker-compose up.
  • Colloquial name resolution removes the need for a manually maintained alias lookup table, reducing ongoing maintenance overhead.