news 2026/9/17 9:04:21

Genkit 与 Vertex AI 语义重排序(Reranker)实战:基于假文档内容的重排示例全解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Genkit 与 Vertex AI 语义重排序(Reranker)实战:基于假文档内容的重排示例全解析

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 配置、硬编码的假文档内容,以及两个重排流程legacyRerankFlowv2RerankFlow
  • src/config.ts:通过dotenv读取PROJECT_IDLOCATION两个环境变量;
  • package.json:项目依赖与运行脚本;
  • tsconfig.json:TypeScript 编译配置。

它的工作方式非常直观:维护一份写死的字符串数组作为"候选文档",接收一个查询字符串,调用 Vertex AI 的语义重排序模型对候选文档打分,最后按相关性分数从高到低返回文档文本与分数。之所以使用"假文档"(Fake Document Content),是为了把演示焦点完全放在 reranker 的接入与调用上,避开真实的检索与数据源集成复杂度。

前置条件

在运行示例之前,需要确认以下三项:

  1. Node.js已安装;
  2. PNPM(包管理器)已安装;
  3. 一个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 开发者界面或向服务器发送请求来调用legacyRerankFlowv2RerankFlow两个流程,观察给定查询(默认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全量云平台权限;
  • vertexAIRerankerslegacy(旧版)重排序插件,通过rerankers数组显式声明要注册的模型,此处注册了semantic-ranker-default@latest。其实现位于 js/plugins/vertexai/src/rerankers/legacy/index.ts,源码注释明确标注@deprecated please use vertexRerankers instead
  • vertexRerankersv2 重排序插件,采用延迟解析(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, })); } );

几个值得注意的要点:

  • inputSchemaquery设置了默认值'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: Documentdocuments: 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: 文本 }记录,连同modelquery与透传的options组成RerankRequest发给后端;响应中的每条 record 携带idscore,插件再按下标找回原始文档,把score合并进metadata生成RankedDocumentdefineReranker中的注释还指出:后端会静默回退到默认模型——因此模型名拼写错误不一定报错,却可能拿到非预期结果,务必核对模型名。

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 映射为带scoreRankedDocument。这也是为什么 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/004semantic-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),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/17 9:00:42

SAE AS5643时间触发总线:IEEE 1394b航电/车载网络设计

第一次在需求文件里看到 SAE AS5643 这几个字符的时候,我的第一反应是:又是 IEEE 1394?这条在消费电子领域早就退场的总线,怎么还在航电和车载平台的方案里活着。等把标准原文翻完、再上手把一套 S400 的环网从零搭起来跑通&#…

作者头像 李华
网站建设 2026/9/17 8:57:10

KubeEdge 项目中的 go-sqlite3:Go 语言 SQLite 驱动的完整实战指南

KubeEdge 项目中的 go-sqlite3:Go 语言 SQLite 驱动的完整实战指南 【免费下载链接】kubeedge Kubernetes Native Edge Computing Framework (project under CNCF) 项目地址: https://gitcode.com/GitHub_Trending/ku/kubeedge 导读 go-sqlite3 是 Go 语言生…

作者头像 李华
网站建设 2026/9/17 8:56:47

树结构k级祖先查询算法与二进制跳跃优化

1. 题目背景与需求分析最近在准备算法面试的同学可能都注意到了,得物2026年春招算法岗的第一道题目涉及了一个有趣的生物家族关系问题。题目描述了一种特殊的无性繁殖生物,每个生物都有唯一的父亲(除了1号生物)。我们需要解决的问…

作者头像 李华
网站建设 2026/9/17 8:56:19

彻底搞懂Qt信号与槽:QPushButton实战与避坑指南

作为一个常年用Qt写桌面应用的开发者,我几乎每天都在和QPushButton打交道。但说句实在话,很多人用了一年两年Qt,依然只是机械地connect(btn, &QPushButton::clicked, ...),对信号与槽的理解停留在“会用”的层面。真正遇到问题…

作者头像 李华
网站建设 2026/9/17 8:55:08

STM32CubeProgrammer物理连接可靠性实战指南

1. 为什么STM32CubeProgrammer不是“装个软件”那么简单——嵌入式AI编程的底层信任锚点你可能刚在AI编程助手的提示下,用自然语言生成了一段漂亮的HAL库初始化代码,甚至让大模型帮你写了完整的FreeRTOS任务调度逻辑。但当你要把这段“AI产出品”真正烧进…

作者头像 李华