Build Your Own Chatbot Without LangChain/LlamaIndex

Senior Developer · 2025-07-24 · 10

TL;DR — Can't I build a chatbot without LangChain or LlamaIndex? Good news! You can absolutely build a powerful chatbot without frameworks. Today, I'll share how to build your own chatbot from A to Z with pure code.

Build Your Own Chatbot Without LangChain/LlamaIndex

💡 "Can I Do This Without Frameworks?"

Hello! I'm a senior developer. Recently, many people have been asking me:

"Can't I build a chatbot without LangChain or LlamaIndex?" "These frameworks feel too heavy..." "I just want to implement the features I need..."

Good news! You can absolutely build a powerful chatbot without frameworks. Today, I'll share how to build your own chatbot from A to Z with pure code.

Custom chatbot development Building a real custom chatbot without frameworks

🎯 Why Build Without Frameworks?

📊 Framework vs Custom Implementation

Aspect Using Framework Custom Implementation
Initial Dev Speed Fast ⚡ Moderate 🚶
Flexibility Limited 🔒 Unlimited 🚀
Bundle Size Large (MBs) 📦 Small (KBs) 🪶
Learning Curve Need to learn framework 📚 Just core concepts 🎯
Maintenance Dependency management 🔧 Full control ⚙️
Performance Optimization Limited ⚠️ Flexible ✨

💪 Advantages of Custom Implementation

  1. Lightweight: Only implement what you need
  2. Transparent: Understand and control all code
  3. Optimizable: Tune performance for specific use cases
  4. Educational: Learn core principles of AI chatbots

Architecture comparison Simple yet powerful architecture

🏗️ Basic Architecture Design

📐 Core Components

┌─────────────────────────────────────────┐
│            User Interface               │
│         (React/Vue/Vanilla JS)          │
└────────────────┬────────────────────────┘
                 │
┌────────────────▼────────────────────────┐
│            API Gateway                  │
│         (Express/FastAPI)               │
└────────────────┬────────────────────────┘
                 │
┌────────────────▼────────────────────────┐
│         Conversation Manager            │
│    (Context/Memory/Session)             │
└────────────────┬────────────────────────┘
                 │
┌────────────────▼────────────────────────┐
│            AI Engine                    │
│    (OpenAI/Claude/Custom)               │
└─────────────────────────────────────────┘

🔑 Component Roles

  1. UI Layer: Handle user input/output
  2. API Gateway: Request routing, auth, rate limiting
  3. Conversation Manager: Manage conversation state
  4. AI Engine: Generate actual responses

💻 Step 1: Backend Implementation (Python)

🐍 Basic Structure Setup

# chatbot.py
import os
import json
from datetime import datetime
from typing import List, Dict, Optional
import openai
from dataclasses import dataclass, asdict

# OpenAI API setup
openai.api_key = os.getenv("OPENAI_API_KEY")

@dataclass
class Message:
    """Message data class"""
    role: str  # 'user' or 'assistant'
    content: str
    timestamp: datetime = None
    
    def __post_init__(self):
        if self.timestamp is None:
            self.timestamp = datetime.now()
    
    def to_dict(self):
        return {
            "role": self.role,
            "content": self.content,
            "timestamp": self.timestamp.isoformat()
        }

class ConversationMemory:
    """Conversation memory management"""
    def __init__(self, max_messages: int = 10):
        self.messages: List[Message] = []
        self.max_messages = max_messages
    
    def add_message(self, message: Message):
        """Add message with memory limit"""
        self.messages.append(message)
        if len(self.messages) > self.max_messages:
            self.messages.pop(0)
    
    def get_context(self) -> List[Dict]:
        """Return context in OpenAI API format"""
        return [{"role": msg.role, "content": msg.content} 
                for msg in self.messages]
    
    def clear(self):
        """Clear conversation"""
        self.messages = []

🧠 Chatbot Core Engine

class Chatbot:
    """Custom chatbot class"""
    def __init__(self, 
                 model: str = "gpt-3.5-turbo",
                 temperature: float = 0.7,
                 max_tokens: int = 500,
                 system_prompt: str = None):
        self.model = model
        self.temperature = temperature
        self.max_tokens = max_tokens
        self.system_prompt = system_prompt or self._default_system_prompt()
        self.memory = ConversationMemory()
        
    def _default_system_prompt(self) -> str:
        """Default system prompt"""
        return """You are a helpful and friendly AI assistant. 
        Provide accurate and useful answers to user questions.
        Keep responses concise yet informative."""
    
    async def get_response(self, user_input: str) -> str:
        """Generate response to user input"""
        # Add user message
        user_message = Message(role="user", content=user_input)
        self.memory.add_message(user_message)
        
        # Build full conversation context
        messages = [
            {"role": "system", "content": self.system_prompt}
        ] + self.memory.get_context()
        
        try:
            # OpenAI API call
            response = await openai.ChatCompletion.acreate(
                model=self.model,
                messages=messages,
                temperature=self.temperature,
                max_tokens=self.max_tokens
            )
            
            # Extract response
            assistant_response = response.choices[0].message.content
            
            # Add assistant message to memory
            assistant_message = Message(
                role="assistant", 
                content=assistant_response
            )
            self.memory.add_message(assistant_message)
            
            return assistant_response
            
        except Exception as e:
            return f"Sorry, an error occurred: {str(e)}"
    
    def set_system_prompt(self, prompt: str):
        """Change system prompt"""
        self.system_prompt = prompt
        
    def clear_memory(self):
        """Clear conversation history"""
        self.memory.clear()

🌐 FastAPI Server Implementation

# server.py
from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
from typing import Optional
import uvicorn
import uuid

app = FastAPI()

# CORS setup
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# Request/Response models
class ChatRequest(BaseModel):
    message: str
    session_id: Optional[str] = None

class ChatResponse(BaseModel):
    response: str
    session_id: str

# Manage chatbot instances per session
sessions = {}

@app.post("/api/chat", response_model=ChatResponse)
async def chat(request: ChatRequest):
    """Chat endpoint"""
    # Generate new session ID if not provided
    session_id = request.session_id or str(uuid.uuid4())
    
    # Get or create chatbot instance for session
    if session_id not in sessions:
        sessions[session_id] = Chatbot()
    
    chatbot = sessions[session_id]
    
    try:
        # Generate response
        response = await chatbot.get_response(request.message)
        
        return ChatResponse(
            response=response,
            session_id=session_id
        )
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@app.delete("/api/chat/{session_id}")
async def clear_chat(session_id: str):
    """Clear conversation history"""
    if session_id in sessions:
        sessions[session_id].clear_memory()
        return {"message": "Conversation cleared successfully"}
    else:
        raise HTTPException(status_code=404, detail="Session not found")

@app.get("/api/health")
async def health_check():
    """Health check"""
    return {"status": "healthy"}

if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=8000)

Backend architecture Clean backend structure

🎨 Step 2: Frontend Implementation

⚛️ React Chatbot UI

// Chatbot.jsx
import React, { useState, useEffect, useRef } from 'react';
import axios from 'axios';
import './Chatbot.css';

const Chatbot = () => {
  const [messages, setMessages] = useState([]);
  const [input, setInput] = useState('');
  const [loading, setLoading] = useState(false);
  const [sessionId, setSessionId] = useState(null);
  const messagesEndRef = useRef(null);
  
  const API_URL = process.env.REACT_APP_API_URL || 'http://localhost:8000';
  
  // Auto scroll
  const scrollToBottom = () => {
    messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
  };
  
  useEffect(() => {
    scrollToBottom();
  }, [messages]);
  
  // Send message
  const sendMessage = async () => {
    if (!input.trim()) return;
    
    const userMessage = {
      role: 'user',
      content: input,
      timestamp: new Date().toISOString()
    };
    
    setMessages(prev => [...prev, userMessage]);
    setInput('');
    setLoading(true);
    
    try {
      const response = await axios.post(`${API_URL}/api/chat`, {
        message: input,
        session_id: sessionId
      });
      
      const assistantMessage = {
        role: 'assistant',
        content: response.data.response,
        timestamp: new Date().toISOString()
      };
      
      setMessages(prev => [...prev, assistantMessage]);
      setSessionId(response.data.session_id);
      
    } catch (error) {
      console.error('Error:', error);
      const errorMessage = {
        role: 'assistant',
        content: 'Sorry, an error occurred. Please try again.',
        timestamp: new Date().toISOString()
      };
      setMessages(prev => [...prev, errorMessage]);
    } finally {
      setLoading(false);
    }
  };
  
  // Handle Enter key
  const handleKeyPress = (e) => {
    if (e.key === 'Enter' && !e.shiftKey) {
      e.preventDefault();
      sendMessage();
    }
  };
  
  // Clear conversation
  const clearChat = async () => {
    if (sessionId) {
      try {
        await axios.delete(`${API_URL}/api/chat/${sessionId}`);
        setMessages([]);
        setSessionId(null);
      } catch (error) {
        console.error('Error clearing chat:', error);
      }
    }
  };
  
  return (
    <div className="chatbot-container">
      <div className="chatbot-header">
        <h2>🤖 My Custom AI Chatbot</h2>
        <button onClick={clearChat} className="clear-btn">
          Clear Chat
        </button>
      </div>
      
      <div className="messages-container">
        {messages.map((message, index) => (
          <div
            key={index}
            className={`message ${message.role}`}
          >
            <div className="message-content">
              {message.content}
            </div>
            <div className="message-time">
              {new Date(message.timestamp).toLocaleTimeString()}
            </div>
          </div>
        ))}
        {loading && (
          <div className="message assistant loading">
            <div className="typing-indicator">
              <span></span>
              <span></span>
              <span></span>
            </div>
          </div>
        )}
        <div ref={messagesEndRef} />
      </div>
      
      <div className="input-container">
        <textarea
          value={input}
          onChange={(e) => setInput(e.target.value)}
          onKeyPress={handleKeyPress}
          placeholder="Type your message..."
          rows="3"
          disabled={loading}
        />
        <button 
          onClick={sendMessage} 
          disabled={loading || !input.trim()}
        >
          Send
        </button>
      </div>
    </div>
  );
};

export default Chatbot;

🎨 Styling (CSS)

/* Chatbot.css */
.chatbot-container {
  max-width: 800px;
  margin: 0 auto;
  height: 90vh;
  display: flex;
  flex-direction: column;
  background: #f5f5f5;
  border-radius: 10px;
  overflow: hidden;
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}

.chatbot-header {
  background: #2c3e50;
  color: white;
  padding: 1rem;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.chatbot-header h2 {
  margin: 0;
  font-size: 1.5rem;
}

.clear-btn {
  background: #e74c3c;
  color: white;
  border: none;
  padding: 0.5rem 1rem;
  border-radius: 5px;
  cursor: pointer;
  transition: background 0.3s;
}

.clear-btn:hover {
  background: #c0392b;
}

.messages-container {
  flex: 1;
  overflow-y: auto;
  padding: 1rem;
  background: white;
}

.message {
  margin-bottom: 1rem;
  display: flex;
  flex-direction: column;
}

.message.user {
  align-items: flex-end;
}

.message.assistant {
  align-items: flex-start;
}

.message-content {
  max-width: 70%;
  padding: 0.75rem 1rem;
  border-radius: 10px;
  word-wrap: break-word;
}

.message.user .message-content {
  background: #3498db;
  color: white;
}

.message.assistant .message-content {
  background: #ecf0f1;
  color: #2c3e50;
}

.message-time {
  font-size: 0.75rem;
  color: #7f8c8d;
  margin-top: 0.25rem;
}

.typing-indicator {
  display: flex;
  align-items: center;
  gap: 4px;
}

.typing-indicator span {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #7f8c8d;
  animation: typing 1.4s infinite;
}

.typing-indicator span:nth-child(2) {
  animation-delay: 0.2s;
}

.typing-indicator span:nth-child(3) {
  animation-delay: 0.4s;
}

@keyframes typing {
  0%, 60%, 100% {
    transform: translateY(0);
  }
  30% {
    transform: translateY(-10px);
  }
}

.input-container {
  display: flex;
  padding: 1rem;
  background: #ecf0f1;
  gap: 1rem;
}

.input-container textarea {
  flex: 1;
  padding: 0.75rem;
  border: 1px solid #bdc3c7;
  border-radius: 5px;
  resize: none;
  font-family: inherit;
}

.input-container button {
  padding: 0.75rem 2rem;
  background: #3498db;
  color: white;
  border: none;
  border-radius: 5px;
  cursor: pointer;
  transition: background 0.3s;
}

.input-container button:hover:not(:disabled) {
  background: #2980b9;
}

.input-container button:disabled {
  background: #95a5a6;
  cursor: not-allowed;
}

Frontend UI Clean chatbot UI

🚀 Step 3: Advanced Features

💾 Conversation History Storage (PostgreSQL)

# database.py
import asyncpg
from datetime import datetime
import json

class ChatDatabase:
    """Conversation history database management"""
    def __init__(self, database_url: str):
        self.database_url = database_url
        self.pool = None
    
    async def init(self):
        """Initialize database connection pool"""
        self.pool = await asyncpg.create_pool(self.database_url)
        
        # Create tables
        async with self.pool.acquire() as conn:
            await conn.execute('''
                CREATE TABLE IF NOT EXISTS conversations (
                    id SERIAL PRIMARY KEY,
                    session_id VARCHAR(255) NOT NULL,
                    user_id VARCHAR(255),
                    message_role VARCHAR(50) NOT NULL,
                    message_content TEXT NOT NULL,
                    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
                );
                
                CREATE INDEX IF NOT EXISTS idx_session_id 
                ON conversations(session_id);
            ''')
    
    async def save_message(self, session_id: str, message: Message, 
                          user_id: Optional[str] = None):
        """Save message"""
        async with self.pool.acquire() as conn:
            await conn.execute('''
                INSERT INTO conversations 
                (session_id, user_id, message_role, message_content)
                VALUES ($1, $2, $3, $4)
            ''', session_id, user_id, message.role, message.content)
    
    async def get_conversation_history(self, session_id: str) -> List[Message]:
        """Get conversation history"""
        async with self.pool.acquire() as conn:
            rows = await conn.fetch('''
                SELECT message_role, message_content, created_at
                FROM conversations
                WHERE session_id = $1
                ORDER BY created_at ASC
            ''', session_id)
            
            return [
                Message(
                    role=row['message_role'],
                    content=row['message_content'],
                    timestamp=row['created_at']
                )
                for row in rows
            ]

🔍 Semantic Search (Embeddings)

# embeddings.py
import numpy as np
from typing import List, Tuple

class SemanticSearch:
    """Embedding-based semantic search"""
    def __init__(self):
        self.embeddings = []
        self.documents = []
    
    async def get_embedding(self, text: str) -> List[float]:
        """Convert text to embedding vector"""
        response = await openai.Embedding.acreate(
            model="text-embedding-ada-002",
            input=text
        )
        return response['data'][0]['embedding']
    
    async def add_document(self, document: str):
        """Add document and create embedding"""
        embedding = await self.get_embedding(document)
        self.embeddings.append(embedding)
        self.documents.append(document)
    
    def cosine_similarity(self, a: List[float], b: List[float]) -> float:
        """Calculate cosine similarity"""
        a = np.array(a)
        b = np.array(b)
        return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))
    
    async def search(self, query: str, top_k: int = 5) -> List[Tuple[str, float]]:
        """Search for most similar documents"""
        query_embedding = await self.get_embedding(query)
        
        similarities = [
            (doc, self.cosine_similarity(query_embedding, emb))
            for doc, emb in zip(self.documents, self.embeddings)
        ]
        
        # Sort by similarity
        similarities.sort(key=lambda x: x[1], reverse=True)
        
        return similarities[:top_k]

# Integrate search into chatbot
class EnhancedChatbot(Chatbot):
    """Chatbot with search capabilities"""
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.search_engine = SemanticSearch()
        self.knowledge_base_loaded = False
    
    async def load_knowledge_base(self, documents: List[str]):
        """Load knowledge base"""
        for doc in documents:
            await self.search_engine.add_document(doc)
        self.knowledge_base_loaded = True
    
    async def get_response(self, user_input: str) -> str:
        """Generate response using search results"""
        context = ""
        
        # Search for relevant information
        if self.knowledge_base_loaded:
            search_results = await self.search_engine.search(user_input, top_k=3)
            if search_results:
                context = "\n\nRelevant information:\n"
                for doc, score in search_results:
                    if score > 0.7:  # Similarity threshold
                        context += f"- {doc}\n"
        
        # Create prompt with context
        enhanced_input = user_input
        if context:
            enhanced_input = f"{user_input}\n{context}"
        
        return await super().get_response(enhanced_input)

🔐 Authentication & Authorization

# auth.py
from datetime import datetime, timedelta
import jwt
from passlib.context import CryptContext

pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")

class AuthManager:
    """Authentication manager"""
    def __init__(self, secret_key: str):
        self.secret_key = secret_key
    
    def create_access_token(self, user_id: str, expires_delta: timedelta = None):
        """Create JWT access token"""
        to_encode = {"sub": user_id}
        if expires_delta:
            expire = datetime.utcnow() + expires_delta
        else:
            expire = datetime.utcnow() + timedelta(hours=24)
        
        to_encode.update({"exp": expire})
        encoded_jwt = jwt.encode(to_encode, self.secret_key, algorithm="HS256")
        return encoded_jwt
    
    def verify_token(self, token: str):
        """Verify token"""
        try:
            payload = jwt.decode(token, self.secret_key, algorithms=["HS256"])
            user_id: str = payload.get("sub")
            if user_id is None:
                return None
            return user_id
        except jwt.PyJWTError:
            return None

# Add auth middleware to FastAPI
from fastapi import Depends, HTTPException, status
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials

security = HTTPBearer()
auth_manager = AuthManager(secret_key="your-secret-key")

async def get_current_user(credentials: HTTPAuthorizationCredentials = Depends(security)):
    """Get current user"""
    token = credentials.credentials
    user_id = auth_manager.verify_token(token)
    if user_id is None:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid authentication credentials",
            headers={"WWW-Authenticate": "Bearer"},
        )
    return user_id

# Protected endpoint
@app.post("/api/chat/protected")
async def protected_chat(
    request: ChatRequest,
    current_user: str = Depends(get_current_user)
):
    """Chat endpoint requiring authentication"""
    # Manage user-specific chatbot instances
    user_session_id = f"{current_user}:{request.session_id}"
    # ... rest of logic

Advanced features Smarter chatbot with advanced features

📊 Performance Optimization

Response Speed Improvement

# 1. Response streaming
async def stream_response(self, user_input: str):
    """Generate response with streaming"""
    messages = [
        {"role": "system", "content": self.system_prompt}
    ] + self.memory.get_context()
    
    response = await openai.ChatCompletion.acreate(
        model=self.model,
        messages=messages,
        temperature=self.temperature,
        max_tokens=self.max_tokens,
        stream=True  # Enable streaming
    )
    
    full_response = ""
    async for chunk in response:
        if chunk['choices'][0]['delta'].get('content'):
            content = chunk['choices'][0]['delta']['content']
            full_response += content
            yield content
    
    # Save complete response to memory
    assistant_message = Message(role="assistant", content=full_response)
    self.memory.add_message(assistant_message)

# 2. Caching implementation
from functools import lru_cache
import hashlib

class CachedChatbot(Chatbot):
    """Chatbot with caching"""
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.cache = {}
        self.cache_ttl = 3600  # 1 hour
    
    def _get_cache_key(self, messages: List[Dict]) -> str:
        """Generate cache key"""
        content = json.dumps(messages, sort_keys=True)
        return hashlib.md5(content.encode()).hexdigest()
    
    async def get_response(self, user_input: str) -> str:
        """Generate response with caching"""
        messages = [
            {"role": "system", "content": self.system_prompt}
        ] + self.memory.get_context()
        
        cache_key = self._get_cache_key(messages)
        
        # Check cache
        if cache_key in self.cache:
            cached_response, timestamp = self.cache[cache_key]
            if datetime.now().timestamp() - timestamp < self.cache_ttl:
                return cached_response
        
        # Cache miss - generate response
        response = await super().get_response(user_input)
        
        # Save to cache
        self.cache[cache_key] = (response, datetime.now().timestamp())
        
        return response

📈 Monitoring & Analytics

# monitoring.py
from prometheus_client import Counter, Histogram, Gauge
import time

# Define metrics
request_count = Counter('chatbot_requests_total', 'Total requests')
request_duration = Histogram('chatbot_request_duration_seconds', 'Request duration')
active_sessions = Gauge('chatbot_active_sessions', 'Active sessions')
error_count = Counter('chatbot_errors_total', 'Total errors')

class MonitoredChatbot(Chatbot):
    """Chatbot with monitoring"""
    
    @request_duration.time()
    async def get_response(self, user_input: str) -> str:
        """Generate response with monitoring"""
        request_count.inc()
        
        try:
            response = await super().get_response(user_input)
            return response
        except Exception as e:
            error_count.inc()
            raise e

# Logging setup
import logging

logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)

class LoggedChatbot(MonitoredChatbot):
    """Chatbot with logging"""
    
    async def get_response(self, user_input: str) -> str:
        logger.info(f"User input: {user_input[:100]}...")
        
        start_time = time.time()
        response = await super().get_response(user_input)
        duration = time.time() - start_time
        
        logger.info(f"Response generated in {duration:.2f}s")
        
        return response

🎯 Real Project: Domain-Specific Chatbot

💼 Customer Service Bot

class CustomerServiceBot(EnhancedChatbot):
    """Customer service specialized chatbot"""
    
    def __init__(self):
        system_prompt = """You are a professional customer service representative.
        Follow these principles:
        1. Always maintain a polite and professional attitude
        2. Accurately identify customer issues
        3. Provide clear step-by-step solutions
        4. Check if additional help is needed
        5. End on a positive note
        """
        
        super().__init__(
            system_prompt=system_prompt,
            temperature=0.3  # Lower temperature for consistency
        )
        
        # Load FAQ database
        self.load_faq_database()
    
    async def load_faq_database(self):
        """Load FAQ database"""
        faqs = [
            "Q: How long does shipping take? A: Standard shipping takes 2-3 days, express arrives same day.",
            "Q: How do I return items? A: Returns accepted within 14 days for unopened items.",
            "Q: What payment methods do you accept? A: We accept credit cards, bank transfers, and digital wallets.",
            # ... more FAQs
        ]
        
        await self.load_knowledge_base(faqs)
    
    async def get_response(self, user_input: str) -> str:
        """Customer service optimized response"""
        # Sentiment analysis
        sentiment = await self.analyze_sentiment(user_input)
        
        # More careful response for negative sentiment
        if sentiment == "negative":
            self.temperature = 0.2
        
        response = await super().get_response(user_input)
        
        # Add emoji for friendliness
        if sentiment == "positive":
            response = "😊 " + response
        elif sentiment == "negative":
            response = "🤝 " + response
        
        return response
    
    async def analyze_sentiment(self, text: str) -> str:
        """Simple sentiment analysis"""
        negative_words = ["angry", "frustrated", "terrible", "worst", "bad"]
        positive_words = ["good", "thanks", "great", "excellent", "happy"]
        
        text_lower = text.lower()
        
        negative_score = sum(1 for word in negative_words if word in text_lower)
        positive_score = sum(1 for word in positive_words if word in text_lower)
        
        if negative_score > positive_score:
            return "negative"
        elif positive_score > negative_score:
            return "positive"
        else:
            return "neutral"

Customer service bot Professional customer service bot

🚀 Deployment & Operations

🐳 Docker Containerization

# Dockerfile
FROM python:3.9-slim

WORKDIR /app

# Install dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Copy app
COPY . .

# Environment variables
ENV PYTHONUNBUFFERED=1

# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=40s --retries=3 \
  CMD curl -f http://localhost:8000/api/health || exit 1

# Run
CMD ["uvicorn", "server:app", "--host", "0.0.0.0", "--port", "8000"]

☸️ Kubernetes Deployment

# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: chatbot-api
spec:
  replicas: 3
  selector:
    matchLabels:
      app: chatbot-api
  template:
    metadata:
      labels:
        app: chatbot-api
    spec:
      containers:
      - name: chatbot-api
        image: your-registry/chatbot-api:latest
        ports:
        - containerPort: 8000
        env:
        - name: OPENAI_API_KEY
          valueFrom:
            secretKeyRef:
              name: chatbot-secrets
              key: openai-api-key
        resources:
          requests:
            memory: "256Mi"
            cpu: "250m"
          limits:
            memory: "512Mi"
            cpu: "500m"
---
apiVersion: v1
kind: Service
metadata:
  name: chatbot-api-service
spec:
  selector:
    app: chatbot-api
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8000
  type: LoadBalancer

📊 Conclusion: You Don't Need Frameworks!

What We Built

  1. Core Chatbot Engine

    • Conversation context management
    • Memory optimization
    • Session management
  2. Advanced Features 🚀

    • Semantic search (Embeddings)
    • Conversation history storage
    • Authentication & authorization
  3. Performance Optimization

    • Response streaming
    • Caching
    • Monitoring
  4. Real Applications 💼

    • Domain-specific bots
    • Sentiment analysis
    • FAQ integration

💡 Key Lessons

  1. Frameworks are just tools: You can build anything if you understand the principles
  2. Build only what you need: Remove unnecessary complexity
  3. Full control: Customize every aspect
  4. Educational value: Deeply understand how AI chatbots work
  • Those who need lightweight chatbots
  • Projects requiring specific features only
  • Need for complete customization
  • Want to deeply understand AI chatbot principles

Next Post Preview: "Building AI Agents to Automate Repetitive Tasks: A Practical Guide"

Share your custom chatbot experiences in the comments! 🤖


Tags: #Chatbot #CustomChatbot #NoFramework #OpenAI #Python #FastAPI #React #AIEngineering #ChatbotDevelopment #BuildFromScratch