# Condensed: RAG with LangChain

Summary: This tutorial demonstrates the implementation of a Retrieval-Augmented Generation (RAG) system using LangChain, covering PDF document processing, text chunking, vector embeddings, and query pipeline setup. It provides specific code for creating a document retrieval system using FAISS vector storage, HuggingFace embeddings (specifically bge-base-en-v1.5 model), and customizable text splitting parameters. The tutorial helps with tasks like document Q&A, information retrieval, and building RAG applications, featuring key functionalities such as PDF loading, text chunking with configurable overlap, vector database creation and persistence, and structured prompt templating for response generation.

*This is a condensed version that preserves essential implementation details and context.*

Here's the condensed tutorial focusing on essential implementation details:

# RAG with LangChain Implementation Guide

## Setup and Prerequisites
```python
# Install required packages
%pip install pypdf langchain langchain-openai langchain-huggingface

# Configure OpenAI API
import os
os.environ["OPENAI_API_KEY"] = "YOUR_API_KEY"
```

## Core Implementation Steps

### 1. Data Loading and Preprocessing
```python
# Load PDF document
from langchain_community.document_loaders import PyPDFLoader
loader = PyPDFLoader("document_path.pdf")
docs = loader.load()

# Split into chunks
from langchain.text_splitter import RecursiveCharacterTextSplitter
splitter = RecursiveCharacterTextSplitter(
    chunk_size=1000,    # Max chunk size
    chunk_overlap=150   # Overlap between chunks
)
corpus = splitter.split_documents(docs)
```

### 2. Indexing and Vector Storage
```python
# Initialize embedding model
from langchain_huggingface.embeddings import HuggingFaceEmbeddings
embedding_model = HuggingFaceEmbeddings(
    model_name="BAAI/bge-base-en-v1.5", 
    encode_kwargs={"normalize_embeddings": True}
)

# Create vector database
from langchain.vectorstores import FAISS
vectordb = FAISS.from_documents(corpus, embedding_model)
retriever = vectordb.as_retriever()

# Optional: Save vector database
vectordb.save_local("vectorstore.db")
```

### 3. RAG Pipeline Setup
```python
# Define prompt template
from langchain_core.prompts import ChatPromptTemplate
template = """
You are a Q&A chat bot.
Use the given context only, answer the question.

<context>
{context}
</context>

Question: {input}
"""
prompt = ChatPromptTemplate.from_template(template)

# Create retrieval chain
from langchain.chains.combine_documents import create_stuff_documents_chain
from langchain.chains import create_retrieval_chain

doc_chain = create_stuff_documents_chain(llm, prompt)
chain = create_retrieval_chain(retriever, doc_chain)
```

### 4. Query Execution
```python
response = chain.invoke({"input": "Your question here"})
print(response['answer'])
```

## Key Configurations
- Chunk size: 1000 characters
- Chunk overlap: 150 characters
- Embedding model: bge-base-en-v1.5
- Vector store: FAISS

## Best Practices
1. Adjust chunk size and overlap based on your document structure
2. Use normalized embeddings for better vector similarity
3. Save vector database for reuse in production
4. Keep prompt template focused and specific to use case