Internal Use Only - Confidential
An intelligent FAQ support chatbot using Retrieval-Augmented Generation (RAG) to answer questions about HR policies, features, and procedures from internal documentation. The system processes HR documentation, generates embeddings, and provides accurate answers using vector similarity search and LLM generation.
Repository: https://github.com/DevAsadYasin/hr-faq-rag-chatbot
This system is designed for HR teams, employees, and customer support to quickly find answers about:
- Employee policies (leave, attendance, remote work)
- Benefits enrollment and administration
- Payroll and compensation information
- HR procedures and workflows
- System features and functionality
- Troubleshooting and support
Customer support receives 200+ repetitive questions daily about HR policies, features, and procedures already documented in internal FAQs and guides. This system provides an intelligent FAQ Support Chatbot that can instantly answer user questions by retrieving relevant information from the company's documentation without requiring manual search or agent intervention.
The system uses a RAG (Retrieval-Augmented Generation) architecture:
- Document Processing: Loads and chunks HR documentation
- Embedding Generation: Creates vector representations (locally, for privacy)
- Index Building: Stores embeddings in FAISS vector store
- Query Processing: Retrieves relevant chunks using hybrid search
- Answer Generation: Uses LLM to generate answers from retrieved context
- Full LangChain Integration: Complete LangChain stack (loaders, splitters, embeddings, vector stores, chains, retrievers)
- Local-First Embeddings: Defaults to local HuggingFace embeddings (no data sent externally for embeddings)
- Intelligent Chunking: LangChain RecursiveCharacterTextSplitter/TokenTextSplitter with overlap for context preservation
- Hybrid Search: Combines semantic vector search with BM25 keyword search for precision (configurable: hybrid/keyword/vector)
- Metadata Filtering: Filter by service, section, document type with lenient filtering
- Query Parsing: Auto-extracts filters from natural language queries
- Multiple Search Modes: Hybrid (default), keyword-only, or vector-only via
SEARCH_MODEenv variable - Production-Ready: Dimensionality validation, batching, retry logic, verification queries
- Index Management: Support for adding vectors and rebuilding with deletions
- Progress Tracking: Visual progress bars for long-running operations
- Multi-LLM Support: OpenRouter, Gemini, and OpenAI with automatic fallback
- Priority-Based Selection: Configurable provider priority (default: OpenRouter โ Gemini โ OpenAI)
- RAG Pipeline: LangChain LCEL chain combining retrieval + generation
- Structured Output: JSON responses with question, answer, related chunks, and provider info
- Quality Evaluation: Optional evaluator agent for answer quality scoring (0-10)
- Confidential Data Safe: Local embeddings ensure no document data leaves your system
- Multi-Format Support: Automatically loads and processes TXT, PDF, Markdown, and DOCX files
- FastAPI REST API: RESTful API with Swagger documentation for programmatic access
- Dual Access Modes: Both CLI script and API endpoints available
assignment02/
โโโ data/
โ โโโ test_document.txt # HR policies and procedures documentation (confidential)
โ โโโ ... # Additional documents (PDF, Markdown, DOCX supported)
โโโ src/
โ โโโ __init__.py
โ โโโ config.py # Configuration management
โ โโโ build_index.py # Index building pipeline
โ โโโ query.py # Query pipeline with hybrid search
โ โโโ api.py # FastAPI REST API endpoints
โ โโโ evaluator.py # Answer quality evaluator
โ โโโ hybrid_search.py # Hybrid search implementation (BM25 + semantic)
โ โโโ metadata_extractor.py # Metadata extraction and query parsing
โ โโโ llm_manager.py # Multi-provider LLM manager with fallback
โ โโโ utils.py # Retry logic, validation, utilities
โโโ run_api.py # FastAPI server entry point
โโโ outputs/
โ โโโ embeddings/ # FAISS vector store + BM25 data
โ โ โโโ faiss_index/ # FAISS vector store (index.faiss, index.pkl)
โ โ โโโ bm25_documents.json # BM25 keyword search data
โ โ โโโ metadata.json # Index metadata
โ โโโ logs/ # Application logs
โ โโโ sample_queries.json # Sample query responses
โโโ tests/
โ โโโ test_core.py # Unit tests
โโโ .env # Environment variables (gitignored)
โโโ .gitignore # Git ignore rules
โโโ requirements.txt # Python dependencies
โโโ README.md # This file
โโโ TECHNICAL_DECISIONS.md # Technical choices and rationale
- Python 3.11+ (required for LangChain v1.0 compatibility)
- pip package manager
- At least one LLM API key: OpenRouter, Gemini, or OpenAI (for answer generation)
- Local embeddings (default, no API key needed for embeddings)
# Clone the repository
git clone https://github.com/DevAsadYasin/hr-faq-rag-chatbot.git
cd hr-faq-rag-chatbot
# OR navigate if already cloned
cd /path/to/hr-faq-rag-chatbotpython -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activateWhy virtual environment?
- Isolates project dependencies
- Prevents conflicts with system packages
- Ensures consistent Python version
pip install -r requirements.txtThis installs:
- LangChain and related packages
- FAISS for vector storage
- Sentence-transformers for local embeddings
- Document loaders (PDF, DOCX, Markdown)
- BM25 for keyword search
- Multi-LLM provider support
Create a .env file in the project root and add your API keys:
Required Configuration:
LLM Provider (set at least one):
OPENROUTER_API_KEY=your-openrouter-key-here
# OR
GEMINI_API_KEY=your-gemini-key-here
# OR
OPENAI_API_KEY=your-openai-key-hereOptional Configuration:
Priority Order (default: openrouter,gemini,openai):
LLM_PRIORITY_ORDER=openrouter,gemini,openaiModel Selection (per provider):
LLM_MODEL_OPENROUTER=openai/gpt-3.5-turbo
LLM_MODEL_GEMINI=gemini-pro
LLM_MODEL_OPENAI=gpt-3.5-turboSearch Mode (default: hybrid):
SEARCH_MODE=hybrid # Options: hybrid, keyword, vectorImportant Notes:
- The system defaults to local embeddings (no API calls for embeddings)
- LLM API keys are only needed for answer generation
- Only selected chunks (top-k) are sent to LLM, not the full document
- See
TECHNICAL_DECISIONS.mdfor detailed explanations
ls data/ # Should show your FAQ documentsSupported file formats:
.txt- Plain text files.md- Markdown files.pdf- PDF documents.docx- Microsoft Word documents
The system automatically:
- Loads all supported documents from the
data/directory - Processes each file according to its format
- Skips unsupported file formats with a warning
# Test imports
python -c "from src.config import *; print('โ
Configuration loaded')"
python -c "from src.llm_manager import LLMManager; print('โ
LLM Manager ready')"First, process the FAQ documents, chunk them, generate embeddings, and create the vector store:
python src/build_index.pyWhat this does:
- Loads all supported documents from
data/directory - Processes each file according to its format (TXT, PDF, Markdown, DOCX)
- Chunks all documents (target: 20+ chunks total)
- Extracts metadata from each chunk (service, section, doc_type, tags)
- Generates embeddings for each chunk (locally, no external API calls)
- Creates FAISS vector store
- Saves BM25 document data for keyword search
- Saves metadata for filtering and debugging
Expected output:
Starting FAQ Index Building Pipeline
Loading: test_document.txt (.txt)
Document loaded successfully. Total characters: 124133
Document chunked into 490 chunks
Creating vector store with 490 chunks
Generating embeddings (this may take a while)...
Vector store created and saved successfully!
BM25 document data saved to: outputs/embeddings/bm25_documents.json
Metadata saved to: outputs/embeddings/metadata.json
Index Building Pipeline Completed Successfully!
Storage Location:
- FAISS Vector Store:
outputs/embeddings/faiss_index/ - BM25 Data:
outputs/embeddings/bm25_documents.json - Metadata:
outputs/embeddings/metadata.json
Custom Document Path:
export FAQ_DOCUMENT_PATH=/path/to/your/documents
python src/build_index.pyQuery the system with a question:
# Using command line argument
python src/query.py "How do I request vacation time?"
# Or run without arguments for sample question
python src/query.pyExample output:
{
"user_question": "How do I request vacation time?",
"system_answer": "To request vacation time, log into the Employee Self-Service Portal, navigate to the Time & Attendance section, select \"Request Time Off\", choose \"Vacation\" as the leave type, enter your start and end dates, and add any comments or notes for your manager. Make sure to submit the request at least 2 weeks (14 calendar days) in advance of the requested start date to allow managers to plan for coverage and ensure business continuity.",
"chunks_related": [
{
"chunk_id": "faq_document_v1_chunk_0012",
"chunk_text": "VACATION LEAVE POLICY\n- Accrual Rate: Full-time employees accrue 1.25 vacation days per month (15 days per year)\n- Request Process: All vacation requests must be submitted through the Employee Self-Service Portal at least 2 weeks in advance...",
"metadata": {
"document_id": "faq_document_v1",
"chunk_index": 12,
"service_name": "time-attendance",
"section": "leave-policies",
"doc_type": "procedure"
}
}
],
"llm_provider": "openrouter"
}Response Structure:
user_question: The original questionsystem_answer: Generated answer from LLMchunks_related: Array of relevant document chunks with metadatallm_provider: Which LLM provider was used (if available)
Evaluate the quality of generated answers:
# Evaluate from sample_queries.json
python src/evaluator.py outputs/sample_queries.jsonStart the API server for programmatic access:
# Using the run script
python run_api.py
# OR using uvicorn directly
uvicorn src.api:app --reload --host 0.0.0.0 --port 8000The API will be available at:
- API Base: http://localhost:8000
- Swagger Docs: http://localhost:8000/docs
- ReDoc: http://localhost:8000/redoc
- Health Check: http://localhost:8000/health
- Query Endpoint: http://localhost:8000/query
Example API Request:
curl -X POST "http://localhost:8000/query" \
-H "Content-Type: application/json" \
-d '{
"question": "How do I request vacation time?",
"filters": {
"service_name": "time-attendance"
}
}'Example Python Client:
import requests
response = requests.post(
"http://localhost:8000/query",
json={
"question": "How do I request vacation time?",
"filters": {"service_name": "time-attendance"}
}
)
print(response.json())Example evaluation output:
{
"score": 9,
"reason": "The answer accurately provides step-by-step instructions. Chunks are highly relevant. Answer is complete and accurate.",
"chunk_relevance_score": 0.95,
"answer_accuracy_score": 0.9,
"completeness_score": 0.95
}Configuration is managed through environment variables in .env file:
Search Mode (default: hybrid):
SEARCH_MODE=hybrid # Options: hybrid, keyword, vectorhybrid: Combines semantic (vector) + keyword (BM25) search (recommended)keyword: Pure BM25 keyword search only (good for exact term matching)vector: Pure semantic/vector search only (good for conceptual queries)
Hybrid Search Method:
HYBRID_SEARCH_METHOD=retrieve_then_filter # Options: retrieve_then_filter, weighted
SEMANTIC_WEIGHT=0.7 # Weight for semantic search (0-1)
KEYWORD_WEIGHT=0.3 # Weight for keyword search (0-1)Embedding Model (default: local):
EMBEDDING_MODEL=local # Recommended for confidential data
LOCAL_EMBEDDING_MODEL=sentence-transformers/all-MiniLM-L6-v2Why local embeddings?
- No document data sent to external services
- Maximum privacy for confidential HR data
- No embedding API costs
- Works offline after initial model download
Provider Priority (default: openrouter,gemini,openai):
LLM_PRIORITY_ORDER=openrouter,gemini,openaiModel Selection:
LLM_MODEL_OPENROUTER=openai/gpt-3.5-turbo
LLM_MODEL_GEMINI=gemini-pro
LLM_MODEL_OPENAI=gpt-3.5-turbo
LLM_TEMPERATURE=0 # Lower = more deterministicCHUNK_SIZE=500 # Characters per chunk
CHUNK_OVERLAP=100 # Overlap between chunks
CHUNKING_METHOD=character # Options: character, tokenTOP_K_CHUNKS=5 # Number of chunks to retrieve
SEARCH_TYPE=similarity # LangChain search type
SIMILARITY_THRESHOLD=0.7 # Minimum similarity scoreBATCH_SIZE=100 # Embedding generation batch size
ENABLE_PROGRESS_BAR=true # Show progress bars
MAX_RETRIES=3 # Retry attempts for API calls
LOG_LEVEL=INFO # Logging levelExample questions the system can answer:
-
Leave and Time-Off Questions:
- "How do I request vacation time?"
- "What is the company's sick leave policy?"
- "How many vacation days do I accrue per month?"
-
Benefits Questions:
- "What is the company's 401k matching policy?"
- "How do I enroll in health insurance?"
- "When is open enrollment for benefits?"
-
Payroll Questions:
- "How do I change my direct deposit information?"
- "When will I receive my W-2?"
- "How do I access my pay stubs?"
-
Policy Questions:
- "What is the remote work policy?"
- "What is the dress code?"
- "What is the process for performance reviews?"
-
Procedural Questions:
- "How do I submit expense reimbursement?"
- "How do I update my personal information?"
- "How do I access training materials?"
-
Troubleshooting Questions:
- "I'm having login issues, what should I do?"
- "My timesheet was rejected, how do I fix it?"
- "I can't access the benefits portal, who should I contact?"
- HR Documentation: Contains internal HR policies and employee information
- Git Ignored: All data files and indexes are excluded from version control
- Local Embeddings: No document data sent externally for embedding generation
- Selective LLM Usage: Only top-k retrieved chunks sent to LLM, not full document
- API Key Security: All API keys stored in
.env(gitignored)
- Never commit
.envfile with API keys - Keep
outputs/embeddings/out of version control - Use local embeddings for maximum privacy
- Rotate API keys regularly
- Review logs for any data exposure
-
"No LLM API keys set"
- Solution: Set at least one API key in
.env:OPENROUTER_API_KEY,GEMINI_API_KEY, orOPENAI_API_KEY
- Solution: Set at least one API key in
-
"Vector store not found"
- Solution: Run
python src/build_index.pyfirst to create the index
- Solution: Run
-
"Document not found"
- Solution: Ensure
data/directory exists and contains supported documents (.txt,.md,.pdf,.docx)
- Solution: Ensure
-
"ModuleNotFoundError"
- Solution: Install dependencies:
pip install -r requirements.txt - Ensure you're in the virtual environment:
source venv/bin/activate
- Solution: Install dependencies:
-
"Low chunk count (< 20)"
- Solution: Increase document size or decrease
CHUNK_SIZEin.env
- Solution: Increase document size or decrease
-
"No chunks retrieved"
- Check if metadata filtering is too strict
- Try different search modes:
SEARCH_MODE=vectororSEARCH_MODE=keyword - Verify index was built successfully
- Index Building: ~2-5 minutes (depends on document size and embedding model)
- Query Processing: ~2-5 seconds (embedding + retrieval + LLM generation)
- Chunk Count: 490+ chunks from comprehensive HR documentation
- Retrieval Speed: < 100ms for top-k search
- Embedding Generation: ~1-2 seconds per 100 chunks (local)
- LLM Dependency: Requires at least one LLM API key (OpenRouter, Gemini, or OpenAI) for answer generation
- Context Window: Limited by LLM context window (varies by model)
- Chunk Size: Fixed chunk size may split related content
- Language: Optimized for English documentation
- TECHNICAL_DECISIONS.md: Detailed explanation of technical choices and rationale
- GitHub Repository: https://github.com/DevAsadYasin/hr-faq-rag-chatbot
- Conversation memory for multi-turn dialogues
- Web UI for interactive querying
- Batch evaluation on test question sets
- Support for multiple languages