RAG-Pipeline bauen mit Open-Source-Tools
RAG (Retrieval-Augmented Generation) ist die wichtigste Technik, um LLMs mit eigenen Daten zu füttern — ohne Fine-Tuning. Wir bauen eine komplette RAG-Pipeline mit kostenlosen Open-Source-Tools.
Was ist RAG?
RAG kombiniert ein LLM mit einer Vektordatenbank. Statt das Modell über alle Ihre Dokumente trainieren zu müssen (teuer, aufwendig), werden relevante Informationen bei jeder Frage dynamisch gesucht und dem Modell als Kontext mitgegeben.
Der RAG-Prozess
Technologie-Stack
| Komponente | Tool | Zweck |
|------------|------|-------|
| LLM | Ollama (Llama 3.1) | Antwort-Generierung |
| Embeddings | nomic-embed-text | Text zu Vektor |
| Vektordatenbank | ChromaDB | Ähnlichkeitssuche |
| Framework | LangChain | Orchestrierung |
| UI | Streamlit | Web-Interface |
| Sprache | Python 3.11+ | Implementierung |
Setup
Abhängigkeiten installieren
``
bash
pip install langchain langchain-community langchain-ollama \
chromadb sentence-transformers streamlit pypdf
`Ollama Modelle laden
`bash
ollama pull llama3.1
ollama pull nomic-embed-text
`Implementierung
1. Dokumente laden und chunken
`python
from langchain_community.document_loaders import PyPDFLoader, TextLoader
from langchain.text_splitter import RecursiveCharacterTextSplitterdef load_documents(path: str):
"""Lädt PDF oder Text-Datei."""
if path.endswith(".pdf"):
loader = PyPDFLoader(path)
else:
loader = TextLoader(path)
return loader.load()
def chunk_documents(docs, chunk_size=1000, chunk_overlap=200):
"""Teilt Dokumente in Chunks."""
splitter = RecursiveCharacterTextSplitter(
chunk_size=chunk_size,
chunk_overlap=chunk_overlap,
separators=["\n\n", "\n", " ", ""]
)
return splitter.split_documents(docs)
`2. Vektordatenbank erstellen
`python
from langchain_ollama import OllamaEmbeddings
from langchain_community.vectorstores import Chromadef create_vectorstore(chunks, persist_dir="./chroma_db"):
"""Erstellt ChromaDB Vektordatenbank."""
embeddings = OllamaEmbeddings(model="nomic-embed-text")
vectorstore = Chroma.from_documents(
documents=chunks,
embedding=embeddings,
persist_directory=persist_dir
)
return vectorstore
`3. RAG-Chain bauen
`python
from langchain_ollama import ChatOllama
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough
from langchain_core.output_parsers import StrOutputParserdef create_rag_chain(vectorstore):
"""Baut die RAG-Chain."""
llm = ChatOllama(
model="llama3.1",
temperature=0.3,
num_ctx=4096
)
retriever = vectorstore.as_retriever(
search_type="similarity",
search_kwargs={"k": 5} # Top 5 relevante Chunks
)
template = """Du bist ein hilfreicher Assistent.
Nutze die folgenden Kontextdokumente, um die Frage zu beantworten.
Wenn die Antwort nicht in den Dokumenten steht, sage: "Ich habe dazu keine Informationen."
Kontext:
{context}
Frage: {question}
Antwort (auf Deutsch):"""
prompt = ChatPromptTemplate.from_template(template)
def format_docs(docs):
return "\n\n".join(doc.page_content for doc in docs)
rag_chain = (
{"context": retriever | format_docs, "question": RunnablePassthrough()}
| prompt
| llm
| StrOutputParser()
)
return rag_chain, retriever
`4. Streamlit UI
`python
import streamlit as st
import osst.set_page_config(page_title="RAG Chatbot", page_icon="🤖")
st.title("🤖 RAG Chatbot")
Session State
if "messages" not in st.session_state:
st.session_state.messages = []
if "vectorstore" not in st.session_state:
st.session_state.vectorstore = None
if "chain" not in st.session_state:
st.session_state.chain = NoneSidebar: Dokumente hochladen
with st.sidebar:
st.header("Dokumente")
uploaded = st.file_uploader(
"PDF oder TXT hochladen",
type=["pdf", "txt"],
accept_multiple_files=True
)
if uploaded and st.button("Verarbeiten"):
with st.spinner("Verarbeite Dokumente..."):
docs = []
for f in uploaded:
with open(f.name, "wb") as fp:
fp.write(f.getvalue())
docs.extend(load_documents(f.name))
chunks = chunk_documents(docs)
st.session_state.vectorstore = create_vectorstore(chunks)
st.session_state.chain, _ = create_rag_chain(
st.session_state.vectorstore
)
st.success(f"{len(chunks)} Chunks indexiert!")Chat Interface
for msg in st.session_state.messages:
with st.chat_message(msg["role"]):
st.markdown(msg["content"])if prompt := st.chat_input("Frage stellen..."):
if st.session_state.chain is None:
st.error("Bitte zuerst Dokumente hochladen!")
else:
st.session_state.messages.append({"role": "user", "content": prompt})
with st.chat_message("user"):
st.markdown(prompt)
with st.chat_message("assistant"):
response = st.session_state.chain.invoke(prompt)
st.markdown(response)
st.session_state.messages.append(
{"role": "assistant", "content": response}
)
`5. Starten
`bash
streamlit run rag_app.py
`Die App läuft unter
http://localhost:8501.Optimierungen
Bessere Retrieval mit Multi-Query
`python
from langchain.retrievers.multi_query import MultiQueryRetrievermulti_retriever = MultiQueryRetriever.from_llm(
retriever=vectorstore.as_retriever(),
llm=ChatOllama(model="llama3.1")
)
`Re-Ranking mit Cross-Encoder
`python
from langchain.retrievers import ContextualCompressionRetriever
from langchain.retrievers.document_compressors import CrossEncoderReranker
from langchain_community.cross_encoders import HuggingFaceCrossEncodermodel = HuggingFaceCrossEncoder(model_name="BAAI/bge-reranker-base")
compressor = CrossEncoderReranker(model=model, top_n=3)
compression_retriever = ContextualCompressionRetriever(
base_compressor=compressor,
base_retriever=vectorstore.as_retriever(search_kwargs={"k": 20})
)
`FAQ
Welche Embedding-Modelle sind am besten?
Für Deutsch: nomic-embed-text (gut), multilingual-e5-large (besser, aber größer), BAAI/bge-m3` (am besten für mehrsprachig).Welche Vektordatenbank?
ChromaDB (einfach, lokal). Für Produktion: Qdrant, Weaviate oder Milvus (skalierbar).
Wie groß sollten Chunks sein?
Sweet Spot: 500-1000 Zeichen mit 100-200 Zeichen Overlap. Bei sehr langen Texten größer (1500-2000).
Kann ich das in Produktion nutzen?
Ja. Für Produktion: Ollama durch eine dedizierte GPU-Inference-Lösung (vLLM) ersetzen, ChromaDB durch Qdrant/Weaviate, Streamlit durch FastAPI + Frontend.
Fazit
Eine RAG-Pipeline mit Open-Source-Tools zu bauen ist 2026 einfacher denn je. Mit LangChain, ChromaDB und Ollama erhalten Sie in unter 100 Zeilen Python einen voll funktionsfähigen Chatbot, der Ihre eigenen Dokumente versteht — komplett lokal, kostenlos und privat.