Complete RAG System Build Guide: From Principles to Practice
The optimal way to give LLMs βprivate memoryβ isnβt fine-tuningβitβs RAG.
What is RAG? Why is it still the preferred solution in 2026?
RAG (Retrieval-Augmented Generation) has an elegantly simple core idea: first retrieve relevant document chunks from a knowledge base, then inject these chunks as context into the LLMβs prompt, allowing the model to generate answers based on real data.
Compared to fine-tuning, RAG has three irreplaceable advantages:
| Dimension | RAG | Fine-tuning |
|---|---|---|
| Knowledge updates | Takes effect in seconds, just update docs | Requires retraining, takes hours |
| Cost | Inference only | GPU training + storage |
| Traceability | Can return source references | Black-box generation |
| Data requirements | Works with just dozens of documents | Usually needs thousands of samples |
This is why in the AI Agent Engineering Production Guide, RAG is listed as the preferred mechanism for agents to acquire domain knowledge.
RAG System Architecture Overview
A production-grade RAG system consists of 5 core modules:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β RAG System Architecture β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β ββββββββββββ ββββββββββββ ββββββββββββββββββββ β
β β Document βββββΆβ Document βββββΆβ Embedding Model β β
β β Input β β Chunking β β text-embedding-3 β β
β βPDF/Word β β β β bge-m3 / gte β β
β βHTML/API β β β β β β
β ββββββββββββ ββββββββββββ ββββββββββ¬ββββββββββ β
β β β
β βΌ β
β ββββββββββββββββββββ β
β β Vector Database β β
β β Pinecone/Chroma β β
β β Weaviate/Qdrant β β
β ββββββββββ¬ββββββββββ β
β β β
β ββββββββββββ ββββββββββββ β β
β β LLM ββββββRetrieval ββββββββββββββ β
β β GPT-4o β β+Reranker β β
β β Claude β β β β
β β Qwen3 β ββββββββββββ β
β ββββββ¬ββββββ β
β β β
β βΌ β
β ββββββββββββ β
β β Final β β
β β Answer β β
β β+ Sources β β
β ββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Vector Database Selection: Pinecone vs Weaviate vs Chroma
Comparison of mainstream vector databases in 2026:
| Feature | Pinecone | Weaviate | Chroma |
|---|---|---|---|
| Deployment | Fully managed SaaS | Self-hosted/Cloud | Embedded/Single-machine |
| Free tier | 100K vectors | Open source free | Open source free |
| Max scale | 10B+ vectors | 10B+ vectors | ~100K (single machine) |
| Hybrid search | β Native | β BM25+Vector | β οΈ Requires extension |
| Multi-tenancy | β Native | β namespace | β οΈ Manual |
| Latency (P99) | ~20ms | ~30ms | ~10ms (local) |
| Use case | Enterprise production | Complex queries | Prototype/small scale |
Selection recommendations:
- Prototype / Local development β Chroma (zero config, pip install ready)
- Small-medium production (< 1M vectors) β Weaviate (strong hybrid search)
- Enterprise / Ultra-large scale β Pinecone (maintenance-free, auto-scaling)
Document Chunking Strategy: The Key to RAG Quality
Document chunking is the most overlooked yet most impactful component in RAG.
4 Mainstream Chunking Strategies
from langchain.text_splitter import (
RecursiveCharacterTextSplitter,
MarkdownHeaderTextSplitter,
TokenTextSplitter
)
# 1. Fixed-size chunking (most basic)
splitter = RecursiveCharacterTextSplitter(
chunk_size=512,
chunk_overlap=50,
separators=["\n\n", "\n", "γ", " ", ""]
)
# 2. Markdown header-based chunking (for technical docs)
md_splitter = MarkdownHeaderTextSplitter(
headers_to_split_on=[
("#", "H1"), ("##", "H2"), ("###", "H3")
]
)
# 3. Semantic chunking (by sentence boundaries)
from langchain_experimental.text_splitter import SemanticChunker
semantic_splitter = SemanticChunker(
embedding_function=embeddings,
breakpoint_threshold_type="percentile",
breakpoint_threshold_amount=95
)
# 4. Recursive chunking + metadata preservation (recommended)
def smart_chunk(document):
"""Choose chunking strategy based on document type"""
if document.metadata["source"].endswith(".md"):
return md_splitter.split_text(document.page_content)
elif len(document.page_content) > 2000:
return splitter.split_text(document.page_content)
else:
return [document.page_content]
Golden Values for Chunking Parameters
| Document Type | chunk_size | overlap | Recommended Strategy |
|---|---|---|---|
| Technical docs | 512-1024 | 50-100 | Markdown header chunking |
| Legal contracts | 1024-2048 | 200 | Paragraph + recursive |
| Conversation logs | 256-512 | 50 | By turn |
| Code files | 512 | 50 | By function/class |
Embedding Model Selection
Recommended embedding models for 2026:
| Model | Dimensions | MTEB Avg | Price | Recommended Scenario |
|---|---|---|---|---|
| text-embedding-3-large | 3072 | 65.1 | $0.13/1M tokens | High precision needs |
| bge-m3 (BAAI) | 1024 | 64.8 | Free (local) | Multilingual + local deployment |
| gte-Qwen2-7B-instruct | 3584 | 67.2 | Free (local) | Highest precision |
| voyage-3-large | 1024 | 66.5 | $0.12/1M tokens | Code+text mixed |
# OpenAI Embedding
from langchain_openai import OpenAIEmbeddings
embeddings = OpenAIEmbeddings(model="text-embedding-3-large")
# Local BGE-M3 (recommended for Chinese scenarios)
from sentence_transformers import SentenceTransformer
model = SentenceTransformer("BAAI/bge-m3")
vectors = model.encode(["document content"], normalize_embeddings=True)
LangChain vs LlamaIndex: Framework Selection
The positioning of these two frameworks has clearly diverged in 2026:
| Dimension | LangChain | LlamaIndex |
|---|---|---|
| Core positioning | General LLM application framework | Focused on data indexing & retrieval |
| RAG capability | Basic chain calls | 20+ advanced RAG patterns built-in |
| Agent support | β Strong LangGraph | β οΈ Basic |
| Learning curve | Medium | Lower (for RAG scenarios) |
| Production-ready | β | β |
| Community ecosystem | Larger | More focused |
Selection recommendations:
- Pure RAG applications β LlamaIndex (more out-of-the-box RAG patterns)
- RAG + Agent hybrid β LangChain + LangGraph (see AI Agent Tools Ultimate Guide)
- Quick prototype β Either works, LlamaIndex has less code
Complete Code Example: Building Production-Grade RAG
Hereβs a complete, runnable RAG system using LlamaIndex + Chroma:
"""
Production-grade RAG system complete implementation
Dependencies: pip install llama-index chromadb llama-index-embeddings-openai
"""
import os
from llama_index.core import (
VectorStoreIndex,
StorageContext,
Settings,
SimpleDirectoryReader
)
from llama_index.vector_stores.chroma import ChromaVectorStore
from llama_index.embeddings.openai import OpenAIEmbedding
from llama_index.core.node_parser import SemanticSplitterNodeParser
from llama_index.core.postprocessor import SentenceTransformerRerank
import chromadb
# 1. Configuration
os.environ["OPENAI_API_KEY"] = "your-key-here"
Settings.embed_model = OpenAIEmbedding(model="text-embedding-3-large")
Settings.llm = None # Can replace with local model
Settings.chunk_size = 512
Settings.chunk_overlap = 50
# 2. Initialize Chroma vector store
chroma_client = chromadb.PersistentClient(path="./chroma_db")
chroma_collection = chroma_client.get_or_create_collection("rag_docs")
vector_store = ChromaVectorStore(chroma_collection=chroma_collection)
# 3. Load and chunk documents
reader = SimpleDirectoryReader("./docs")
documents = reader.load_data()
# Semantic chunking (better than fixed-size)
splitter = SemanticSplitterNodeParser(
buffer_size=1,
breakpoint_percentile_threshold=95,
embed_model=Settings.embed_model
)
nodes = splitter.get_nodes_from_documents(documents)
# 4. Build index
storage_context = StorageContext.from_defaults(vector_store=vector_store)
index = VectorStoreIndex(nodes, storage_context=storage_context)
# 5. Create query engine (with reranking)
reranker = SentenceTransformerRerank(
model="BAAI/bge-reranker-v2-m3",
top_n=5
)
query_engine = index.as_query_engine(
similarity_top_k=20, # First retrieve 20
node_postprocessors=[reranker], # Then rerank to top 5
)
# 6. Query
response = query_engine.query("How to choose the right chunk_size for RAG systems?")
print(f"Answer: {response}")
print(f"\nSource references:")
for node in response.source_nodes:
print(f" - {node.metadata.get('file_name', 'unknown')} (similarity: {node.score:.3f})")
Performance Optimization: From 3 Seconds to 200 Milliseconds
Retrieval Layer Optimization
# 1. Hybrid search (vector + BM25 keywords)
from llama_index.core import QueryFusionRetriever
retriever = QueryFusionRetriever(
[
index.as_retriever(similarity_top_k=10), # Vector retrieval
bm25_retriever, # Keyword retrieval
],
mode="reciprocal_rerank", # Fusion ranking
similarity_top_k=15,
)
# 2. Query rewriting (improves recall)
from llama_index.core.query_engine import RetrieverQueryEngine
from llama_index.core.postprocessor import MetadataReplacementPostProcessor
# 3. Cache hot queries
from cachetools import TTLCache
query_cache = TTLCache(maxsize=1000, ttl=3600)
Latency Optimization Benchmark Data
| Optimization | Latency (P50) | Latency (P99) | Improvement |
|---|---|---|---|
| Baseline (naive RAG) | 2800ms | 4200ms | - |
| + Switch to Pinecone | 1200ms | 1800ms | 57% β |
| + Query result caching | 350ms | 800ms | 87% β |
| + Async LLM streaming | 280ms | 450ms | 90% β |
| + Quantized embedding | 200ms | 320ms | 93% β |
Real-World Application Scenarios
Scenario 1: Enterprise Internal Knowledge Base
# Connect enterprise docs: Confluence, Feishu, Notion
from llama_index.readers.confluence import ConfluenceReader
from llama_index.readers.notion import NotionPageReader
# Access control: isolate by department
def query_with_acl(user_dept, question):
filters = MetadataFilters(filters=[
ExactMatchFilter(key="department", value=user_dept)
])
return query_engine.query(question, filters=filters)
Scenario 2: Code Repository Q&A
# Index GitHub repositories, answer code questions
from llama_index.readers.github import GithubRepositoryReader
reader = GithubRepositoryReader(
github_token=os.environ["GITHUB_TOKEN"],
owner="microsoft",
repo="vscode",
filter_directories=(["src"], GithubRepositoryReader.FilterType.INCLUDE),
)
docs = reader.load_data(branch="main")
# After building index, can answer: "How does VSCode's plugin system load extensions?"
Scenario 3: Multimodal RAG (Charts + Text)
# Use GPT-4o to extract chart descriptions, then index with text
from llama_index.multi_modal_llms.generic import GenericMultiModalLLM
# Charts β Text descriptions β Chunk and index with original text
# Suitable for financial reports, technical whitepapers with many charts
For more Agent + RAG combined scenarios, see the MCP Workflow Orchestration Guide and Dify Platform Complete Guide.
Frequently Asked Questions (FAQ)
Q1: What should the chunk_size be for RAG?
A: Thereβs no universal value. Technical documentation recommends 512-1024 tokens, legal contracts recommend 1024-2048 tokens. The core principle is: each chunk should contain a complete semantic unit (a paragraph, a section, a function). Itβs recommended to use A/B testing to find the optimal value on your dataset.
Q2: Do I need to deploy a vector database myself?
A: It depends on scale. For prototyping, use Chroma (embedded, no deployment needed); for production with < 1 million vectors, you can use Weaviate Cloud or Qdrant Cloud; for ultra-large scale or high compliance requirements, self-hosting is recommended.
Q3: What if RAG retrieves the wrong documents?
A: Three layers of defense: β Use hybrid search (vector + BM25) to improve recall; β‘ Add a Reranker model (like bge-reranker) for fine-ranking; β’ Add instructions in the prompt: βIf the provided context is not relevant, please say βIβm not sureββ.
Q4: Can LangChain and LlamaIndex be used together?
A: Absolutely. A common pattern is: LlamaIndex handles data indexing and retrieval, LangChain handles Agent orchestration and tool calling. The two integrate seamlessly through LlamaIndexβs RetrieverTool.
Q5: Whatβs the best embedding model for Chinese RAG?
A: For Chinese scenarios in 2026, the top choices are bge-m3 (BAAI open source, free for local deployment) or text-embedding-3-large (OpenAI, highest precision). If you have large data volumes and limited budget, the gte-Qwen2 series offers the best value.
Q6: What are the evaluation metrics for RAG systems?
A: There are three core metrics: β Retrieval accuracy (Hit Rate@K) β the proportion of top K results containing the correct answer; β‘ Answer faithfulness β whether the answer is based on retrieved content; β’ Answer relevancy β whether the answer is on-topic. The RAGAS framework is recommended for automated evaluation.
Summary
Key decision points for building a production-grade RAG system:
- Vector database: Use Chroma for prototypes, Pinecone/Weaviate for production
- Chunking strategy: Semantic chunking > fixed-size, chunk_size needs A/B testing
- Embedding model: bge-m3 for Chinese, text-embedding-3-large for English
- Framework choice: LlamaIndex for pure RAG, LangChain for RAG+Agent
- Performance optimization: Hybrid search + Reranker + caching can reduce latency from 3s to 200ms
RAG isnβt a silver bullet, but itβs the most mature solution for LLMs to safely and controllably use private data. In 2026, with the maturation of multimodal RAG and Agentic RAG, its application scenarios continue to expand.