Eino 的 DocumentTransformer 是一个文本预处理组件:把任意来源的原始文档拆成语义完整、长度合适的小片段,并附带丰富的元数据,为后续的 Embedding、Indexer、Retriever 乃至 ChatModel 提供“干净原料”。
典型动作:分割、过滤、合并、提取、结构化。
type Transformer interface {
Transform(ctx context.Context,
src []*schema.Document,
opts ...TransformerOption) ([]*schema.Document, error)
}
- 输入:[]*schema.Document(原始文档)
- 输出:[]*schema.Document(转换后的片段)
每个 schema.Document 含
- Content:正文
- Metadata:来源、标题、页码、自定义 KV 等
官方已提供的实现(开箱即用)
| 实现 | 功能 | 场景 |
|---|---|---|
| MarkdownHeaderSplitter | 按 Markdown 标题层级切分 | 技术文档、README |
| TextSplitter(Recursive) | 按字符/句子/段落递归切分,可指定 chunk-size & overlap | 通用长文本 |
| SemanticSplitter | 先用 Embedding 得到语义边界,再切分 | 保证语义完整性 |
| DocumentFilter | 根据规则或正则过滤文档 | 剔除广告、敏感词 |
| ScoreReranker | 对片段重新打分排序 | 多路召回后精排 |
Document Loader与上下游组件的关系:
Document Loader(把文件/网页变成 Document) →
DocumentTransformer ( 把 Document 切成片段)→
Embedding(把片段向量化) → Indexer(把向量写入向量数据库) → Retriever(召回片段给 LLM 生成答案) → ChatTemplate → ChatModel
使用示例1:(独立使用)
ctx := context.Background()
// 初始化 transformer (以 markdown 为例)
transformer, err := markdown.NewHeaderSplitter(ctx, &markdown.HeaderConfig{
// 配置参数
Headers: map[string]string{
"##": "headerNameOfLevel2",
},
})
if err != nil {
log.Fatalf("markdown.NewHeaderSplitter failed, err=%v", err)
}
markdownDoc := &schema.Document{
Content: " #Title 0\n 测试内容 \n ## Title 1\nHello Word\n## Title 2\nWord Hello \n ",
}
log.Printf("===== call Header Splitter directly =====")
// 转换文档
transformedDocs, err := transformer.Transform(ctx, []*schema.Document{markdownDoc})
if err != nil {
log.Fatalf("transformer.Transform failed, err=%v", err)
}
for idx, doc := range transformedDocs {
log.Printf("doc segment %v: %v", idx, doc.Content)
}
这里transformer按markdown的二级标题进行分割(注意1级及2级均会被分割), 测试输出如下图:

image.png
使用示例2:(在chain中使用)
// 初始化 transformer (以 markdown 为例)
transformer, err := markdown.NewHeaderSplitter(ctx, &markdown.HeaderConfig{
// 配置参数
Headers: map[string]string{
"##": "headerNameOfLevel2",
},
})
if err != nil {
log.Fatalf("markdown.NewHeaderSplitter failed, err=%v", err)
}
markdownDoc := &schema.Document{
Content: " #Title 0\n 测试内容 \n ## Title 1\nHello Word\n## Title 2\nWord Hello \n ",
}
chain := compose.NewChain[[]*schema.Document, []*schema.Document]()
chain.AppendDocumentTransformer(transformer)
// 在运行时使用
run, err := chain.Compile(ctx)
if err != nil {
log.Fatalf("chain.Compile failed, err=%v", err)
}
outDocs, err := run.Invoke(ctx, []*schema.Document{markdownDoc})
if err != nil {
log.Fatalf("run.Invoke failed, err=%v", err)
}
for idx, doc := range outDocs {
log.Printf("doc segment %v: %v", idx, doc.Content)
}