ai

RAG-Pipeline bauen mit Open-Source-Tools

RAG-Pipeline mit Open-Source-Tools bauen: LangChain, ChromaDB, Ollama und Streamlit. Schritt-für-Schritt Tutorial für Retrieval-Augmented Generation 2026.

von Ultrion Redaktion2026-08-074 Min Lesezeit
Werbung (AdSense — In-Article)


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

  • Dokumente laden — PDFs, Websites, Markdown

  • Text chunken — In kleine Abschnitte teilen

  • Embeddings erstellen — Jeden Chunk als Vektor repräsentieren

  • In Vektordatenbank speichern — Für schnelle Ähnlichkeitssuche

  • Bei einer Frage: Ähnliche Chunks finden → dem LLM als Kontext geben → Antwort generieren
  • 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 RecursiveCharacterTextSplitter

    def 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 Chroma

    def 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 StrOutputParser

    def 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 os

    st.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 = None

    Sidebar: 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 MultiQueryRetriever

    multi_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 HuggingFaceCrossEncoder

    model = 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.

    Werbung (AdSense — In-Article Bottom)

    Verwandte Artikel