Eino-Document 组件使用指南Eino-Document 是 cloudwego/eino 生态中的文档处理库提供了从多种来源加载文档、解析不同格式、对文档进行分割 transform 等全链路能力。本文介绍Document 各组件的用法及典型应用场景代码链接。目录1. 核心概念2. 文档加载Loader2.1 本地文件加载器2.2 Web URL 加载器2.3 AWS S3 加载器3. 文档解析器Parser3.1 文本解析器3.2 HTML 解析器3.3 PDF 解析器4. 扩展解析器ExtParser5. 文档分割器Splitter5.1 递归字符分割器5.2 Markdown 标题分割器5.3 语义分割器6. 完整实战加载 HTML → 解析 → 分割7. 总结1. 核心概念Eino-Document 将文档处理流程抽象为以下几层层次组件职责加载层Loader从各类来源本地文件、Web URL、S3读取原始数据解析层Parser将原始数据HTML、PDF、纯文本解析为结构化的schema.Document分割层Splitter将大文档切分为适合 LLM 处理的小块Chunk编排层ExtParser根据文件扩展名自动选择合适的解析器核心数据结构schema.Document包含两个字段typeDocumentstruct{Contentstring// 文档正文内容MetaDatamap[string]any// 元数据如文件名、标题、语言等}2. 文档加载LoaderLoader 负责从不同来源获取文档内容返回[]*schema.Document。所有 Loader 都实现了Loader接口typeLoaderinterface{Load(ctx context.Context,source document.Source)([]*schema.Document,error)}2.1 本地文件加载器使用eino-ext/components/document/loader/file支持根据文件扩展名自动选择解析器。importfileloadergithub.com/cloudwego/eino-ext/components/document/loader/fileloader,err:fileloader.NewFileLoader(ctx,fileloader.FileLoaderConfig{// UseNameAsID: true, // 可选使用文件名作为文档 ID})docs,err:loader.Load(ctx,document.Source{URI:./testdata/sample.txt,})Loader 会自动将文件名、扩展名、源路径等信息注入MetaData// 读取元数据iffileName,ok:doc.MetaData[fileloader.MetaKeyFileName].(string);ok{fmt.Println(文件名:,fileName)}ifextension,ok:doc.MetaData[fileloader.MetaKeyExtension].(string);ok{fmt.Println(扩展名:,extension)}2.2 Web URL 加载器使用eino-ext/components/document/loader/url默认使用 HTML 解析器处理网页内容。importurlloadergithub.com/cloudwego/eino-ext/components/document/loader/urlloader,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 加载文件。imports3loadergithub.com/cloudwego/eino-ext/components/document/loader/s3region:us-east-1loader,err:s3loader.NewS3Loader(ctx,s3loader.LoaderConfig{Region:region,// 也可通过环境变量或 AWS 配置文件自动读取凭证})// URI 格式s3://bucket-name/path/to/filedocs,err:loader.Load(ctx,document.Source{URI:s3://my-bucket/documents/article.pdf,})注意Region为指针类型*string需要取地址传入。3. 文档解析器ParserParser 将原始数据解析为schema.Document。接口定义如下typeParserinterface{Parse(ctx context.Context,reader io.Reader,opts...Option)([]*schema.Document,error)}3.1 文本解析器使用内置的parser.TextParser直接解析纯文本。importgithub.com/cloudwego/eino/components/document/parsertextParser: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等指定部分并自动解析元数据标题、描述、语言、字符集。importhtmlparsergithub.com/cloudwego/eino-ext/components/document/parser/htmlhtmlParser,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))解析完成后可读取丰富的元数据iftitle,ok:doc.MetaData[htmlparser.MetaKeyTitle].(string);ok{fmt.Println(标题:,title)}ifdesc,ok:doc.MetaData[htmlparser.MetaKeyDesc].(string);ok{fmt.Println(描述:,desc)}iflang,ok:doc.MetaData[htmlparser.MetaKeyLang].(string);ok{fmt.Println(语言:,lang)}3.3 PDF 解析器使用eino-ext/components/document/parser/pdf支持按页分割或合并为单个文档。importpdfparsergithub.com/cloudwego/eino-ext/components/document/parser/pdfpdfParser,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. 扩展解析器ExtParserExtParser根据文件扩展名自动分派对应的解析器是生产环境中处理多格式文件的推荐方式。import(github.com/cloudwego/eino-ext/components/document/parser/htmlgithub.com/cloudwego/eino-ext/components/document/parser/pdfgithub.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接口typeTransformerinterface{Transform(ctx context.Context,docs[]*schema.Document)([]*schema.Document,error)}5.1 递归字符分割器RecursiveSplitter按分隔符递归切分文档是最通用的分割方式。importrecursivegithub.com/cloudwego/eino-ext/components/document/transformer/splitter/recursivesplitter,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/End5.2 Markdown 标题分割器HeaderSplitter根据 Markdown 标题结构#、##、###进行分割保留文档结构完整性。importmarkdowngithub.com/cloudwego/eino-ext/components/document/transformer/splitter/markdownsplitter,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 模型计算文本块之间的语义相似度在语义断点处分割适合保持内容的语义完整性。import(semanticgithub.com/cloudwego/eino-ext/components/document/transformer/splitter/semanticarkgithub.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.9BufferSize:1,// 拼接邻居块的数量提高准确性MinChunkSize:50,// 最小块大小Separators:[]string{\n,.,?,!},})chunks,err:splitter.Transform(ctx,[]*schema.Document{doc})6. 完整实战加载 HTML → 解析 → 分割以下示例演示从本地 HTML 文件加载经由 RecursiveSplitter 分割的完整流程packagemainimport(contextfmtlogfileloadergithub.com/cloudwego/eino-ext/components/document/loader/filerecursivegithub.com/cloudwego/eino-ext/components/document/transformer/splitter/recursivegithub.com/cloudwego/eino/components/documentgithub.com/cloudwego/eino/schema)funcmain(){ctx:context.Background()// 步骤 1创建文件加载器fileLoader,err:fileloader.NewFileLoader(ctx,fileloader.FileLoaderConfig{})iferr!nil{log.Fatalf(创建文件加载器失败: %v,err)}// 步骤 2加载 HTML 文件docs,err:fileLoader.Load(ctx,document.Source{URI:../testdata/article.html,})iferr!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,})iferr!nil{log.Fatalf(创建分割器失败: %v,err)}// 步骤 4分割文档varallChunks[]*schema.Documentfor_,doc:rangedocs{chunks,err:splitter.Transform(ctx,[]*schema.Document{doc})iferr!nil{log.Printf(分割文档失败: %v,err)continue}allChunksappend(allChunks,chunks...)}fmt.Printf(分割后得到 %d 个文档块\n\n,len(allChunks))// 步骤 5打印结果fori,chunk:rangeallChunks{fmt.Printf( 块 %d \n,i1)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)}}funcmin(a,bint)int{ifab{returna}returnb}7. 总结Eino-Document 提供了从加载 → 解析 → 分割的完整文档处理链路场景推荐方案加载本地文件FileLoader 自动识别扩展名加载网页内容URLLoader加载 S3 文件S3Loader多格式统一解析ExtParser通用文本分割RecursiveSplitterMarkdown 文档分割HeaderSplitter语义感知分割SemanticSplitter Embedding通过组合不同的 Loader、Parser 和 Splitter可以灵活构建满足各类需求的文档处理流水线。