document_loader_contracts_and_options-interface 子模块
概述
本子模块定义了 Eino 文档处理系统的核心抽象契约。如果说整个文档摄取系统是一家公司,那么这个子模块就是公司的"职位描述"——它定义了有哪些岗位、每个岗位的职责是什么,但不管谁来坐这个位置。
核心职责:
- 定义文档的来源(Source)
- 定义加载器的抽象接口(Loader)
- 定义转换器的抽象接口(Transformer)
核心组件
Source —— 文档的"地址"
type Source struct {
URI string
}
设计意图:
Source 是整个文档处理流水线的起点。它极简的设计是有意为之的:
- 单一职责:只携带"去哪里找文档"的信息,不包含任何处理逻辑
- ** URI 泛化**:URI 不仅限于 HTTP URL,还可以是:
- 本地文件路径:
file:///path/to/document.pdf - 云存储路径:
s3://bucket/document.docx - 任意可寻址的资源
- 本地文件路径:
- 服务可达性保证:文档注释中明确要求"确保 URI 可以被服务访问",这意味着 Source 的使用者需要自己处理 URI 的解析和访问
类比:把 Source 想象成一张写有地址的明信片。邮递员(Loader)不需要知道这个地址背后是什么房子,只需要知道把明信片送到指定位置即可。
Loader 接口 —— 文档加载的统一契约
type Loader interface {
Load(ctx context.Context, src Source, opts ...LoaderOption) ([]*schema.Document, error)
}
设计意图:
Loader 接口是整个模块最核心的抽象。它的设计体现了几个关键考量:
| 设计决策 | 理由 |
|---|---|
返回切片 []*schema.Document |
一个 Source 可能包含多个文档(如一个 ZIP 文件),也可能是单一文档,统一返回切片简化调用方逻辑 |
可变选项 opts ...LoaderOption |
使用函数式选项模式,允许加载器接受灵活的配置,同时保持 API 简洁 |
| 返回 error | 加载失败是常态(文件不存在、格式损坏、网络超时),错误必须显式处理 |
与 Parser 的关系:
Loader 和 Parser 是合作关系,但职责不同:
- Loader:负责从 Source 获取原始内容(可能是二进制流、HTML 字符串等)
- Parser:负责解析原始内容为结构化的 Document
一个典型的实现可能同时扮演两个角色,也可能在 Loader 内部调用独立的 Parser。
Transformer 接口 —— 文档转换的统一契约
type Transformer interface {
Transform(ctx context.Context, src []*schema.Document, opts ...TransformerOption) ([]*schema.Document, error)
}
设计意图:
Transformer 接口的存在是为了支持文档的后处理流水线。常见的转换操作包括:
| 转换类型 | 说明 | 示例 |
|---|---|---|
| 分割 | 将大文档拆分为小块 | 文档切分器(Chunker) |
| 过滤 | 移除不符合条件的文档 | 长度过滤、元数据过滤 |
| 增强 | 为文档添加额外信息 | 添加嵌入向量、标注 |
设计一致性:
Transformer 的签名与 Loader 保持高度一致:
- 都是可变选项模式
- 都返回
[]*schema.Document - 都接受
context.Context
这种一致性允许它们被串联成处理链:
// 伪代码:文档处理流水线
docs, err := loader.Load(ctx, source)
docs, err = chunker.Transform(ctx, docs)
docs, err = filter.Transform(ctx, docs)
数据流
Source (URI)
│
▼
Loader.Load()
│
├─ 获取原始内容 (HTTP/本地文件/云存储)
│
├─ (可选) 调用 Parser 解析
│
└─ 返回 []*schema.Document
│
▼
Transformer.Transform()
│
├─ 转换逻辑 (切分/过滤/增强)
│
└─ 返回处理后的文档
与其他组件的关系
| 组件 | 关系 |
|---|---|
| Source | Loader 的输入参数,Transformer 的输入可能来自 Loader 的输出 |
| LoaderOption | Loader 接口的可变参数,为加载过程提供配置 |
| TransformerOption | Transformer 接口的可变参数,为转换过程提供配置 |
| schema.Document | Loader 返回、Transformer 处理的基本单元 |
实现注意事项
实现 Loader 接口
type MyLoader struct {
// 内部状态
}
func (m *MyLoader) Load(ctx context.Context, src document.Source, opts ...document.LoaderOption) ([]*schema.Document, error) {
// 1. 提取通用选项
commonOpts := document.GetLoaderCommonOptions(&document.LoaderOptions{}, opts...)
// 2. 提取实现特定选项
myOpts := document.GetLoaderImplSpecificOptions(&MyOptions{}, opts...)
// 3. 加载逻辑
// ...
return docs, nil
}
实现 Transformer 接口
func (t *MyTransformer) Transform(ctx context.Context, src []*schema.Document, opts ...document.TransformerOption) ([]*schema.Document, error) {
myOpts := document.GetTransformerImplSpecificOptions(&MyTransformOptions{}, opts...)
// 转换逻辑
// ...
return result, nil
}
小结
这个子模块建立的抽象层是整个文档处理系统的基础:
- Source 提供了统一的文档寻址方式
- Loader 定义了如何从各种来源获取文档
- Transformer 定义了如何对文档进行流水线处理
这三个抽象共同构成了"文档摄取"的骨架,使得框架可以:
- 轻松扩展新的加载器类型
- 自由组合转换步骤
- 保持 API 的一致性和可预测性