如今,检索增强生成(RAG)已经成为构建依赖外部数据的可靠人工智能应用程序的首选方案。它有助于克服大型语言模型(LLM)的固有局限,减少幻觉,并基于可信来源提供专业的回复。
随着RAG技术关注度的持续提升,探索、测试和优化不同RAG策略的工具需求也日益增长。AutoRAG正是为此而生的一款较新解决方案,它可以将大部分开发流程实现自动化,使开发者能够轻松尝试多种配置、评估管道性能,从而找到最适合自身应用场景的方案。
本文将介绍AutoRAG的工作原理,以及如何使用这项技术创建端到端的RAG应用程序。
什么是检索增强生成(RAG)?RAG主要由检索器和生成器两部分组成。这两部分共同构成RAG管道,使其能够针对复杂查询提供准确答案。生成器会读取检索器找到的上下文,并基于这些信息生成回答。
RAG是一种将外部数据搜索与生成模型相结合的方法,通过为模型生成的答案提供可靠参考来提高准确性。RAG的一些应用程序包括聊天『机器人』️、知识助手、分析解决方案以及企业问答系统。
RAG的关键组件有几个构建模块使RAG成功并影响RAG提供准确信息的能力。这些包括检索器、嵌入模型和生成器。
- 检索器:RAG的第一步是使用检索器对文档进行索引,然后检索器将在索引中搜索相关的文档块。
- 嵌入模型:索引可以基于文档块的相似度,通过相似性搜索、向量嵌入或混合检索等多种方法实现。
- 生成器(LLM):生成器必须依赖于准确的上下文才能产生准确的响应。这就是必须利用最佳版本的上下文来生成准确响应的原因。
什么是AutoRAG以及何时使用
AutoRAG是一个允许用户快速创建、评估和优化多个RAG管道的框架。它可以帮助开发人员快速测试多个设计选择,而无需编写自定义评估脚本。当开发团队希望比较不同的检索方法、嵌入模型、分块策略或者生成方式时,就会使用AutoRAG。
借助AutoRAG,开发人员可以快速迭代多种不同的RAG配置,因为它会自动运行测试,并提供检索准确性和生成管道最佳配置的评估结果。当用户需要进行系统评估或想要测试大量流程配置时,就应该使用AutoRAG。
AutoRAG解决了什么问题?
AutoRAG解决了使RAG开发耗时的多个挑战。随着RAG项目变得越来越复杂,这些挑战变得更加显著。
- 管道探索:它无需人工编写代码,就能对各种相似性度量、分块大小、嵌入模型和检索器进行实验。
- 评估:AutoRAG包含评估指标,包括检索准确性、引文正确性和答案质量,使其易于评估RAG管道的有效性。
- 优化:AutoRAG识别最有效的配置,使开发团队能够为其数据和用例的配置做出最佳决策。
准备构建:先决条件和设置
构建适合使用AutoRAG开发基于RAG的应用程序的开发环境。这意味着需要建立Python环境、依赖项、数据,并从LLM或嵌入模型提供商那里找到需要的凭证。
开发人员必须构建定义良好的Python环境以及几个额外的依赖项,才能成功运行AutoRAG。如果环境不洁或配置不当,可能会遇到依赖项冲突,导致RAG实验无法顺利进行。
1.Python设置
复制
python3 -m venv autorag-venv
source autorag-venv/bin/activate
python -m pip install --upgrade pip
- Python 3.10或更高版本
- 使用venv或conda创建的虚拟环境
- 用于安装包的pip
2.核心依赖项
根据AutoRAG的要求安装以下软件包:
复制
pip install AutoRAG pandas langchain sentence-transformers faiss-cpu
- autorag
- pandas
- sentence-transformers
- faiss-cpu(或其他向量存储后端)
- langchain或langchain-community(用于大型语言模型集成)
3.导出LLM/嵌入密钥
复制
export OPENAI_API_KEY="sk-..."
如果使用其他提供商的产品,可以设置其类似的环境(env)变量。
使用AutoRAG构建RAG应用程序
要使用AutoRAG和知识库创建基于RAG的应用程序,按照以下主要步骤进行:
- 索引与嵌入:将每条信息转换为嵌入向量,并存储在向量数据库中。
- 检索与管道实验:如果需要可以创建QA评估集,然后运行AutoRAG对不同的RAG管道进行实验,以确定效果最佳的方案。
- 部署:使用优化后的RAG管道响应用户查询。
数据导入与预处理
首先,加载原始文档:
Python
复制
import json
import os
from pathlib import Path
import PyPDF2
def parse_pdf(pdf_path="data/raw_docs/attention.pdf", out_path="data/parsed.jsonl"):
os.makedirs("data", exist_ok=True)
with open(pdf_path, "rb") as f, open(out_path, "w", encoding="utf-8") as fout:
reader = PyPDF2.PdfReader(f)
for i, page in enumerate(reader.pages):
text = page.extract_text() or ""
fout.write(json.dumps({
"doc_id": "attention.pdf",
"page": i + 1,
"content": text,
"source": "attention.pdf",
"title": "Attention Is All You Need"
}) + "\n")
print("Parsed PDF → data/parsed.jsonl")
parse_pdf()
以下方法用于分割和分块文档:
python
复制
import json
def chunk_text(text, chunk_size=600, overlap=60):
words = text.split()
i = 0
chunks = []
while i < len(words):
chunk = words[i:i + chunk_size]
chunks.append(" ".join(chunk))
if i + chunk_size >= len(words):
break
i += chunk_size - overlap
return chunks
def create_corpus(parsed="data/parsed.jsonl", out="data/corpus.jsonl"):
with open(parsed, "r") as fin, open(out, "w") as fout:
for line in fin:
row = json.loads(line)
chs = chunk_text(row["content"])
for idx, c in enumerate(chs):
fout.write(json.dumps({
"id": f"{row['doc_id']}_p{row['page']}_c{idx}",
"doc_id": row["doc_id"],
"page": row["page"],
"chunk_id": idx,
"content": c,
"source": row["source"],
"title": row["title"]
}) + "\n")
print("Created corpus → data/corpus.jsonl")
create_corpus()
以下代码用于规范化元数据:
python
复制
import json
def normalize_metadata(path="data/corpus.jsonl"):
rows = []
with open(path) as fin:
for line in fin:
obj = json.loads(line)
obj.setdefault("source", "attention.pdf")
obj.setdefault("title", "Attention Is All You Need")
rows.append(obj)
with open(path, "w") as fout:
for r in rows:
fout.write(json.dumps(r) + "\n")
print("Metadata normalized.")
normalize_metadata()
索引/嵌入与存储设置
现在使用嵌入模型:
python
复制
import json
import numpy as np
import faiss
from sentence_transformers import SentenceTransformer
import os
def build_faiss_index(corpus="data/corpus.jsonl", index_dir="data/faiss_index"):
os.makedirs(index_dir, exist_ok=True)
texts, ids = [], []
with open(corpus) as f:
for line in f:
row = json.loads(line)
texts.append(row["content"])
ids.append(row["id"])
model = SentenceTransformer("all-MiniLM-L6-v2")
embeddings = model.encode(texts, convert_to_numpy=True)
faiss.normalize_L2(embeddings)
index = faiss.IndexFlatIP(embeddings.shape[1])
index.add(embeddings)
faiss.write_index(index, f"{index_dir}/index.faiss")
json.dump(ids, open(f"{index_dir}/ids.json", "w"))
print("Stored FAISS index at", index_dir)
build_faiss_index()
向量存储或数据库设置:
复制
vectordb: faiss_local
index_dir: data/faiss_index
embedding_module: sentence_transformers/all-MiniLM-L6-v2
使用AutoRAG进行检索和RAG管道实验首先,创建问答(QA)评估数据集:
python
复制
import pandas as pd
from autorag.data.qa.schema import Raw, Corpus
from autorag.data.qa.sample import random_single_hop
from autorag.data.qa.query.llama_gen_query import factoid_query_gen
from autorag.data.qa.generation_gt.llama_index_gen_gt import make_basic_gen_gt
from llama_index.llms.openai import OpenAI
def create_qa():
raw_df = pd.read_parquet("data/parsed.parquet")
corpus_df = pd.read_parquet("data/corpus.parquet")
raw_inst = Raw(raw_df)
corpus_inst = Corpus(corpus_df, raw_inst)
llm = OpenAI()
sampled = corpus_inst.sample(random_single_hop, n=140)
sampled = sampled.make_retrieval_gt_contents()
sampled = sampled.batch_apply(factoid_query_gen, llm=llm)
sampled = sampled.batch_apply(make_basic_gen_gt, llm=llm)
sampled.to_parquet("data/qa.parquet", index=False)
print("Created data/qa.parquet")
create_qa()
运行AutoRAG评估:
复制
configs/default_rag_config.yaml
node_lines:
- node_line_name: retrieve_node_line
nodes:
- node_type: semantic_retrieval
top_k: 3
modules:
- module_type: vectordb
vectordb: faiss_local
index_dir: data/faiss_index
embedding_module: sentence_transformers/all-MiniLM-L6-v2
- node_line_name: post_retrieve_node_line
nodes:
- node_type: prompt_maker
modules:
- module_type: fstring
prompt: |
Use the passages to answer the question.
Question: {query}
Passages: {retrieved_contents}
Answer:
- node_type: generator
modules:
- module_type: openai_llm
llm: gpt-4o-mini
batch: 8
使用以下代码运行评估器:
python
复制
from autorag.evaluator import Evaluator
evaluator = Evaluator(
qa_data_path="data/qa.parquet",
corpus_data_path="data/corpus.parquet"
)
evaluator.start_trial("configs/default_rag_config.yaml")
运行RAG:
用户查询:“Transformer模型中的多头注意力是什么?”
最佳实践与建议构建稳健可靠的RAG应用程序需要精心规划。以下是一些最佳实践:
- 保留原始文本与嵌入:始终保存每个内容块的原始文本或其引用,不要仅依赖嵌入向量。
- 合理分块:分块时应保持语义完整性,建议使用统一的分词器,设置合适块大小(例如300~512个令牌),并保持内容块重叠(例如50个重叠令牌)。
- 缓存嵌入:在发送重复查询或处理大量内容时,缓存相同内容的嵌入以提高效率。
- 监控质量:使用标准指标监控检索和生成性能;例如,AutoRAG提供了用于评估检索F1值、召回率和答案正确性的标准指标;可以使用这些指标来识别RAG系统性能的任何问题。
- 保护密钥:切勿在代码中硬编码API密钥或模型令牌,应该使用环境变量或安全存储库进行管理。
遵循上述指南,开发团队将能够构建稳健可靠的RAG应用程序,充分发挥AutoRAG的自动化优势,并获得高质量结果。
结论RAG 应用的设计包含数据处理和检索技术之间的多个组件。AutoRAG 使开发人员能够自动化实验阶段和评估流程,从而简化 RAG 应用的创建。借助 AutoRAG,开发人员可以快速试验各种流程设计,并基于确凿的数据推出更优秀的 RAG 应用。
遵循本文档中的说明,用户将能够通过实施最佳方法,构建一个可靠、准确且即用型的应用程序。利用 AutoRAG 的优化功能并结合成熟的最佳实践,团队将更有机会打造最佳的 AI 体验,同时减少耗时的手动配置工作。
常见问题解答Q1. AutoRAG主要用于什么?
A:AutoRAG 用于RAG管道探索、评估和优化的自动化。它帮助开发人员确定检索和生成任务的最佳配置。
Q2.使用AutoRAG需要大型数据集吗?
A:不需要,AutoRAG适用于小型和大型数据集。然而,更多数据可以提高评估准确性和检索性能。
Q3.应该选择哪种嵌入模型?
A:用户的选择取决于具体应用场景。轻量模型(如MiniLM)运行速度较快,而BGE或Jina等模型则能提供更高的语义准确性。



