Eino-Document 组件使用指南

Eino-Document 组件使用指南

Eino-Document 是 cloudwego/eino 生态中的文档处理库,提供了从多种来源加载文档、解析不同格式、对文档进行分割 transform 等全链路能力。本文介绍Document 各组件的用法及典型应用场景,代码链接


目录

  • [1. 核心概念](#1. 核心概念)
  • [2. 文档加载(Loader)](#2. 文档加载(Loader))
    • [2.1 本地文件加载器](#2.1 本地文件加载器)
    • [2.2 Web URL 加载器](#2.2 Web URL 加载器)
    • [2.3 AWS S3 加载器](#2.3 AWS S3 加载器)
  • [3. 文档解析器(Parser)](#3. 文档解析器(Parser))
    • [3.1 文本解析器](#3.1 文本解析器)
    • [3.2 HTML 解析器](#3.2 HTML 解析器)
    • [3.3 PDF 解析器](#3.3 PDF 解析器)
  • [4. 扩展解析器(ExtParser)](#4. 扩展解析器(ExtParser))
  • [5. 文档分割器(Splitter)](#5. 文档分割器(Splitter))
    • [5.1 递归字符分割器](#5.1 递归字符分割器)
    • [5.2 Markdown 标题分割器](#5.2 Markdown 标题分割器)
    • [5.3 语义分割器](#5.3 语义分割器)
  • [6. 完整实战:加载 HTML → 解析 → 分割](#6. 完整实战:加载 HTML → 解析 → 分割)
  • [7. 总结](#7. 总结)

1. 核心概念

Eino-Document 将文档处理流程抽象为以下几层:

层次 组件 职责
加载层 Loader 从各类来源(本地文件、Web URL、S3)读取原始数据
解析层 Parser 将原始数据(HTML、PDF、纯文本)解析为结构化的 schema.Document
分割层 Splitter 将大文档切分为适合 LLM 处理的小块(Chunk)
编排层 ExtParser 根据文件扩展名自动选择合适的解析器

核心数据结构 schema.Document 包含两个字段:

go 复制代码
type Document struct {
    Content  string            // 文档正文内容
    MetaData map[string]any   // 元数据(如文件名、标题、语言等)
}

2. 文档加载(Loader)

Loader 负责从不同来源获取文档内容,返回 []*schema.Document。所有 Loader 都实现了 Loader 接口:

go 复制代码
type Loader interface {
    Load(ctx context.Context, source document.Source) ([]*schema.Document, error)
}

2.1 本地文件加载器

使用 eino-ext/components/document/loader/file,支持根据文件扩展名自动选择解析器。

go 复制代码
import fileloader "github.com/cloudwego/eino-ext/components/document/loader/file"

loader, err := fileloader.NewFileLoader(ctx, &fileloader.FileLoaderConfig{
    // UseNameAsID: true, // 可选:使用文件名作为文档 ID
})

docs, err := loader.Load(ctx, document.Source{
    URI: "./testdata/sample.txt",
})

Loader 会自动将文件名、扩展名、源路径等信息注入 MetaData

go 复制代码
// 读取元数据
if fileName, ok := doc.MetaData[fileloader.MetaKeyFileName].(string); ok {
    fmt.Println("文件名:", fileName)
}
if extension, ok := doc.MetaData[fileloader.MetaKeyExtension].(string); ok {
    fmt.Println("扩展名:", extension)
}

2.2 Web URL 加载器

使用 eino-ext/components/document/loader/url,默认使用 HTML 解析器处理网页内容。

go 复制代码
import urlloader "github.com/cloudwego/eino-ext/components/document/loader/url"

loader, err := urlloader.NewLoader(ctx, &urlloader.LoaderConfig{})

docs, err := loader.Load(ctx, document.Source{
    URI: "https://example.com",
})

2.3 AWS S3 加载器

使用 eino-ext/components/document/loader/s3,支持从 S3 bucket 加载文件。

go 复制代码
import s3loader "github.com/cloudwego/eino-ext/components/document/loader/s3"

region := "us-east-1"
loader, err := s3loader.NewS3Loader(ctx, &s3loader.LoaderConfig{
    Region: &region,
    // 也可通过环境变量或 AWS 配置文件自动读取凭证
})

// URI 格式:s3://bucket-name/path/to/file
docs, err := loader.Load(ctx, document.Source{
    URI: "s3://my-bucket/documents/article.pdf",
})

注意Region 为指针类型 *string,需要取地址传入。


3. 文档解析器(Parser)

Parser 将原始数据解析为 schema.Document。接口定义如下:

go 复制代码
type Parser interface {
    Parse(ctx context.Context, reader io.Reader, opts ...Option) ([]*schema.Document, error)
}

3.1 文本解析器

使用内置的 parser.TextParser,直接解析纯文本。

go 复制代码
import "github.com/cloudwego/eino/components/document/parser"

textParser := parser.TextParser{}

reader := strings.NewReader("这是要解析的文本内容。\n可以包含多行。")
docs, err := textParser.Parse(ctx, reader, parser.WithURI("text://sample.txt"))

3.2 HTML 解析器

使用 eino-ext/components/document/parser/html,可提取 <body> 等指定部分,并自动解析元数据(标题、描述、语言、字符集)。

go 复制代码
import htmlparser "github.com/cloudwego/eino-ext/components/document/parser/html"

htmlParser, err := htmlparser.NewParser(ctx, &htmlparser.Config{
    Selector: &htmlparser.BodySelector, // 只提取 body 内容
})

reader := strings.NewReader(htmlContent)
docs, err := htmlParser.Parse(ctx, reader, parser.WithURI("https://example.com/page.html"))

解析完成后可读取丰富的元数据:

go 复制代码
if title, ok := doc.MetaData[htmlparser.MetaKeyTitle].(string); ok {
    fmt.Println("标题:", title)
}
if desc, ok := doc.MetaData[htmlparser.MetaKeyDesc].(string); ok {
    fmt.Println("描述:", desc)
}
if lang, ok := doc.MetaData[htmlparser.MetaKeyLang].(string); ok {
    fmt.Println("语言:", lang)
}

3.3 PDF 解析器

使用 eino-ext/components/document/parser/pdf,支持按页分割或合并为单个文档。

go 复制代码
import pdfparser "github.com/cloudwego/eino-ext/components/document/parser/pdf"

pdfParser, err := pdfparser.NewPDFParser(ctx, &pdfparser.Config{
    ToPages: false, // false: 合并所有页;true: 每页一个文档
})

file, _ := os.Open("./testdata/sample.pdf")
docs, err := pdfParser.Parse(ctx, file,
    parser.WithURI("./testdata/sample.pdf"),
    // pdfparser.WithToPages(true), // 可选:运行时覆盖配置
)

4. 扩展解析器(ExtParser)

ExtParser 根据文件扩展名自动分派对应的解析器,是生产环境中处理多格式文件的推荐方式。

go 复制代码
import (
    "github.com/cloudwego/eino-ext/components/document/parser/html"
    "github.com/cloudwego/eino-ext/components/document/parser/pdf"
    "github.com/cloudwego/eino/components/document/parser"
)

htmlParser, _ := htmlparser.NewParser(ctx, &htmlparser.Config{})
pdfParser, _ := pdfparser.NewPDFParser(ctx, &pdfparser.Config{ToPages: false})

extParser, err := parser.NewExtParser(ctx, &parser.ExtParserConfig{
    Parsers: map[string]parser.Parser{
        ".html": htmlParser,
        ".htm":  htmlParser,
        ".pdf":  pdfParser,
    },
    // FallbackParser: 不支持的扩展名会降级使用 TextParser
})

// 根据 URI 自动选择解析器
file, _ := os.Open("testdata/sample.html")
docs, err := extParser.Parse(ctx, file, parser.WithURI("testdata/sample.html"))

5. 文档分割器(Splitter)

当文档长度超过 LLM 的上下文窗口时,需要将文档切分为小块(Chunk)。所有 Splitter 都实现了 Transformer 接口:

go 复制代码
type Transformer interface {
    Transform(ctx context.Context, docs []*schema.Document) ([]*schema.Document, error)
}

5.1 递归字符分割器

RecursiveSplitter 按分隔符递归切分文档,是最通用的分割方式。

go 复制代码
import recursive "github.com/cloudwego/eino-ext/components/document/transformer/splitter/recursive"

splitter, err := recursive.NewSplitter(ctx, &recursive.Config{
    ChunkSize:   500,                        // 每个块最多 500 字符
    OverlapSize: 50,                         // 块之间重叠 50 字符(保持上下文连续)
    Separators:  []string{"\n", ".", "?", "!"},
    KeepType:    recursive.KeepTypeNone,     // 丢弃分隔符
    // KeepTypeStart / KeepTypeEnd 可保留分隔符在块开头或结尾
})

chunks, err := splitter.Transform(ctx, []*schema.Document{doc})

核心参数说明:

参数 说明
ChunkSize 每个块的最大字符数
OverlapSize 相邻块之间的重叠字符数,用于保持语义连贯
Separators 分隔符列表,按优先级顺序尝试切割
KeepType 分隔符保留策略(None/Start/End)

5.2 Markdown 标题分割器

HeaderSplitter 根据 Markdown 标题结构(######)进行分割,保留文档结构完整性。

go 复制代码
import markdown "github.com/cloudwego/eino-ext/components/document/transformer/splitter/markdown"

splitter, err := markdown.NewHeaderSplitter(ctx, &markdown.HeaderConfig{
    Headers: map[string]string{
        "#":   "title",      // 一级标题 → 元数据 title
        "##":  "section",    // 二级标题 → 元数据 section
        "###": "subsection", // 三级标题 → 元数据 subsection
    },
    TrimHeaders: false, // false: 保留标题在内容中;true: 移除标题行
})

chunks, err := splitter.Transform(ctx, []*schema.Document{doc})

注意 :Markdown 分割器基于标题结构,不支持 ChunkSize 参数。

5.3 语义分割器

SemanticSplitter 利用 Embedding 模型计算文本块之间的语义相似度,在语义断点处分割,适合保持内容的语义完整性。

go 复制代码
import (
    semantic "github.com/cloudwego/eino-ext/components/document/transformer/splitter/semantic"
    ark "github.com/cloudwego/eino-ext/components/embedding/ark"
)

embedder, err := ark.NewEmbedder(ctx, &ark.EmbeddingConfig{
    APIKey: os.Getenv("ARK_API_KEY"),
    Model:  os.Getenv("ARK_MODEL"),
})

splitter, err := semantic.NewSplitter(ctx, &semantic.Config{
    Embedding:    embedder,                    // 计算语义相似度的 Embedding 模型
    Percentile:   0.7,                         // 分割阈值(越小越激进,默认 0.9)
    BufferSize:   1,                           // 拼接邻居块的数量,提高准确性
    MinChunkSize: 50,                          // 最小块大小
    Separators:   []string{"\n", ".", "?", "!"},
})

chunks, err := splitter.Transform(ctx, []*schema.Document{doc})

6. 完整实战:加载 HTML → 解析 → 分割

以下示例演示从本地 HTML 文件加载,经由 RecursiveSplitter 分割的完整流程:

go 复制代码
package main

import (
    "context"
    "fmt"
    "log"

    fileloader "github.com/cloudwego/eino-ext/components/document/loader/file"
    recursive "github.com/cloudwego/eino-ext/components/document/transformer/splitter/recursive"
    "github.com/cloudwego/eino/components/document"
    "github.com/cloudwego/eino/schema"
)

func main() {
    ctx := context.Background()

    // 步骤 1:创建文件加载器
    fileLoader, err := fileloader.NewFileLoader(ctx, &fileloader.FileLoaderConfig{})
    if err != nil {
        log.Fatalf("创建文件加载器失败: %v", err)
    }

    // 步骤 2:加载 HTML 文件
    docs, err := fileLoader.Load(ctx, document.Source{
        URI: "../testdata/article.html",
    })
    if err != nil {
        log.Fatalf("加载文档失败: %v", err)
    }
    fmt.Printf("加载了 %d 个文档\n", len(docs))

    // 步骤 3:创建递归分割器
    splitter, err := recursive.NewSplitter(ctx, &recursive.Config{
        ChunkSize:   500,
        OverlapSize: 50,
        Separators:  []string{"\n", ".", "?", "!"},
        KeepType:    recursive.KeepTypeNone,
    })
    if err != nil {
        log.Fatalf("创建分割器失败: %v", err)
    }

    // 步骤 4:分割文档
    var allChunks []*schema.Document
    for _, doc := range docs {
        chunks, err := splitter.Transform(ctx, []*schema.Document{doc})
        if err != nil {
            log.Printf("分割文档失败: %v", err)
            continue
        }
        allChunks = append(allChunks, chunks...)
    }
    fmt.Printf("分割后得到 %d 个文档块\n\n", len(allChunks))

    // 步骤 5:打印结果
    for i, chunk := range allChunks {
        fmt.Printf("=== 块 %d ===\n", i+1)
        fmt.Printf("内容长度: %d 字符\n", len(chunk.Content))
        fmt.Printf("内容预览: %s...\n", chunk.Content[:min(100, len(chunk.Content))])
        fmt.Printf("元数据: %v\n\n", chunk.MetaData)
    }
}

func min(a, b int) int {
    if a < b {
        return a
    }
    return b
}

7. 总结

Eino-Document 提供了从加载 → 解析 → 分割的完整文档处理链路:

场景 推荐方案
加载本地文件 FileLoader + 自动识别扩展名
加载网页内容 URLLoader
加载 S3 文件 S3Loader
多格式统一解析 ExtParser
通用文本分割 RecursiveSplitter
Markdown 文档分割 HeaderSplitter
语义感知分割 SemanticSplitter + Embedding

通过组合不同的 Loader、Parser 和 Splitter,可以灵活构建满足各类需求的文档处理流水线。

相关推荐
lolo大魔王6 小时前
Go语言的反射机制
开发语言·后端·算法·golang
deepdata_cn7 小时前
智能体(ReAct)架构范式
智能体
XMYX-08 小时前
16 - Go 协程(goroutine):从基础到实战
开发语言·golang
lolo大魔王8 小时前
Go语言的文件处理操作
golang
陈振wx:zchen20089 小时前
SpringAI+DeepSeek大模型开发
大模型·springai·deepseek
jieyucx9 小时前
Golang 完整安装与 VSCode 开发环境搭建教程
开发语言·vscode·golang
liu****9 小时前
LangGraph-AI应用开发框架(二)
windows·langchain·大模型·工作流·langgraph
xixixi7777710 小时前
从Mythos到GPT-5.4-Cyber:AI安全竞赛的“双轨”分化与防御新范式
网络·gpt·安全·机器学习·架构·大模型·claude
loong_XL10 小时前
2026智能体爆发现象级产品:OpenClaw、Hermes Agent、Claude Cowork
大模型·agent·智能体·claw·龙虾