dify实现分析-rag-内容检索rerank的两种实现

dify实现分析-rag-内容检索rerank的两种实现

概述

本文介绍dify的rerank的实现原理。rerank可以对检索到的多个文档进行重排序。通过重排序可以找到更加合适的文档分块。

dify中的两种rerank实现方式

dify中提供两种rerank的方式:

  • 使用rerank模型:一种是通过rerank模型来直接对输入文档列表(documents)和问题(query)的相关性进行评估,打分,并返回与问题最合适的文档列表。
  • 根据权重计算:嵌入向量以及文档分词与query相似度的综合分数。先对文档和query进行分词处理,然后计算每个文档和query的相似度分数;在对文档列表以及query进行向量化处理,并计算每个文档和query向量的相似度分数。然后根据权重把两者的分数和权重相乘,并加起来。就得到了每个文档的最终相似度。然后取分数最大的top_n个文档。

rerank的两种rerank模式的定义代码如下:

class RerankRunnerFactory:
    @staticmethod
    def create_rerank_runner(runner_type: str, *args, **kwargs) -> BaseRerankRunner:
        match runner_type:
            case RerankMode.RERANKING_MODEL.value:
                return RerankModelRunner(*args, **kwargs)
            case RerankMode.WEIGHTED_SCORE.value:
                return WeightRerankRunner(*args, **kwargs)
            case _:
                raise ValueError(f"Unknown runner type: {runner_type}")

权重rerank的实现:WeightRerankRunner

基于权重的rerank是在WeightRerankRunner.run()函数中实现的,该函数的实现逻辑如下:

  1. 相对document进行去重处理
  2. 使用BM25算法对query和每个doucment进行分词处理,并计算每个文档和query的相似度分数。这样就得到每个document和query的相似度分数。
  3. 对query和document进行向量化处理,并计算每个document和query向量的相似度分数。这样就得到每个document和query的向量的相似度分数。
  4. 针对每个document:将基于分词和向量的两个分数按照给定的权重综合计算,得到每个document和query相似度的最终评分。
  5. 根据document的得分对其进行排序,并选择得分最高的top_n的个document返回。

WeightRerankRunner中rerank的实现代码如下:

class WeightRerankRunner(BaseRerankRunner):
	def run(
        self,
        query: str,
        documents: list[Document],
        score_threshold: Optional[float] = None,
        top_n: Optional[int] = None,
        user: Optional[str] = None,
    ) -> list[Document]:
        """
        Run rerank model
        :param query: search query
        :param documents: documents for reranking
        :param score_threshold: score threshold
        :param top_n: top n
        :param user: unique user id if needed

        :return:
        """
        docs = []
        doc_id = []
        unique_documents = []
        # 对文档列表去重
        for document in documents:
            if document.metadata["doc_id"] not in doc_id:
                doc_id.append(document.metadata["doc_id"])
                docs.append(document.page_content)
                unique_documents.append(document)

        documents = unique_documents

        rerank_documents = []
        # 对query和每个文档分块进行分词处理,并计算每个文档和query的相似度分数。
        query_scores = self._calculate_keyword_score(query, documents)

        # 对query和document进行向量化处理,并计算每个document和query向量的相似度分数
        query_vector_scores = self._calculate_cosine(self.tenant_id, query, documents, self.weights.vector_setting)
        # 针对每个document:将基于分词和向量的两个分数按照给定的权重综合计算,得到最终的评分
        for document, query_score, query_vector_score in zip(documents, query_scores, query_vector_scores):
            # format document
            # 计算综合得分
            score = (
                self.weights.vector_setting.vector_weight * query_vector_score
                + self.weights.keyword_setting.keyword_weight * query_score
            )
            # 如果设置了 score_threshold 且文档的综合评分为负数,则跳过
            if score_threshold and score < score_threshold:
                continue
            # 添加文档的综合评分到元数据中
            document.metadata["score"] = score
            rerank_documents.append(document)
        # 将所有符合要求的文档按分数从高到低排序。
        rerank_documents = sorted(rerank_documents, key=lambda x: x.metadata["score"], reverse=True)
        # 根据 top_n 参数返回评分最高的前 N 个文档;如果不设置 top_n,则返回所有符合条件的文档。
        return rerank_documents[:top_n] if top_n else rerank_documents

使用rerank模型的实现:RerankModelRunner

使用rerank模型来实现document的rerank的实现比较简单,实现逻辑如下:

  1. 对document进行去重处理,若是dify文档,记录doc_id。
  2. 调用rerank模型来对document进行重拍处理,并输出重排序后的document列表。这里要注意,rerank模型的输入参数:
     rerank_result = self.rerank_model_instance.invoke_rerank(
            query=query, docs=docs, score_threshold=score_threshold, top_n=top_n, user=user
        )
  1. 格式化重新排序后的document,生成Document对象,并把排序后的分数添加到document.metadata[“score”]字段中。

说明:rerank模型是用户通过页面配置的。

使用rerank模型实现的代码如下:

class RerankModelRunner(BaseRerankRunner):
    def __init__(self, rerank_model_instance: ModelInstance) -> None:
        self.rerank_model_instance = rerank_model_instance

    def run(
        self,
        query: str,
        documents: list[Document],
        score_threshold: Optional[float] = None,
        top_n: Optional[int] = None,
        user: Optional[str] = None,
    ) -> list[Document]:
        """
        Run rerank model
        :param query: search query
        :param documents: documents for reranking
        :param score_threshold: score threshold
        :param top_n: top n
        :param user: unique user id if needed
        :return:
        """
        docs = []
        doc_id = set()
        unique_documents = []
        # 对文档列表去重,针对dify的文档,记录doc_id
        for document in documents:
            if document.provider == "dify" and document.metadata["doc_id"] not in doc_id:
                doc_id.add(document.metadata["doc_id"])
                docs.append(document.page_content)
                unique_documents.append(document)
            elif document.provider == "external":
                if document not in unique_documents:
                    docs.append(document.page_content)
                    unique_documents.append(document)

        documents = unique_documents

        # 调用rerank模型对文档进行重排,该方法返回一个包含重新排序后的document(如文本和索引)
        rerank_result = self.rerank_model_instance.invoke_rerank(
            query=query, docs=docs, score_threshold=score_threshold, top_n=top_n, user=user
        )

        rerank_documents = []

        # 格式化重新排序后的文档
        for result in rerank_result.docs:
            # format document
            rerank_document = Document(
                page_content=result.text,
                metadata=documents[result.index].metadata,
                provider=documents[result.index].provider,
            )
            # 将重新排序后的分数添加到新文档的元数据中
            rerank_document.metadata["score"] = result.score
            # 添加到rerank_documents结果列表中
            rerank_documents.append(rerank_document)

        return rerank_documents

说明:dify支持多种rerank模型的实现,都继承了RerankModel类。

总结

本文介绍了dify的两种rerank方式的实现。目前dify中支持2种rerank方式,一种通过rerank模型来实现,一种是通过计算分词和向量与query的相似度来实现。另外,dify支持多种rerank模型,可以根据需要进行选择。

### 部署 Dify Rerank 模型 为了在本地环境中部署 DifyRerank 模型,需遵循一系列特定的操作流程来确保模型能够正常运行并提供高效的检索服务。 #### 准备环境 安装必要的依赖项和工具包对于构建稳定的工作环境至关重要。建议使用 Python 虚拟环境管理器如 `venv` 或者 `conda` 来隔离项目所需的软件包版本[^1]。 ```bash python -m venv myenv source myenv/bin/activate # Linux or macOS myenv\Scripts\activate # Windows pip install --upgrade pip setuptools wheel ``` #### 安装 Xinference 和其他组件 Xinference 是用于加载和管理各种 AI 模型的服务框架,在此场景下负责托管 Rerank 模型实例。通过 Pip 可以方便地获取最新发布的官方发行版: ```bash pip install xinference ``` 除了 Xinference 外,还需根据具体需求安装额外的支持库,比如 Transformers 库以便处理自然语言理解任务中的文本编码工作;以及 FastAPI 或 Flask 等 Web 框架用来创建 RESTful API 接口供外部调用访问已部署好的模型服务[^2]。 #### 下载预训练模型文件 前往指定资源页面下载适用于目标应用场景的预训练权重参数集,并将其放置于合适的位置等待后续加载操作。通常情况下这些二进制数据会被保存成 `.bin`, `.pt`, 或 `.ckpt` 文件格式。 #### 启动 Xinference Server 并加载模型 启动服务器之前先确认所有前置条件均已满足——即完成了上述准备工作之后再继续执行下面这一步骤。利用命令行界面传递相应选项给程序入口脚本从而初始化 HTTP(S)监听端点及关联业务逻辑处理器件。 ```bash xinference serve & ``` 接着向正在运行着的应用发送 POST 请求告知其准备就绪状态下的新成员加入通知消息体中携带有关待导入对象的关键描述信息(例如名称、路径等),这样就能让平台识别到新增加进来的大规模神经网络结构了。 ```json { "model_name": "dify-rerank", "path_to_model_weights": "/path/to/downloaded/model" } ``` 最后可以通过浏览器或者 Postman 工具测试接口响应情况验证整个过程是否顺利完成。当一切按计划行事时应该能够在返回的数据包里面发现预期之内的条目列表展示出刚刚上传成功的那个实体记录。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值