FlagOpen / FlagEmbedding

Retrieval and Retrieval-augmented LLMs
MIT License
6.71k stars 480 forks source link

BGE-M3如何在RAG应用中使用Hybrid Retrieve #458

Open weiminw opened 6 months ago

weiminw commented 6 months ago

首先感谢BGE提供的这么强大的模型, 我们在之前的RAG应用中, 对企业的文档通过BGE将资料转成向量存储到milvus中, 用户查询时通过dense retrieve 从milvus召回文档,我们使用的是langchain作为框架. 请问如果用BGE配合使用做 dense+sparse retrieve 有没有例子可以参考. 目前是在不知道如何进行. 万分感谢.

weiminw commented 6 months ago

我能想到的使用流程大概是这样的, 对原始的文档, 通过BGE-M3 进行向量化, 由于M3 可以同时返回dense 和 sparse embeding. 将两种向量同时存入miluvs中不同的列, 检索的时候, 使用M3 将query同时向量化dense和sparse 同时进行检索. 获得dense+ sparse 再进行rerank. 这个思路是否正确?

staoxiao commented 6 months ago

感谢对我们工作的关注! sparse embeding不能像dense embedding那样使用,需要其他方法建立索引。目前miluvs似乎已经支持sprase索引,参考https://github.com/milvus-io/milvus/issues/29419 。后面我们会逐步与开源社区合作把混合检索这块弄得更简单使用。

建好索引后,可让dense和sparse索引分别检索一部分数据,再获得dense+ sparse进行重排,也可以利用其他方法重排。

weiminw commented 6 months ago

非常感谢您的回复,祝新年快乐,bge越来越好

Mrfranken commented 6 months ago

@weiminw @staoxiao hi, 不好意思打扰了。最近拜读了贵项目文件夹目录下MLDR的相关检索代码。 其中包含了spaser和dense结合FAISS的应用,请问是否有关于multi-vector(Colbert)结合FAISS的示例呢。我查阅了很多资料,似乎都没有Colbert verctor和FAISS结合的例子,先感谢您的回复了~

Mrfranken commented 6 months ago

@weiminw BTW , MLDR目录下似乎已经有了使用hybrid检索的例子,您可以看一下

staoxiao commented 6 months ago

@weiminw @staoxiao hi, 不好意思打扰了。最近拜读了贵项目文件夹目录下MLDR的相关检索代码。 其中包含了spaser和dense结合FAISS的应用,请问是否有关于multi-vector(Colbert)结合FAISS的示例呢。我查阅了很多资料,似乎都没有Colbert verctor和FAISS结合的例子,先感谢您的回复了~

multi-vector(Colbert)在第一阶段比较难使用,空间和时间消耗都很大,该向量需要进一步压缩,暂时不推荐使用。

aus70 commented 6 months ago

qdrant 支持稠密向量和稀疏向量,我打算试一试,实现 Vespa 使用的加权稠密/稀疏/科尔伯特检索。

Mrfranken commented 6 months ago

qdrant 支持稠密向量和稀疏向量,我打算试一试,实现 Vespa 使用的加权稠密/稀疏/科尔伯特检索。

hi 请问您qdrant研究有进展吗,能否交流一下

aus70 commented 6 months ago

我刚刚完成了我的小型平台,该平台可以批量处理文档,并将嵌入内容保存为 avro 格式。我使用 Podman 而不是 Docker 启动了一个 qdrant 实例,没有出现任何问题。今天晚些时候,我将开始为向量编制索引,并向大家汇报进展情况。

Mrfranken commented 6 months ago

我刚刚完成了我的小型平台,该平台可以批量处理文档,并将嵌入内容保存为 avro 格式。我使用 Podman 而不是 Docker 启动了一个 qdrant 实例,没有出现任何问题。今天晚些时候,我将开始为向量编制索引,并向大家汇报进展情况。

If you could, could u make a tutorial for how to use podman to run qdrant and combine them with BGE M3, I think that will be great!

dl942702882 commented 5 months ago

qdrant 支持稠密向量和稀疏向量,我打算试一试,实现 Vespa 使用的加权稠密/稀疏/科尔伯特检索。

我刚才试过了,本地模式下,还是采用的暴力求解的方式,通过计算2个稀疏向量的dot #product后排序完成检索过程(https://github.com/qdrant/qdrant-client/blob/master/qdrant_client/local/sparse.py#L60);

不过这不是我想要的,在大数据集下,应该有一种合适的存储 & 索引机制同时能够满足 低成本的存储 以及 高效的topn检索。跟dense向量类似。

qdrant的代码可以参考下面的:

from qdrant_client import QdrantClient, models

COLLECTION_NAME = "sparse_collection"

def cal_text_sparse(text):
    query = bge_m3.encode([text],
                          return_dense=True, return_sparse=True, return_colbert_vecs=True)
    query_sparse = query['lexical_weights'][0]
    print(query_sparse)
    query_sparse_indices = list(query_sparse.keys())
    query_sparse_values = list(query_sparse.values())
    return query_sparse_indices, query_sparse_values

if __name__ == '__main__':

    client = QdrantClient(":memory:")
    client.recreate_collection(
        collection_name=COLLECTION_NAME,
        vectors_config={},
        sparse_vectors_config={
            "text": models.SparseVectorParams(
                index=models.SparseIndexParams(
                    on_disk=True,
                )
            )
        },
    )
    doc1_indices, doc1_values = cal_text_sparse("北京是中国的首都")
    doc2_indices, doc2_values = cal_text_sparse("原神是米哈游开发的一款画质精美的二次元游戏")
    doc3_indices, doc3_values = cal_text_sparse("腾讯是中国的一家游戏,社交公司,开发了王者荣耀")
    doc4_indices, doc4_values = cal_text_sparse("众神派对是一款不氪金的手游,画质非常不错")
    client.upsert(
        collection_name=COLLECTION_NAME,
        points=[
            models.PointStruct(
                id=1,
                payload={},
                vector={
                    "text": models.SparseVector(
                        indices=doc1_indices, values=doc1_values
                    )
                },
            ),
            models.PointStruct(
                id=2,
                payload={},
                vector={
                    "text": models.SparseVector(
                        indices=doc2_indices, values=doc2_values
                    )
                },
            ),
            models.PointStruct(
                id=3,
                payload={},
                vector={
                    "text": models.SparseVector(
                        indices=doc3_indices, values=doc3_values
                    )
                },
            ),
            models.PointStruct(
                id=4,
                payload={},
                vector={
                    "text": models.SparseVector(
                        indices=doc4_indices, values=doc4_values
                    )
                },
            )
        ],
    )

    # Preparing a query vector
    query_text = "给我推荐一个画质漂亮的手游吧"
    query_indices, query_values = cal_text_sparse(query_text)
    # Searching for similar documents
    result = client.search(
        collection_name=COLLECTION_NAME,
        query_vector=models.NamedSparseVector(
            name="text",
            vector=models.SparseVector(
                indices=query_indices,
                values=query_values,
            ),
        ),
        with_vectors=True,
    )
    print(len(result))

    for item in result:
        print(item)
staoxiao commented 5 months ago

The new version of Milvus has been released. Now, you can use the hybrid retrieval of bge-m3 following https://github.com/milvus-io/pymilvus/blob/master/examples/hello_hybrid_sparse_dense.py

c121914yu commented 5 months ago

The new version of Milvus has been released. Now, you can use the hybrid retrieval of bge-m3 following https://github.com/milvus-io/pymilvus/blob/master/examples/hello_hybrid_sparse_dense.py

似乎就是分别计算2个向量得分后通过RRF进行重新排序。

Mycroft-s commented 5 months ago

The new version of Milvus has been released. Now, you can use the hybrid retrieval of bge-m3 following https://github.com/milvus-io/pymilvus/blob/master/examples/hello_hybrid_sparse_dense.py

@staoxiao @c121914yu 不好意思打扰了,感谢BGE模型卓越的性能,请问对于[dense,sparse]的混合搜索结果,能否有方法使用大模型的api进行rerank。目前设计的hybrid_earch方法似乎是根据两种向量的相似度得分用RRF进行rerank的,貌似都是基于milvus的向量之间的重排。您觉得对于RRF之后的结果使用大模型再次重排是否有必要。以及能否有机会针对两种向量使用大模型对于语义进行混合的重排,我们之前的RAG模块是用dense向量找到文本对于文本进行大模型的重排序。再次感谢BGE做出的不可替代的贡献。