☰
构造 Korvus Pipeline:在 PostgresML 中配置文档分割、语义嵌入与全文搜索的完整指南
2026/10/8 1:52:52 网站建设 项目流程
  • 后端
  • 人工智能
  • 机器学习
  • RAG
  • 向量数据库

【免费下载链接】postgresml

Postgres with GPUs for ML/AI apps.

项目地址:https://gitcode.com/gh_mirrors/po/postgresml
点击查看免费下载

Pipeline 是 Korvus(PostgresML 的开源 RAG SDK)中负责文档处理的编排核心:它用一段 JSON 风格的 schema 声明"对文档的哪些字段做什么变换",从而把原始文档转换为可供向量检索、关键词检索和混合检索直接使用的 chunks、embeddings 与 tsvectors。本文将基于 Korvus 的官方指南与仓库源码,逐步讲解 Pipeline 的结构、三种核心变换(Splitting、Embedding、tsvector 生成)的配置方法、多字段变换、自托管专属参数,以及 Pipeline schema 在 SDK 底层是如何被解析和执行的。读完本文,你将能够为自己的文档结构设计并落地一套完整的 Pipeline 配置,并理解它与 Collection 检索能力(向量搜索、全文搜索、RAG)之间的衔接关系。

Pipeline 是什么:从文档到可检索索引的转换编排

Korvus 的文档处理模型分两层:Collection负责存放原始文档;Pipeline则定义"如何处理这些文档字段",它由一系列施加在文档上的变换组成,支持的变换类型包括:

  • Splitting(文本分割):把长文本切成便于嵌入与检索的 chunk;
  • Embedding(语义嵌入):为文本生成向量,用于语义检索;
  • tsvector 生成(全文搜索准备):把文本转为 PostgreSQL 全文检索向量,用于关键词检索。

三者的组合决定了文档最终可被哪些方式检索。如果你只关心如何在代码里调用 Pipeline 与 Collection,可以参考 Pipelines API;本文则聚焦"如何构造 Pipeline schema"本身。

Pipeline 以 JSON 形式声明;在 Python、JavaScript 中它是对象字面量,在 Rust 与 C 中则通过 JSON 字符串传入。本文以 Python 为例,同样的 schema 可以平移到 JavaScript、Rust 或 C。

先理解文档结构:Pipeline 的输入约定

创建有效的 Pipeline 之前,必须先弄清文档长什么样——因为 Pipeline 只处理你在 schema 中显式声明的字段。本文沿用官方指南给出的简单文档结构:

example_document = { "id": "doc_001", # Unique identifier for the document "title": "Introduction to Machine Learning", # Document title "text": "Machine learning is a branch of artificial intelligence..." # Main content }

其中id是文档的唯一标识,title是标题,text是正文。你的 Pipeline 将决定这些字段分别经历哪些变换:例如只处理text,还是同时处理title与text。

Pipeline 的结构:名称 + schema

Pipeline构造函数接收两个参数:第一个是 Pipeline 名称(如"v0"),第二个是 schema。下面的例子会对文档的text字段依次执行分割、语义嵌入、tsvector 生成:

pipeline = Pipeline( "v0", { "text": { "splitter": {"model": "recursive_character"}, "semantic_search": { "model": "Alibaba-NLP/gte-base-en-v1.5", }, "full_text_search": { "configuration": "english" } }, }, )

从源码结构看,schema 的每个字段值(即"字段动作")恰好对应三种可选的变换键。SDK 在 pgml-sdks/pgml/src/pipeline.rs 中定义了ValidFieldAction结构,只接受splitter、semantic_search、full_text_search三个键,且每个键都可选——这正解释了为什么可以只配置其中一种或几种变换。

上面例子中的顶层键是text,意味着该变换对象仅作用于文档的text字段。其内部包含三个子键,下面逐一拆解。

Splitter:控制文本如何被切分

splitter对象接收两个参数:

  • model:用于分割的模型名称(字符串);
  • parameters:可选对象,传递给分割模型的参数。

对于recursive_character分割器,最常见的调参项是最大块大小(chunk_size)与块间重叠(chunk_overlap),例如:

pipeline = Pipeline( "v0", { "text": { "splitter": { "model": "recursive_character", "parameters": { "chunk_size": 1500, "chunk_overlap": 40 } }, "semantic_search": { "model": "Alibaba-NLP/gte-base-en-v1.5", }, "full_text_search": { "configuration": "english" } }, }, )

chunk_size决定每个 chunk 的字符上限,chunk_overlap让相邻 chunk 保留重叠文本,避免语义在边界处被截断。从源码看,splitter的model参数其实是可选的:splitter.rs 中Splitter::new在未指定名称时会默认使用recursive_character。分割器及其参数会被登记到数据库中的pgml.splitters表(见 queries.rs),后续切分时由pgml.chunk(...)函数按名称与参数调用(见 queries.rs)。

Semantic Search:控制如何生成嵌入向量

semantic_search对象同样接收两个参数:

  • model:用于生成嵌入的模型名称(字符串,通常为 Hugging Face 模型 ID);
  • parameters:可选对象,传递给嵌入模型。

很多嵌入模型在生成向量时要求特定前缀提示词。例如intfloat/e5-small-v2要求存储用嵌入必须以passage:开头,可以这样配置:

pipeline = Pipeline( "v0", { "text": { "splitter": {"model": "recursive_character"}, "semantic_search": { "model": "intfloat/e5-small-v2", "parameters": { "prompt": "passage: " } }, "full_text_search": { "configuration": "english" } }, }, )

(注:官方指南原文此处笔误为"传递给 splitter model",实际这些参数会传给嵌入模型。)从源码确认:semantic_search.model是必填项,而parameters、source、hnsw均为可选(见 pipeline.rs 中的ValidEmbedAction定义)。模型未指定时,SDK 会默认使用Alibaba-NLP/gte-base-en-v1.5(见 model.rs)。

嵌入的实际生成发生在同步阶段:SDK 会向数据库执行pgml.embed(...)调用,把每个 chunk 的文本批量转为向量并写入该字段对应的 embeddings 表(见 queries.rs)。生成的向量还会自动建立 HNSW 索引以支撑高效召回(详见下文"进阶定制"一节)。

Full Text Search:配置全文检索语言

full_text_search对象只接收一个键:configuration。它会直接作为 PostgreSQL 全文检索函数to_tsvector的配置参数传入,最常用的取值是english——即你希望启用哪种语言的全文检索。

从源码可以看到这一点:在 queries.rs 的GENERATE_TSVECTORS_FOR_CHUNK_IDS查询中,configuration被直接嵌入to_tsvector('%d', chunk),同时 tsvector 会存入该字段对应的_tsvectors表,并建立 GIN 索引以加速关键词查询(见 pipeline.rs)。

需要特别注意的是:如果要执行混合检索(hybrid search,即语义 + 关键词),必须在 Pipeline schema 中提供full_text_search键。向量检索与全文过滤的配合方式可参见 向量检索指南 中的full_text_filter用法。

对多个字段进行变换

实际场景中常常需要对文档的多个字段做检索。做法是在 schema 顶层同时声明多个字段键,并为每个键分别配置变换。例如对abstract只做嵌入与全文搜索,对text做分割 + 嵌入 + 全文搜索:

pipeline = Pipeline( "v0", { "abstract": { "semantic_search": { "model": "Alibaba-NLP/gte-base-en-v1.5", }, "full_text_search": { "configuration": "english" } }, "text": { "splitter": {"model": "recursive_character"}, "semantic_search": { "model": "Alibaba-NLP/gte-base-en-v1.5", }, "full_text_search": { "configuration": "english" } }, }, )

上面的 Pipeline 会为abstract生成嵌入与 tsvector,为text生成 chunk、嵌入与 tsvector。于是我们可以同时对文档的text与abstract两个字段发起检索。注意:未配置splitter的字段不会被切分——从源码看,SDK 会把该字段的原始值整体作为一个 chunk 写入 chunks 表(见 queries.rs 的"无分割器"查询),这也解释了为什么abstract这类短字段通常不需要 splitter。多字段检索的具体写法见 向量检索指南。

自托管实例的专属参数

本小节仅适用于自托管(self-hosted)的 PostgresML 实例。对于 PostgresML 官方托管的实例,以下参数不是必需的。

信任远程代码(Trust Remote Code)

部分 Hugging Face 模型要求传入trust_remote_code=true才会加载。在构造 Pipeline 时把它作为semantic_search.parameters传入即可:

pipeline = Pipeline( "v0", { "text": { "semantic_search": { "model": "Alibaba-NLP/gte-base-en-v1.5", "parameters": { "trust_remote_code": True } } } } )

Hugging Face 认证

访问 Hugging Face 上的 gated(受限)仓库时,需要把 Hugging Face token 传入 Pipeline:

pipeline = Pipeline( "v0", { "text": { "semantic_search": { "model": "Alibaba-NLP/gte-base-en-v1.5", "parameters": { "trust_remote_code": True, "token": "YOUR_TOKEN" } } } } )

从源码可以印证这些参数的传递路径:semantic_search.parameters会原样保存在模型对象中(见 model.rs),并在嵌入生成时作为kwargs参数传给pgml.embed(...)(见 queries.rs)。

源码视角:Pipeline schema 如何被解析与执行

理解 schema 的底层解析过程,有助于写出更精确的配置。在 pipeline.rs 中,json_to_schema会对 schema 做逐键解析:每个字段动作先被反序列化为ValidFieldAction(包含 splitter / semantic_search / full_text_search),再转换为可执行的FieldAction(内置真正的Splitter、Model与HNSW实例)。值得注意的是,serde(deny_unknown_fields)意味着 schema 中出现未知键会直接报错,因此字段动作的键必须严格限定为上述三个。

当 Pipeline 第一次被挂载到 Collection(add_pipeline)时,SDK 会:

  1. 把 Pipeline 的名称与 schema 存入pgml.pipelines表(见 pipeline.rs);
  2. 为该 Pipeline 创建独立的数据库 schema,并按字段生成_chunks、_embeddings、_tsvectors三套表及对应索引(见 pipeline.rs);
  3. 自动对 Collection 中已有的文档执行同步(sync_documents),其内部按"先生成 chunk → 再对 chunk 生成嵌入 → 再对 chunk 生成 tsvector"的顺序逐字段处理(见 pipeline.rs)。

这也是"首次把 Pipeline 添加到 Collection 时,其中的已有文档会自动完成切分与嵌入"这一行为的底层来源。同理,当 Pipeline 被移除或重新同步(resync)时,SDK 会先清空旧的 chunks 再按新 schema 重建(见 pipeline.rs)。

进阶定制:模型来源与向量索引

除官方指南覆盖的三种变换外,构造 Pipeline 时还有两个常用的进阶配置项,均定义在 schema 的semantic_search对象内(详见 Pipelines API)。

使用 OpenAI 嵌入模型

Korvus 支持 Hugging Face 上的绝大多数开源模型,也支持 OpenAI 的嵌入模型。只要把source指定为openai,并设置环境变量OPENAI_API_KEY:

pipeline = Pipeline( "test_pipeline", { "body": { "splitter": {"model": "recursive_character"}, "semantic_search": {"model": "text-embedding-ada-002", "source": "openai"}, }, }, )

从源码确认,模型运行时有Python与OpenAI两种(见 model.rs),未指定source时默认按本地 Python 运行时处理(model.rs)。

定制 HNSW 向量索引

默认情况下,SDK 使用 HNSW 索引做向量召回,默认参数为m = 16、ef_construction = 64(见 pipeline.rs)。这两个参数可以在semantic_search.hnsw中覆盖:

pipeline = Pipeline( "test_pipeline", { "body": { "splitter": {"model": "recursive_character"}, "semantic_search": { "model": "Alibaba-NLP/gte-base-en-v1.5", "hnsw": {"m": 100, "ef_construction": 200}, }, }, }, )

m控制 HNSW 图每个节点的最大连接数,ef_construction控制建图时的候选集大小;更大的值通常带来更高的召回率与更慢的构建/内存开销,需要按数据规模权衡。SDK 在建表时会用这两个值生成USING hnsw ... vector_cosine_ops索引(见 pipeline.rs)。

把 Pipeline 挂载到 Collection 并开启检索

构造好 Pipeline 之后,把它添加到 Collection 即完成整个索引流程:

collection = Collection("test_collection") await collection.add_pipeline(pipeline)

添加完成后,Pipeline 会随文档的 upsert 自动运行;已添加过的 Pipeline 也可以在后续代码中只按名称引用(Pipeline("v0")无需再传 schema),并可通过disable_pipeline/enable_pipeline/remove_pipeline控制其生命周期(详见 Pipelines API)。

有了 Pipeline 支撑的索引,就可以在 Collection 上执行向量检索、文档检索或一步到位的 RAG 查询——例如在rag调用中让 Pipeline 同时完成全文检索、向量检索、重排与文本生成。这些检索语义都建立在本文所构造的 schema 之上,具体写法可参考 向量检索指南 与 RAG 指南。

  • 后端
  • 人工智能
  • 机器学习
  • RAG
  • 向量数据库

【免费下载链接】postgresml

Postgres with GPUs for ML/AI apps.

项目地址:https://gitcode.com/gh_mirrors/po/postgresml
点击查看免费下载

相关推荐

上一篇:GTK3应用日志最佳实践:kiran-log高效集成与使用技巧
下一篇:Postman to OpenAPI Converter

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询