<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Azariah Arthur</title>
    <description>The latest articles on DEV Community by Azariah Arthur (@azariah_arthur_5ae83be2ec).</description>
    <link>https://dev.to/azariah_arthur_5ae83be2ec</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4105615%2F6416303d-9815-4d78-a8a1-d869a1f92d11.jpg</url>
      <title>DEV Community: Azariah Arthur</title>
      <link>https://dev.to/azariah_arthur_5ae83be2ec</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/azariah_arthur_5ae83be2ec"/>
    <language>en</language>
    <item>
      <title>Building a RAG Pipeline with FastAPI — Part 1: From Documents to Vector Data</title>
      <dc:creator>Azariah Arthur</dc:creator>
      <pubDate>Wed, 02 Sep 2026 07:09:58 +0000</pubDate>
      <link>https://dev.to/azariah_arthur_5ae83be2ec/building-a-rag-pipeline-with-fastapi-part-1-from-documents-to-vector-data-3b3a</link>
      <guid>https://dev.to/azariah_arthur_5ae83be2ec/building-a-rag-pipeline-with-fastapi-part-1-from-documents-to-vector-data-3b3a</guid>
      <description>&lt;p&gt;I've been experimenting with Retrieval-Augmented Generation (RAG), and instead of building the entire application in one massive project, I decided to break it into smaller pieces.&lt;/p&gt;

&lt;p&gt;The goal is to eventually build a document intelligence application that can take a collection of documents and allow users to interact with the information inside them.&lt;/p&gt;

&lt;p&gt;I'm splitting the build into four stages:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Document ingestion&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Retrieval&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Augmented generation&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The complete application&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This article covers Part 1: &lt;strong&gt;document ingestion&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;A document is easy for a human to read.&lt;/p&gt;

&lt;p&gt;A PDF, Word document, or text file can contain exactly the information we're looking for, but an AI system can't simply perform a semantic search over the raw file.&lt;/p&gt;

&lt;p&gt;We first need to transform the document into a representation that our system can search efficiently.&lt;/p&gt;

&lt;p&gt;The basic pipeline looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Document
   ↓
Text Extraction
   ↓
Chunking
   ↓
Embeddings
   ↓
Vector Database
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is what I set out to build for the first stage of this project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1 — Extracting the Text
&lt;/h2&gt;

&lt;p&gt;The first step is getting the actual text out of the document.&lt;/p&gt;

&lt;p&gt;The system currently supports:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;.txt&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.pdf&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.docx&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once the text has been extracted, we can begin preparing it for the embedding model.&lt;/p&gt;

&lt;p&gt;But there is a problem.&lt;/p&gt;

&lt;p&gt;A document can contain thousands or even millions of characters.&lt;/p&gt;

&lt;p&gt;Trying to embed an entire document as a single vector would lose too much information and make retrieval much less useful.&lt;/p&gt;

&lt;p&gt;That's where chunking comes in.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2 — Chunking the Document
&lt;/h2&gt;

&lt;p&gt;Instead of treating the document as one giant piece of text, we divide it into smaller chunks.&lt;/p&gt;

&lt;p&gt;For this project, I'm using &lt;strong&gt;recursive chunking&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The basic idea is to progressively split the text using increasingly smaller separators until the resulting pieces fit within the desired chunk size.&lt;/p&gt;

&lt;p&gt;Conceptually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Large Document
      ↓
Paragraphs
      ↓
Sentences
      ↓
Smaller Text Segments
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Chunk size and overlap matter here.&lt;/p&gt;

&lt;p&gt;If chunks are too large, retrieval can return a lot of irrelevant information.&lt;/p&gt;

&lt;p&gt;If they're too small, we can lose the surrounding context that makes a piece of text meaningful.&lt;/p&gt;

&lt;p&gt;Overlap helps preserve some of that context between neighboring chunks.&lt;/p&gt;

&lt;p&gt;The result is something more like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Document
 ├── Chunk 1
 ├── Chunk 2
 ├── Chunk 3
 ├── Chunk 4
 └── ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we have manageable pieces of text that can be converted into vectors.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3 — Generating Embeddings
&lt;/h2&gt;

&lt;p&gt;The next step is turning each chunk into an embedding.&lt;/p&gt;

&lt;p&gt;An embedding is essentially a numerical representation of the meaning of a piece of text.&lt;/p&gt;

&lt;p&gt;For this project, I'm using &lt;strong&gt;BAAI/bge-m3&lt;/strong&gt; through Sentence Transformers.&lt;/p&gt;

&lt;p&gt;The process looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"Some piece of document text..."
              ↓
        BGE-M3 Model
              ↓
     [0.012, -0.083, ...]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exact numbers aren't particularly useful to look at individually.&lt;/p&gt;

&lt;p&gt;What matters is that semantically similar pieces of text should have similar representations in vector space.&lt;/p&gt;

&lt;p&gt;That gives us a way to perform semantic search later.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4 — Storing the Vectors
&lt;/h2&gt;

&lt;p&gt;Once the embeddings have been generated, we need somewhere to store them.&lt;/p&gt;

&lt;p&gt;I'm using &lt;strong&gt;Qdrant&lt;/strong&gt; as the vector database.&lt;/p&gt;

&lt;p&gt;Each stored record contains the vector along with information that allows us to associate it with the original chunk of text.&lt;/p&gt;

&lt;p&gt;Conceptually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Qdrant

Vector
   +
Document Chunk
   +
Metadata
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This gives us the foundation for the retrieval stage.&lt;/p&gt;

&lt;p&gt;Later, when a user asks a question, we can embed that question and search Qdrant for vectors that are semantically similar.&lt;/p&gt;

&lt;p&gt;But we're not there yet.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Current Pipeline
&lt;/h2&gt;

&lt;p&gt;At the end of Part 1, the system can take a document and process it through the entire ingestion pipeline:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;             DOCUMENT
                 ↓
          TEXT EXTRACTION
                 ↓
          RECURSIVE CHUNKING
                 ↓
             BGE-M3
                 ↓
             EMBEDDINGS
                 ↓
              QDRANT
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important distinction is that &lt;strong&gt;we haven't built the question-answering system yet&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;We've only built the foundation that makes retrieval possible.&lt;/p&gt;

&lt;p&gt;And that's intentional.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next?
&lt;/h2&gt;

&lt;p&gt;Now that the documents have been converted into searchable vectors, we have a new problem:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do we find the right information when someone asks a question?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That's the focus of Part 2.&lt;/p&gt;

&lt;p&gt;We'll take a user query, convert it into an embedding, search the vector database, and retrieve the most relevant pieces of the original documents.&lt;/p&gt;

&lt;p&gt;Eventually, those retrieved pieces will become the context used by an LLM.&lt;/p&gt;

&lt;p&gt;The complete system will look more like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Documents
    ↓
Ingestion
    ↓
Vector Database
    ↓
Retrieval
    ↓
Relevant Context
    ↓
LLM
    ↓
Answer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But for now, we have the first major piece working.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Documents → Chunks → Embeddings → Qdrant&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I'm documenting the entire build as I go, including the problems and design decisions along the way.&lt;/p&gt;

&lt;h3&gt;
  
  
  Follow the build
&lt;/h3&gt;

&lt;p&gt;🎥 &lt;strong&gt;YouTube:&lt;/strong&gt; &lt;a href="https://www.youtube.com/watch?v=jcJ8hbsAigY" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=jcJ8hbsAigY&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;💻 &lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/azariah11dev/Minimal-RAG-Engine" rel="noopener noreferrer"&gt;https://github.com/azariah11dev/Minimal-RAG-Engine&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Part 2 will cover the retrieval layer.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>python</category>
      <category>rag</category>
      <category>fastapi</category>
    </item>
  </channel>
</rss>
