在当今快速发展的人工智能领域,大型语言模型(LLM)已经成为无处不在的技术,它们不仅改变了我们与机器交流的方式,还在各行各业中发挥着革命性的影响。
然而,尽管LLM + RAG的能力已经让人惊叹,但我们在使用RAG优化LLM的过程中,还是会遇到许多挑战和困难,包括但不限于检索器返回不准确或不相关的数据,并且基于错误或过时信息生成答案。因此本文旨在提出RAG常见的7大挑战,并附带各自相应的优化方案,期望能够帮助我们改善RAG。
下图展示了RAG系统的两个主要流程:检索和查询;红色方框代表可能会遇到的挑战点,主要有7项:
- 1. Missing Content: 缺失內容
- 2. Missed Top Ranked: 错误排序內容,导致正确答案沒有被成功 Retrieve
- 3. Not in Context: 上限文限制,导致正确答案沒有被采用
- 4. Wrong Format: 格式错误
- 5. Incomplete: 回答不全面
- 6. Not Extracted: 未能检索信息
- 7. Incorrect Specificity: 不合适的详细回答
由于篇幅比较长,所以这篇文章我们先谈前 3 项:
这些挑战不仅关系到系统的可用性和准确性,还直接影响到用户对技术的信任度。为了解决这些问题,以下是针对每个挑战的优化方案:
缺失内容(Missing Content)
当 RAG
系统面对的问题无法从现有文件中得到答案时,就会出现这种情况。在最佳情况下,我们希望 RAG
系统直接回答「我不知道」。然而,实际上RAG
系统常常会编造或错误回答问题。
针对这个问题,目前有两大解决策略:
1. 数据清理
俗话说"吃什么、吐什么"。原始数据质量对信息处理系统的准确性至关重要,若输入数据错误或矛盾,或者预处理步骤不当,则无论检索增强生成(RAG)系统有多先进,也无法从混乱数据中提取有价值信息。这意味着我们必须在数据源选择、数据清洗、预处理等环节投入资源和技术,以确保输入数据尽可能准确和一致。这个策略不仅适用于本文讨论的问题,也适用于所有数据处理流程中,数据质量始终是关键。
2. prompt 工程
在知识库缺乏相关信息、导致系统可能给出看似合理但实际上错误答案的情况下,使用提示工程是一个非常有帮助的解决方式。例如通过设定提示:“如果你对答案不确定,就直接告诉我你不知道”,如此可以鼓励模型采取更谨慎和诚实的回应态度,从而避免误导用户。虽然不能保证系统回答的绝对准确性,但通过这样的提示, 确实能提高回答品质。
未命中排名靠前的内容(Missed Top Ranked)
这个挑战主要在于“答案在文件中,但由于排名靠前而未能提供给用户”。理论上,检索系统会为每个文档分配一个排名,此排名将决定其在后续处理中的使用程度。然而,在实际操作中,受限于性能和资源,通常只有排名最高的前 K 个文档会被选取并展示给用户。这里的 K 是基于性能考虑的参数。
针对该问题,存在两种解决方式:
1. 调整参数以优化搜索效果
该部分提出了两个方面调整以增加 RAG
效率和准确性:chunk_size
如果要直接在 langchain
调整块大小,请使用以下代码:
from langchain.text_splitter import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter(chunk_size=100)
all_splits = text_splitter.split_documents(PDF_data)
k
值涉及到检索器应该返回多少个答案,我们可以选择返回更多的答案,以确保正确答案不会被 LLM
忽略:
retriever = vectordb.as_retriever(search_kwargs={"k": 8})
qa = RetrievalQA.from_chain_type(
llm=llm,
chain_type="stuff",
retriever=retriever,
verbose=True
)
2. 优化检索文档的排序
在将检索到的文件送到LLM
前,先对文件进行最佳化排序,能大幅提升RAG
系统的效能,因为初始排序无法反映件与查询的真实相关性。这系列的论文可以看Liu et al.2023,论文中指出,将最相似的文档放在开头或结尾时,效能通常最高,因为模型容易迷失在中间。
在langchain
中,我们可以使用langchain
原生的Long-Context Reorder
或Cohere Reranker
来实现,请参考官方文件。
2.1 Long-Context Reorder
retriever = vectordb.as_retriever(search_kwargs={"k": 8})
query = "What can you tell me about the Celtics?"
# 按相关度分数排序获取相关文档
docs = retriever.get_relevant_documents(query)
# 重新排序文件:
# 列表中不太相关的文件将排在中间位置。开始/结尾处的相关要素。
reordering = LongContextReorder()
reordered_docs = reordering.transform_documents(docs)
# 确认前后共有4份相关文件。
print(reordered_docs)
2.2 Cohere Reranker
from langchain.retrievers import ContextualCompressionRetriever
from langchain.retrievers.document_compressors import CohereRerank
from langchain_community.llms import Cohere
retriever = vectordb.as_retriever(search_kwargs={"k": 8})
query = "What can you tell me about the Celtics?"
# 按相关性得分排序以获取相关文件
docs = retriever.get_relevant_documents(query)
# 使用Cohere重新排名端点来对返回的结果进行重新排名
llm = Cohere(temperature=0)
compressor = CohereRerank()
compression_retriever = ContextualCompressionRetriever(
base_compressor=compressor, base_retriever=retriever
)
compressed_docs = compression_retriever.get_relevant_documents(
"What did the president say about Ketanji Jackson Brown"
)
pretty_print_docs(compressed_docs)
Not in Context(上下文限制)
论文有提到:「答案所在的文档虽从数据库中检索出来,但并未包含在生成答案的上下文中。」这种情况通常发生在返回的文档太多,需透过一个整合过程来提取答案的情境。为了解决这个问题,扩大上下文的处理范围是一种方式,此外也建议可以尝试以下方法:
1.调整检索策略
Langchain
中提供许多检索的方法,确保我们在RAG
中能拿到最符合问题的文件,详细的列表可以参考官网,其中包含:
- 1. Vectorstore
- 2. ParentDocument
- 3. Multi Vector
- 4. Self Query
- 5. Contextual Compression
- 6. Time-Weighted Vectorstore
- 7. Multi-Query Retriever
- 8. Ensemble
- 9. Long-Context Reorder
这些策略为我们提供了一种灵活多样的方式,能够根据不同的检索需求和应用场景进行调整,以此提升检索过程中的准确性和效率。
2. 微调 embedding
Fine-tuning
嵌入模型针对特定任务是提高检索准确性的有效方法。如果我们的 embedding model
是开源的,可以使用 LlamaIndex
功能进行实现。与 Langchian
相比,LlamaIndex
是为了检索数据而优化的软件包,在这方面提供了详细教程,而 Langchian
则没有相应功能。
以下示范如何设置微调框架、执行微调操作并获取经过微调的模型,也可参考官方文档[1]。
finetune_engine = SentenceTransformersFinetuneEngine(
train_dataset,
model_id="BAAI/bge-small-en",
model_output_path="test_model",
val_dataset=val_dataset,
)
finetune_engine.finetune()
embed_model = finetune_engine.get_finetuned_model()
引用链接
[1] 官方文档: https://docs.llamaindex.ai/en/stable/examples/finetuning/embeddings/finetune_embedding.html