Building a Minimal Retrieval-Augmented Generation (RAG) System with LangChain, OpenAI, and Pinecone

Large Language Models (LLMs) are powerful, but they come with an important limitation: they only know what was included during training. They cannot natively reason over private documents, internal knowledge bases, or freshly updated content.

This is where Retrieval-Augmented Generation (RAG) becomes essential.

This post walks through a minimal, production-ready RAG example using LangChain, OpenAI, and Pinecone, focusing on clarity, correctness.

🚀 What This Project Demonstrates

This demo shows how to:
  • Load and chunk documents
  • Generate vector embeddings using OpenAI
  • Store embeddings in Pinecone
  • Retrieve relevant context at query time
  • Generate answers strictly grounded in retrieved data
This approach dramatically reduces hallucinations and makes LLM responses explainable and auditable.

🧩 High-Level Architecture

The system follows a clean two-phase flow:

1️⃣ Indexing Phase (Offline / One-Time)

  • Load a text document
  • Split it into chunks
  • Generate embeddings
  • Store vectors in Pinecone

2️⃣ Query Phase (Runtime)

  • Convert a user question into an embedding
  • Retrieve the most relevant chunks
  • Inject retrieved context into the prompt
  • Generate an answer using an LLM

📁 Project Structure

langchain-rag-demo/
├── load_file_to_vector_db.py   # Indexing step
├── main.py                     # Query + generation
├── example_pinecone.txt        # Sample document
├── pyproject.toml              # Dependencies
├── .env                        # API keys (local only)
└── README.md 

🔧 Step 1: Loading Data into the Vector Database

The indexing script performs four key steps:

  • Load the document
  • Split text into chunks
  • Create embeddings
  • Store vectors in Pinecone
Key design choices:
  • Fixed chunk size for predictable retrieval
  • Zero overlap for simplicity
  • Environment-based configuration for security
Once this script runs, the document becomes searchable via semantic similarity.

🔍 Step 2: Querying with RAG

At runtime, the application:
  • Retrieves the top-K most relevant chunks
  • Injects them into a strict prompt template
  • Forces the model to answer only from retrieved context
  • Returns "I don't know" if the answer is missing
This constraint is critical for enterprise and compliance-sensitive workloads.

🛡️ Prompt Guardrails (Why They Matter)

Use ONLY the following context to answer the question.
If the answer is not in the context, say "I don't know". 

This single rule:

  • Prevents hallucinations
  • Makes failures explicit
  • Improves trustworthiness of responses

⚙️ Configuration via Environment Variables

All sensitive configuration is externalized:
OPENAI_API_KEY=...
OPENAI_MODEL=...
PINECONE_API_KEY=...
PINECONE_INDEX_NAME=... 
This keeps the codebase:
  • Portable
  • CI/CD-friendly
  • Safe for public repositories

🧪 Why This Minimal Example Matters

Despite its simplicity, this project already matches real-world RAG patterns used in:
  • Internal documentation assistants
  • Customer support bots
  • Knowledge base search
  • Developer tooling
  • Compliance-aware AI systems
It provides a clean foundation that can later be extended with:
  • Metadata filtering
  • Hybrid search
  • Reranking
  • Streaming responses
  • Tool calling

📌 Final Thoughts

RAG is not an advanced optimization—it is a baseline requirement for reliable LLM systems.
This demo intentionally avoids unnecessary abstractions to make the core ideas clear and reusable across projects.
📎 Source code available on GitHub