ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Mastra 接入 Amazon S3 Vectors:@mastra/s3vectors 向量存储完整实战指南

Mastra 接入 Amazon S3 Vectors:@mastra/s3vectors 向量存储完整实战指南 Mastra 接入 Amazon S3 Vectorsmastra/s3vectors 向量存储完整实战指南【免费下载链接】mastraMastra is the modern TypeScript framework for AI-powered applications and agents.项目地址: https://gitcode.com/GitHub_Trending/ma/mastra导读mastra/s3vectors是 Mastra 框架为Amazon S3 VectorsPreview 服务提供的向量存储实现将向量写入 S3 的vector buckets向量桶并在vector indexes向量索引中执行亚秒级相似度查询。本文以该包的官方 README 为骨架结合其源码实现与测试用例系统讲解从安装、初始化、建索引、写入向量到带复杂过滤条件的相似度查询的完整链路并深入剖析索引名归一化、过滤器翻译器、Date 元数据序列化等底层机制帮助你直接在 Mastra 应用中使用 S3 Vectors 构建 RAG 与语义检索能力。⚠️ 前置提示Amazon S3 Vectors 目前是Preview 服务。预览功能可能在没有通知的情况下变更或移除且不受 AWS SLA 覆盖行为、配额与区域可用性都可能随时变化本库也会为了与 AWS 保持一致而引入破坏性变更。在生产环境使用前请先确认目标区域的可用性与最新服务文档。一、功能概览与适用场景S3 Vectors 将向量存储拆分为两个概念vector bucket向量桶存放向量数据的容器是 S3 Vectors 服务层级的顶层资源vector index向量索引在桶内创建、按维度与距离度量组织的可查询集合相似度查询在索引上进行。mastra/s3vectors把上述概念封装为符合 MastraMastraVector抽象接口的S3Vectors类见 抽象基类定义因此它可以像其他 Mastra 向量存储一样被 RAG、Memory、Agent 等上层模块直接使用同时保留了 S3 Vectors 独有的能力与限制。适合以下场景已在 AWS 上使用 S3 生态希望将向量数据与对象存储、IAM、CloudTrail 等体系统一管理的团队需要 JSON 风格过滤语法$eq、$gt、$in、$and等做元数据条件检索的应用希望获得强一致索引语义、无需轮询等待索引就绪的检索链路见测试中的waitForIndexing: async () {}。二、安装在 Mastra 项目中安装npm install mastra/s3vectors该包依赖aws-sdk/client-s3vectors当前仓库中锁定的版本为^3.1095.0与lukeed/uuid用于自动生成向量 ID并以mastra/core 1.0.0-0 2.0.0-0作为 peerDependency见 package.json。项目 Node.js 版本需不低于22.13.0。三、初始化与配置import { S3Vectors } from mastra/s3vectors; const vectorStore new S3Vectors({ // 必填目标 S3 Vectors 桶名 vectorBucketName: process.env.S3VECTORS_BUCKET!, // 例如 my-vector-bucket // 可选AWS SDK v3 客户端配置region、credentials 放在这里 clientConfig: { region: process.env.AWS_REGION!, // 例如 us-east-1 // credentials 可以依赖 AWS 默认凭证链环境变量 / IAM Role / ~/.aws/credentials }, // 可选不可用于过滤的元数据键在创建索引时一并提交给 S3 Vectors nonFilterableMetadataKeys: [content], });对应源码中的S3VectorsOptions见 stores/s3vectors/src/vector/index.ts#L39-L43配置项类型必填说明vectorBucketNamestring✅目标向量桶名缺失时构造器会抛出MastraError错误 ID 为S3VECTORS_INITIALIZATION_MISSING_BUCKET_NAME分类为ErrorCategory.USERclientConfigS3VectorsClientConfig❌透传给aws-sdk/client-s3vectors的S3VectorsClient配置凭证未显式给出时走 AWS 默认凭证链nonFilterableMetadataKeysstring[]❌声明为不可过滤的元数据键用于存放大段文本如文档正文避免其参与索引过滤认证与凭证clientConfig直接透传给 AWS SDK v3 的S3VectorsClient源码中new S3VectorsClient({ ...(opts.clientConfig ?? {}) })因此凭证解析完全遵循 AWS SDK 的默认凭证链环境变量AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY/AWS_SESSION_TOKEN、共享凭证文件、EC2/ECS 角色等均可生效无需额外配置。连接与断开await vectorStore.connect(); // 空操作AWS SDK 按请求管理 HTTP无需常驻连接 await vectorStore.disconnect(); // 释放底层 HTTP handler避免 socket 泄漏connect()在实现中是无操作满足基类接口disconnect()调用client.destroy()释放底层 HTTP 句柄见 stores/s3vectors/src/vector/index.ts#L91-L109。在长生命周期服务如 Serverless 函数复用、Agent 常驻进程结束时调用disconnect()是好习惯。四、索引管理创建、列举、描述与删除4.1 创建索引await vectorStore.createIndex({ indexName: my-index, // _ 会被替换为 -字母统一转小写 dimension: 1536, // 向量维度必须为正整数 metric: cosine, // 距离度量cosine默认或 euclidean不支持 dotproduct });创建索引时底层通过CreateIndexCommand提交数据类型固定为float32维度dimension必须是正整数否则抛MastraErrorS3VECTORS_CREATE_INDEX_INVALID_ARGS度量仅支持cosine与euclidean传入dotproduct会被拒绝测试should reject unsupported metric dotproduct on createIndex验证了该行为见 index.test.ts若配置了nonFilterableMetadataKeys会在创建索引时通过metadataConfiguration.nonFilterableMetadataKeys一并提交。索引名归一化重要createIndex、upsert、query等所有操作都会对索引名执行归一化——把_替换为-并转为小写normalizeIndexName见 stores/s3vectors/src/vector/index.ts#L662-L667。例如My_Index实际会操作my-index。集成测试专门验证了这一行为见 index.test.ts。幂等语义当 AWS 返回ConflictException索引已存在时实现会通过GetIndex校验既有索引的 schema若维度与度量匹配则静默返回视为 no-op不匹配也不会改变已存在索引见 index.test.ts 的重复创建测试。4.2 列举索引const indexes: string[] await vectorStore.listIndexes();底层分页调用ListIndexesCommand自动遍历nextToken直到取完所有索引名。4.3 描述索引const stats await vectorStore.describeIndex({ indexName: my-index }); // 返回 { dimension: number, metric: cosine | euclidean, count: number }其中count通过分页ListVectors每页最多 1000 条逐项累计复杂度为 O(n)源码注释明确提醒不要在热路径上调用见 stores/s3vectors/src/vector/index.ts#L560-L580。4.4 删除索引await vectorStore.deleteIndex({ indexName: my-index });底层调用DeleteIndexCommand集成测试中的清理逻辑对已删除情形做了容错already deleted is fine。五、写入向量upsert 与 ID 生成const vectors [ [0.1, 0.2 /* ... */], [0.3, 0.4 /* ... */], ]; const metadata [ { text: doc1, genre: documentary, year: 2023, createdAt: new Date(2024-01-01) }, { text: doc2, genre: comedy, year: 2021 }, ]; // 如果不传 ids会自动生成 UUID const ids await vectorStore.upsert({ indexName: my-index, vectors, metadata, }); // ids: string[] —— 返回实际使用的 ID显式传入或自动生成upsert的底层行为见 stores/s3vectors/src/vector/index.ts#L181-L212先通过GetIndex读取索引维度逐一向量校验维度是否一致维度不符即报错测试should handle invalid dimension vectors验证 3 维向量写入 4 维索引会被拒绝未提供ids时使用lukeed/uuid的v4()生成 UUID通过PutVectorsCommand批量写入向量数据以data.float32提交。Date 元数据的自动序列化写入时normalizeMetadata会把Date类型的元数据值统一转换为epoch 毫秒数v instanceof Date ? v.getTime() : v避免 S3 Vectors 无法识别 JSDate对象见 stores/s3vectors/src/vector/index.ts#L648-L655。因此createdAt: new Date(2024-01-01)会被存储为数值并可直接参与数值范围过滤。集成测试normalizes date values in filter using filter.ts验证了该往返行为写入Date后可按$gt过滤并还原为同一时刻。六、相似度查询query 与过滤语法6.1 基础查询const results await vectorStore.query({ indexName: my-index, queryVector: [0.1, 0.2 /* ... */], topK: 10, // 返回邻居数量S3 Vectors 上限为 30 // S3 Vectors 基于 JSON 的过滤语法$eq, $ne, $gt, $gte, $lt, $lte, $in, $nin, $exists, $and, $or filter: { $and: [{ genre: { $in: [documentary, comedy] } }, { year: { $gte: 2020 } }], }, includeVector: false, // 设为 true 时在结果中包含原始向量 }); // 结果示例 for (const r of results) { console.log(r.id, r.score, r.metadata /*, r.vector (当 includeVector: true 时) */); }6.2 关键实现细节queryVector 必填S3 Vectors 不支持纯元数据查询缺少queryVector会抛出MastraErrorS3VECTORS_QUERY_MISSING_VECTORqueryVector必须是非空的 float32 数组topK必须为正整数默认值topK默认为10includeVector默认为falseincludeVector 的二次拉取S3 Vectors 的查询响应本身不携带向量数据因此当includeVector: true时实现会对命中的 key 发起一次GetVectorsCommandreturnData: true补齐原始向量见 stores/s3vectors/src/vector/index.ts#L268-L302距离到分数的单调变换查询返回的是距离distance越小越优实现通过score 1 / (1 distance)转换为(0, 1]区间的分数仅改变数值刻度、不改变排序分数越大代表越相似见 stores/s3vectors/src/vector/index.ts#L609-L611过滤为空视为不过滤undefined、null、{}均被翻译器视为空过滤条件直接透传为无过滤查询集成测试handles undefined/empty/null filter覆盖了三种情形。6.3 过滤语法完整操作符参考S3 Vectors 采用基于 JSON 的过滤语法mastra/s3vectors通过内置翻译器S3VectorsFilterTranslator见 stores/s3vectors/src/vector/filter.ts在发送前做翻译与校验。支持的操作符与取值约束如下类别操作符取值约束示例基础比较$eqstring / number / boolean字段直接写值时隐含$eq{ category: electronics }基础比较$nestring / number / boolean{ category: { $ne: electronics } }数值比较$gt/$gtenumberDate会自动转为 epoch 毫秒{ price: { $gt: 100 } }数值比较$lt/$ltenumberDate会自动转为 epoch 毫秒{ price: { $lte: 100 } }数组操作$in非空数组元素为 string / number / boolean{ category: { $in: [electronics, books] } }数组操作$nin非空数组元素为 string / number / boolean{ category: { $nin: [electronics, books] } }逻辑操作$and非空数组可隐式或显式书写{ $and: [{ price: { $gt: 100 } }, { category: electronics }] }逻辑操作$or非空数组{ $or: [{ price: { $lt: 50 } }, { category: books }] }元素操作$existsboolean{ rating: { $exists: true } }明确不支持的语法传入会被拒绝操作符$not、$nor、$regex、$all、$elemMatch、$size、$text以及任何未在上表列出的操作符测试throws on unsupported operators逐一验证见 filter.test.ts顶层直接使用非逻辑操作符如{ $gt: 100 }$and/$or/$in/$nin使用空数组等值位置使用Date、对象或数组数组等值必须改用$in/$ninnull/undefined等值逻辑操作符出现在字段级或操作符内部如{ field: { $and: [...] } }。6.4 翻译器的隐式 AND 规范化值得特别说明的是翻译器会在发送前把隐式 AND规范化为显式$and。例如{ genre: comedy, year: { $gte: 2020 } }会被翻译为{ $and: [{ genre: comedy }, { year: { $gte: 2020 } }] }见 filter.ts 与测试 filter.test.ts。因此在你的应用代码里既可以写显式$and也可以直接并列多个字段两种写法最终都会以 S3 Vectors 认可的形态发送。其他翻译器行为Date 归一化范围操作符$gt/$gte/$lt/$lte与数组元素中的Date会转成 epoch 毫秒但等值位置$eq/$ne/隐式等值不允许Date-0 归一化-0会被归一化为0见 filter.ts点号嵌套字段支持用点号访问嵌套元数据如user.profile.age: { $gt: 25 }见 filter.test.ts同字段多条件同一字段可同时写多个条件如{ price: { $gte: 10, $lte: 50 } }。6.5 复杂过滤示例const results await vectorStore.query({ indexName: my-index, queryVector: [0.1, 0.2 /* ... */], topK: 10, filter: { $and: [ { category: { $in: [electronics, computers] } }, { price: { $gte: 100, $lte: 1000 } }, { $or: [{ stock: { $gt: 0 } }, { preorder: true }], }, ], }, });6.6 供 Agent 使用的内置提示词包内还导出了S3VECTORS_PROMPT见 stores/s3vectors/src/vector/prompt.ts其中完整列出了 S3 Vectors 支持的操作符、示例、不支持的语法以及各类限制如过滤只作用于可过滤的元数据键使用不可过滤键会失败可过滤元数据值必须是原始类型或原始类型数组大段/长文本字段应标记为不可过滤且不能用于过滤。当你在 Agent 工具中动态生成过滤条件时可以把该提示词注入 LLM让模型生成的过滤器严格限定在受支持语法范围内从源头规避使用了不支持操作符而被拒绝的情况。七、向量级更新与删除7.1 按 ID 更新向量 / 元数据// 更新向量与元数据 await vectorStore.updateVector({ indexName: my-index, id: some-vector-id, update: { vector: [0.9, 0.1 /* ... */], metadata: { label: updated } }, }); // 仅更新元数据保留原向量 await vectorStore.updateVector({ indexName: my-index, id: some-vector-id, update: { metadata: { label: updated } }, }); // 仅更新向量保留原元数据 await vectorStore.updateVector({ indexName: my-index, id: some-vector-id, update: { vector: [0.9, 0.1 /* ... */] }, });由于 S3 Vectors 的PutVectors是整体替换语义实现采用先Get当前项 → 合并 → 再Put的策略见 stores/s3vectors/src/vector/index.ts#L418-L477。注意以下行为至少要提供update.vector或update.metadata之一否则报No updates provided若目标 ID 不存在且未提供update.vector会报Vector id not found. Provide update.vector to create it.id必填缺失时抛出MastraErrorS3VECTORS_UPDATE_VECTOR_INVALID_ARGS。集成测试覆盖了三种更新模式及错误分支见 index.test.ts。7.2 按 ID 删除向量await vectorStore.deleteVector({ indexName: my-index, id: some-vector-id });底层调用DeleteVectorsCommand删除后describeIndex().count会相应减少见 index.test.ts。7.3 批量删除暂未实现批量删除接口deleteVectors({ indexName, filter, ids })当前会直接抛出MastraError错误信息为deleteVectors is not yet implemented for S3Vectors vector store错误 IDS3VECTORS_DELETE_VECTORS_NOT_SUPPORTED见 stores/s3vectors/src/vector/index.ts#L512-L524。如需批量清理现阶段可基于listIndexes/query拿到 ID 后逐个调用deleteVector。八、错误处理机制S3Vectors将所有 AWS 层错误统一包装为MastraError附带结构化的错误元数据便于上层捕获与排查见 stores/s3vectors/src/vector/index.ts 中各方法实现错误 ID 形如S3VECTORS_OPERATION_CATEGORY例如S3VECTORS_UPSERT_FAILED、S3VECTORS_QUERY_FAILED、S3VECTORS_DELETE_INDEX_FAILEDdomain为ErrorDomain.STORAGEcategory区分错误来源参数校验类为ErrorCategory.USER调用方问题AWS 服务错误为ErrorCategory.THIRD_PARTY未实现特性为ErrorCategory.SYSTEM错误详情details会携带相关上下文如indexName、dimension、metric等。基于此应用层可以用统一的catch (e: MastraError)分支处理超限、参数错误与服务故障并按category决定是否重试或直接暴露给用户。九、源码结构与测试验证包内源码结构位于 stores/s3vectors/srcvector/index.tsS3Vectors主类实现MastraVector抽象接口的全部方法vector/filter.tsS3VectorsFilterTranslator过滤器翻译器负责操作符校验、隐式 AND 规范化与Date→ epoch 毫秒转换vector/prompt.tsS3VECTORS_PROMPT供 LLM 构造合法过滤条件的提示词vector/filter.test.ts过滤器翻译器的单元测试覆盖全部操作符、错误分支与边界值vector/index.test.ts集成测试需要设置S3_VECTORS_BUCKET_NAME与AWS_REGION或S3_VECTORS_REGION环境变量才会执行否则整组跳过测试覆盖索引创建/归一化/幂等、完整读写查流程、includeVector二次拉取、不同维度含 1536 维、不同度量、过滤校验、向量更新/删除、错误处理等并通过internal/storage-test-utils的createVectorTestSuite工厂跑一遍跨存储的通用向量契约测试。集成测试还印证了一个 S3 Vectors 的显著特性索引写入后立即强一致——upsert之后describeIndex().count立即反映新数量查询无需等待索引刷新waitForIndexing为空实现见 index.test.ts这与其他需要轮询索引就绪的向量库形成鲜明对比。十、限制与注意事项汇总Preview 服务功能、限制、区域可用性均可能随 AWS 调整包本身也可能跟随引入破坏性变更度量仅支持cosine与euclideandotproduct不支持topK 上限S3 Vectors 单次查询上限为 30过滤能力边界操作符是受支持列表的严格子集不支持$regex、$not、$nor、$elemMatch、$size、$text等过滤只能作用于可过滤元数据键大文本字段请通过nonFilterableMetadataKeys声明等值类型受限等值只接受 string / number / booleannull、undefined、对象、数组、Date均不能用于等值查询必须携带向量S3 Vectors 不支持纯元数据查询批量删除未实现deleteVectors会抛未实现错误describeIndex().count为 O(n)内部会分页遍历全部向量计数不要在热路径调用索引名归一化_→-、大写转小写命名时需注意如在多环境共用桶时避免因大小写差异造成混淆。十一、端到端最小示例将以上内容串起来一个最小可运行的完整流程如下import { S3Vectors } from mastra/s3vectors; const vectorStore new S3Vectors({ vectorBucketName: process.env.S3VECTORS_BUCKET!, clientConfig: { region: process.env.AWS_REGION! }, nonFilterableMetadataKeys: [content], // 大段文本不作为过滤键 }); try { // 1. 建索引重复调用幂等 await vectorStore.createIndex({ indexName: products, dimension: 1536, metric: cosine }); // 2. 写入 const ids await vectorStore.upsert({ indexName: products, vectors: [embeddingA, embeddingB], // 各 1536 维 metadata: [ { content: ..., category: electronics, price: 1299, inStock: true }, { content: ..., category: books, price: 45, inStock: false }, ], }); // 3. 带过滤的相似度查询 const results await vectorStore.query({ indexName: products, queryVector: embeddingA, topK: 5, filter: { category: electronics, price: { $gte: 500 } }, // 隐式 AND 会被规范化 includeVector: true, }); for (const r of results) { console.log(r.id, r.score, r.metadata); } } finally { await vectorStore.disconnect(); // 释放底层 HTTP handler }以上流程即构成一个可运行的 S3 Vectors 语义检索基础链路在此基础上你可以将S3Vectors实例注入 Mastra 的 RAG / Memory / Agent 组件复用 Mastra 统一的向量存储抽象。更详细的 API 参考可查阅该包维护的 官方参考文档。【免费下载链接】mastraMastra is the modern TypeScript framework for AI-powered applications and agents.项目地址: https://gitcode.com/GitHub_Trending/ma/mastra创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表