ITPub博客

首页 > 人工智能 > 人工智能 > 在 Spring AI 2.1 中使用你自己的嵌入

在 Spring AI 2.1 中使用你自己的嵌入

人工智能 作者:ITPUB社群 时间:1970-01-01 08:33:46 0 删除 编辑

VectorStore.add() 接收文本文档,使用存储配置的模型生成嵌入,并保存两者。Spring AI 2.1 为已经拥有嵌入或从图像、视频或音频生成嵌入的应用程序新增了 upsert。它接受与应用程序提供的向量配对的文档,而不调用存储的嵌入模型。新的 similaritySearch 重载也接受查询嵌入,让应用程序同时控制索引和搜索。

何时提供你自己的嵌入

让我们看一个真实世界的例子。考虑一个家具目录,其中列有一个产品为“扶手椅,型号 A42”。它的照片显示绿色天鹅绒软垫和木腿,但如果描述中缺少这些细节,搜索“绿色天鹅绒扶手椅”可能会错过它。

多模态嵌入模型生成可以直接比较的图像和文本嵌入,让搜索将客户的话与照片匹配。应用程序使用 upsert 存储照片嵌入,然后使用同一模型嵌入搜索文本以找到最接近的匹配。

如果模型支持将该内容与文本查询进行比较,视频或音频搜索的工作方式类似。例如,存储关于更换过滤器(04:00 到 04:30)的训练视频片段的嵌入,并在元数据中包含视频 URL 以及开始和结束时间。搜索“如何更换过滤器”然后可以返回一个结果,应用程序在 04:00 打开它。

现有的文本嵌入也受益,无论它们来自提供商的批处理 API(应用程序编程接口)、另一个团队还是数据库迁移。add() 会再次生成它们。直接写入数据库避免了这一点,但需要匹配 Spring AI 的字段名称和格式,用于 ID、文本、元数据和向量,以便它可以读取和搜索记录。upsert 为你处理该存储格式。

索引产品图像

对于家具目录,假设我们使用 Spring AI 的 VertexAiMultimodalEmbeddingModel,它支持文本、图像和视频。下面的示例使用这两个字段:

private final VertexAiMultimodalEmbeddingModel multimodal;

private final VectorStore vectorStore;

首先,我们为产品照片生成嵌入,并将其与我们要存储的文档配对:

Document photo = Document.builder()
    .media(new Media(MimeTypeUtils.IMAGE_JPEG, product.photo()))
    .build();
float[] vector = this.multimodal.call(new DocumentEmbeddingRequest(photo)).getResult().getOutput();

Document row = Document.builder()
    .id(UUID.nameUUIDFromBytes(product.sku().getBytes(UTF_8)).toString())
    .text("")
    .metadata(DocumentMetadata.CONTENT_REF.value(), product.photoUrl())
    .metadata("sku", product.sku())
    .metadata("inStock", product.inStock())
    .build();

this.vectorStore.upsert(List.of(new EmbeddedDocument(row, vector)));

photo 携带发送给模型的图像;row 保存产品元数据和照片引用。EmbeddedDocument 将 row 与图像嵌入(即 vector)配对。

Document 需要文本或媒体。当前的向量存储实现会持久化 ID、文本、元数据和向量,并使用这些字段重建搜索结果。它们会拒绝照片等媒体 Document,因为无法持久化其媒体内容。上面使用 .text("") 可保持行有效,同时照片保留在外部存储中;upsert 永远不会嵌入该空文本。.text(...) 中的产品描述会被保存并随搜索结果返回,但 upsert 仍会使用提供的图像嵌入,而不会嵌入该描述。

DocumentMetadata.CONTENT_REF 在元数据中保存照片的 URL。应用程序使用它来显示搜索结果;Spring AI 不会获取该照片。

运行此示例之前,请确保向量存储的维度与模型的输出匹配。例如,对于 1408 维嵌入,请设置 PGvector 的 spring.ai.vectorstore.pgvector.dimensions=1408,或在其 builder 上使用 dimensions(1408)。现有表的向量列也必须具有兼容的维度。

使用查询嵌入进行搜索

使用相同的多模态模型嵌入客户的搜索文本:

float[] query = this.multimodal.call(new DocumentEmbeddingRequest(new Document("green velvet armchair")))
    .getResult()
    .getOutput();

Listchairs = this.vectorStore.similaritySearch(query,
        SearchRequest.builder().topK(12).filterExpression("inStock == true").build());

similaritySearch(float[], SearchRequest) 使用提供的向量,而不调用存储的嵌入模型。该请求控制 topK、相似度阈值和元数据过滤器;任何查询文本都会被忽略。

使用专为比较图像和文本而设计的模型生成产品图像和查询文本嵌入。使用不相关的模型进行查询可能会产生无意义的结果,即使其嵌入具有相同的维度数。使用接受查询文本的重载时请记住这一点:它使用存储配置的嵌入模型。

遵循模型推荐的输入设置来索引内容和嵌入查询;使用错误的设置可能会降低搜索相关性。如果之后更改模型,您可能需要重新生成存储的嵌入。将模型名称和版本保留在元数据中有助于识别哪些 Document 需要更新。

更新现有 Document

upsert 会插入具有新 ID 的 Document,并替换具有现有 ID 的 Document,因此如上例中那样从产品 SKU 派生的稳定 ID 可让索引作业更新照片而不会创建重复项。此替换约定适用于所有支持的存储;对于 add(),重复 ID 的行为取决于存储。

每次 upsert 调用接受一个 Document 列表及其嵌入。空列表会直接返回而不写入任何内容。单次调用内的写入不保证具有事务性:如果其中一个失败,调用会抛出异常,但某些 Document 可能已经写入。在解决原因后,使用相同的 ID 和输入重试整个列表。

向量验证

EmbeddedDocument 在构造时会拒绝空向量和非有限值(NaN 或无穷大)。当存储知道其索引维度时,会在写入前检查列表中的每个向量,因此维度不匹配会阻止任何写入。这些检查无法检测不兼容的嵌入空间。

Spring AI 从配置中或通过读取现有索引、表或集合来获取预期的向量大小。只有在创建索引且未指定大小时,才会向嵌入模型查询维度。

如果 Spring AI 无法读取索引的预期向量大小且未配置任何大小,除 Redis 之外的存储仍会将向量发送到数据库,由数据库执行自己的大小检查。Spring AI 会在下一次调用时再次尝试读取预期大小。

Redis 可以保存大小错误的向量而不报告错误,但该文档不会出现在向量搜索结果中。为防止这种情况,RedisVectorStore 在无法确定预期大小时会在写入前抛出异常。请配置与 Redis 索引匹配的维度,或确保索引存在且可读,然后重试。

向量存储支持

VectorStore.upsert(List

截至 Spring AI 2.1.0-RC1,PGvector、Redis、Elasticsearch、Qdrant 和 OpenSearch 均支持 upsert 以及使用查询嵌入进行搜索。

对于扩展 AbstractObservationVectorStore 的存储,请实现 doUpsert 和 doSimilaritySearch(float[], SearchRequest),并重写 supportsUpsert() 和 supportsQueryEmbeddingSearch() 使其返回 true。基类会在创建观测之前检查支持情况,并将 upsert 作为单独操作记录在向量存储指标中。

现有应用程序可以继续使用 add() 让存储为文本文档生成嵌入。



转载声明:本文为转载整理,原文版权归原作者及原站点所有。

原文来源:Spring Blog

原创地址:https://spring.io/blog/2026/10/28/spring-ai-upsert-own-embeddings

原文作者:Spring Blog;如有侵权,请联系管理员删除。

请登录后发表评论 登录
全部评论

注册时间:2022-11-21

  • 博文量
    1255
  • 访问量
    560951