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

    DSGVO und Data Residency, wenn ein LLM im Spiel ist

    Wo läuft das Modell, wo liegen die Embeddings, wo die Logs? Die technische Liste, die eine Datenschutzprüfung für KI-Systeme erst möglich macht.

    Artikel lesen

    RAG in Produktion

    Der Weg von einer RAG-Demo zu einem System, das ein Audit besteht: Chunking, Hybrid-Retrieval, Reranking, Quellenbindung, Evaluation, Mandanten.

    Artikel lesen

    Termin

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