TL;DR
Deepset Haystack is the leading open-source Python framework for building production-grade Retrieval-Augmented Generation (RAG) applications in 2026. This comprehensive guide covers document ingestion, embedding generation, vector search, pipeline orchestration, and LLM integration for building intelligent knowledge systems.
What Is Haystack?
Haystack is an end-to-end framework for building custom LLM applications centered around retrieval-augmented generation. Developed by Deepset, it provides composable components for every step of the RAG pipeline — from document loading and preprocessing to retrieval, ranking, and generation. With 20k+ stars on GitHub, Haystack has become the go-to framework for enterprise RAG deployments.
Key Features
- End-to-End Pipeline: Complete RAG pipeline from documents to answers
- Document Store Agnostic: Works with Elasticsearch, OpenSearch, Pinecone, Weaviate, Milvus, and more
- Embedding Integration: Built-in support for OpenAI, Hugging Face, Ollama, and custom embedders
- Retrievers: BM25, dense vector, hybrid search with cross-encoders
- Rankers: Cross-encoder reranking for improved precision
- LLM Support: OpenAI, Anthropic, Hugging Face, Ollama, vLLM, and custom providers
- Evaluation Tools: Built-in evaluation for retrieval and generation quality
- Production Ready: Tested at enterprise scale with monitoring and observability
Architecture Overview
Haystack follows a component-based architecture where each piece of the pipeline is a modular, swappable component: ```` Documents → Preprocessing → Embedding → Storage → Retrieval → Reranking → Generation │ │ │ │ │ │ │ └── FileConverter ──┘ └── Embedder ─┘ └── Retriever ─┘ └── Generator ──┘
## Installation Guide
### Basic Installation
`````bash
pip install haystack-ai
# For full features with all document converters
pip install "haystack-ai[docx,pdf]"
Provider-Specific Installations
# OpenAI integration
pip install openai
# Hugging Face integration
pip install transformers sentence-transformers torch
# Elasticsearch document store
pip install elasticsearch
# Weaviate document store
pip install weaviate-client
Verify Installation
from haystack import Pipeline, Component
# Check version
import haystack
print(f"Haystack version: {haystack.__version__}")
# Create a simple pipeline
pipeline = Pipeline()
print("Pipeline created successfully!")
Building Your First RAG Pipeline
Step 1: Document Ingestion
Load and preprocess documents: `````python from haystack import Pipeline, Document from haystack.components.converters import TextFileToDocument from haystack.components.preprocessors import DocumentCleaner, DocumentSplitter from haystack.components.embedders import SentenceTransformersDocumentEmbedder
Load documents from directory
converter = TextFileToDocument() cleaner = DocumentCleaner() splitter = DocumentSplitter(split_by=“word”, split_length=500, split_overlap=50)
Process documents
result = converter.run(sources=["./documents/*.txt"]) documents = result[“documents”]
Clean and split
result = cleaner.run(documents=documents) documents = result[“documents”]
result = splitter.run(documents=documents) documents = result[“documents”]
print(f"Processed {len(documents)} document chunks")
### Step 2: Generate Embeddings
Convert text to vector embeddings: `````python
from haystack.components.embedders import SentenceTransformersDocumentEmbedder
# Use local embeddings (no API key needed)
embedder = SentenceTransformersDocumentEmbedder(
model="sentence-transformers/all-MiniLM-L6-v2",
progress_bar=True
)
# Add embeddings to documents
result = embedder.run(documents=documents)
documents_with_embeddings = result["documents"]
print(f"Embedded {len(documents_with_embeddings)} documents")
Step 3: Store in Vector Database
from haystack_integrations.document_stores.weaviate import WeaviateDocumentStore
from haystack.components.writers import DocumentWriter
# Connect to Weaviate
document_store = WeaviateDocumentStore(url="http://localhost:8080")
# Write documents to store
writer = DocumentWriter(document_store=document_store)
result = writer.run(documents=documents_with_embeddings)
print(f"Wrote {result[written]} documents to store")
Step 4: Build Retrieval Pipeline
from haystack_integrations.components.retrievers.weaviate import WeaviateEmbeddingRetriever
from haystack.components.builders import PromptBuilder
from haystack_integrations.components.generators.openai import OpenAIGenerator
# Define retrieval and generation components
retriever = WeaviateEmbeddingRetriever(document_store=document_store)
prompt_builder = PromptBuilder(template="""
Context: {% for doc in documents %}
{% endfor %}
Question:
Answer based on the context above: """)
generator = OpenAIGenerator(model="gpt-4o")
# Build the pipeline
rag_pipeline = Pipeline()
rag_pipeline.add_component("retriever", retriever)
rag_pipeline.add_component("prompt_builder", prompt_builder)
rag_pipeline.add_component("generator", generator)
# Connect components
rag_pipeline.connect("retriever.documents", "prompt_builder.documents")
rag_pipeline.connect("prompt_builder.prompt", "generator.prompt")
Step 5: Query the Pipeline
def ask_question(query: str, top_k: int = 5) -> str: result = rag_pipeline.run({
"retriever": {"query": query, "top_k": top_k},
"prompt_builder": {"question": query}
})
return result["generator"]["replies"][0]
answer = ask_question("What are the main features of Haystack?")
print(answer)
Advanced Retrieval Strategies
Hybrid Search (BM25 + Dense)
Combine keyword and semantic search for best results: `````python from haystack_integrations.document_stores.elasticsearch import ElasticsearchDocumentStore from haystack_integrations.components.retrievers.elasticsearch import ElasticsearchEmbeddingRetriever
Elasticsearch supports hybrid search natively
document_store = ElasticsearchDocumentStore( hosts=“http://localhost:9200”, index=“documents” )
Hybrid retriever combines BM25 and dense vectors
retriever = ElasticsearchEmbeddingRetriever( document_store=document_store, top_k=10, filters={“field_type”: “dense”} )
### Cross-Encoder Reranking
Improve retrieval precision with cross-encoder reranking: `````python
from haystack_integrations.components.rankers.transformers import TransformersRanker
# Rerank retrieved documents using a cross-encoder
ranker = TransformersRanker(
model="cross-encoder/ms-marco-MiniLM-L-6-v2",
top_k=5
)
# Integrate into pipeline
rag_pipeline.add_component("ranker", ranker)
rag_pipeline.connect("retriever.documents", "ranker.documents")
Multi-Query Retrieval
Generate multiple queries for better coverage: `````python from haystack.components.generators.chat import OpenAIChatGenerator from haystack.components.builders import PromptBuilder
multi_query_prompt = PromptBuilder(template=""" You are an AI assistant that generates search queries. Given the following question, generate 3 different search queries that could help find the answer.
Question:
Generate exactly 3 queries, one per line: """)
multi_query_gen = OpenAIChatGenerator(model=“gpt-4o-mini”)
Build multi-query pipeline
mq_pipeline = Pipeline() mq_pipeline.add_component(“prompt_builder”, multi_query_prompt) mq_pipeline.add_component(“generator”, multi_query_gen) mq_pipeline.connect(“prompt_builder.prompt”, “generator.prompt”)
Get multiple queries
result = mq_pipeline.run({“prompt_builder”: {“question”: original_query}}) queries = result[“generator”][“replies”][0].split("\n")[:3]
Retrieve for each query
all_docs = [] for q in queries: docs = retriever.run(query=q.strip(), top_k=5)[“documents”] all_docs.extend(docs)
Deduplicate and rank
unique_docs = deduplicate_documents(all_docs)
## LLM Integration
### Supported LLM Providers
| Provider | Package | Models |
|
* * *
|
* * *
|
* * *
|
| OpenAI | haystack-integrations-generators-openai | GPT-4o, GPT-4 Turbo, o1 |
| Anthropic | haystack-integrations-generators-anthropic | Claude 3.5 Sonnet, Haiku |
| Hugging Face | haystack-integrations-generators-hugging-face | Any HF model |
| Ollama | haystack-integrations-generators-ollama | Local models |
| vLLM | haystack-integrations-generators-vllm | High-throughput serving |
| Cohere | haystack-integrations-generators-cohere | Command R+, R |
### Using Ollama for Local LLMs
Run LLMs entirely locally with no API costs: `````python
from haystack_integrations.components.generators.ollama import OllamaGenerator
generator = OllamaGenerator(
model="llama3.1:8b",
url="http://localhost:11434",
generation_kwargs={
"temperature": 0.7,
"num_ctx": 4096,
}
)
# Generate response
result = generator.run(prompt="Explain RAG in simple terms")
print(result["replies"][0])
Streaming Responses
Stream LLM responses in real-time: `````python from haystack_integrations.components.generators.openai import OpenAIGenerator
generator = OpenAIGenerator( model=“gpt-4o”, streaming_callback=lambda chunk: print(chunk.data.choices[0].delta.content, end="") )
result = generator.run(prompt=“Write a detailed explanation of machine learning”)
## Evaluation and Monitoring
### Retrieval Evaluation
Evaluate how well your retriever finds relevant documents: `````python
from haystack import Pipeline
from haystack.dataclasses import Document, GeneratedAnswer
from haystack_integrations.components.evaluators.ragas import RagasEvaluator
# Create evaluation pipeline
evaluator = RagasEvaluator(
metrics=["faithfulness", "context_precision", "context_recall"],
generator=OpenAIGenerator(model="gpt-4o"),
embedder=SentenceTransformersDocumentEmbedder(
model="sentence-transformers/all-MiniLM-L6-v2"
)
)
# Evaluate on test dataset
results = evaluator.run(
questions=test_questions,
ground_truths=test_answers,
contexts=retrieved_documents
)
print(f"Average faithfulness: {results[faithfulness]:.3f}")
print(f"Average context recall: {results[context_recall]:.3f}")
Custom Evaluation Metrics
Build custom evaluation pipelines: `````python from haystack import component
@component class RelevanceChecker: @component.output_types(is_relevant=bool, confidence=float) def run(self, query: str, document: Document) -> dict: # Simple relevance scoring keywords = set(query.lower().split()) doc_words = set(document.content.lower().split())
overlap = keywords.intersection(doc_words)
precision = len(overlap) / max(len(keywords), 1)
recall = len(overlap) / max(len(doc_words), 1)
return {
"is_relevant": precision > 0.3,
"confidence": (precision + recall) / 2
}
Use in pipeline
pipeline = Pipeline() pipeline.add_component(“checker”, RelevanceChecker())
## Production Deployment
### Docker Deployment
`````dockerfile
FROM python:3.11-slim
RUN apt-get update && apt-get install -y \
build-essential \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
requirements.txt: ````` haystack-ai fastapi uvicorn openai sentence-transformers
### FastAPI Integration
Build a REST API around your RAG pipeline: `````python
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from haystack import Pipeline
app = FastAPI(title="RAG API")
# Load pipeline at startup
rag_pipeline = load_rag_pipeline()
class QueryRequest(BaseModel): question: str
top_k: int = 5
use_reranking: bool = True
class QueryResponse(BaseModel): answer: str
sources: list
confidence: float
@app.post("/query", response_model=QueryResponse)
async def query(request: QueryRequest): try: result = await rag_pipeline.ainvoke({
"retriever": {"query": request.question, "top_k": request.top_k},
"prompt_builder": {"question": request.question}
})
answer = result["generator"]["replies"][0]
return QueryResponse(
answer=answer,
sources=result.get("sources", []),
confidence=result.get("confidence", 0.0)
)
except Exception as e: raise HTTPException(status_code=500, detail=str(e))
Kubernetes Deployment
apiVersion: apps/v1
kind: Deployment
metadata: name: rag-service
spec: replicas: 3
selector: matchLabels: app: rag
template: spec: containers: - name: rag-api
image: rag-service:latest
ports: - containerPort: 8000
resources: limits: cpu: "2"
memory: "4Gi"
nvidia.com/gpu: 1
env: - name: OPENAI_API_KEY
valueFrom: secretKeyRef: name: api-keys
key: openai
- name: WEAVIATE_URL
valueFrom: secretKeyRef: name: weaviate
key: url
Comparison with Alternatives
| Feature | Haystack | LangChain | LlamaIndex | RAGFlow | |
|
|
|
|
| | Python Native | ✅ | ✅ | ✅ | Partial | | Type Safety | Good | Limited | Moderate | Limited | | Evaluation | Built-in | Manual | Manual | Basic | | Multi-Document Store | 15+ | 20+ | 10+ | 5+ | | Learning Curve | Easy | Steep | Moderate | Easy | | Enterprise Features | ✅ | Partial | Partial | ✅ | | Open Source | MIT | MIT | Apache 2.0 | Apache 2.0 |
Document Preprocessing Pipeline
Efficient preprocessing is critical for RAG quality: `````python from haystack.components.preprocessors import RecursiveDocumentSplitter from haystack.components.preprocessors import DocumentCleaner from haystack.components.extractors import NamedEntityExtractor
Advanced document splitting
splitter = RecursiveDocumentSplitter( split_by=“sentence”, split_length=5, split_overlap=2, split_threshold=0.5 )
Clean documents
cleaner = DocumentCleaner( lowercase=True, remove_empty_lines=True, remove_extra_whitespace=True, remove_repeated_substrings=True )
Extract entities for metadata enrichment
extractor = NamedEntityExtractor( device=“cuda” if torch.cuda.is_available() else “cpu” )
Full preprocessing pipeline
preprocess_pipeline = Pipeline() preprocess_pipeline.add_component(“cleaner”, cleaner) preprocess_pipeline.add_component(“splitter”, splitter) preprocess_pipeline.add_component(“extractor”, extractor) preprocess_pipeline.connect(“cleaner.documents”, “splitter.documents”) preprocess_pipeline.connect(“splitter.documents”, “extractor.documents”)
result = preprocess_pipeline.run({“cleaner”: {“documents”: raw_documents}}) processed_docs = result[“extractor”][“documents”]
### Hybrid Search Implementation
Combine keyword and semantic search for best retrieval: `````python
from haystack_integrations.document_stores.elasticsearch import ElasticsearchDocumentStore
from haystack_integrations.components.retrievers.elasticsearch import ElasticsearchEmbeddingRetriever
from haystack_integrations.components.rankers.elasticsearch import ElasticsearchRanker
# Connect to Elasticsearch cluster
document_store = ElasticsearchDocumentStore(
hosts="http://localhost:9200",
index="rag_documents"
)
# Hybrid retriever combines BM25 + dense vectors
retriever = ElasticsearchEmbeddingRetriever(
document_store=document_store,
top_k=10,
filters={"source_type": "pdf"},
query_embedding=query_embedding,
return_embedding=True
)
# Rank results with cross-encoder
ranker = ElasticsearchRanker(
model="cross-encoder/ms-marco-MiniLM-L-6-v2",
top_k=5
)
# Build hybrid pipeline
hybrid_pipeline = Pipeline()
hybrid_pipeline.add_component("retriever", retriever)
hybrid_pipeline.add_component("ranker", ranker)
hybrid_pipeline.connect("retriever.documents", "ranker.documents")
result = hybrid_pipeline.run({
"retriever": {"query": user_question},
"ranker": {"query": user_question}
})
Multi-Tenant RAG Architecture
Support multiple users with isolated knowledge bases: `````python from haystack import Pipeline, Document
class MultiTenantRAG: def init(self): self.tenant_pipelines = {} self.tenant_stores = {}
def setup_tenant(self, tenant_id: str, document_store_url: str): """Initialize RAG pipeline for a tenant"""
store = WeaviateDocumentStore(url=document_store_url)
retriever = WeaviateEmbeddingRetriever(document_store=store)
prompt_builder = PromptBuilder(template=self.template)
generator = OpenAIGenerator(model="gpt-4o")
pipeline = Pipeline()
pipeline.add_component("retriever", retriever)
pipeline.add_component("prompt_builder", prompt_builder)
pipeline.add_component("generator", generator)
pipeline.connect("retriever.documents", "prompt_builder.documents")
pipeline.connect("prompt_builder.prompt", "generator.prompt")
self.tenant_pipelines[tenant_id] = pipeline
self.tenant_stores[tenant_id] = store
async def query(self, tenant_id: str, question: str) -> dict: """Query tenant-specific RAG pipeline"""
pipeline = self.tenant_pipelines.get(tenant_id)
if not pipeline: raise ValueError(f"Tenant {tenant_id} not configured")
result = await pipeline.arun({
"retriever": {"query": question, "top_k": 5},
"prompt_builder": {"question": question}
})
return {
"answer": result["generator"]["replies"][0],
"sources": len(result["retriever"]["documents"])
}
### Embedding Model Selection Guide
Choosing the right embedding model impacts retrieval quality: | Model | Dimensions | Max Tokens | mAP Score | Speed | Best For |
|
* * *
|
* * *
|
* * *
|
* * *
|
* * *
|
* * *
|
| all-MiniLM-L6-v2 | 384 | 256 | 42.3 | Fast | General purpose |
| all-mpnet-base-v2 | 768 | 512 | 58.7 | Medium | High accuracy |
| text-embedding-3-small | 1536 | 8191 | 61.2 | Fast | OpenAI API |
| text-embedding-3-large | 3072 | 8191 | 63.5 | Slow | Maximum accuracy |
| e5-mistral-7b-instruct | 4096 | 8192 | 65.1 | Slow | Research |
`````python
# Benchmark embedding models
from sentence_transformers import SentenceTransformer
import numpy as np
def benchmark_model(model_name: str, test_queries: list, relevant_docs: list) -> float: model = SentenceTransformer(model_name)
query_embeddings = model.encode(test_queries)
doc_embeddings = model.encode(relevant_docs)
# Compute recall@K
scores = np.dot(query_embeddings, doc_embeddings.T)
recalls = []
for i, score_row in enumerate(scores): top_k_idx = np.argsort(score_row)[-5:]
if i in top_k_idx: recalls.append(1.0)
else: recalls.append(0.0)
return np.mean(recalls)
# Compare models
models = [
"all-MiniLM-L6-v2",
"all-mpnet-base-v2",
"text-embedding-3-small"
]
for model in models: recall = benchmark_model(model, queries, docs)
print(f"{model}: Recall@5 = {recall:.3f}")
````
## Production Checklist
- [ ] Select appropriate embedding model for your use case
- [ ] Configure document chunking strategy based on content type
- [ ] Set up monitoring for retrieval quality metrics
- [ ] Implement caching for repeated queries
- [ ] Add rate limiting for API endpoints
- [ ] Configure fallback providers for reliability
- [ ] Set up logging for audit trails
- [ ] Test with production-quality input data
- [ ] Implement prompt injection detection
- [ ] Document resource requirements for each deployment
## FAQ
### Q1: How does Haystack compare to LangChain?
Haystack focuses specifically on RAG pipelines with a simpler, more opinionated approach. LangChain is more general-purpose but requires more boilerplate for RAG. Haystack has better built-in evaluation tools and cleaner abstractions for document processing.
### Q2: Can I use Haystack without any cloud APIs?
Yes, Haystack works entirely offline with local models. Use Ollama for LLMs, sentence-transformers for embeddings, and Elasticsearch or Chroma for document storage. No API keys required.
### Q3: What document formats does Haystack support?
Haystack supports PDF, DOCX, TXT, HTML, Markdown, CSV, JSON, images (with OCR), and email files through its converter components. Custom converters can be added for proprietary formats.
### Q4: How do I handle large document collections?
Use chunking strategies appropriate for your data size. For millions of documents, combine Elasticsearch with hybrid search and implement pagination. Consider using distributed document stores like Weaviate or Milvus for horizontal scaling.
### Q5: Is Haystack suitable for production use?
Yes, Haystack is used in production by many enterprises. It supports monitoring, logging, and can be deployed with standard containerization tools. The pipeline architecture makes it easy to add retries, caching, and rate limiting.
### Q6: How do I evaluate my RAG pipeline?
Use Haystack's built-in evaluators for retrieval quality (recall, precision) and generation quality (faithfulness, answer relevance). Run evaluations regularly as you modify your pipeline configuration.
### Q7: Can I customize the retrieval strategy?
Yes, Haystack supports BM25, dense vector, hybrid search, and cross-encoder reranking. You can combine multiple strategies and tune parameters like top_k, similarity thresholds, and filter conditions.
## Sources
- [Haystack Documentation](https://docs.haystack.deepset.ai/)
- [Haystack GitHub Repository](https://github.com/deepset-ai/haystack)
- [Deepset Blog](https://www.deepset.ai/blog)
- [Haystack Integrations](https://docs.haystack.deepset.ai/docs/integrations)
## Call to Action
Build production-ready RAG applications with Haystack. [Start building](https://dibi8.com/auth/) today with our deployment guides and pipeline templates.
{
"@context": "https://schema.org",
"@type": "Article",
"headline": "Deepset Haystack — Build Production-Ready RAG Applications with Python",
"datePublished": "2026-07-17",
"dateModified": "2026-07-17",
"author": {
"@type": "Organization",
"name": "Dibi8"
},
"publisher": {
"@type": "Organization",
"name": "Dibi8",
"logo": {
"@type": "ImageObject",
"url": "https://dibi8.com/logo.png"
}
},
"mainEntityOfPage": {
"@type": "WebPage",
"@id": "https://dibi8.com/resources/deepset-haystack-rag-framework-complete-guide"
}
}
</script>
* * *
## Related Articles
- [markitdown-universal-file-to-markdown-converter](deepset-haystack-rag-framework-complete-guide)
- [alpaca-trading-api-stock-broker](deepset-haystack-rag-framework-complete-guide)
- [appwrite-backend-as-service](deepset-haystack-rag-framework-complete-guide)
- [arize-ai-observability-llm](deepset-haystack-rag-framework-complete-guide)
- [cognee-ai-memory-platform](deepset-haystack-rag-framework-complete-guide)
* * *
*Found this helpful? [Join our Telegram community](https://t.me/DIBI8_Group) for daily AI tool updates!*