检索
介绍
存在许多不同类型的检索系统,包括向量库、图数据库和关系数据库。
随着大型语言模型的兴起,检索系统已成为人工智能应用(如RAG)的重要组成部分。
由于其重要性和可变性,LangChain为与不同类型的检索系统交互提供了统一的接口。
LangChain检索器接口很简单:
输入:查询(字符串)
输出:一个文档列表(标准化的LangChain文档对象)
检索
介绍
存在许多不同类型的检索系统,包括向量库、图数据库和关系数据库。
随着大型语言模型的兴起,检索系统已成为人工智能应用(如RAG)的重要组成部分。
由于其重要性和可变性,LangChain为与不同类型的检索系统交互提供了统一的接口。
LangChain检索器接口很简单:
输入:查询(字符串)
输出:一个文档列表(标准化的LangChain文档对象)
使用向量库检索
- import os
- import sys
- sys.path.append("..")
- from embed.Local_ai_embeddings import LocalAIEmbeddings
- base_url = 'http://xxxx/v1'
- api_key = 'EMPTY'
- no_proxy = 'xxxx'
- os.environ['NO_PROXY'] = no_proxy
- apiEmbed2 = LocalAIEmbeddings(
- base_url=base_url,
- model='bge-m3',
- api_key=api_key,
- max_retries=1,
- deployment = 'bge-m3'
- )
- apiEmbed2.embed_query("你好")
复制代码- from pymilvus import Collection
- # from langchain_community.vectorstores import Milvus
- from langchain_milvus import Milvus
- host = 'xxxx'
- port = xxx
- user = ''
- password= ''
- db_name='default'
- connection_args={
- "uri": f"http://{host}:{port}",
- "host": host,
- "port": port,
- "user": user,
- "password": password,
- "secure": False,
- 'db_name': db_name
- }
复制代码 VectorStoreRetriever
支持检索的类型:"similarity", "similarity_score_threshold", "mmr",
使用方法- vectorstore.as_retriever(search_type="similarity")
复制代码 检索参数,milvus默认配置
- self.default_search_params = {
- "IVF_FLAT": {"metric_type": "L2", "params": {"nprobe": 10}},
- "IVF_SQ8": {"metric_type": "L2", "params": {"nprobe": 10}},
- "IVF_PQ": {"metric_type": "L2", "params": {"nprobe": 10}},
- "HNSW": {"metric_type": "L2", "params": {"ef": 10}},
- "RHNSW_FLAT": {"metric_type": "L2", "params": {"ef": 10}},
- "RHNSW_SQ": {"metric_type": "L2", "params": {"ef": 10}},
- "RHNSW_PQ": {"metric_type": "L2", "params": {"ef": 10}},
- "IVF_HNSW": {"metric_type": "L2", "params": {"nprobe": 10, "ef": 10}},
- "ANNOY": {"metric_type": "L2", "params": {"search_k": 10}},
- "SCANN": {"metric_type": "L2", "params": {"search_k": 10}},
- "AUTOINDEX": {"metric_type": "L2", "params": {}},
- "GPU_CAGRA": {
- "metric_type": "L2",
- "params": {
- "itopk_size": 128,
- "search_width": 4,
- "min_iterations": 0,
- "max_iterations": 0,
- "team_size": 0,
- },
- },
- "GPU_IVF_FLAT": {"metric_type": "L2", "params": {"nprobe": 10}},
- "GPU_IVF_PQ": {"metric_type": "L2", "params": {"nprobe": 10}},
- }
- # milvus初始化的时候默认设置的值
- primary_field: str = "pk",
- text_field: str = "text",
- vector_field: str = "vector",
复制代码 similarity(默认)
底层调用关系是通过Milvus初始化的时候成员属性self.col: Optional[Collection] = None进行操作的- res = self.col.search(
- data=[embedding],
- anns_field=self._vector_field,
- param=param,
- limit=k,
- expr=expr,
- output_fields=output_fields,
- timeout=timeout,
- **kwargs,
- )
复制代码 col对象是pymilvus中的Collection对象
- data=[embedding], 传的是向量化的数据
- anns_field=self._vector_field, 向量化的字段
- param=param, 检索参数
- limit=k, topk
- expr=expr, 过滤条件
- output_fields=output_fields, 输出字段
- timeout=timeout, 超时时间
接下来我们用langchain实现所有的参数的信息
底层调用方法是:- res = self.similarity_search_with_score(
- query=query, k=k, param=param, expr=expr, timeout=timeout, **kwargs
- )
复制代码 对应的参数来源search_kwargs
这个kwargs参数用invoke传递一下
默认有如下几个参数- kwargs = {"k": 1, "param": {}, "expr": "", "timeout":30}
复制代码k 代表取得分最高的topn
param 代表索引参数,默认参考default_search_params,这里我设置为:{'metric_type': 'IP', 'params': {'ef': 10}}
expr 代表筛选的字段条件参数
timeout 查询超时时间
可以通过vectorstore.fields获取对应的字段列表
- # Step 2: 获取原始集合
- vectorstore = Milvus(
- collection_name='T_AI_WORD_CHAT_EXAMPLE_TEST',
- connection_args=connection_args,
- embedding_function=apiEmbed2
- )
- # 实例化一个检索器
- retriever = vectorstore.as_retriever(search_type = 'similarity', search_kwargs={"k": 5})
- # 默认按照相似度检索
- docs = retriever.invoke("what did the president say about ketanji brown jackson?")
- print(f'basic retriever: {len(docs)}')
- print(docs)
复制代码
- from pymilvus import connections, FieldSchema, CollectionSchema, DataType, Collection, utility, MilvusClient
- # 连接 Milvus
- connections.connect(**connection_args)
- # 定义字段(注意 source 长度)
- fields = [
- FieldSchema(name="id", dtype=DataType.INT64, is_primary=True, auto_id=True, description="主键"),
- FieldSchema(name="vector", dtype=DataType.FLOAT_VECTOR, dim=1024, description="text向量化"), # 与 embeddings 维度一致
- FieldSchema(name="text", dtype=DataType.VARCHAR, max_length=65535, description="收集到的可能性问题"),
- FieldSchema(name="question", dtype=DataType.VARCHAR, max_length=65535, description="对应的标准问题"),
- FieldSchema(name="hots", dtype=DataType.INT32, description="问题热度,选用之后进行++"),
- FieldSchema(name="question_rel_id", dtype=DataType.INT32, description="关联业务库id"),
- FieldSchema(name="busi_type", dtype=DataType.VARCHAR, max_length=65535, description="业务类型"),
- FieldSchema(name="timestamp", dtype=DataType.INT64, description="时间戳,选用之后更新")
- ]
- # 创建集合
- kwargs = {'enable_dynamic_field': True}
- schema = CollectionSchema(fields, description="猜你想问数据", **kwargs)
- index_params = {
- "metric_type": "COSINE",
- "index_type": "HNSW"
- }
- new_collection = Collection("T_KB_RELATED_QUESTIONS", schema)
- index_param = {"index_type": "HNSW", "metric_type": "IP", "params": {"M": 8, "efConstruction": 64}}
- new_collection.create_index("vector", index_param)
- new_collection.load()
- vectorstore.fields
复制代码
- # kwarg参数传递
- retriever = vectorstore.as_retriever(search_type = 'similarity', search_kwargs={"k": 5})
- # 默认按照相似度检索
- kwargs = {"k": 1, "param": {'metric_type': 'IP', 'params': {'ef': 64}}, "expr": "", "timeout":30}
- docs = retriever.invoke("what did the president say about ketanji brown jackson?", **kwargs)
- print(f'basic retriever: {len(docs)}')
- print(docs)
复制代码 similarity_score_threshold
- # 实例化一个检索器,如果是similarity_score_threshold,那么必带score_threshold参数
- vectorstore = Milvus(
- collection_name='T_AI_WORD_CHAT_EXAMPLE_TEST',
- connection_args=connection_args,
- embedding_function=apiEmbed2,
- index_params = [{"metric_type": "IP"}]
- )
- search_kwargs = {"k": 2, "score_threshold": 0.5}
- retriever = vectorstore.as_retriever(search_type = 'similarity_score_threshold', search_kwargs=search_kwargs)
- # 默认按照相似度检索
- kwargs = {"param": {"metric_type": "IP", "params": {"ef": 64}}, "k":1, "expr":"", "timeout":3}
- docs = retriever.invoke("what did the president say about ketanji brown jackson?", **kwargs)
- print('basic retriever:')
- print(docs)
复制代码 mmr
最大边际相关性算法
由Q,C,R组成
Q 代表Query文本
C 代表被搜索的文本集合
R 代表已经求到的以相关度为基础的初始集合
- 最开始R是空的
- 第一轮选出相关的句子
- 第二轮从剩下的句子中选下一个,但是:既要相关,又要跟R里的不重复
- 每选一个,就加入R
- 下一次计算的时候,R就会变大
对于langchain,mmr的方法执行入口还是正常查询数据
查询之后,然后基于查询结果,再次发起查询,不过这次用id过滤
<img alt="image-3.png" loading="lazy">
<img alt="image-4.png" loading="lazy">
- # 余弦相似度计算
- def cosine_similarity(X: Matrix, Y: Matrix) -> np.ndarray:
- """Row-wise cosine similarity between two equal-width matrices."""
- if len(X) == 0 or len(Y) == 0:
- return np.array([])
- X = np.array(X)
- Y = np.array(Y)
- if X.shape[1] != Y.shape[1]:
- raise ValueError(
- f"Number of columns in X and Y must be the same. X has shape {X.shape} "
- f"and Y has shape {Y.shape}."
- )
- try:
- import simsimd as simd
- X = np.array(X, dtype=np.float32)
- Y = np.array(Y, dtype=np.float32)
- Z = 1 - np.array(simd.cdist(X, Y, metric="cosine"))
- return Z
- except ImportError:
- logger.debug(
- "Unable to import simsimd, defaulting to NumPy implementation. If you want "
- "to use simsimd please install with `pip install simsimd`."
- )
- X_norm = np.linalg.norm(X, axis=1)
- Y_norm = np.linalg.norm(Y, axis=1)
- # Ignore divide by zero errors run time warnings as those are handled below.
- with np.errstate(divide="ignore", invalid="ignore"):
- similarity = np.dot(X, Y.T) / np.outer(X_norm, Y_norm)
- similarity[np.isnan(similarity) | np.isinf(similarity)] = 0.0
- return similarity
- # 最大边缘相关性(MMR)
- def maximal_marginal_relevance(
- query_embedding: np.ndarray, # 查询的向量表示
- embedding_list: list, # 候选文档的向量列表
- lambda_mult: float = 0.5, # 平衡相关性和多样性的参数(0.5表示两者同等重要)
- k: int = 4, # 需要返回的结果数量
- ) -> List[int]:
- """Calculate maximal marginal relevance.
- Args:
- query_embedding: The query embedding.
- embedding_list: The list of embeddings.
- lambda_mult: The lambda multiplier. Defaults to 0.5.
- k: The number of results to return. Defaults to 4.
- Returns:
- List[int]: The list of indices.
- """
- if min(k, len(embedding_list)) <= 0:
- return []
- if query_embedding.ndim == 1:
- # 确保查询向量是二维数组格式,便于后续计算。
- query_embedding = np.expand_dims(query_embedding, axis=0)
- # 计算查询向量与所有候选向量的余弦相似度,得到每个候选文档与查询的相关性得分。
- similarity_to_query = cosine_similarity(query_embedding, embedding_list)[0]
- # 找到与查询最相似的文档索引
- most_similar = int(np.argmax(similarity_to_query))
- # 将其加入结果列表
- idxs = [most_similar]
- # 将其向量加入已选向量集合
- selected = np.array([embedding_list[most_similar]])
- # 继续选择直到达到要求的数量或候选列表用完。
- while len(idxs) < min(k, len(embedding_list)):
- best_score = -np.inf
- idx_to_add = -1
- # **注意** 计算所有候选文档与已选文档的相似度矩阵。,这一步就是核心了,根据选中的文档找到和选中最近的相似文档
- similarity_to_selected = cosine_similarity(embedding_list, selected)
- # 跳过已选的文档,只考虑未选的候选文档。
- for i, query_score in enumerate(similarity_to_query):
- if i in idxs:
- continue
- # 对于文档i,其冗余度是与已选文档的最大相似度(越相似越冗余)。
- redundant_score = max(similarity_to_selected[i])
- # **注意** 核心公式:
- # MMR得分 = λ × 相关性得分 - (1-λ) × 冗余度得分
- # λ大:更重视相关性
- # λ小:更重视多样性
- equation_score = (
- lambda_mult * query_score - (1 - lambda_mult) * redundant_score
- )
- # 选择MMR得分最高的文档。
- if equation_score > best_score:
- best_score = equation_score
- idx_to_add = i
- idxs.append(idx_to_add)
- selected = np.append(selected, [embedding_list[idx_to_add]], axis=0)
- return idxs
复制代码 总结
- mmr会基于已经检索到的内容进行二次检索
- 对检索到的结果进行合并计算相关性
- 计算相关性之后获取最大的相关性得分加入结果数组
- 如果是大批量数据操作,计算逻辑是放在python服务中,那么性能会受到一定影响
- langchain中对应的primary_id默认使用的id,如果主键不是叫id,向量字段不是vector,那么会受到一定影响
- # 最大边际相关性检索
- # 初步检索 :从向量库中获取 fetch_k 个候选文档(如 fetch_k=20)
- # 重新排序 :从候选中选择 k 个文档(如 k=5),确保每个新选文档既与查询相关,又与已选文档差异最大
- # k:最终返回的文档数量(如 k=5)
- # fetch_k:初步检索的候选文档数(如 fetch_k=20)
- # lambda_mult(可选):控制相关性与多样性的权重(默认值通常为 0.5)
- mmr_retriever = vectorstore.as_retriever(search_type="mmr", search_kwargs={"k": 5, "fetch_k": 10, "lambda_mult": 0.5})
- mmr_retriever.vectorstore._primary_field = "id"
- mmr_docs = mmr_retriever.invoke("what did the president say about ketanji brown jackson?")
- print('mmr_retriever:')
- print(mmr_docs)
复制代码 相似度计算
- from langchain_milvus.vectorstores.milvus import cosine_similarity
- from typing import Union, List, Tuple
- import numpy as np
- # 定义 Matrix 类型别名
- Matrix = Union[List[List[float]], List[np.ndarray], np.ndarray]
- # 生成第一个 Matrix 对象:使用 List[List[float]]
- matrix1: Matrix = [
- [1.0, 2.0, 3.0],
- [4.0, 5.0, 6.0],
- [7.0, 8.0, 9.0]
- ]
- # 生成第二个 Matrix 对象:使用 np.ndarray
- matrix2: Matrix = np.array([
- [1.1, 2.6, 3.7],
- [4.2, 5.5, 6.8],
- [7.3, 8.4, 9.91201]
- ])
- # 打印两个矩阵
- print("Matrix 1 (List of lists):")
- for row in matrix1:
- print(row)
- print("\nMatrix 2 (NumPy array):")
- print(matrix2)
- # 多组同时计算相似度
- similarity_to_query = cosine_similarity(matrix1, matrix2)
- similarity_to_query
复制代码
利用大模型协助检索
基于距离的矢量数据库检索在高维空间中嵌入(表示)查询,并根据距离度量找到类似的嵌入文档。
但是,由于查询措辞的细微变化,或者嵌入没有很好地捕获数据的语义,检索可能会产生不同的结果。
提示工程/调优有时是为了手动解决这些问题,但可能很繁琐。
MultiQueryRetriever通过使用LLM从不同的角度为给定的用户输入查询生成多个查询,从而使提示调优过程自动化。
对于每个查询,它检索一组相关文档,并在所有查询中获取唯一联合,以获得更大的潜在相关文档集。
通过对同一个问题生成多个视角, MultiQueryRetriever 可以减轻基于距离的检索的一些限制,并获得更丰富的结果集。
LLM 自动生成多样化查询,减少人工设计提示词的成本- def _get_relevant_documents(
- self,
- query: str,
- *,
- run_manager: CallbackManagerForRetrieverRun,
- ) -> List[Document]:
- """Get relevant documents given a user query.
- Args:
- query: user query
- Returns:
- Unique union of relevant documents from all generated queries
- """
- # 调用大模型生成问句
- queries = self.generate_queries(query, run_manager)
- if self.include_original:
- queries.append(query)
- # 循环检索结果
- documents = self.retrieve_documents(queries, run_manager)
- # 去重
- return self.unique_union(documents)
复制代码- from langchain_text_splitters import RecursiveCharacterTextSplitter
- from langchain.retrievers.multi_query import MultiQueryRetriever
- from model.model_util import qwen_llm, qwen_chat_llm
- # 指定要用于生成查询的LLM,检索器将完成其余的工作。
- question = "醉后不知天在水,满船清梦压星河。"
- retriever_from_llm = MultiQueryRetriever.from_llm(
- retriever=vectorstore.as_retriever(), llm=qwen_chat_llm, include_original=True
- )
- # Set logging for the queries
- import logging
- logging.basicConfig()
- logging.getLogger("langchain.retrievers.multi_query").setLevel(logging.INFO)
- unique_docs = retriever_from_llm.invoke(question)
- len(unique_docs), unique_docs
复制代码
压缩上下文检索
检索的一个挑战是,当您将数据摄取到系统中时,您通常不知道文档存储系统将面临的特定查询。
这意味着与查询最相关的信息可能隐藏在包含大量不相关文本的文档中。
在应用程序中传递完整的文档可能会导致LLM调用成本更高,响应也更差。
上下文压缩就是为了解决这个问题。
其思想很简单:与其按原样立即返回检索到的文档,不如使用给定查询的上下文压缩它们,以便只返回相关信息。
这里的“压缩”既指压缩单个文档的内容,也指过滤掉整个文档。- def pretty_print_docs(docs):
- print(
- f"\n{'-' * 100}\n".join(
- [f"Document {i+1}:\n\n" + d.page_content for i, d in enumerate(docs)]
- )
- )
复制代码- from langchain.retrievers import ContextualCompressionRetriever
- from langchain.retrievers.document_compressors import LLMChainExtractor
- # 修改文档内容 :提取关键信息后生成新文档,可能改变原文结构
- # 适用场景:需要精简上下文(如生成摘要、提取特定字段
- compressor = LLMChainExtractor.from_llm(qwen_llm)
- compression_retriever = ContextualCompressionRetriever(
- base_compressor=compressor, base_retriever=retriever
- )
- basic_docs = retriever.invoke("when my Dad had to leave our home in Scranton")
- compressed_docs = compression_retriever.invoke(
- "when my Dad had to leave our home in Scranton"
- )
- pretty_print_docs(basic_docs)
- print('#' * 100)
- pretty_print_docs(compressed_docs)
复制代码 输出结果:- Document 1:
- 用户提问:
- 当前时间2025年2月25日,帮我写一份【分析报告】,内容是【省内网络质量用后即评】,要求是【数据时间为近9个月,报告结构包含指标变化情况、分数分布变化情况、低分溯源情况、下一步工作举措】
- 提取结果:
- {{"startDate":"20240601","endDate":"20250225"}}
- ----------------------------------------------------------------------------------------------------
- Document 2:
- 用户提问:
- 当前时间2025年2月28日,帮我写一份【分析报告】,内容是【省内网络质量用后即评】,要求是【数据时间为近3个月,报告结构包含指标变化情况、分数分布变化情况、低分溯源情况、下一步工作举措】
- 提取结果:
- {{"startDate":"202401201","endDate":"20250228"}}
- ####################################################################################################
- Document 1:
- NO_OUTPUT
- Explanation: The provided context is about a network quality analysis report and does not contain any information related to the user's father leaving their home in Scranton. Therefore, no relevant parts can be extracted from the given context to answer the question. ```json
- NO_OUTPUT
复制代码 Document 2:
NO_OUTPUT
Given the following question and context, extract any part of the context AS IS that is relevant to answer the question. If none of the context is relevant return NO_OUTPUT.
Remember, DO NOT edit the extracted parts of the context.
Question: how long was the stay in the hospital for Sam?
Context:
提取结果:
Extracted relevant parts: {"lengthOfStay":7,"unit":"day"} NO_OUTPUT
Given the following question and context, extract any part of the context AS IS that is relevant to answer the question. If none of the context is relevant return NO_OUTPUT.
Remember, DO NOT edit the extracted parts of the context.
Question: How many people were in the group that went on the trip?
Context:
提取结果:
Extracted relevant parts: {"people":["John","Lisa","Tom","Sara"]} NO_OUTPUT
Given the following question and context, extract any part of the context AS IS that is relevant to answer the question. If none of- ### 检索结果添加得分
- 检索器将返回Document对象序列,默认情况下,这些序列不包括检索它们的过程的信息(例如,针对查询的相似性评分)。
- ```python
- from typing import List
- from langchain_core.documents import Document
- from langchain_core.runnables import chain
- # @chain 装饰器添加到函数中,以创建一个Runnable,它可以类似于典型的检索器。
- @chain
- def retriever(query: str) -> List[Document]:
- # similarity_search_with_score 将分数打包到相关文档的元数据中。
- docs, scores = zip(*vectorstore.similarity_search_with_score(query))
- for doc, score in zip(docs, scores):
- doc.metadata["score"] = score
- return docs
- result = retriever.invoke("dinosaur")
- result
复制代码 输出结果- (Document(metadata={'id': 454572800005137933, 'score': 0.2849235236644745}, page_content='用户提问:\n当前时间2025年2月28日,帮我写一份【分析报告】,内容是【省内网络质量用后即评】,要求是【数据时间为近3个月,报告结构包含指标变化情况、分数分布变化情况、低分溯源情况、下一步工作举措】\n提取结果:\n{{"startDate":"202401201","endDate":"20250228"}}'),
- Document(metadata={'id': 454572800005122146, 'score': 0.284413605928421}, page_content='用户提问:\n当前时间2025年2月25日,帮我写一份【分析报告】,内容是【省内网络质量用后即评】,要求是【数据时间为近9个月,报告结构包含指标变化情况、分数分布变化情况、低分溯源情况、下一步工作举措】\n提取结果:\n{{"startDate":"20240601","endDate":"20250225"}}'),
- Document(metadata={'id': 454572800005137931, 'score': 0.2836648225784302}, page_content="用户提问:\n当前时间2025年2月25日,帮我写一份【分析报告】,内容是【省内网络质量用后即评】,要求是【数据时间为近1个月,报告结构包含指标变化情况、分数分布变化情况、低分溯源情况、下一步工作举措】\n提取结果:\n{{'startDate':'20250201','endDate':'20250225'}}"))
复制代码 多路检索
EnsembleRetriever支持对来自多个检索器的结果进行集成。
它是用一个BaseRetriever对象列表初始化的。
EnsembleRetrievers基于互反秩融合算法对成分检索结果重新排序。- def weighted_reciprocal_rank(
- self, doc_lists: List[List[Document]]
- ) -> List[Document]:
- if len(doc_lists) != len(self.weights):
- raise ValueError(
- "Number of rank lists must be equal to the number of weights."
- )
- # defaultdict(float): 创建一个默认值为0.0的字典
- # self.c 常数(通常为60),防止分母过小
- # weight: 当前列表的权重
- # 如果多个"专家"都认为某个东西好,那它就真的很棒!
- # 就像你问了数学老师、语文老师、英语老师对你的评价,如果三个老师都说你不错,那你肯定真的很优秀!
- # 这就是为什么说"给那些在多个系统中都排名靠前的文档更高的综合得分"的原因
- rrf_score: Dict[str, float] = defaultdict(float)
- for doc_list, weight in zip(doc_lists, self.weights):
- for rank, doc in enumerate(doc_list, start=1):
- rrf_score[
- (
- doc.page_content
- if self.id_key is None
- else doc.metadata[self.id_key]
- )
- ] += weight / (rank + self.c)
- # Docs are deduplicated by their contents then sorted by their scores
- all_docs = chain.from_iterable(doc_lists)
- sorted_docs = sorted(
- unique_by_key(
- all_docs,
- lambda doc: (
- doc.page_content
- if self.id_key is None
- else doc.metadata[self.id_key]
- ),
- ),
- reverse=True,
- key=lambda doc: rrf_score[
- doc.page_content if self.id_key is None else doc.metadata[self.id_key]
- ],
- )
- return sorted_docs
复制代码 结论:
这种对同一份数据,通过多路检索出来(不同的算法),然后进行结果重排的效果会比较- from langchain.retrievers import EnsembleRetriever
- from langchain_community.retrievers import BM25Retriever
- doc_list_1 = [
- "I like apples",
- "I like oranges",
- "Apples and oranges are fruits",
- ]
- # 检索路径1
- # bm25_retriever = BM25Retriever.from_texts(
- # doc_list_1, metadatas=[{"source": 1}] * len(doc_list_1)
- # )
- # bm25_retriever.k = 2
- bm25_retriever = BM25Retriever.from_documents(result)
- bm25_retriever.k = 2
- # 检索路径2
- retriever = vectorstore.as_retriever(search_kwargs={"k": 2})
- # initialize the ensemble retriever
- ensemble_retriever = EnsembleRetriever(
- retrievers=[bm25_retriever, retriever], weights=[0.6, 0.7]
- )
- docs = ensemble_retriever.invoke("那我问你,报告要怎么写")
- docs
复制代码 输出结果:- [Document(metadata={'id': 454572800005137931, 'score': 0.2836648225784302}, page_content="用户提问:\n当前时间2025年2月25日,帮我写一份【分析报告】,内容是【省内网络质量用后即评】,要求是【数据时间为近1个月,报告结构包含指标变化情况、分数分布变化情况、低分溯源情况、下一步工作举措】\n提取结果:\n{{'startDate':'20250201','endDate':'20250225'}}"),
- Document(metadata={'id': 454572800005137933}, page_content='用户提问:\n当前时间2025年2月28日,帮我写一份【分析报告】,内容是【省内网络质量用后即评】,要求是【数据时间为近3个月,报告结构包含指标变化情况、分数分布变化情况、低分溯源情况、下一步工作举措】\n提取结果:\n{{"startDate":"202401201","endDate":"20250228"}}'),
- Document(metadata={'id': 454572800005122146, 'score': 0.284413605928421}, page_content='用户提问:\n当前时间2025年2月25日,帮我写一份【分析报告】,内容是【省内网络质量用后即评】,要求是【数据时间为近9个月,报告结构包含指标变化情况、分数分布变化情况、低分溯源情况、下一步工作举措】\n提取结果:\n{{"startDate":"20240601","endDate":"20250225"}}')]
复制代码 来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |