当前位置: 首页> 房产> 建材 > 如何实现 Embedding 相似度查询

如何实现 Embedding 相似度查询

时间:2025/7/11 13:53:31来源:https://blog.csdn.net/hawk2014bj/article/details/141861976 浏览次数:0次

Embedding 是 LLM 的重要组件,如果通过 LlamaIndex 进行 Embedding 查询,使用 Vector Index 就可以方便的实现。如果我们想自己实现 Embedding 的相似度计算呢?Embedding 的流程是调用 Embedding 模型,模型返回向量,查询向量,自己实现的好处是不需要依赖 LlamaIndex,可以自己实现Vector存储、Vector 查询。这里我们可以借鉴 LlamaIndex 的实现方式,LlamaIndex 多种 Index,SummaryIndex 默认是返回所有的节点,同时也支持 Embedding 和 LLM 进行搜索。本文根据 SummaryIndex 的实现方式,实现自己的 Embedding 的相似度查询。

创建 Embedding

Embedding 是通过模型生成向量,LlamaIndex中,所有 Model 都是继承自 BaseEmbedding,通过get_query_embedding 获取向量,Ollama Embedding 创建 Vector。

from llm import get_ollama_embbedingembed_model = get_ollama_embbeding()
res = embed_model.get_query_embedding("北京")

LlamaIndex 调用 Ollama API 获取 Embedding,可以通过 Ollama 的 Python 库自行调用。
在这里插入图片描述
生成向量:
在这里插入图片描述

相似度

有了 Embedding 向量之后,接下来就是找相似度了,参考 LlamaIndex 中 SummaryIndex 中的 SummaryIndexEmbeddingRetriever,_retrieve 函数代码如下,首先获取所有的 Nodes,随后将生成 Vector,最后相似度计算:

def _retrieve(self,query_bundle: QueryBundle,) -> List[NodeWithScore]:"""Retrieve nodes."""node_ids = self._index.index_struct.nodes# top k nodesnodes = self._index.docstore.get_nodes(node_ids)query_embedding, node_embeddings = self._get_embeddings(query_bundle, nodes)top_similarities, top_idxs = get_top_k_embeddings(query_embedding,node_embeddings,similarity_top_k=self._similarity_top_k,embedding_ids=list(range(len(nodes))),)top_k_nodes = [nodes[i] for i in top_idxs]node_with_scores = []for node, similarity in zip(top_k_nodes, top_similarities):node_with_scores.append(NodeWithScore(node=node, score=similarity))logger.debug(f"> Top {len(top_idxs)} nodes:\n")nl = "\n"logger.debug(f"{nl.join([n.get_content() for n in top_k_nodes])}")return node_with_scores

下面的方法是是计算 Query 与 Node 之间的相似度,默认算法是余弦相似度算法,方法比较简单,相似度算法可以通过 similarity_fn 进行自定义。

def get_top_k_embeddings(query_embedding: List[float],embeddings: List[List[float]],similarity_fn: Optional[Callable[..., float]] = None,similarity_top_k: Optional[int] = None,embedding_ids: Optional[List] = None,similarity_cutoff: Optional[float] = None,
) -> Tuple[List[float], List]:"""Get top nodes by similarity to the query."""if embedding_ids is None:embedding_ids = list(range(len(embeddings)))similarity_fn = similarity_fn or default_similarity_fnembeddings_np = np.array(embeddings)query_embedding_np = np.array(query_embedding)similarity_heap: List[Tuple[float, Any]] = []for i, emb in enumerate(embeddings_np):similarity = similarity_fn(query_embedding_np, emb)if similarity_cutoff is None or similarity > similarity_cutoff:heapq.heappush(similarity_heap, (similarity, embedding_ids[i]))if similarity_top_k and len(similarity_heap) > similarity_top_k:heapq.heappop(similarity_heap)result_tups = sorted(similarity_heap, key=lambda x: x[0], reverse=True)result_similarities = [s for s, _ in result_tups]result_ids = [n for _, n in result_tups]return result_similarities, result_ids

similarity_fn 主要包括三种(欧氏距离、点积和余弦),LlamaIndex 中的实现如下,使用 NP 库实现。

def similarity(embedding1: Embedding,embedding2: Embedding,mode: SimilarityMode = SimilarityMode.DEFAULT,
) -> float:"""Get embedding similarity."""if mode == SimilarityMode.EUCLIDEAN:# Using -euclidean distance as similarity to achieve same ranking orderreturn -float(np.linalg.norm(np.array(embedding1) - np.array(embedding2)))elif mode == SimilarityMode.DOT_PRODUCT:return np.dot(embedding1, embedding2)else:product = np.dot(embedding1, embedding2)norm = np.linalg.norm(embedding1) * np.linalg.norm(embedding2)return product / norm

根据上面的逻辑,实现自己的相似度算法,这里只用余弦,这里使用英文做测试,nomic-embed-text 这个模型中文能力不行。

import numpy as np
def similarity(embedding1: list[float],embedding2: list[float]
) -> float:"""Get embedding similarity."""product = np.dot(embedding1, embedding2)norm = np.linalg.norm(embedding1) * np.linalg.norm(embedding2)return product / normfrom llm import get_ollama_embbedingembed_model = get_ollama_embbeding()
res1 = embed_model.get_query_embedding("The sun is shining brightly over the clear blue sky, and birds are chirping cheerfully.")
res2 = embed_model.get_query_embedding("The stock market faced a significant downturn today due to rising inflation concerns.")
res3 = embed_model.get_query_embedding("The cat is sitting on the windowsill, basking in the warm sunlight.")
res4 = embed_model.get_query_embedding("The feline rests on the windowsill, enjoying the warmth of the sun.")similarity(res1, res2), similarity(res3, res4)

在这里插入图片描述

总结

通过参考 LlamaIndex 的代码,本文实现了向量相似度算法,自己实现相似度算法比较简单,开发、测试也不用依赖过多的第三方库,如果使用其他语言,也容易实现。

关键字:如何实现 Embedding 相似度查询

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: