A clean, modular Retrieval-Augmented Generation (RAG) backend prototype built with LangChain (JS/TS), Node.js/Express, and local Ollama models.
This repository demonstrates the fundamental flow of a modern RAG system:
- Load a Document: Ingests PDF documents (
Leave_Policy.pdf) using LangChain'sPDFLoader. - Text Chunking: Splits large documents into semantically meaningful chunks with overlap using
RecursiveCharacterTextSplitter. - Vector Embeddings: Generates mathematical vector embeddings via Ollama using
nomic-embed-text. - In-Memory Vector Store: Stores chunks and embeddings in memory using
MemoryVectorStore. - Similarity Retrieval: Retrieves the top-K most relevant chunks using
vectorStore.asRetriever(). - Prompt Formatting & LLM Response: Connects context and user queries into a
ChatPromptTemplateand generates grounded responses withChatOllama(gemma3:4b). - Hallucination Safeguard: Strictly instructs the model to acknowledge when evidence is insufficient ("I cannot find this information in the provided leave policy document.").
- Runtime: Node.js (v20+ recommended) with TypeScript &
tsx - Framework: Express.js
- Orchestration: LangChain (
@langchain/core,@langchain/ollama,@langchain/community,@langchain/textsplitters) - Embedding Model:
nomic-embed-text(running locally via Ollama) - LLM:
gemma3:4b(running locally via Ollama)
├── Leave_Policy.pdf # Sample company leave policy document
├── src/
│ ├── config/
│ │ └── models.ts # Ollama model initialization & configuration constants
│ ├── services/
│ │ ├── vectorStore.service.ts # In-memory vector database singleton
│ │ ├── ingestion.service.ts # PDF loading, text chunking, and embedding
│ │ └── rag.service.ts # Retrieval, prompt engineering, and LCEL pipeline
│ ├── controllers/
│ │ └── rag.controller.ts # Express request handlers
│ ├── routes/
│ │ └── rag.routes.ts # API route definitions
│ └── index.ts # Express server entry point
├── package.json
└── tsconfig.json
Make sure Ollama is installed and running with the required models:
ollama pull nomic-embed-text
ollama pull gemma3:4bnpm install --legacy-peer-depsnpm run devThe server will run on http://localhost:3000.
- Method:
GET - URL:
http://localhost:3000/api/rag/status
Loads, splits, embeds, and indexes Leave_Policy.pdf into vector memory.
- Method:
POST - URL:
http://localhost:3000/api/rag/ingest - Headers:
Content-Type: application/json - Body:
{}
- Method:
POST - URL:
http://localhost:3000/api/rag/ask - Headers:
Content-Type: application/json - Body:
{
"question": "How many days of casual leave do I get per year, and can I carry it forward?"
}- Method:
POST - URL:
http://localhost:3000/api/rag/ask - Headers:
Content-Type: application/json - Body:
{
"question": "What is the reimbursement limit for gym memberships?"
}- Response:
{
"success": true,
"data": {
"question": "What is the reimbursement limit for gym memberships?",
"answer": "I cannot find this information in the provided leave policy document.",
"retrievedChunksCount": 2,
"sources": [ ... ]
}
}