Chroma向量DB中原始与压缩块检索的提示词长度异常问题
问题描述
我用Chroma向量DB检索相关文本块来响应用户查询,创建了两个Chroma实例,分别存储原始文本块和压缩文本块(通过移除冠词及部分停用词实现压缩)。理论上基于原始块生成的提示词token长度应该大于压缩块的,但在k值(检索文档数)、查询内容、块大小都相同的情况下,多次出现相反情况,导致提示词没达到压缩效果。
代码片段
from langchain.text_splitter import RecursiveCharacterTextSplitter CHROMA_PATH_COMPR = 'docs/chroma_22225311123335326326622123155783567999592220111221823527982/' CHROMA_PATH = 'docs/chroma_323333322253371255175333363916217279211239913512622611/' text_splitter = RecursiveCharacterTextSplitter(chunk_size=1400,chunk_overlap=700,separators=["\n\n", "\n", ". ", " ", ""]) def input_file(): file_path = input("Enter file path : ") loader = PyPDFLoader(file_path) pages = loader.load() return pages def get_original_chunks(pages): orig_chunks= text_splitter.split_documents(pages) return orig_chunks def retrieve_relevant_chunks_original(orig_chunks,query): db_chroma = Chroma.from_documents(documents= orig_chunks,embedding=getembeddings(),persist_directory=CHROMA_PATH,collection_name="OriginalChunks") vector_store_retriever_orig = db_chroma.as_retriever(search_type="mmr",search_kwargs={'k':5,'lambda_mult':0.1}) retrieved_context = vector_store_retriever_orig.get_relevant_documents(query) return retrieved_context def get_compressed_chunks(orig_chunks,query): compressedchunks=[] startTime = timeit.default_timer() for i in range(len(orig_chunks)): orig_chunks[i].page_content = compressprompt(orig_chunks[i].page_content) compressedchunks.append(orig_chunks[i]) endTime = timeit.default_timer() time_compr = endTime-startTime print("Time taken to compress chunks = \t",time_compr) db_chroma_compr = Chroma.from_documents(documents= compressedchunks,embedding=getembeddings(),persist_directory=CHROMA_PATH_COMPR,collection_name="CompressedChunks") vector_store_retriever_compr = db_chroma_compr.as_retriever(search_type="mmr",search_kwargs={'k':5,'lambda_mult':0.1}) retrieved_compr_context = vector_store_retriever_compr.get_relevant_documents(query) return retrieved_compr_context
问题分析
出现这种反常识情况的核心原因如下:
- 检索结果不匹配:原始块和压缩块的embedding基于不同文本生成,MMR检索返回的文档集合可能完全不同。即使k值相同,原始块检索到的可能是本身较短的文本块,而压缩块检索到的可能是原本较长、即使压缩后token数仍比前者多的块。
- 压缩效果不稳定:如果原始文本中停用词、冠词占比极低,压缩后的token数减少有限;极端情况下,若文本以短词为主,移除少量停用词后token数差异不明显,甚至可能因分割逻辑或其他因素出现反超。
- 代码数据污染:
get_compressed_chunks函数直接修改了orig_chunks的page_content属性,会导致后续复用orig_chunks时数据被污染,影响原始块检索结果的一致性。 - Token计数误差:如果通过字符数估算token数,而非用专业工具精确统计,可能产生感知误差,实际原始块的token数确实更少。
解决方案建议
- 隔离原始数据:压缩时复制原始chunk对象,避免直接修改原数据:
import copy # 修改get_compressed_chunks中的循环逻辑 for chunk in orig_chunks: compressed_chunk = copy.deepcopy(chunk) compressed_chunk.page_content = compressprompt(chunk.page_content) compressedchunks.append(compressed_chunk) - 精确统计Token数:用tiktoken工具精确统计检索结果的token数,排除估算误差:
import tiktoken def count_tokens(text, model="gpt-3.5-turbo"): enc = tiktoken.encoding_for_model(model) return len(enc.encode(text)) # 分别统计原始和压缩检索结果的总token数 orig_total = sum(count_tokens(doc.page_content) for doc in retrieved_context) compr_total = sum(count_tokens(doc.page_content) for doc in retrieved_compr_context) - 验证压缩函数有效性:单独测试
compressprompt函数,对多个原始块统计压缩前后的token变化,确保压缩逻辑能稳定减少token数。 - 固定对比样本:如果要验证压缩效果,先手动选择几个固定的文本块,分别用原始和压缩版本计算token数,排除检索结果不一致的干扰。
内容的提问来源于stack exchange,提问作者user25185721
相关产品推荐
相关产品推荐

