Large Language Models (LLMs) like GPT-4 are incredibly intelligent, but they suffer from two fatal flaws: they hallucinate facts, and their knowledge is frozen in time. If you ask an LLM about your company's proprietary internal documents, it will fail. Retrieval-Augmented Generation (RAG) solves this by allowing your backend to 'read' your private database, find the relevant information, and inject it into the LLM's prompt before it answers.


Module 1: What is an Embedding?

Computers do not understand words; they understand numbers. An embedding is a process that converts a sentence into a massive array of floating-point numbers (a Vector) that represents the semantic meaning of that sentence.

Generating an Embedding (Node.js)javascript
import OpenAI from 'openai';
const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });

async function generateEmbedding(text) {
  const response = await openai.embeddings.create({
    model: 'text-embedding-3-small',
    input: text,
  });
  // Returns an array of 1536 floating point numbers: [-0.012, 0.443, -0.992...]
  return response.data[0].embedding;
}

Module 2: The Vector Database

Standard SQL databases (PostgreSQL) are designed to find exact matches (WHERE name = 'John'). Vector Databases (like Pinecone, Weaviate, or pgvector) are designed to find mathematical similarity between embeddings using algorithms like Cosine Similarity or K-Nearest Neighbors (KNN).

Storing Data in Pineconejavascript
import { Pinecone } from '@pinecone-database/pinecone';

const pc = new Pinecone({ apiKey: process.env.PINECONE_API_KEY });
const index = pc.index('company-docs');

async function ingestDocument(docId, textContext) {
  const vector = await generateEmbedding(textContext);
  
  await index.upsert([
    {
      id: docId,
      values: vector,
      // Store the original text as metadata so we can retrieve it later
      metadata: { text: textContext, author: 'HR Dept' }
    }
  ]);
}

Module 3: The RAG Pipeline Architecture

When a user asks a question, we don't send it straight to the LLM. Instead, we execute the RAG Pipeline.

The 4 Steps of RAG

  • 1. Embed the Query: Convert the user's question into a Vector.
  • 2. Search: Query the Vector DB for the top 3 most mathematically similar vectors.
  • 3. Augment: Extract the original text from the database results and inject it into a strict System Prompt.
  • 4. Generate: Send the Augmented Prompt to the LLM.
The RAG Execution Flowjavascript
async function askQuestion(userQuery) {
  // 1. Embed the user's question
  const queryVector = await generateEmbedding(userQuery);

  // 2. Search Pinecone for the Top 3 most relevant documents
  const searchResults = await index.query({
    vector: queryVector,
    topK: 3,
    includeMetadata: true
  });

  // 3. Extract the text
  const contextText = searchResults.matches.map(m => m.metadata.text).join('\n\n');

  // 4. Augment the Prompt
  const systemPrompt = `
    You are a helpful company assistant. Answer the user's question ONLY using the context provided below.
    If the answer is not in the context, say "I don't know."
    
    CONTEXT:
    ${contextText}
  `;

  // 5. Generate Answer
  const completion = await openai.chat.completions.create({
    model: 'gpt-4-turbo',
    messages: [
      { role: 'system', content: systemPrompt },
      { role: 'user', content: userQuery }
    ]
  });

  return completion.choices[0].message.content;
}

Module 4: Advanced Document Chunking

You cannot embed a 500-page PDF as a single vector. You must split it into "Chunks". If chunks are too small (1 sentence), you lose context. If chunks are too large (10 pages), the embedding becomes mathematically diluted.