Genkit 与 Vertex AI 语义重排序(Reranker)实战:基于假文档内容的重排示例全解析
【免费下载链接】genkitOpen-source framework for building agentic apps in JavaScript, Go, Dart, and Python, built and used in production by Google项目地址: https://gitcode.com/GitHub_Trending/ge/genkit
Genkit 是 Google 出品的开源 AI 应用框架,支持在 JavaScript、Go、Dart 与 Python 中构建可生产的 Agent 应用。语义重排序(Reranking)是其 RAG(检索增强生成)体系中的关键一环:在向量检索返回一批候选文档后,用专门的 reranker 模型按与查询的相关性重新打分排序,从而提升送进 LLM 的上下文质量。本文以仓库中js/testapps/vertexai-reranker示例应用为核心,从零讲解如何用 Genkit 的 Vertex AI 插件对一组文档执行语义重排,包括环境准备、运行方式、两个版本(legacy 与 v2)的流程实现,并深入源码剖析rerank调用链与插件底层原理。读完本文,你将能独立搭建并扩展一个基于 Vertex AI reranker 的重排序流程,并理解如何在真实 RAG 系统中落地这一能力。
示例概览:一个"麻雀虽小"的完整重排应用
该示例位于仓库的 js/testapps/vertexai-reranker 目录,结构如下:
- src/index.ts:示例主体,包含 Genkit 配置、硬编码的假文档内容,以及两个重排流程
legacyRerankFlow与v2RerankFlow; - src/config.ts:通过
dotenv读取PROJECT_ID与LOCATION两个环境变量; - package.json:项目依赖与运行脚本;
- tsconfig.json:TypeScript 编译配置。
它的工作方式非常直观:维护一份写死的字符串数组作为"候选文档",接收一个查询字符串,调用 Vertex AI 的语义重排序模型对候选文档打分,最后按相关性分数从高到低返回文档文本与分数。之所以使用"假文档"(Fake Document Content),是为了把演示焦点完全放在 reranker 的接入与调用上,避开真实的检索与数据源集成复杂度。
前置条件
在运行示例之前,需要确认以下三项:
- Node.js已安装;
- PNPM(包管理器)已安装;
- 一个Vertex AI项目,且具备访问重排序模型(reranking models)所需的权限。注意示例通过 Google Cloud 认证访问 Vertex AI 服务,因此本地通常还需要配置好 Google Cloud 凭据(如
gcloud auth application-default login,或通过 config.ts 中传入的googleAuth配置使用服务账号),确保google-auth-library能取得有效令牌。
环境准备:安装依赖与环境变量
步骤 1:安装依赖
克隆仓库后进入示例目录,执行:
pnpm install示例的 package.json 通过workspace:*协议直接引用本仓库的genkit与@genkit-ai/vertexai源码包,因此依赖安装会在仓库工作区(pnpm workspace)内完成,保证示例始终与当前源码版本一致。
步骤 2:配置环境变量
在示例根目录创建.env文件,并设置:
PROJECT_ID=your_project_id_here LOCATION=your_location_here这两个变量分别指定 Vertex AI 的项目 ID 与区域(例如us-central1)。它们被 config.ts 读取:
import { config } from 'dotenv'; config(); export const PROJECT_ID = process.env.PROJECT_ID!; export const LOCATION = process.env.LOCATION!;dotenv在模块加载时执行config(),随后以非空断言的方式导出两个常量。注意:仓库中并未附带.env.example文件,请直接创建.env;若变量缺失,应用会因读取undefined而在初始化阶段报错。
运行示例:启动 Genkit 服务器
准备就绪后,在示例目录启动 Genkit 开发服务器:
genkit start这会启动托管重排流程的服务器。如果你没有全局安装 Genkit CLI,也可以使用 package.json 中预置的开发脚本:
pnpm genkit:dev其定义是genkit start -- npx tsx --watch src/index.ts——先用tsx直接运行 TypeScript 源码(带--watch热重载),再由 Genkit 服务器托管流程。启动后即可通过 Genkit 开发者界面或向服务器发送请求来调用legacyRerankFlow与v2RerankFlow两个流程,观察给定查询(默认geometry)下的文档重排结果。
示例源码逐段解析
Genkit 配置:三个插件的组合
src/index.ts 中通过genkit({...})完成初始化,同时挂载了三个插件:
const ai = genkit({ plugins: [ vertexAI({ projectId: PROJECT_ID, location: LOCATION, googleAuth: { scopes: ['https://www.googleapis.com/auth/cloud-platform'], }, }), vertexAIRerankers({ projectId: PROJECT_ID, location: LOCATION, rerankers: ['semantic-ranker-default@latest'], }), vertexRerankers(), ], });三者分工明确:
vertexAI:Vertex AI 主插件,负责 Gemini 模型、认证等基础能力,googleAuth.scopes申请cloud-platform全量云平台权限;vertexAIRerankers:legacy(旧版)重排序插件,通过rerankers数组显式声明要注册的模型,此处注册了semantic-ranker-default@latest。其实现位于 js/plugins/vertexai/src/rerankers/legacy/index.ts,源码注释明确标注@deprecated please use vertexRerankers instead;vertexRerankers:v2 重排序插件,采用延迟解析(lazy resolve)机制,无需预先枚举模型,调用时按名称动态解析。其实现位于 js/plugins/vertexai/src/rerankers/v2/index.ts。
这个示例故意同时演示两代插件 API,方便读者对比迁移。
假文档内容
src/index.ts 定义了 15 条数学、物理与流行文化主题的字符串,作为待重排的候选文档:
const FAKE_DOCUMENT_CONTENT = [ 'pythagorean theorem', // 勾股定理 'e=mc^2', 'pi', 'dinosaurs', "euler's identity", 'prime numbers', 'fourier transform', 'ABC conjecture', 'riemann hypothesis', 'triangles', "schrodinger's cat", 'quantum mechanics', 'the avengers', "harry potter and the philosopher's stone", 'movies', ];可以看到集合中既有与数学/物理高度相关的条目(勾股定理、傅里叶变换),也有明显无关的条目(《复仇者联盟》、恐龙),这样当查询为geometry(几何)时,重排结果能直观展示"相关文档排前、无关文档沉底"的效果。
legacyRerankFlow:旧版 API 的完整调用
legacyRerankFlow 演示了旧版插件的使用方式:
export const legacyRerankFlow = ai.defineFlow( { name: 'legacyRerankFlow', inputSchema: z.object({ query: z.string().default('geometry') }), outputSchema: z.array( z.object({ text: z.string(), score: z.number(), }) ), }, async ({ query }) => { const documents = FAKE_DOCUMENT_CONTENT.map((text) => Document.fromText(text) ); const rerankedDocuments = await ai.rerank({ reranker: 'vertexai/semantic-ranker-default@latest', query: Document.fromText(query), documents, }); return rerankedDocuments.map((doc) => ({ text: doc.text, score: doc.metadata.score, })); } );几个值得注意的要点:
inputSchema给query设置了默认值'geometry',即使不传参数也能运行;- 文档先通过
Document.fromText(text)包装为 Genkit 的Document对象; reranker以字符串形式直接指定模型,命名空间为vertexai/...,这是 legacy 插件注册时使用的名称(见下文源码);- 返回结果通过
doc.metadata.score取出每个文档的重排分数,与doc.text一起组成输出。
v2RerankFlow:新 API 与选项参数
v2RerankFlow 演示了 v2 插件的调用,并带上了topN等请求选项:
export const v2RerankFlow = ai.defineFlow( { name: 'v2RerankFlow', inputSchema: z.object({ query: z.string().default('geometry') }), outputSchema: z.array( z.object({ text: z.string(), score: z.number(), }) ), }, async ({ query }) => { const documents = FAKE_DOCUMENT_CONTENT.map((text) => Document.fromText(text) ); const response = await ai.rerank({ reranker: vertexRerankers.reranker('semantic-ranker-fast-004'), documents, query, options: { topN: 3, ignoreRecordDetailsInResponse: true, }, }); return response.map((doc: RankedDocument) => ({ text: doc.text, score: doc.metadata.score, })); } );与 legacy 版本的差异体现在:
reranker改为通过vertexRerankers.reranker('semantic-ranker-fast-004')构造类型安全的引用(Reference),而不是裸字符串,编译期即可校验模型名;query直接传字符串即可(底层rerank会代为转换为Document);- 传入
options指定topN: 3(只返回分数最高的 3 条)与ignoreRecordDetailsInResponse: true(响应只含记录 ID 与分数,减少回包体积); - 使用了
semantic-ranker-fast-004,这是较新的快速版模型,与 legacy 流程中的semantic-ranker-default@latest形成对照。
两个流程输出结构完全一致:{ text, score }数组,按相关度降序排列,方便上层直接消费。
底层原理:rerank 调用链与插件实现
核心 API:rerank 函数与 RankedDocument
重排序是 Genkit AI 层的一等公民。在 js/ai/src/reranker.ts 中定义了整套类型体系:
RerankerFn:reranker 实现函数签名,接收query: Document、documents: Document[]和选项,返回RerankerResponse;RankedDocument:继承Document并强制要求metadata.score为数字,额外提供score()便捷方法(见 js/ai/src/reranker.ts#L50-L66);rerank(registry, params):统一入口。当reranker参数是字符串时,会执行registry.lookupAction('/reranker/' + name)从注册表中解析出实际 action;查询为字符串时自动Document.fromText包装;最终把响应中的documents逐一映射为RankedDocument(js/ai/src/reranker.ts#L194-L219)。
从源码结构看,ai.rerank会绑定到 Genkit 实例自身的 registry,因此上述两个流程中的ai.rerank({...})最终都会走这条调用链:流程 → ai.rerank → registry 解析 reranker action → 插件实现函数 → Vertex AI 服务 → 按分数排序的 RankedDocument[]。
v2 插件:配置模式、已知模型与请求构造
v2 的模型实现集中在 js/plugins/vertexai/src/rerankers/v2/reranker.ts,它定义了请求选项的 Zod Schema:
export const VertexRerankerConfigSchema = z.object({ topN: z.number().optional().describe('Number of top documents to rerank'), ignoreRecordDetailsInResponse: z.boolean().optional().describe(...), location: z.string().optional().describe('Google Cloud location, e.g., "us-central1"'), }).passthrough();三个可选参数的含义分别为:返回 Top-N 条结果、响应是否仅含记录 ID 与分数、覆盖请求区域。.passthrough()允许透传后续新增的参数,具备前向兼容性。
该文件还维护了已知模型清单:
export const KNOWN_MODELS = { 'semantic-ranker-default@latest': commonRef('semantic-ranker-default@latest'), 'semantic-ranker-default-004': commonRef('semantic-ranker-default-004'), 'semantic-ranker-fast-004': commonRef('semantic-ranker-fast-004'), 'semantic-ranker-default-003': commonRef('semantic-ranker-default-003'), 'semantic-ranker-default-002': commonRef('semantic-ranker-default-002'), } as const;通过isRerankerModelName判断名称是否以semantic-ranker-开头,配合 v2/index.ts 中的resolver,实现按需延迟定义——只有真正被引用到的模型才会被解析注册。
请求构造与响应映射的细节也在 v2/reranker.ts:插件把每个文档序列化为{ id: 下标, content: 文本 }记录,连同model、query与透传的options组成RerankRequest发给后端;响应中的每条 record 携带id与score,插件再按下标找回原始文档,把score合并进metadata生成RankedDocument。defineReranker中的注释还指出:后端会静默回退到默认模型——因此模型名拼写错误不一定报错,却可能拿到非预期结果,务必核对模型名。
legacy 插件:逐步废弃的实现
legacy 实现位于 js/plugins/vertexai/src/rerankers/legacy/reranker.ts,其vertexAiRerankers函数在初始化时遍历rerankOptions,为每个模型调用ai.defineReranker注册名为vertexai/${name}的 action。它直接使用 Google Auth 客户端向getRerankEndpoint(projectId, location)构造的 HTTP 端点发起POST请求,并将响应 records 映射为带score的RankedDocument。这也是为什么 legacy 流程中要写'vertexai/semantic-ranker-default@latest'这样的命名空间字符串。同时它也提供了vertexAiRerankerRef工厂函数用于构造引用。两代实现的差异(注册时机、命名空间、选项传递方式)正是升级到 v2 时需要注意的迁移点。
从示例到生产:扩展方向
示例本身只演示了"固定文档 + 查询"的重排闭环,从源码结构看,将它扩展为真实 RAG 组件并不复杂:
- 接入真实检索源:把
FAKE_DOCUMENT_CONTENT替换为向量检索(retriever)返回的候选文档,例如仓库中 js/plugins/vertexai/src/vectorsearch 提供的 Vector Search 检索器; - 控制返回数量:生产场景通常对召回集先粗排再精排,v2 的
topN选项可限制精排输出条数,降低下游 LLM 的输入成本; - 观察与调试:借助 Genkit 开发者界面可查看每次
ai.rerank调用的输入输出与分数,便于调优查询与候选集; - 多模型对比:利用
KNOWN_MODELS中列出的semantic-ranker-default-002/003/004、semantic-ranker-fast-004等模型做效果评测,选择与业务语料最匹配的版本。
总结
js/testapps/vertexai-reranker示例以最简形式完整呈现了 Genkit + Vertex AI 语义重排序的接入路径:通过.env配置项目与区域、用genkit start托管流程、经ai.rerank统一调用底层插件。示例同时保留了 legacy 与 v2 两代插件 API 的对照实现,而 js/ai/src/reranker.ts 与 js/plugins/vertexai/src/rerankers/v2/reranker.ts 则揭示了从注册表解析、请求构造到RankedDocument返回的完整链路。示例采用 Apache License 2.0 许可(详见仓库根目录 LICENSE),在此基础上可以轻松扩展出面向真实数据源的精排流水线,为 RAG 应用提供高质量的上下文筛选能力。
【免费下载链接】genkitOpen-source framework for building agentic apps in JavaScript, Go, Dart, and Python, built and used in production by Google项目地址: https://gitcode.com/GitHub_Trending/ge/genkit
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考