Mastra 本地语义召回实战:@mastra/fastembed 与 ONNX Runtime 本地 Embedding 模型集成指南
2026/9/15 17:20:18 网站建设 项目流程

Mastra 本地语义召回实战:@mastra/fastembed 与 ONNX Runtime 本地 Embedding 模型集成指南

【免费下载链接】mastraMastra is the modern TypeScript framework for AI-powered applications and agents.项目地址: https://gitcode.com/GitHub_Trending/ma/mastra

@mastra/fastembed是 Mastra 框架内置的本地 Embedding 模型集成包,基于 ONNX Runtime 在进程内直接运行小型嵌入模型,无需任何外部 API 调用。本文围绕该包的安装、与@mastra/memory的语义召回(Semantic Recall)集成、内置模型与初始化参数、底层推理与模型缓存原理展开,帮助你把它作为Memory的本地embedder,为 Agent 构建数据不出本机的语义检索能力。

包定位与设计背景

@mastra/fastembed(源码位于 packages/fastembed)提供了一套由 ONNX Runtime 驱动的本地嵌入模型方案。它的核心特点包括:

  • 完全本地推理:模型以 ONNX 格式运行在onnxruntime-node上,文本向量化不依赖远程 API,适合对数据隐私、延迟和成本敏感的场景。
  • 维护分支而非上游依赖:该包是 fastembed-js),因此@mastra/fastembed不再依赖已停止维护的fastembednpm 包,规避了上游停更带来的供应链风险。
  • 为 Mastra Memory 而生:包的主入口导出的fastembed对象实现了 Mastra Embedding Model 接口,可直接作为new Memory({ embedder: fastembed })的配置项,为语义召回提供本地向量化能力。

从 packages/fastembed/package.json 可以看到其运行时依赖:onnxruntime-node(1.26.0)、@anush008/tokenizers(分词器)、@huggingface/hub(Hugging Face 模型下载)、progress(下载进度条)与tar(压缩包解压),引擎要求 Node.js>= 22.13.0,包以 ESM 为主并同时导出 CommonJS 构建。

安装与环境要求

npm install @mastra/fastembed

安装完成后,首次实际调用会触发模型下载(详见下文“模型获取与缓存”一节),因此请确保运行环境可以访问模型源(Qdrant FastEmbed 的 GCS 存储桶与 Hugging Face)。若你的项目使用 pnpm 管理依赖,可直接将包加入dependencies后重新安装即可。

与 Mastra Memory 集成:本地语义召回

默认用法(AI SDK v3)

README 给出的最小集成方式,是把它作为Memoryembedder传入:

import { Memory } from '@mastra/memory'; import { fastembed } from '@mastra/fastembed'; const memory = new Memory({ // ... other memory options embedder: fastembed, });

Memory的构造器接收embedder选项后,会在两类场景中用到它(见 packages/memory/src/index.ts 中的校验逻辑):

  • retrieval: { vector: true }的向量检索;
  • 语义召回(semantic recall):即semanticRecall配置为true(或{ scope: 'resource' }等)时,将历史消息向量化并做相似度检索,其中topKmessageRange控制召回数量与范围。

需要特别注意的是:语义召回要求同时配置 vector store 与 embedder。源码中对应的校验是:未配置 embedder 时抛出 “retrieval: { vector: true }requires an embedder” 与 “Subconscious semantic knowledge requires an embedder” 的错误(packages/memory/src/index.ts)。因此实际使用时通常是这样:

import { Memory } from '@mastra/memory'; import { LibSQLStore } from '@mastra/libsql'; import { LibSQLVector } from '@mastra/libsql'; import { fastembed } from '@mastra/fastembed'; const store = new LibSQLStore({ config: { url: 'file:memory.db' } }); const vector = new LibSQLVector({ config: { url: 'file:vectors.db' } }); const memory = new Memory({ store, vector, embedder: fastembed, semanticRecall: true, });

此外,packages/memory/src/index.ts 中还有一处针对本包的专门处理注释:“for fastembed multiple initial calls to embed will fail if the model hasn't been downloaded yet”(使用 fastembed 时,模型尚未下载完成的首次多次调用可能失败),并会通过this.embedder.provider === 'fastembed'判断走对应的重试路径。也就是说,首次使用前模型下载是异步的,生产环境建议先用下文介绍的warmup()预热

面向不同 AI SDK 版本的兼容层

@mastra/fastembed的入口(packages/fastembed/src/index.ts)同时注册了三种规范版本的 provider,保证不同 AI SDK 主版本都能对接:

规范版本对应 AI SDK导出属性
v1(legacy)AI SDK v4smallLegacybaseLegacy
v2AI SDK v5smallV2baseV2
v3AI SDK v6(默认)smallbasemultilingualE5LargeQuerymultilingualE5LargePassagefastembed本身

fastembed对象本身即 v3 规范的bge-small-en-v1.5模型实例,同时挂载了上述命名属性便于显式选用具体模型。每个模型的maxEmbeddingsPerCall均为256,并声明supportsParallelCalls: true,允许并发嵌入调用。

内置模型与 API 一览

fastembed入口默认注册四个 v3 模型 ID:bge-small-en-v1.5bge-base-en-v1.5multilingual-e5-large-querymultilingual-e5-large-passage。而底层的EmbeddingModel枚举(packages/fastembed/src/fastembed.ts)则支持更完整的模型清单,配合listSupportedModels()可得到维度与说明:

枚举值模型 ID向量维度说明
BGESmallENfast-bge-small-en384快速英文模型
BGESmallENV15fast-bge-small-en-v1.5384v1.5 快速英文模型(默认)
BGEBaseENfast-bge-base-en768基础英文模型
BGEBaseENV15fast-bge-base-en-v1.5768v1.5 基础英文模型
BGESmallZHfast-bge-small-zh-v1.5512快速中文模型
AllMiniLML6V2fast-all-MiniLM-L6-v2384Sentence Transformer MiniLM-L6-v2
MLE5Largefast-multilingual-e5-large1024多语言模型,官方推荐用于非英文场景

入口同时导出了以下类型与类,便于底层直接使用:

  • EmbeddingModelFlagEmbedding(稠密向量模型类)
  • SparseTextEmbeddingSparseEmbeddingModelSparseVector(稀疏向量,SPLADE)
  • ExecutionProvider(执行后端枚举)
  • InitOptionsInitSparseOptions等初始化参数类型

底层实现:FlagEmbedding 推理流水线

FlagEmbedding(packages/fastembed/src/fastembed.ts)是稠密嵌入的核心实现,其工作流可拆解为四步:

  1. 模型获取init()中若指定标准模型,会调用retrieveModel(model, cacheDir, showDownloadProgress)https://storage.googleapis.com/qdrant-fastembed/<model>.tar.gz下载模型压缩包(其中AllMiniLML6V2的 URL 命名略有特殊处理),解压到cacheDir并删除压缩包。若指定CUSTOM模型,则要求同时提供modelAbsoluteDirPathmodelName,直接加载本地目录中的 ONNX 文件。
  2. 加载分词器loadTokenizerFromDir()依次读取tokenizer.jsonconfig.jsontokenizer_config.jsonspecial_tokens_map.json,通过@anush008/tokenizers构造Tokenizer,按min(maxLength, model_max_length)设置截断与填充,并注册特殊 token。注意MLE5LargeAllMiniLML6V2默认加载model.onnx,其余模型默认加载model_optimized.onnx
  3. 创建 ONNX Sessionort.InferenceSession.create(modelPath, { executionProviders, graphOptimizationLevel: 'all' }),默认 CPU 执行并开启全量图优化。
  4. 批处理推理与归一化embed()为 AsyncGenerator,默认以 256 条文本为一批;每批内并行tokenizer.encode,组装input_idsattention_masktoken_type_ids三个 int64 Tensor(MLE5Large会剔除token_type_ids),运行 session 后取last_hidden_state,按[batch, seq, hidden]维度切片还原每条文本的向量,最后做L2 归一化normalize()中除以向量模长,并加了1e-12的 epsilon 防止除零)。

值得注意的细节是FlagEmbedding的语义前缀约定:

  • passageEmbed(texts)会给每条文本加passage:前缀;
  • queryEmbed(query)会给查询加query:前缀。

这与入口层generatePrefixedEmbeddings()对 E5 模型的处理一脉相承:E5 系列是对称性较弱的模型,query 与 passage 必须使用不同前缀才能取得正确相似度。这一点在单元测试中有明确断言(packages/fastembed/src/index.test.ts):multilingualE5LargeQuery.doEmbed(['hello'])实际送入模型的是['query: hello'],而multilingualE5LargePassage送入['passage: hello']bge系列则不加前缀(packages/fastembed/src/index.test.ts)。

SparseTextEmbedding:SPLADE 稀疏检索

除了稠密向量,包还提供SparseTextEmbedding用于稀疏检索(packages/fastembed/src/fastembed.ts):

  • 内置模型SpladePPEnV1prithivida/Splade_PP_en_v1,词表大小 30522),模型文件从 Hugging Face 仓库按清单下载(onnx/model.onnxtokenizer.jsonconfig.json等 5 个文件)。
  • 推理结果经过log(1 + ReLU(logits))后处理,并对每个 token 维度取整条序列上的最大值,最终产出SparseVector{ values: number[], indices: number[] },只保留正值项,天然稀疏。
  • queryEmbed/passageEmbed同样可用,测试中验证了稀疏向量的indicesvalues长度一致且值均大于 0(packages/fastembed/src/fastembed_splade.test.ts)。

稀疏向量可配合支持稀疏检索的向量库使用,作为稠密检索的补充。

模型缓存与预热:避免重复下载

入口层的模型访问全部经由 packages/fastembed/src/model-cache.ts 的getCachedModel()完成,其设计要点:

  • 固定缓存目录~/.cache/mastra/fastembed-modelsos.homedir()下的.cache/mastra/fastembed-models),首次访问时自动递归创建。
  • Promise 级缓存:内部用Map<FastEmbedModelType, Promise<FlagEmbedding>>缓存初始化中的 Promise。同一模型并发请求共享同一次FlagEmbedding.init,不会重复下载;初始化失败时会从 Map 中删除以便下次重试。相关单元测试验证了“重复调用只初始化一次”“并发请求共享初始化”“small/base 各自独立缓存”等行为(packages/fastembed/src/model-cache.test.ts)。

针对“并发测试/首次启动导致模型下载竞争”的问题,入口导出warmup()

import { warmup } from '@mastra/fastembed'; // 在启动阶段调用,只下载模型文件、不创建 ONNX session await warmup();

warmup()底层调用warmupFastEmbedModels()(packages/fastembed/src/model-cache.ts),预先下载bge-small-en-v1.5bge-base-en-v1.5两个默认模型。生产服务建议在启动阶段执行预热,避免首个请求承担下载延迟。

初始化选项详解

底层FlagEmbedding.init()/SparseTextEmbedding.init()的选项(InitOptions,见 packages/fastembed/src/fastembed.ts)默认值与说明如下:

选项类型默认值说明
modelEmbeddingModel/SparseEmbeddingModelBGESmallENV15/SpladePPEnV1要加载的模型
executionProvidersExecutionProvider[]['cpu']ONNX 执行后端:cpucudawebglwasmxnnpack(见 ExecutionProvider 枚举)
maxLengthnumber512序列最大长度,会被tokenizer_config.json中的model_max_length进一步收紧
cacheDirstring'local_cache'模型缓存目录;入口层自动改用~/.cache/mastra/fastembed-models
showDownloadProgressbooleantrue下载时是否显示进度条
modelAbsoluteDirPathPathLike''CUSTOM模型必填:本地模型目录
modelNamestring''CUSTOM模型必填:ONNX 文件名

选择自定义 ONNX 模型时,目录内须同时包含tokenizer.jsonconfig.jsontokenizer_config.jsonspecial_tokens_map.json与 ONNX 模型文件(测试中即从sentence-transformers/all-MiniLM-L6-v2下载这组文件后加载,见 packages/fastembed/src/fastembed_custom.test.ts)。选择 CUDA/XNNPACK 等非 CPU 后端时,需要确认运行环境的 ONNX Runtime 包含对应原生扩展。

测试与验证

包内测试分为两类:

  • 单元测试npm test):通过 mock 验证入口层模型注册、E5 前缀、模型缓存语义(packages/fastembed/src/index.test.ts、packages/fastembed/src/model-cache.test.ts)。
  • 真实模型测试npm run test:models,对应vitest run --project 'models:packages/fastembed'):每个内置模型一套测试(如 packages/fastembed/src/fastembed_bgebasev15.test.ts),覆盖init、单条/批量/小批量embedqueryEmbedpassageEmbed,并断言输出向量维度(bge-base 为 768、MiniLM 自定义模型为 384 等)。其中canonical values 测试固定了参考输入(如'hello world')的期望向量前若干维数值,用以锁定模型输出的一致性,防止依赖或实现变动悄悄改变向量结果。

使用注意事项

  1. 首次调用延迟:模型文件需要从 GCS/Hugging Face 下载(每个模型数百 MB 级别),首次doEmbed可能耗时较长;并发场景下建议先调用warmup()
  2. 磁盘与网络:模型缓存在~/.cache/mastra/fastembed-models,可复用跨进程,但需保证目录可写且磁盘空间充足。
  3. 模型选型:英文场景默认bge-small-en-v1.5(384 维,速度快、体积小);需要更高精度选bge-base-en-v1.5(768 维);非英文/多语言场景按官方建议选择multilingual-e5-large(1024 维,query/passage 分开注册)。
  4. E5 前缀不可混用:query 与 passage 必须使用对应角色模型(入口已分开注册为multilingualE5LargeQuerymultilingualE5LargePassage),混用会显著降低检索质量。

小结

@mastra/fastembed把原本需要外部 API 的文本向量化能力完全下沉到本地:它以 vendored 的 fastembed-js 源码 + ONNX Runtime 实现了稠密(BGE / MiniLM / E5)与稀疏(SPLADE)两类嵌入模型,通过三套规范版本的 provider 无缝对接 MastraMemory的语义召回,并提供模型缓存、预热与批量推理等工程化细节。对希望在 Agent 应用中实现隐私友好、零 API 成本的语义检索的开发者而言,直接以embedder: fastembed接入即可快速落地。

【免费下载链接】mastraMastra is the modern TypeScript framework for AI-powered applications and agents.项目地址: https://gitcode.com/GitHub_Trending/ma/mastra

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

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

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

立即咨询