Langchain-Chatchat[四、RAG对话流程代码解析]

文章目录


前言

复制代码
`知识库管理 ' 创建知识库:【智慧城市 (pg @ text-embedding-v1)】,上传文件:"智慧城市.xlsx",
文档向量化加强embedding存储,完成 文档知识库的创建。

本章节主要是基于 知识库,跟踪、分析【知识库做 RAG对话】的流程

1.知识库管理

  • 新创建知识库【智慧城市 (pg @ text-embedding-v1)】*,上传文件 "智慧城市.xlsx"

    智慧城市.xlsx文件:

2.RAG对话

选择知识库 :智慧城市
知识匹配分数阈值 : 0.5
勾 选 :仅返回检索结果

前提
Langchain-Chatchat[一、本地开发环境部署]

知识库管理

PyCharm 配置debug调试参数:start -a


一、RAG对话流程图

RAG对话主流程

流程图生成的AI智能体 mermaid脚本

markup 复制代码
请使用mermaid 根据下面的文案 画一个时序图,请整合到一个图中使用 alt ... end 区分四大主流程。确保图表能正常生成的情况下在考虑友好性
RAG对话主流程
1.入口kb_routes.py#async def kb_chat_endpoint(),调用await kb_chat()
2.kb_chat.py#await kb_chat()
	a.获取向量服务PGKBService:KBServiceFactory.get_service_by_name(kb_name)
		i.加载Pgvector:调用def _load_pg_vector(self),设置参数distance_strategy=cosine (向量索引策略:余弦相似度)
	b.返回EventSourceResponse(knowledge_base_chat_iterator()),返回问答的结果
		i.knowledge_base_chat_iterator()方法:内部执行:
			1.wait run_in_threadpool(search_docs,query=query,...),返回source_documents;知识库文档做相似
			  度查询:kb_doc_api.py#def search_docs(query,knowledge_base_name,top_k...)
			2.将OpenAIChatOutput模型对象转换成Json:yield 	
			  OpenAIChatOutput(....docs=source_documents)).model_dump_json()
		ii.SSE Stream流数据推送,调用EventSourceResponse(OpenAIChatOutput对象Json),见子流程:SSE Stream流数据推送

mermaid在线工具

子流程:知识库文档相似度、分数检索

流程图生成的AI智能体 mermaid脚本

markup 复制代码
请使用mermaid 根据下面的文案 画一个时序图,请整合到一个图中使用 alt ... end 区分四大主流程。确保图表能正常生成的情况下在考虑友好性
子流程:内容增强检索的相似度和分数查询
入口pg_kb_service.py#def do_search(query,top_k,score_threshold)
	a.创建文档检索服务实例VectorstoreRetrieverService,并递归调用vectorstore.py文件class VectorstoreRetrieverService(BaseRetrieverService)类#get_relevant_documents(query,)方法执行查询
	b.递归父类文档检索服务BaseRetriever 抽象方法_get_relevant_documents(query,):retrievals.py文件
	c.父类回调文档检索服务_get_relevant_documents(query,*)方法,此方法内判断search_type等于'similarity_score_threshold'时,调用vectorstores.py#similarity_search_with_relevance_scores(query:智慧城市客服服务人数是多少)相似性分数接口,设置向量索引策略和相似度查询,将异构的向量数据库检索结果标准化,内部执行
		i.设置向量索引策略:relevance_score_fn = self._select_relevance_score_fn()确定向量索引策略余弦相似度cosine;
		ii.相似度查询:similarity_search_with_score(query, k, **kwargs),流程如下:
			1.pgvector.py:调用def similarity_search_with_score(query:智慧城市客服服务人数是多少),对查询内容进行加强embedding:self.embedding_function.embed_query(query);
			2.对加强embedding内容进行向量查询度和分数查询:similarity_search_with_score_by_vector(embedding)
			3.最终调用def __query_collection(embedding)查询向量表langchain_pg_embedding,返回Document对象(内容,分数score)
	d.余弦距离转换成余弦相似度:调用vectorstores.py#_cosine_relevance_score_fn(distance)遍历Document对象(内容,分数score),标准化文档和分数,分数范围在(0.0,1.0)之间,返回docs_and_similarities
	e.相似度检查:遍历docs_and_similarities属性similarity,是否在范围(0.0,1.0)之间
		i.如果不在范围内告警:Relevance scores must be between 0 and 1...);
		ii.在范围内则返回docs_and_similarities

子流程:SSE Stream流数据推送

二、流程核心部分说明

2.1 修改PgVector向量索引策略为余弦相似度:"cosine"

pg_kb_service.py#def _load_pg_vector(self)

代码如下(片断):

python 复制代码
    def _load_pg_vector(self):
        self.pg_vector = PGVector(
            embedding_function=get_Embeddings(self.embed_model),
            collection_name=self.kb_name,
            distance_strategy=DistanceStrategy.COSINE,
            connection=PGKBService.engine,
            connection_string=Settings.kb_settings.kbs_config.get("pg").get("connection_uri"),
        )

说明:修改PGVector 向量索引策略为余弦相似度:"cosine"时,在后续执行 向量相似度和分数检索时才能将 PG向量表内的加强余弦距离转换成余弦相似度,分数控制在(0.0,1.0)之间,否则在检测分数范围时,由于不在范围内告警:Relevance scores must be between 0 and 1...);,无法响应到任何内容。

2.2 内容增强检索的相似度和分数查询

主体入口 vectorstores.py#def similarity_search_with_relevance_scores

python 复制代码
     def similarity_search_with_relevance_scores(
        self,
        query: str,
        k: int = 4,
        **kwargs: Any,
    ) -> List[Tuple[Document, float]]:
       
        score_threshold = kwargs.pop("score_threshold", None) #知识匹配分数阈值 0.5

        # 主体 向量相似度和分数检索
        docs_and_similarities = self._similarity_search_with_relevance_scores(
            query, k=k, **kwargs
        )

        # 在检测分数范围(0.0,1.0)之间,
        if any(
            similarity < 0.0 or similarity > 1.0
            for _, similarity in docs_and_similarities
        ):
            # 不在,告警
            warnings.warn(
                "Relevance scores must be between"
                f" 0 and 1, got {docs_and_similarities}"
            )

        if score_threshold is not None:
            # 分数是否在 知识匹配分数阈值 0.5 之上
            docs_and_similarities = [
                (doc, similarity)
                for doc, similarity in docs_and_similarities
                if similarity >= score_threshold
            ]
            
            # 不在,告警
            if len(docs_and_similarities) == 0:
                warnings.warn(
                    "No relevant docs were retrieved using the relevance score"
                    f" threshold {score_threshold}"
                )
        # 在,返回docs_and_similarities对象,包括:相似的文档内容和分数-similarity
        return docs_and_similarities

说明:PGVector 默认的向量索引策略为最大内积:"l2",在后续执行 向量相似度和分数检索,分数控制会在(0.0,无穷大)间,,由于不在范围内一直告警:Relevance scores must be between 0 and 1...),无法响应到任何内容。

2.2.1 查询内容加强embedding

localai_embeddings.py#

python 复制代码
 def embed_query(self, text: str) -> List[float]:
     """Call out to LocalAI's embedding endpoint for embedding query text.

     Args:
         text: The text to embed.

     Returns:
         Embedding for the text.
     """
     embedding = self._embedding_func(text, engine=self.deployment)
     return embedding


 def _embedding_func(self, text: str, *, engine: str) -> List[float]:
        """Call out to LocalAI's embedding endpoint."""
        # handle large input text
        if self.model.endswith("001"):
            # See: https://github.com/openai/openai-python/issues/418#issuecomment-1525939500
            # replace newlines, which can negatively affect performance.
            text = text.replace("\n", " ")
        return (
            embed_with_retry(
                self,
                input=[text],
                **self._invocation_params,
            )
            .data[0]
            .embedding
        )

def embed_with_retry(embeddings: LocalAIEmbeddings, **kwargs: Any) -> Any:
    """Use tenacity to retry the embedding call."""
    retry_decorator = _create_retry_decorator(embeddings)

    @retry_decorator
    def _embed_with_retry(**kwargs: Any) -> Any:
        response = embeddings.client.create(**kwargs)
        return _check_response(response)

    return _embed_with_retry(**kwargs)

2.2.2 相似度和分数查询

pgvector.py#similarity_search_with_score_by_vector(embedding...)

python 复制代码
 def similarity_search_with_score_by_vector(
        self,
        embedding: List[float],
        k: int = 4,
        filter: Optional[dict] = None,
    ) -> List[Tuple[Document, float]]:
        results = self.__query_collection(embedding=embedding, k=k, filter=filter)

        return self._results_to_docs_and_scores(results)
python 复制代码
    # 向量加强检索 查询
    def __query_collection(
        self,
        embedding: List[float],
        k: int = 4,
        filter: Optional[Dict[str, str]] = None,
    ) -> List[Any]:
        """Query the collection."""
        with Session(self._bind) as session:  # type: ignore[arg-type]
            collection = self.get_collection(session)
            if not collection:
                raise ValueError("Collection not found")

            filter_by = [self.EmbeddingStore.collection_id == collection.uuid]
            if filter:
                if self.use_jsonb:
                    filter_clauses = self._create_filter_clause(filter)
                    if filter_clauses is not None:
                        filter_by.append(filter_clauses)
                else:
                    # Old way of doing things
                    filter_clauses = self._create_filter_clause_json_deprecated(filter)
                    filter_by.extend(filter_clauses)

            _type = self.EmbeddingStore

            results: List[Any] = (
                session.query(
                    self.EmbeddingStore,
                    self.distance_strategy(embedding).label("distance"),  # type: ignore
                )
                .filter(*filter_by)
                .order_by(sqlalchemy.asc("distance"))
                .join(
                    self.CollectionStore,
                    self.EmbeddingStore.collection_id == self.CollectionStore.uuid,
                )
                .limit(k)
                .all()
            )

        return results

3.余弦距离转换成余弦相似度

vectorstores.py#_cosine_relevance_score_fn(distance)

python 复制代码
@staticmethod
  def _cosine_relevance_score_fn(distance: float) -> float:
       """Normalize the distance to a score on a scale [0, 1]."""
       return 1.0 - distance


四、常见问题

问题1:RAG对话:一直告警Relevance scores must be between 0 and 1...),XXXXXXXXX,无法响应到任何内容。

原因:PGVector 默认的向量索引策略为最大内积:"l2",在后续执行 向量相似度和分数检索,分数范围为(0.0,无穷大)间,不在(0,1)范围间。

解决方案:修改PGVector 默认的向量索引策略为弦相似度:COSINE,将向量检索的分数控制在(0,1)范围间.


相关推荐
ServBay1 小时前
Django 6.0 发布,新增原生任务队列与 CSP 支持
后端·python·django
β添砖java1 小时前
python第一阶段第九章异常、模块、包
开发语言·python
2501_941982051 小时前
企业微信Python SDK:高效群发消息实战
开发语言·python·企业微信
yue0081 小时前
C# Environment类的介绍
开发语言·c#·environment
即将进化成人机1 小时前
Spring Boot配置文件
java·开发语言·intellij-idea
龙智DevSecOps解决方案1 小时前
Java开发基础:什么是Spring Boot?一文了解其优势、对比以及如何通过Perforce JRebel实现高效开发
java·开发语言·spring boot·jrebel·perforce·java开发
PPPPickup1 小时前
easychat---创建,获取,获取详细,退群,解散,添加与移除群组
java·开发语言·后端·maven
用户12039112947262 小时前
AIGC 时代,数据库终于可以“听懂人话”了:从零打造自然语言操作 SQLite 的完整实战
python·sqlite·aigc
Q_Q5110082852 小时前
python+django/flask+vue农业电商服务系统
spring boot·python·pycharm·django·flask