> For the complete documentation index, see [llms.txt](https://docs.neuron-ai.dev/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.neuron-ai.dev/neuron-v3-zh/rag/data-loader.md).

# 数据加载器

{% hint style="info" %}
前置条件

本指南假设你已经熟悉 RAG。请查看专门文档： <https://docs.neuron-ai.dev/rag>
{% endhint %}

要构建一个结构化 AI 应用，你需要能够将你拥有的所有信息转换为文本，这样你就可以生成嵌入、将它们保存到向量存储中，然后将其提供给你的 Agent 以回答用户的问题。

<figure><img src="/files/ed312722fbb964306c9e0cca64e4d33c5f6002c5" alt=""><figcaption></figcaption></figure>

Neuron 为你提供了若干工具（数据加载器）来简化这一过程。

```php
use App\Neuron\MyRAG;
use NeuronAI\RAG\DataLoader\FileDataLoader;

MyRAG::make()->addDocuments(
    // 使用文件数据加载器组件处理文本文件
    FileDataLoader::for(__DIR__.'/my-article.md')->getDocuments()
);
```

使用 Neuron 工具包，你可以创建数据加载管道，并借助统一接口的优势，方便各组件之间的交互，例如嵌入提供器、向量存储和文件读取器。

## FileDataLoader

如果你需要从文件中提取文本， `FileDataLoader` 可让你处理任何简单的文本文档。

```php
use NeuronAI\RAG\DataLoader\FileDataLoader;

// 读取文件并获取“documents”
$documents = FileDataLoader::for(__DIR__.'/my-article.md')->getDocuments();

// 传入目录以处理所有文件
$documents = FileDataLoader::for(__DIR__)->getDocuments();
```

默认情况下 `FileDataLoader` 它会按文件系统中的原样读取文件内容，但并非所有文件类型都适合被当作纯文本处理。Neuron 为你提供了 ReaderInterface 以及若干预定义的读取器组件，适用于最常见的文件格式。

请注意，每个文件读取器都与一种文件扩展名相关联。因此，数据加载器会根据输入文件的扩展名自动使用相应的读取器。

### PDF 读取器

{% hint style="warning" %}
要使用 `PdfReader` 你需要安装 [**poppler**](https://en.wikipedia.org/wiki/Pdftotext) 工具。
{% endhint %}

```php
use NeuronAI\RAG\DataLoader\FileDataLoader;

// 注册 PDF 读取器
$documents = FileDataLoader::for(__DIR__)
    ->addReader('pdf', new \NeuronAI\RAG\DataLoader\PdfReader())
    ->getDocuments();
```

### HTML 转 Markdown 读取器

{% hint style="warning" %}
要使用 `HtmlReader` 你需要安装 [**html2text**](https://github.com/mtibben/html2text) composer 包。
{% endhint %}

```php
use NeuronAI\RAG\DataLoader\FileDataLoader;

// 注册 PDF 读取器
$documents = FileDataLoader::for(__DIR__)
    ->addReader(['html', 'xhtml'], new \NeuronAI\RAG\DataLoader\HtmlReader())
    ->getDocuments();
```

### StringDataLoader

如果你已经从数据库或其他来源获取到了文本，你可以使用 StringDataLoader 将这些文本转换为文档，供链中的其他 Neuron 组件进行嵌入和存储：

```php
use App\Neuron\MyRAG;
use NeuronAI\RAG\DataLoader\StringDataLoader;

$contents = [
    // 字符串列表（你想要嵌入的文本）
];

foreach ($contents as $text) {
    $documents = StringDataLoader::for($text)->getDocuments(); 
    
    MyRAG::make()->addDocuments($documents);
}
```

### 文档元数据

从数据加载器获取文档数组后，你最终可以为文档附加自定义元数据，这些元数据将与其他文档默认字段一起保存到向量存储中：

```php
$documents = FileDataLoader::for($directory)->getDocuments(); 

foreach($documents as $document) {
    $document->addMetadata('user_id', 1234);
}

MyRAG::make()->addDocuments($documents);
```

一旦这些自定义字段进入向量存储，你就可以对支持此功能的数据库使用混合搜索。

{% hint style="info" %}
混合搜索允许你将语义搜索查询的范围缩小到在其他文档字段上匹配某些条件的记录，而不只是比较向量嵌入。请了解 [向量存储部分](/neuron-v3-zh/rag/vector-store.md) 以了解哪些数据库支持混合搜索。
{% endhint %}

## 文本分割器

Neuron 数据加载器接收文件或文本输入，并生成一个 `\NeuronAI\RAG\Document` 对象数组。这些文档是可嵌入的单元。原始文本会被拆分成更小的文本片段，以便转换为嵌入并保存到向量存储中。

数据加载器用于将长文本拆分为块的逻辑可以通过不同策略进行自定义。Neuron 提供了一个专门用于此目的的组件，名为“Splitter”，并且可以根据你偏好或需要的策略附加到数据加载器上：

```php
$documents = FileDataLoader::for($directory)
    ->withSplitter(
        new DelimiterTextSplitter()
    )
    ->getDocuments();
```

### DelimiterTextSplitter（默认）

这是所有数据加载器的默认分割器。

```php
$documents = FileDataLoader::for($directory)
    ->withSplitter(
        new DelimiterTextSplitter(
            maxLength: 1000,
            separator: '.',
            wordOverlap: 0
        )
    )
    ->getDocuments();
```

这些参数都会影响你的 RAG agent 的性能和准确性。

#### 最大长度

每个块都不会长于这个值，最终会被拆分成更小的文档。长度会影响嵌入表示的准确性。你的文本单元越长，嵌入表示就会越不准确。

#### 分隔符

文本首先会根据分隔符拆分为块。默认情况下，该组件使用句号字符。你最终可以为文本使用任意分隔符来自定义这个分隔符。

#### 重叠

有时，将前一个和后一个块中的词带入同一文档中会很有用，以增强文本相邻部分之间的语义联系。默认情况下不应用重叠。

### SentenceTextSplitter

将文本拆分为句子，按词分组为块，并可选地按词应用重叠。

```php
$documents = FileDataLoader::for($directory)
    ->withSplitter(
        new SentenceTextSplitter(
            maxWords: 200,
            overlapWords: 0
        )
    )
    ->getDocuments();
```

**最大词数**：每个块的最大词数

**重叠词数**：块之间重叠的词数

### 实现自定义分割器

你可以通过实现以下接口来实现自定义拆分逻辑 `SplitterInterface`:

```php
namespace NeuronAI\RAG\Splitter;

use NeuronAI\RAG\Document;

interface SplitterInterface
{
    /**
     * @return Document[]
     */
    public function splitDocument(Document $document): array;

    /**
     * @param  Document[]  $documents
     * @return Document[]
     */
    public function splitDocuments(array $documents): array;
}
```

你可以与外部服务交互，或者创建自己的逻辑，将长文本拆分为更小的块。创建好自定义实现后，你可以在数据加载器中使用它：

```php
class CustomSplitter implements SplitterInterface
{
    public function splitDocument(Document $document): array
    {
        // 你的逻辑在这里...
    }
    
    public function splitDocuments(array $documents): array
    {
        // 你的逻辑在这里...
    }
}

// 在数据加载器管道中使用自定义分割器
$documents = FileDataLoader::for($directory)
    ->withSplitter(
        new CustomSplitter()
    )
    ->getDocuments();
```

## 重新索引知识源

重新索引是 RAG 系统设计中的热门话题，因为将文本拆分成块的做法会使得当原始知识内容发生变化时，难以更新单个信息片段。

在 Neuron 中，该 `Document` 类旨在携带一些元数据，帮助你识别存储到向量数据库中的每一条知识的来源，例如 `sourceType` 和 `sourceName` 字段。利用这些信息，你可以轻松地将向量存储更新为先前用作知识来源的文件内容的更新版本。

{% hint style="warning" %}
文件的新版本 **必须具有相同的路径和名称** 你最初使用的那个，否则这些文档会被作为新的文档添加。
{% endhint %}

```php
$documents = FileDataLoader::for("/path/to/directory")
    ->withSplitter(
        new SentenceTextSplitter(
            maxWords: 200,
            overlapWords: 0
        )
    )
    ->getDocuments();

// 按 sourceType 和 sourceName 重新索引
MyRAG::make()->reindexBySource($documents);
```

如果 `sourceType` 和 `sourceName` 这些 Documents 中有一部分已经存在于向量存储中，它们将被删除，而新版本的 Documents 将被保存。其他文档将照常存储到向量数据库中。

## 使用独立组件

在下面的示例中，我们使用了 RAG agent 实例来处理摄取管道的最后一部分：为文档块生成嵌入，并将它们存储到 jthe 向量数据库中。

作为替代，你可以不借助 RAG agent 实例，而是将嵌入提供器和向量存储作为独立组件使用。请记住，这里的向量存储必须与 RAG agent 连接到同一个。

```php
use App\Neuron\MyRAG;
use NeuronAI\RAG\DataLoader\FileDataLoader;
use NeuronAI\RAG\DataLoader\StringDataLoader;
use NeuronAI\RAG\EmbeddingProvider\OpenAIEmbeddingProvider;
use NeuronAI\RAG\VectorStore\FileVectorStore;

$embedder = new OpenAIEmbeddingProvider(
    key: 'OPENAI_API_KEY',
    model: 'OPENAI_MODEL'
);

$store = new FileVectoreStore(
    directory: __DIR__,
    key: 'demo'
);

// 处理文件和内容
$documents = FileDataLoader::for(__DIR__.'/documents');
    ->addReader('pdf', new \NeuronAI\RAG\DataLoader\PdfReader())
    ->getDocuments(); 

// 生成嵌入并将文档存储到向量数据库中
$store->addDocuments(
    $embedder->embedDocuments($documents)
);

```

通过这个简单的流程，你可以将 GB 级数据摄取到向量存储中，为你的 RAG agent 提供支持。
