From a0b3741babb26cdd26d9bf0ae320da68d77097f9 Mon Sep 17 00:00:00 2001 From: Luis Quintanilla <46974588+luisquintanilla@users.noreply.github.com> Date: Thu, 9 Oct 2025 16:18:32 -0400 Subject: [PATCH] Initial commit --- docs/ai/conceptual/data-ingestion.md | 130 ++++++++++++++++++ .../ai/media/data-ingestion/DataIngestion.png | Bin 0 -> 49252 bytes docs/ai/toc.yml | 2 + 3 files changed, 132 insertions(+) create mode 100644 docs/ai/conceptual/data-ingestion.md create mode 100644 docs/ai/media/data-ingestion/DataIngestion.png diff --git a/docs/ai/conceptual/data-ingestion.md b/docs/ai/conceptual/data-ingestion.md new file mode 100644 index 0000000000000..f339091d7c2f7 --- /dev/null +++ b/docs/ai/conceptual/data-ingestion.md @@ -0,0 +1,130 @@ +--- +title: Data ingestion +description: Introduction to data ingestion +author: luisquintanilla +ms.author: luquinta +ms.date: 11/11/2025 +ms.topic: concept-article +--- + +# Data Ingestion + +## What is data ingestion? + +Data ingestion is the process of collecting, reading, and preparing data from different sources such as files, databases, APIs, or cloud services so it can be used in downstream applications. In practice, this follows the familiar Extract-Transform-Load (ETL) workflow: + +- **Extract** data from its original source, whether that is a PDF, Word document, audio file, or web API. +- **Transform** the data by cleaning, chunking, enriching, or converting formats. +- **Load** the data into a destination like a database, vector store, or AI model for retrieval and analysis. + +For AI and machine learning scenarios, especially Retrieval-Augmented Generation (RAG), data ingestion is not just about moving data. It is about making data usable for intelligent applications. This means representing documents in a way that preserves their structure and meaning, splitting them into manageable chunks, enriching them with metadata or embeddings, and storing them so they can be retrieved quickly and accurately. + +## Why data ingestion matters for AI applications + +Imagine you're building a RAG-powered chatbot to help employees find information across your company's vast collection of documents. These documents might include PDFs, Word files, PowerPoint presentations, and web pages scattered across different systems. + +Your chatbot needs to understand and search through thousands of documents to provide accurate, contextual answers. But raw documents aren't suitable for AI systems. You need to transform them into a format that preserves meaning while making them searchable and retrievable. + +This is where data ingestion becomes critical. You need to extract text from different file formats, break large documents into smaller chunks that fit within AI model limits, enrich the content with metadata, generate embeddings for semantic search, and store everything in a way that enables fast retrieval. Each step requires careful consideration of how to preserve the original meaning and context. + +## What is Microsoft.Extensions.DataIngestion? + +Microsoft.Extensions.DataIngestion provides foundational .NET components for data ingestion. It enables developers to read, process, and prepare documents for AI and machine learning workflows, especially Retrieval-Augmented Generation (RAG) scenarios. + +With these building blocks, developers can create robust, flexible, and intelligent data ingestion pipelines tailored for their application needs: + +- **Unified document representation:** Represent any file type (PDF, Image, Microsoft Word, etc.) in a consistent format that works well with large language models. +- **Flexible data ingestion:** Read documents from both cloud services and local sources using multiple built-in readers, making it easy to bring in data from wherever it lives. +- **Built-in AI enhancements:** Automatically enrich content with summaries, sentiment analysis, keyword extraction, privacy-focused PII removal, and classification, preparing your data for intelligent workflows. +- **Customizable chunking strategies:** Split documents into chunks using token-based, section-based, or semantic-aware approaches, so you can optimize for your retrieval and analysis needs. +- **Production-ready storage:** Store processed chunks in popular vector databases and document stores, with support for embedding generation, making your pipelines ready for real-world scenarios. +- **End-to-end pipeline composition:** Chain together readers, processors, chunkers, and writers with the DocumentPipeline API, reducing boilerplate and making it easy to build, customize, and extend complete workflows. + +All of these components are open and extensible by design. You can add custom logic, new connectors, and extend the system to support emerging AI scenarios. By standardizing how documents are represented, processed, and stored, .NET developers can build reliable, scalable, and maintainable data pipelines without reinventing the wheel for every project. + +### Building on stable foundations + +![Data Ingestion Architecture Diagram](../media/data-ingestion/DataIngestion.png) + +These new data ingestion abstractions are built on top of proven and extensible components in the .NET ecosystem, ensuring reliability, interoperability, and seamless integration with existing AI workflows: + +- **Microsoft.ML.Tokenizers:** Tokenizers provide the foundation for chunking documents based on tokens. This enables precise splitting of content, which is essential for preparing data for large language models and optimizing retrieval strategies. +- **Microsoft.Extensions.AI:** This set of libraries powers enrichment transformations using large language models. It enables features like summarization, sentiment analysis, keyword extraction, and embedding generation, making it easy to enhance your data with intelligent insights. +- **Microsoft.Extensions.VectorData:** This set of libraries offers a consistent interface for storing processed chunks in a wide variety of vector stores, including Qdrant, Azure SQL, CosmosDB, MongoDB, ElasticSearch, and many more. This ensures your data pipelines are ready for production and can scale across different storage backends. + +In addition to familiar patterns and tools, these abstractions build on already extensible components. Plug-in capability and interoperability are paramount, so as the rest of the .NET AI ecosystem grows, the capabilities of the data ingestion components grow as well. This approach empowers developers to easily integrate new connectors, enrichments, and storage options, keeping their pipelines future-ready and adaptable to evolving AI scenarios. + +## Data ingestion building blocks + +The Microsoft.Extensions.DataIngestion library is built around several key components that work together to create a complete data processing pipeline. Let's explore each component and how they fit together. + +### Documents and Document Readers + +At the foundation of the library is the `Document` type, which provides a unified way to represent any file format without losing important information. The `Document` is Markdown-centric because large language models work best with Markdown formatting. + +The `DocumentReader` abstraction handles loading documents from various sources, whether local files or remote URIs. The library includes several built-in readers: + +- **Azure Document Intelligence** +- **LlamaParse** +- **MarkItDown** +- **Markdown** + +This design means you can work with documents from different sources using the same consistent API, making your code more maintainable and flexible. + +```csharp +// TODO: Add code snippet +``` + +### Document Processing + +Document processors apply transformations at the document level to enhance and prepare content. The library currently supports: + +- **Image processing** to extract text and descriptions from images within documents +- **Table processing** to preserve tabular data structure and make it searchable + +### Chunks and Chunking Strategies + +Once you have a document loaded, you typically need to break it down into smaller pieces called chunks. Chunks represent subsections of a document that can be efficiently processed, stored, and retrieved by AI systems. This chunking process is essential for retrieval-augmented generation scenarios where you need to find the most relevant pieces of information quickly. + +The library provides several chunking strategies to fit different use cases: + +- **Token-based chunking** splits text based on token counts, ensuring chunks fit within model limits +- **Section-based chunking** splits on headers and natural document boundaries +- **Semantic-aware chunking** preserves complete thoughts and ideas across chunk boundaries + +These chunking strategies build on the Microsoft.ML.Tokenizers library to intelligently split text into appropriately sized pieces that work well with large language models. The right chunking strategy depends on your document types and how you plan to retrieve information. + +```csharp +// TODO: Add code snippet +``` + +### Chunk Processing and Enrichment + +After documents are split into chunks, you can apply processors to enhance and enrich the content. Chunk processors work on individual pieces and can perform: + +- **Content enrichment** including automatic summaries, sentiment analysis, and keyword extraction +- **PII removal** for privacy-focused content sanitization using large language models +- **Classification** for automated content categorization based on predefined categories + +These processors use Microsoft.Extensions.AI to leverage large language models for intelligent content transformation, making your chunks more useful for downstream AI applications. + +### Document Writer and Storage + +The `DocumentWriter` stores processed chunks into a data store for later retrieval. Using Microsoft.Extensions.AI and Microsoft.Extensions.VectorData, the library provides abstractions and implementations that support storing chunks in any vector store supported by Microsoft.Extensions.VectorData. + +This includes popular options like Azure SQL Server, CosmosDB, PostgreSQL, MongoDB, and many others. The writer can also automatically generate embeddings for your chunks using Microsoft.Extensions.AI, making them ready for semantic search and retrieval scenarios. + +### Document Processing Pipeline + +The `DocumentPipeline` API allows you to chain together the various data ingestion components into a complete workflow. You can combine: + +- **Readers** to load documents from various sources +- **Processors** to transform and enrich document content +- **Chunkers** to break documents into manageable pieces +- **Writers** to store the final results in your chosen data store + +This pipeline approach reduces boilerplate code and makes it easy to build, test, and maintain complex data ingestion workflows. + +```csharp +//TODO: Add code snippet +``` \ No newline at end of file diff --git a/docs/ai/media/data-ingestion/DataIngestion.png b/docs/ai/media/data-ingestion/DataIngestion.png new file mode 100644 index 0000000000000000000000000000000000000000..ee897f2e08b03165eafea2fe3f5dee947a71901e GIT binary patch literal 49252 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 gu&@pxi+WtF?gXEZq