System Logs

TX-FD33 // tech

Markdown ist das beste Zwischenformat für RAG

Audio, PDF, Office, Notizen — alles auf Markdown normalisieren, dann erst chunken. Warum dieser Schritt 80 Prozent der Retrieval-Qualität entscheidet.

2026.04.22/// 5 min read
> sys.log | category: tech | tags: RAG / LLM / Embeddings / fridai
Table of contents

Wer eine RAG-Pipeline auf gemischten Quellen aufbaut — Audio-Mitschnitte, PDFs, Word-Dokumente, Notizen — kommt schnell an die Stelle, wo das Chunking versagt. Nicht weil die Chunks zu gross oder zu klein sind, sondern weil die Quelle voller Layout-Reste ist, die das Embedding verwirren.

Die Lösung ist langweilig: alles auf Markdown bringen, dann erst chunken.

Was schiefläuft, wenn man's nicht tut

Ein PDF-Extract liefert dir Spaltenumbrüche, Seitenzahlen und „Page 4 of 12"-Zeilen mitten im Text. Ein Word-Dokument bringt invisible Formatierungs-Tags. Ein Audio-Transkript hat Wiederholungen, Füllwörter, Sprecherwechsel ohne klare Struktur.

Wer das direkt embeddet, embedded die Layout-Artefakte mit. Das Resultat: Chunks, die syntaktisch ähnlich sind („Page 4 of 12"-Wiederholungen) ranken in der Vektorsuche hoch, semantisch relevante Inhalte verlieren.

Warum Markdown

Markdown ist genau strukturiert genug, um semantische Information zu erhalten — Headings, Listen, Code-Blöcke, Hervorhebungen — und genau plain genug, um nichts mitzuschleppen, was beim Embedden stört.

Konkret heisst das:

  • Kein Layout, keine Spalten, keine Seitenumbrüche
  • Hierarchie über #-Levels statt Schriftgrössen
  • Listen als Listen, nicht als Pseudo-Tabellen
  • Code als Code-Block, nicht als Bild

Das macht das anschliessende Chunking deterministisch. Du kannst entlang von Headings splitten, oder entlang von Absätzen, oder mit fixer Token-Länge — alles funktioniert, weil das Eingangsformat sauber ist.

Pipeline-Schritt

Der Konvertierungsschritt ist meist der unspannendste der ganzen Pipeline und gleichzeitig der wirkungsvollste:

def to_markdown(source: Path) -> str:
    match source.suffix.lower():
        case ".pdf":
            return pdf_to_markdown(source)
        case ".docx":
            return docx_to_markdown(source)
        case ".wav" | ".mp3" | ".m4a":
            transcript = transcribe(source)
            return transcript_to_markdown(transcript)
        case ".md" | ".txt":
            return source.read_text()
        case _:
            raise UnsupportedFormat(source.suffix)

Audio-Quellen bekommen einen zusätzlichen Schritt: das Transkript wird strukturiert (Sprecher, Themen, Zeitmarken), bevor es als Markdown gespeichert wird. Das ist kein Luxus — es ist der Unterschied zwischen einer durchsuchbaren Sitzung und einer Word-Wolke mit Zeitstempeln.

Was du gewinnst

  • Deterministisches Chunking — gleicher Input, gleiche Chunks, immer
  • Bessere Retrieval-Qualität — weil Embeddings auf Inhalt zielen, nicht auf Layout-Rauschen
  • Debuggbare Pipeline — du kannst dir das Markdown anschauen und siehst, was das LLM sieht
  • Reproduzierbarkeit — wenn du das Embedding-Modell wechselst, läuft der Re-Index auf den gleichen Chunks

Wer eine RAG-Pipeline plant: rechne Zeit für die Normalisierung ein. Sie ist nicht der Hot-Path, aber sie entscheidet, ob die ganze Pipeline brauchbare Antworten liefert.

signal routing // hardware patchbay

Linked Transmissions

signal.tags
RAGLLMEmbeddingsfridai
tx.next_sequence

standalone transmission