文档的加载和转换
2026年4月16日 · 437 字 · 3 分钟
如何使用eino框架加载和转换不同格式的文档 在构建RAG(检索增强生成)系统时,第一步就是要处理各种格式的文档。企业内部的文档可能是Word、PDF、Excel、HTML等多种格式,我们需要将这些文档加载并转换为统一的文本格式,才能进行后续的向量化和检索。 首先创建各种格式的解析器实例: 使用 设计优势: 使用 运行测试可以看到不同格式文档的解析结果: Markdown文档解析: HTML文档解析: HTML文档会过滤掉标签,只提取文本内容: PDF文档解析: PDF文档会保留原有的排版格式: Excel表格解析: 表格数据会以行列形式输出: Word文档解析: Word文档会区分正文和表格: 除了直接解析,还可以使用 FileLoader vs Parse的区别: 在RAG系统中,长文档需要分割成小块才能进行有效的检索: 使用 运行测试可以看到文档被按标题分割: 输出结果: 分割原理:为什么需要文档加载和转换
文档解析
创建解析器
ctx := context.Background()
// 文本解析器(默认)
textParser := parser.TextParser{}
// Word文档解析器
docParser, err := docx.NewDocxParser(ctx, &docx.Config{
IncludeTables: true, // 包含表格
IncludeFooters: false, // 不包含页脚
IncludeHeaders: false, // 不包含页眉
})
// HTML解析器
selector := "body"
htmlParser, err := html.NewParser(ctx, &html.Config{
Selector: &selector, // 只解析body部分
})
// PDF解析器
pdfParser, err := pdf.NewPDFParser(ctx, &pdf.Config{})
// Excel解析器
excelParser, err := xlsx.NewXlsxParser(ctx, &xlsx.Config{})
统一解析器
ExtParser 将所有解析器统一管理:// 创建扩展解析器
extParser, err := parser.NewExtParser(ctx,
&parser.ExtParserConfig{
Parsers: map[string]parser.Parser{
".docx": docParser,
".html": htmlParser,
".pdf": pdfParser,
".xlsx": excelParser,
},
FallbackParser: textParser, // 默认使用文本解析器
},
)
解析文档
ParseFile 函数解析文档:func ParseFile(docPath string) {
ctx := context.Background()
// ... 创建解析器代码 ...
// 打开文件
file, err := os.Open(docPath)
if err != nil {
log.Fatal(err)
}
defer file.Close()
// 解析文档
doc, err := extParser.Parse(ctx, file, parser.WithURI(docPath))
if err != nil {
log.Fatal(err)
}
// 输出解析结果
for _, v := range doc {
fmt.Println(v.Content)
}
}
测试结果
go test -v -run TestLoadDocument
# 美国用工政策
## 美国的工资
全国(联邦)最低工资为每小时7.25USD或每月1,160USD。
## 美国的工作时间
标准工作时间为每天8小时,每周40小时,标准工作周为周一至周五。
...
美国用工政策
美国的工资
全国(联邦)最低工资为每小时7.25USD或每月1,160USD。
美国的工作时间
标准工作时间为每天8小时,每周40小时,标准工作周为周一至周五。
...
美国用工政策
美国的工资
全国(联邦)最低工资为每小时7.25USD或每月1,160USD。
美国的工作时间
标准工作时间为每天8小时,每周40小时,标准工作周为周一至周五。
...
Tom 1 4 7
Lily 2 5 8
Jerry 3 6 9
=== MAIN CONTENT ===
### 观沧海
树木丛生,百草丰茂。
秋风萧瑟,洪波涌起。
=== TABLES ===
| 观沧海 | |
| -------- | -------- |
| | |
| 树木丛生 | 百草丰茂 |
| 秋风萧瑟 | 洪波涌起 |
文档加载
使用FileLoader
FileLoader 来加载文档:func LoadDoc(docPath string) {
ctx := context.Background()
// ... 创建解析器代码 ...
// 创建文件加载器
loader, err := file.NewFileLoader(ctx, &file.FileLoaderConfig{
Parser: extParser,
UseNameAsID: true, // 使用文件名作为文档ID
})
// 加载文档
docs, err := loader.Load(ctx, document.Source{
URI: docPath,
})
// 输出加载结果
for _, v := range docs {
fmt.Println(v.Content)
}
}
Parse: 直接解析文件流,返回文档列表Load: 从指定URI加载文档,可以添加更多元数据信息文档转换
为什么需要文档分割
Markdown标题分割
HeaderSplitter 按Markdown标题分割文档:func TransformDoc(docPath string) {
// 读取文件内容
file, err := os.Open(docPath)
if err != nil {
log.Fatal(err)
}
defer file.Close()
content, err := io.ReadAll(file)
if err != nil {
log.Fatal(err)
}
// 创建文档对象
doc := schema.Document{
Content: string(content),
}
ctx := context.Background()
// 创建标题分割器
splitTransformer, _ := markdown.NewHeaderSplitter(ctx, &markdown.HeaderConfig{
Headers: map[string]string{
"##": "", // 按##标题分割
},
TrimHeaders: true, // 不包含标题本身
})
// 执行分割
transformedDocs, _ := splitTransformer.Transform(ctx, []*schema.Document{&doc})
// 输出分割结果
for k, v := range transformedDocs {
fmt.Printf("segment %d, content : %s\n", k, v.Content)
}
}
测试结果
go test -v -run TestTransformDocument
segment 0, content : # 美国用工政策
segment 1, content : 全国(联邦)最低工资为每小时7.25USD或每月1,160USD。
segment 2, content : 标准工作时间为每天8小时,每周40小时,标准工作周为周一至周五。
segment 3, content : 美国9个国家公共假日,元旦:1月1日;马丁路德金日:一月的第三个星期一...
...
segment 14, content : 没有永久居民身份或工作签证的外国人不得在美国工作...
##)作为分割点TrimHeaders: true 表示分割后的内容不包含标题本身schema.Document 对象