catchadmin/docloader

A PHP document loader and splitter for RAG applications

Installs: 0

Dependents: 0

Suggesters: 0

Security: 0

pkg:composer/catchadmin/docloader

v1.0.0 2026-02-04 04:17 UTC

This package is not auto-updated.

Last update: 2026-02-09 02:01:47 UTC


README

DocLoader Logo

DocLoader

一个用于 RAG(检索增强生成)应用的 PHP 文档加载与分块工具库

PHP 8.1+ MIT License Tests PHPStan

安装基础使用进阶使用组件一览

特性

  • 🔥 支持多种文档格式:TXT、PDF、HTML、Markdown
  • 🌍 支持中英文混合文本分割
  • ✂️ 智能分块策略,适配 RAG 向量化需求
  • 📑 Markdown 层级分块,保留文档结构信息
  • 🔧 高度可扩展,支持自定义 Reader 和 Splitter
  • 📦 零配置开箱即用

安装

composer require catchadmin/docloader

系统依赖

PDF 解析需要安装 Poppler Utils(pdftotext):

系统安装命令
Ubuntu/Debiansudo apt-get install poppler-utils
CentOS/RHELsudo yum install poppler-utils
macOSbrew install poppler
Windows下载 Poppler 并添加 bin 目录到 PATH

基础使用

从字符串加载

use Catch\DocLoader\Loader\StringLoader;

$documents = StringLoader::for('这是一段文本内容...')
    ->getDocuments();

// 设置来源名称
$documents = StringLoader::for('内容', 'my-document')
    ->getDocuments();

从文件加载

use Catch\DocLoader\Loader\FileLoader;

// 加载单个文件
$documents = FileLoader::for('/path/to/file.txt')
    ->getDocuments();

// 加载整个目录(递归)
$documents = FileLoader::for('/path/to/documents/')
    ->getDocuments();

加载 PDF 文件

use Catch\DocLoader\Loader\FileLoader;
use Catch\DocLoader\Reader\PdfReader;

$documents = FileLoader::for('/path/to/document.pdf')
    ->addReader('pdf', new PdfReader())
    ->getDocuments();

自定义 pdftotext 路径

// Windows 示例
$pdfReader = new PdfReader('C:\poppler\bin\pdftotext.exe');

$documents = FileLoader::for('/path/to/document.pdf')
    ->addReader('pdf', $pdfReader)
    ->getDocuments();

加载 HTML 文件

use Catch\DocLoader\Loader\FileLoader;
use Catch\DocLoader\Reader\HtmlReader;

$documents = FileLoader::for('/path/to/page.html')
    ->addReader(['html', 'htm'], new HtmlReader())
    ->getDocuments();

加载 Markdown 文件

use Catch\DocLoader\Loader\FileLoader;
use Catch\DocLoader\Reader\MarkdownReader;

$documents = FileLoader::for('/path/to/document.md')
    ->addReader('md', new MarkdownReader())
    ->getDocuments();

// 配置选项
$mdReader = new MarkdownReader(
    preserveHeadings: true,  // 是否保留标题标记(默认 true)
    useGfm: true             // 是否使用 GitHub Flavored Markdown(默认 true)
);

$documents = FileLoader::for('/path/to/docs/')
    ->addReader('md', $mdReader)
    ->getDocuments();

进阶使用

文本分块策略

DelimiterSplitter(分隔符分块)

按指定分隔符分割文本,适合结构化文档:

use Catch\DocLoader\Splitter\DelimiterSplitter;

$splitter = new DelimiterSplitter(
    maxLength: 500,      // 每块最大字符数
    separator: "\n",     // 分隔符(默认空格)
    wordOverlap: 20      // 词重叠数(保持上下文连贯)
);

$documents = FileLoader::for($path)
    ->withSplitter($splitter)
    ->getDocuments();

SentenceSplitter(句子分块)- 推荐用于 RAG

按句子边界分割,支持中英文,适合自然语言文档:

use Catch\DocLoader\Splitter\SentenceSplitter;

$splitter = new SentenceSplitter(
    maxWords: 150,       // 每块最大词数
    overlapWords: 20     // 重叠词数
);

$documents = FileLoader::for($path)
    ->withSplitter($splitter)
    ->getDocuments();

RAG 推荐参数: | 参数 | 推荐值 | 说明 | |-----|-------|------| | maxWords | 100-200 | 约 300-600 中文字符 | | overlapWords | 15-30 | 约 10-20% 重叠 |

MarkdownSplitter(Markdown 层级分块)- 推荐用于知识库

按 Markdown 标题层级智能分块,保留文档结构信息:

use Catch\DocLoader\Splitter\MarkdownSplitter;

$splitter = new MarkdownSplitter(
    maxLevel: 3,                    // 最深切分到 H3
    minChunkSize: 50,               // 最小块字符数
    includeHeadingInContent: true   // chunk 内容包含标题
);

$documents = FileLoader::for('/knowledge-base/')
    ->addReader('md', new MarkdownReader())
    ->withSplitter($splitter)
    ->getDocuments();

分块示例:

# 第一章           → Chunk1: {level:1, title:"第一章", path:["第一章"]}
内容...
## 1.1 节          → Chunk2: {level:2, title:"1.1 节", path:["第一章","1.1 节"], parentId:Chunk1.id}
内容...
### 1.1.1 小节     → Chunk3: {level:3, title:"1.1.1 小节", path:["第一章","1.1 节","1.1.1 小节"]}

层级信息字段: | 字段 | 类型 | 说明 | |-----|------|------| | level | int | 层级深度(0=无标题,1=H1,2=H2...) | | sectionTitle | string | 当前章节标题 | | headingPath | array | 完整标题路径 | | parentId | string | 父块 ID |

文件过滤

$documents = FileLoader::for('/path/to/docs/')
    // 只处理指定扩展名
    ->setIncludeExtensions(['pdf', 'txt', 'md'])
    // 排除匹配的文件/目录
    ->setExcludePatterns(['*.tmp', '.git/*', 'node_modules/*'])
    ->addReader('pdf', new PdfReader())
    ->getDocuments();

多格式混合加载

$documents = FileLoader::for('/path/to/docs/')
    ->addReader('pdf', new PdfReader())
    ->addReader(['html', 'htm'], new HtmlReader())
    ->withSplitter(new SentenceSplitter(maxWords: 150, overlapWords: 20))
    ->getDocuments();

Document 对象

每个文档块包含以下属性:

$document->id;          // 唯一 ID(自动生成)
$document->content;     // 文本内容
$document->sourceType;  // 来源类型:'files', 'string'
$document->sourceName;  // 来源名称:文件名或自定义名称
$document->embedding;   // 向量嵌入(默认空数组,由外部填充)
$document->score;       // 相关性分数(默认 0)
$document->metadata;    // 自定义元数据

操作 Document

// 链式设置
$document->setContent('新内容')
    ->setSourceName('custom-name')
    ->setMetadata(['author' => '张三', 'date' => '2024-01-01'])
    ->addMetadata('category', '技术文档');

// 序列化为 JSON
$json = json_encode($document);

自定义扩展

自定义 Reader

实现 ReaderInterface 接口:

use Catch\DocLoader\Reader\ReaderInterface;

class MarkdownReader implements ReaderInterface
{
    public static function getText(string $filePath, array $options = []): string
    {
        $content = file_get_contents($filePath);
        // 处理 Markdown 语法...
        return $content;
    }

    public function read(string $filePath): string
    {
        return static::getText($filePath);
    }
}

// 使用
$documents = FileLoader::for('/docs/')
    ->addReader('md', new MarkdownReader())
    ->getDocuments();

自定义 Splitter

继承 AbstractSplitter(推荐):

use Catch\DocLoader\Splitter\AbstractSplitter;
use Catch\DocLoader\Document;

class ParagraphSplitter extends AbstractSplitter
{
    public function __construct(
        private int $minLength = 100
    ) {}

    public function splitDocument(Document $document): array
    {
        $paragraphs = preg_split('/\n{2,}/', $document->getContent());
        
        $result = [];
        foreach ($paragraphs as $para) {
            if (mb_strlen($para) >= $this->minLength) {
                $newDoc = new Document(trim($para));
                $newDoc->sourceType = $document->getSourceType();
                $newDoc->sourceName = $document->getSourceName();
                $result[] = $newDoc;
            }
        }
        
        return $result;
    }
}

// 使用
$documents = FileLoader::for($path)
    ->withSplitter(new ParagraphSplitter(minLength: 50))
    ->getDocuments();

RAG 最佳实践

推荐配置

use Catch\DocLoader\Loader\FileLoader;
use Catch\DocLoader\Reader\PdfReader;
use Catch\DocLoader\Splitter\SentenceSplitter;

$documents = FileLoader::for('/knowledge-base/')
    ->addReader('pdf', new PdfReader())
    ->setIncludeExtensions(['pdf', 'txt', 'md'])
    ->setExcludePatterns(['*.tmp', '.*'])
    ->withSplitter(new SentenceSplitter(
        maxWords: 150,      // 适合大多数 embedding 模型
        overlapWords: 25    // 约 15% 重叠
    ))
    ->getDocuments();

// 准备向量化
foreach ($documents as $doc) {
    $text = $doc->getContent();
    // 调用 embedding API...
    // $embedding = $embeddingService->embed($text);
    // $doc->setEmbedding($embedding);
}

分块大小建议

Embedding 模型maxWords说明
OpenAI text-embedding-3150-200支持 8191 tokens
Cohere embed-v3100-150支持 512 tokens
BGE-M3200-300支持 8192 tokens

组件一览

Loader(加载器)

说明
StringLoader从字符串加载
FileLoader从文件或目录加载

Reader(读取器)

说明依赖
TextFileReader纯文本文件
PdfReaderPDF 文件pdftotext
HtmlReaderHTML 文件html2text/html2text
MarkdownReaderMarkdown 文件league/commonmark

Splitter(分块器)

说明推荐场景
DelimiterSplitter按分隔符+最大长度结构化文档
SentenceSplitter按句子+最大词数自然语言文档(推荐)
MarkdownSplitter按标题层级+保留结构Markdown 知识库(推荐)

License

MIT License