Skip to main content

RAG on a VDS: AI Answers Based on Your Documents

AI Agents on VPS · 19.04.2026 · 5 min read
Illustration for “RAG on a VDS: AI Answers Based on Your Documents”

What Is RAG?

RAG (Retrieval-Augmented Generation) is a technique in which an LLM first searches a knowledge base for relevant fragments before generating a response. This lets the model answer questions about your documents accurately, without requiring fine-tuning.

How RAG works: 1) The document is split into chunks → 2) Each chunk is turned into a vector → 3) The vectors are stored in a vector database → 4) Similar chunks are found for the query → 5) The LLM generates a response using the context.

Components of a RAG System

  • Document loaders — PDF, DOCX, TXT, web pages
  • Text Splitter — splitting into chunks (500-1000 tokens)
  • Embedding model — converting text into vectors
  • Vector database — Chroma, Qdrant, FAISS
  • LLM — generating a response based on the retrieved context

Installing Dependencies

pip install langchain langchain-ollama langchain-community
pip install chromadb pypdf sentence-transformers

Complete RAG Example in Python

from langchain_community.document_loaders import PyPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.vectorstores import Chroma
from langchain_community.embeddings import OllamaEmbeddings
from langchain_ollama import OllamaLLM
from langchain.chains import RetrievalQA

# Load and split the document
loader = PyPDFLoader("document.pdf")
docs = loader.load()
splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=50)
chunks = splitter.split_documents(docs)

# Create the vector database
embeddings = OllamaEmbeddings(model="nomic-embed-text")
db = Chroma.from_documents(chunks, embeddings, persist_directory="./chroma_db")

# RAG chain
llm = OllamaLLM(model="llama3.2")
qa = RetrievalQA.from_chain_type(llm=llm, retriever=db.as_retriever())
result = qa.invoke("What is the main topic of this document?")
print(result["result"])

Embedding Models for Ollama

# Download a specialized embedding model
ollama pull nomic-embed-text

# Or the English variant
ollama pull mxbai-embed-large
Chunk size: Chunks that are too large (2000+ tokens) reduce search accuracy. Chunks that are too small (100 tokens) lose context. Optimal: 300-800 tokens with 10-15% overlap.

Common RAG Errors

Most RAG problems are not in the code but in retrieval quality — the model answers without using the context because the wrong context was retrieved in the first place.

The Model Ignores the Retrieved Context

A common cause is a prompt that does not force the model to rely specifically on the retrieved chunks: it answers from general knowledge unless you explicitly say "answer only based on the provided context, and if the answer is not there, say you do not know." The second cause is a retriever returning too few chunks (k=1-2), so the needed fragment never makes it into the selection.

Dimension Mismatch When Adding Documents to Chroma

chromadb.errors.InvalidDimensionException: Embedding dimension 768 does not match collection dimensionality 1024

This error occurs when the same Chroma collection received embeddings generated by different models — they have different vector dimensions. The fix is to use a single embedding model for the entire lifetime of the collection, or create a separate collection when switching models.

Chroma, Qdrant, and FAISS Compared

Criterion Chroma Qdrant FAISS
Deployment Embedded, no server Separate server or Docker Library, no server
Persistence out of the box Yes Yes Index must be saved manually
Metadata filtering Basic Advanced None
Good for Prototypes and small datasets Production at large scale Maximum in-memory search speed

When RAG Is Not a Good Fit

  • There are few documents and they all fit within the model's context window — it is simpler to pass the whole text in the prompt, without a vector database.
  • Data changes almost in real time — you would have to constantly re-index chunks, and the answer would still lag behind.
  • You need exact calculations or aggregation across all documents at once — RAG finds similar fragments, it does not sum values or compare every record.
  • User questions require reasoning across the whole knowledge base rather than individual fragments — full-text analysis or a SQL query fits better than vector search here.

Verifying Search Quality

results = db.similarity_search_with_score("a test question from your knowledge base", k=3)
for doc, score in results:
    print(score, doc.page_content[:100])

Run a search with a question you know is answered somewhere in the documents, and check that the right chunk ends up among the most relevant results. If it is in the database but does not make the top-k, try reducing the chunk size or increasing k before switching embedding models.

Another nuance is updating documents in the database. If the source file changes, simply re-adding chunks to the same Chroma collection creates duplicates instead of replacing the old versions. Before re-indexing, either delete the chunks tied to the previous source identifier or create a separate collection for each document version and explicitly point the retriever at the current one.

Was this article helpful?
← Back to Knowledge Base Ask Support