文章目录
- 论文概述
- RAG工作流程
- 核心代码解读
- 软件架构
- 查询引擎构建
- 数据加载与索引创建
- 微调嵌入模型
- 项目应用
- 结论
在人工智能领域,大型语言模型(LLMs)因其强大的文本生成能力而备受关注。然而,这些模型在生成信息时可能会产生过时的信息或编造事实。为了解决这一问题,检索增强生成(Retrieval-Augmented Generation, RAG)技术应运而生。本文将对论文《Searching for Best Practices in Retrieval-Augmented Generation》进行解读,并结合其核心代码实现进行分析。
论文概述
论文《Searching for Best Practices in Retrieval-Augmented Generation》由复旦大学的研究人员撰写,旨在探索RAG技术的最佳实践。RAG通过结合预训练模型和基于检索的模型,提供了一个增强模型性能的稳健框架。论文通过广泛的实验,提出了几种策略,旨在在性能和效率之间取得平衡。
RAG工作流程
论文将RAG过程划分为如下阶段,并通过实验说明每个阶段模块选择最佳实践方案。
- Query Classification:并非所有查询都需要检索增强。
- Chunking:块大小显著影响性能。更大的块提供了更多的上下文,增强了理解,但增加了处理时间。较小的分块提高了检索的召回率,减少了时间,但可能缺乏足够的上下文。使用sliding window技术更加有效,即将文本按照句子进行划分,每个块包含窗口大小个句子。
- Embedding:嵌入模型选择LLM-Embedder,其与BAAI/big-large-en的效果相当,但前者的大小比后者小三倍。
- Vector Database:Milvus支持多种索引类型、十亿规模的向量支持、混合搜索和云原生能力。
- Retrieval:HyDE(pseudoDoc+query)+Hybrid Search(=0.3*BM25+Original embedding)。
- Reranking:monoT5模型参数量小且准确率相对较高,RankLLaMA绝对准确率更高。
- Repacking:reverse方式最好。
- Summarization:Recomp | Fangyuan Xu,Weijia Shi, and Eunsol Choi. Recomp: Improving retrieval-augmented lms with compression and selective augmentation. arXiv preprint arXiv:2310.04408, 2023.
- Generator Fine-tuning:混合相关和随机上下文可以增强生成器对无关信息的鲁棒性,同时保证相关信息的有效利用。用一个相关文档和一个随机选择的文档来训练。
核心代码解读
博主对论文进行实现,并将代码发布至github,地址为:rag-best-practices,如果对您的工作有帮助,请给一个star※,感谢!也欢迎大家fork项目,以此为baseline构建自己的RAG应用。
软件架构
项目基于 LlamaIndex RAG框架实现,向量数据库选择Qdrant。 大模型选择基于Ollama本地调用qwen2-1.5b模型,嵌入模型选择BAAI/bge-large-zh-v1.5。 选择原因:
- LlamaIndex框架对当前较为常用的技术进行了模块化封装,个人认为相较于langchain框架来说,其抽象层级更高,把更多的时间用于高层次的思考,而不是陷入编程的细节。
- Qdrant数据库比Milvus更容易部署,且文档较为详细直观。
查询引擎构建
在query.py
文件中,定义了一个函数build_query_engine
,用于构建查询引擎。这个函数根据是否使用混合搜索、重排等参数,构建不同的查询引擎。
rag_query_engine = index.as_query_engine(similarity_top_k=top_k,
text_qa_template=qa_prompt_tmpl,
node_postprocessors=[reranker, MetadataReplacementPostProcessor(
target_metadata_key="window")],
sparse_top_k=12,
vector_store_query_mode="hybrid",
response_synthesizer=get_response_synthesizer(
response_mode=response_mode),
)
数据加载与索引创建
在utils.py
文件中,定义了load_txt_data
函数,用于加载混合数据并创建索引。这个函数使用了滑动窗口分块技术,并利用Qdrant作为向量存储。
def load_txt_data(input_file, persist_dir, with_sliding_window: bool, chunk_size=512, chunk_overlap=128):
documents = SimpleDirectoryReader(input_files=input_file).load_data()
if with_sliding_window:
# Sliding windows chunking & Extract nodes from documents
node_parser = SentenceWindowNodeParser.from_defaults(
# how many sentences on either side to capture
window_size=3,
# the metadata key that holds the window of surrounding sentences
window_metadata_key="window",
# the metadata key that holds the original sentence
original_text_metadata_key="original_sentence",
)
else:
node_parser = SentenceSplitter(chunk_size=512, chunk_overlap=128)
nodes = node_parser.get_nodes_from_documents(documents, show_progress=True)
# indexing & storing
try:
storage_context = StorageContext.from_defaults(persist_dir=persist_dir)
index = load_index_from_storage(storage_context, show_progress=True)
except:
index = VectorStoreIndex(nodes=nodes, show_progress=True)
index.storage_context.persist(persist_dir=persist_dir)
return index, nodes
微调嵌入模型
在FTEmbed.py
文件中,提供了微调嵌入模型的相关函数。这些函数包括数据准备、微调和评估。
def finetuning_data_preparation(...):
docs_nodes = load_corpus(all_data, verbose=verbose)
train_nodes = docs_nodes[:int(2 * len(docs_nodes) / 3)]
val_nodes = docs_nodes[int(2 * len(docs_nodes) / 3 + 1):]
# 自带保存
train_dataset = generate_qa_embedding_pairs(llm=llm, nodes=train_nodes, verbose=verbose,
output_path="ft_data/qa_finetune_train_dataset.json")
val_dataset = generate_qa_embedding_pairs(llm=llm, nodes=val_nodes, verbose=verbose,output_path="ft_data/qa_finetune_val_dataset.json")
train_dataset.save_json(train_dataset_dir)
val_dataset.save_json(val_dataset_dir)
def finetuning_embedding(...):
train_dataset = EmbeddingQAFinetuneDataset.from_json(train_dataset_dir)
val_dataset = EmbeddingQAFinetuneDataset.from_json(val_dataset_dir)
finetune_engine = SentenceTransformersFinetuneEngine(
train_dataset,
model_id=model_name,
model_output_path=model_output_path,
val_dataset=val_dataset,
)
if not os.path.exists(model_output_path): # 如果已经存在微调好的模型就不用重新微调了
finetune_engine.finetune()
embed_model = finetune_engine.get_finetuned_model()
print(embed_model)
return embed_model
项目应用
论文中提出的RAG最佳实践,可以应用于多种场景,如问答系统、内容生成等。通过结合检索和生成,RAG能够提供更准确、更丰富的信息。
结论
RAG技术通过检索增强生成,有效地提高了大型语言模型的准确性和可靠性。论文《Searching for Best Practices in Retrieval-Augmented Generation》通过广泛的实验,为RAG的实际应用提供了宝贵的指导。结合论文的核心代码实现,我们可以更深入地理解RAG的工作机制和最佳实践。