DANIEL KIRCHNER
Alle Artikel
10. April 20268 min Lesezeit

Naive RAG: Was chunk_size=1000 und reine Vektorsuche anrichten

RAGLangChainMilvusOpenAIPythonKI

Dieser Text war einmal ein Praxisguide. Derselbe Stack steht weiter unten, als Befund, nicht als Bauanleitung.

In einem Gesundheitsprojekt lagen 500+ Videos und PDFs in Milvus, grob 50.000 Chunks, Antworten unter 100 ms. Revision fragt nicht nach der Latenz. Sie fragt nach der Stelle.

Was wir gebaut haben, war naives Retrieval: Chunking nach Zeichenzahl, nur Vektoren, kein Reranking. Halluzinationen sind dann kein Zufall.

Was danach kommen muss, steht in Hybrid-RAG und Reranking.

Was die Pipeline tat

Drei Stufen, wie in jedem Tutorial:

  • Ingestion: Dokumente laden, in Chunks schneiden, Vektoren schreiben
  • Retrieval: Similarity Search
  • Generation: Top-k Chunks ins Prompt, Modell erzeugen lassen
  • Stack: LangChain, GPT-4o, selbst-gehostetes Milvus (Docker), FastAPI, Python 3.12. Selbst-hosten war richtig: in dem Umfeld dürfen die Daten das Haus nicht verlassen. Der Fehler saß nicht bei Milvus. Er saß in der Annahme, Ähnlichkeit sei ein Beleg.

    Befund 1: feste Chunk-Größe

    from langchain.text_splitter import RecursiveCharacterTextSplitter
    
    splitter = RecursiveCharacterTextSplitter(
        chunk_size=1000,
        chunk_overlap=200,
    )
    chunks = splitter.split_documents(docs)
    

    1000 / 200 war ein Kompromiss nach Gefühl. Überschriften, Tabellen, Normstellen: egal. Ein Chunk riss mitten in einer Tabelle. Der Nachbar-Chunk klang ähnlich und gewann die Suche. Die Aussage im Prompt stammte aus der falschen Zeile.

    Chunk-Qualität schlägt Quantität. Das bleibt wahr. Feste Zeichenzahl erzeugt trotzdem erwartbare Fehler.

    Befund 2: nur Vektoren

    from langchain_openai import OpenAIEmbeddings
    from langchain_milvus import Milvus
    
    embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
    vectorstore = Milvus.from_documents(
        documents=chunks,
        embedding=embeddings,
        connection_args={"host": "localhost", "port": "19530"},
        collection_name="knowledge_base",
    )
    

    Cosine-Similarity findet Paraphrasen. Sie findet keine Aktenzeichen, keine Paragraphen, keine Produktcodes. Metadata-Filter hätten geholfen. Wir hatten sie. Sie ersetzen keine Keyword-Suche.

    Befund 3: ungeprüftes Top-k

    from langchain.chains import RetrievalQA
    
    qa_chain = RetrievalQA.from_chain_type(
        llm=llm,
        chain_type="stuff",
        retriever=vectorstore.as_retriever(search_kwargs={"k": 5}),
    )
    

    Die fünf nächsten Chunks gingen ins Prompt. Kein Reranker. Keine Regel „keine Quelle, keine Aussage“. „Ähnlich“ wurde wie „belegt“ behandelt. Quellenbindung verlangt das Gegenteil.

    Evaluation war von Tag 1 geplant. Das Set existierte. Es hat die schnelle Pipeline nicht gestoppt, weil das Set Stil prüfte, nicht Herkunft.

    Was ich heute anders mache

  • Chunks an Überschriften und Tabellen, nicht an chunk_size=1000
  • Hybrid: Keyword plus Vektor, dann Rerank
  • Harte Regel: fehlt der öffenbare Beleg, sagt das System Nein
  • Evaluation an der Quelle, nicht am Wohlklang
  • Der passende Einstieg ist der LLM-Readiness-Check. Tag 2 ist Retrieval und Quellenbindung. Praxis: Gesundheits-Chatbot.

    Verwandte Artikel

    Hybrid-RAG und Reranking statt naiver Vektorsuche

    Chunking nach Zeichenzahl und reine Vektorsuche erzeugen erwartbare Halluzinationen. Was Hybrid-Suche und Reranking ändern, und was der ältere RAG-Artikel falsch lehrt.

    Artikel lesen

    Mandantentrennung für RAG und Agenten

    Ein Pilot für einen Kunden ist kein Produkt für zwanzig. Was Mandantentrennung in RAG- und Agentensystemen konkret heißt.

    Artikel lesen

    Termin

    30 Minuten. Wenn der Use-Case nicht in den Betrieb kann, sage ich das.