Eino: Document Transformer 使用说明

基本介绍

Document Transformer 是一个用于文档转换和处理的组件。它的主要作用是对输入的文档进行各种转换操作,如分割、过滤、合并等,从而得到满足特定需求的文档。这个组件可用于以下场景中:

  • 将长文档分割成小段落以便于处理
  • 根据特定规则过滤文档内容
  • 对文档内容进行结构化转换
  • 提取文档中的特定部分

组件定义

接口定义

type Transformer interface {
    Transform(ctx context.Context, src []*schema.Document, opts ...TransformerOption) ([]*schema.Document, error)
}

Transform 方法

  • 功能:对输入的文档进行转换处理

  • 参数:

    • ctx:上下文对象,用于传递请求级别的信息,同时也用于传递 Callback Manager
    • src:待处理的文档列表
    • opts:可选参数,用于配置转换行为
  • 返回值:

    • []*schema.Document:转换后的文档列表
    • error:转换过程中的错误信息

Document 结构体

【TODO】 可把所有的公共结构体放到一个特定的地方

type Document struct {
    // ID 是文档的唯一标识符
    ID string    
    // Content 是文档的内容
    Content string
    // MetaData 用于存储文档的元数据信息
    MetaData map[string]any
}

Document 结构体是文档的标准格式,包含以下重要字段:

  • ID:文档的唯一标识符,用于在系统中唯一标识一个文档

  • Content:文档的实际内容

  • MetaData:文档的元数据,可以存储如下信息:

    • 文档的来源信息
    • 文档的向量表示(用于向量检索)
    • 文档的分数(用于排序)
    • 文档的子索引(用于分层检索)
    • 其他自定义元数据

公共 Option

Transformer 组件使用 TransformerOption 来定义可选参数,目前没有公共的 option。每个具体的实现可以定义自己的特定 Option,通过 WrapTransformerImplSpecificOptFn 函数包装成统一的 TransformerOption 类型。

使用方式

单独使用

// 初始化 transformer (以 markdown 为例)
transformer, err := markdown.NewHeaderSplitter(ctx, &markdown.HeaderSplitterConfig{
    // 配置参数
})
if err != nil {
    return err
}

// 转换文档
transformedDocs, err := transformer.Transform(ctx, docs)
if err != nil {
    return err
}

在编排中使用

// 在 Chain 中使用
chain := compose.NewChain[[]*schema.Document, []*schema.Document]()
chain.AppendDocumentTransformer(transformer)

// 编译并运行
runnable, err := chain.Compile()
if err != nil {
    return err
}
result, err := runnable.Invoke(ctx, input)

// 在 Graph 中使用
graph := compose.NewGraph[[]*schema.Document, []*schema.Document]()
graph.AddDocumentTransformerNode("transformer_node", transformer)

Option 和 Callback 使用

Callback 使用示例

// 创建 callback handler
handler := &document.TransformerCallbackHandler{
    OnStart: func(ctx context.Context, info *callbacks.RunInfo, input *document.TransformerCallbackInput) context.Context {
        fmt.Printf("开始转换文档,输入文档数量: %d\n", len(input.Input))
        return ctx
    },
    OnEnd: func(ctx context.Context, info *callbacks.RunInfo, output *document.TransformerCallbackOutput) context.Context {
        fmt.Printf("文档转换完成,输出文档数量: %d\n", len(output.Output))
        return ctx
    },
}

// 使用 callback handler
helper := template.NewHandlerHelper().
    Transformer(handler).
    Handler()

// 在运行时使用
runnable, err := chain.Compile()
if err != nil {
    return err
}
result, err := runnable.Invoke(ctx, input, compose.WithCallbacks(helper))

已有实现

  1. Markdown Header Splitter: 基于 Markdown 标题进行文档分割 Splitter - markdown
  2. Text Splitter: 基于文本长度或分隔符进行文档分割 Splitter - semantic
  3. Document Filter: 基于规则过滤文档内容 Splitter - recursive

自行实现参考

实现自定义的 Transformer 组件时,需要注意以下几点:

  1. option 的处理
  2. callback 的处理

Option 机制

自定义 Transformer 需要实现自己的 Option 机制:

// 定义 Option 结构体
type MyTransformerOptions struct {
    ChunkSize int
    Overlap int
    MinChunkLength int
}

// 定义 Option 函数
func WithChunkSize(size int) document.TransformerOption {
    return document.WrapTransformerImplSpecificOptFn(func(o *MyTransformerOptions) {
        o.ChunkSize = size
    })
}

func WithOverlap(overlap int) document.TransformerOption {
    return document.WrapTransformerImplSpecificOptFn(func(o *MyTransformerOptions) {
        o.Overlap = overlap
    })
}

Callback 处理

Transformer 实现需要在适当的时机触发回调:

// 这是由 transformer 定义的回调输入输出,自行组件在实现时需要满足结构的含义
type TransformerCallbackInput struct {
    Input []*schema.Document
    Extra map[string]any
}

type TransformerCallbackOutput struct {
    Output []*schema.Document
    Extra map[string]any
}

完整实现示例

type MyTransformer struct {
    chunkSize int
    overlap int
    minChunkLength int
}

func NewMyTransformer(config *MyTransformerConfig) (*MyTransformer, error) {
    return &MyTransformer{
        chunkSize: config.DefaultChunkSize,
        overlap: config.DefaultOverlap,
        minChunkLength: config.DefaultMinChunkLength,
    }, nil
}

func (t *MyTransformer) Transform(ctx context.Context, src []*schema.Document, opts ...document.TransformerOption) ([]*schema.Document, error) {
    // 1. 处理 Option
    options := &MyTransformerOptions{
        ChunkSize: t.chunkSize,
        Overlap: t.overlap,
        MinChunkLength: t.minChunkLength,
    }
    options = document.GetTransformerImplSpecificOptions(options, opts...)
    
    // 2. 获取 callback manager
    cm := callbacks.ManagerFromContext(ctx)
    
    // 3. 开始转换前的回调
    ctx = cm.OnStart(ctx, info, &document.TransformerCallbackInput{
        Input: src,
    })
    
    // 4. 执行转换逻辑
    docs, err := t.doTransform(ctx, src, options)
    
    // 5. 处理错误和完成回调
    if err != nil {
        ctx = cm.OnError(ctx, info, err)
        return nil, err
    }
    
    ctx = cm.OnEnd(ctx, info, &document.TransformerCallbackOutput{
        Output: docs,
    })
    
    return docs, nil
}

func (t *MyTransformer) doTransform(ctx context.Context, src []*schema.Document, opts *MyTransformerOptions) ([]*schema.Document, error) {
    // 实现文档转换逻辑
    return docs, nil
}

注意事项

  • 转换后的文档需要注意对 metadata 的处理,注意保留原 metadata,以及新增自定义的 metadata

其他参考文档


最后修改 January 9, 2025 : feat: add eino cn docs (#1182) (ad75444)