LlamaIndex 实战:从数据连接到 RAG 问答(阿里云 DashScope + 混合加载)
【学习记录】LlamaIndex 实战:从数据连接到 RAG 问答(阿里云 DashScope + 混合加载)
本文基于 LlamaIndex 框架,结合阿里云 DashScope(通义千问)的 LLM 和嵌入模型,完整演示了从多源文档加载(本地文件 + 网页) 到构建向量索引再到自然语言问答的 RAG 全流程。同时深入解析了数据连接器(Data Connectors)的设计与 PDF 解析的底层原理。读完本文,将能独立搭建一套国产化 RAG 系统。
📌 目录
- 环境配置与 API 密钥
- 替换 OpenAI 为阿里云 DashScope
- 混合数据加载:本地文件 + 网页
- 构建索引与查询引擎
- Data Connectors 深度解析
- 5.1 支持的数据源
- 5.2 Llama Hub 与 Llama Cloud
- 5.3 PDF 解析全流程(4 步详解)
- 常见问题与优化建议
- 总结
一、环境配置与 API 密钥
import os
from llama_index.core import Settings, VectorStoreIndex, SimpleDirectoryReader
from llama_index.llms.dashscope import DashScope
from llama_index.embeddings.dashscope import DashScopeEmbedding
from llama_index.readers.file import PyMuPDFReader
from llama_index.readers.web import BeautifulSoupWebReader
# 设置阿里云 API Key(请替换为自己的真实密钥)
os.environ["DASHSCOPE_API_KEY"] = "your-dashscope-api-key"
导入必要模块:
Settings:全局配置对象,用于设置 LLM 和 Embedding 模型。
VectorStoreIndex:用于构建向量索引的核心类。
SimpleDirectoryReader:读取本地文件夹中的文档。
DashScope 和 DashScopeEmbedding:阿里云 DashScope 的 LLM 和嵌入模型适配器。
设置环境变量 DASHSCOPE_API_KEY,值为从阿里云百炼平台获取的真实 API Key。注意:实际使用时应避免硬编码,建议从 .env 文件读取或使用环境变量。
二、替换 OpenAI 为阿里云 DashScope
# 配置大语言模型(LLM)
Settings.llm = DashScope(
model_name="qwen-max",
api_key=os.getenv("DASHSCOPE_API_KEY")
)
# 配置嵌入模型(Embedding)
Settings.embed_model = DashScopeEmbedding(
model_name="text-embedding-v2",
api_key=os.getenv("DASHSCOPE_API_KEY")
)
qwen-max:通义千问旗舰版,适合复杂指令和长上下文。text-embedding-v2:输出 1536 维向量,与 OpenAItext-embedding-ada-002维度一致,可无缝替换。- 通过这两行配置,LlamaIndex 内部的检索和生成组件将全部使用阿里云服务。
三、混合数据加载:本地文件 + 网页
from llama_index.core import SimpleDirectoryReader
from llama_index.readers.file import PyMuPDFReader
from llama_index.readers.web import BeautifulSoupWebReader
SimpleDirectoryReader:LlamaIndex 的核心文档加载器,可以读取指定目录下的所有文件(根据扩展名自动选择解析器)。
PyMuPDFReader:基于 PyMuPDF(fitz)的 PDF 解析器,能够提取文本及其在页面上的坐标信息(适合需要位置信息的场景,如 RAG 时引用具体段落)。
BeautifulSoupWebReader:基于 BeautifulSoup 的网页加载器,用于抓取指定 URL 的 HTML 内容并提取纯文本。
3.1 本地文件加载(使用 PyMuPDFReader 获取坐标信息)
local_loader = SimpleDirectoryReader(
input_dir="./data",
required_exts=[".pdf", ".docx", ".pptx", ".epub", ".md"],
file_extractor={
".pdf": PyMuPDFReader(), # 为 PDF 显式指定带坐标的解析器
}
)
local_docs = local_loader.load_data()
input_dir=“./data”:指定要读取的文件夹路径。
required_exts=[…]:只处理扩展名在列表中的文件,忽略其他类型。
file_extractor={“.pdf”: PyMuPDFReader()}:为 .pdf 文件显式指定使用 PyMuPDFReader(而不是默认的 PDFReader)。这样解析出的 PDF 文档会包含文本的位置坐标(例如每个字符的边界框),便于后续做“段落高亮”或“来源定位”。
对于其他格式(如 .docx, .pptx 等),LlamaIndex 会使用内置的默认加载器(如 DocxReader, PptxReader),不需要在 file_extractor 中列出。
创建一个 BeautifulSoupWebReader 实例,默认使用 requests + beautifulsoup4 抓取网页并提取正文文本。
3.2 网页加载
web_loader = BeautifulSoupWebReader()
web_docs = web_loader.load_data(urls=[
"https://cloud.tencent.com/developer/article/2499999"
])
local_loader.load_data():递归扫描 ./data 目录下的所有符合要求的文件,将它们分别解析为 LlamaIndex 的 Document 对象列表。每个 Document 包含 text(文本内容)和 metadata(如文件名、页数、创建时间等)。
web_loader.load_data(urls=[…]):抓取指定网页的 HTML,提取主文本内容,并返回一个 Document 对象列表(通常每个 URL 对应一个文档)。
documents = local_docs + web_docs:将本地文档和网页文档合并为一个列表,便于后续构建索引或查询。
3.3 合并文档
documents = local_docs + web_docs
- 直接使用
+操作符合并不同来源的Document列表,统一送入后续索引。
3.4 调试:打印文档预览
from pprint import pprint
for doc in local_docs:
pprint(doc.text[:200]) # 打印前200字符预览
print('-' * 130)
四、构建索引与查询引擎
假设我们已经通过上述步骤得到了 documents 列表(或直接使用之前加载的 documents_cloud),接下来构建索引。
# 构建向量索引
index = VectorStoreIndex.from_documents(documents)
# 创建查询引擎
query_engine = index.as_query_engine()
# 执行查询
response = query_engine.query("2022年实现营业收入?中文回答。")
print(response)
VectorStoreIndex.from_documents() 内部流程:
- 文本分块(Node Parsing):默认
chunk_size=1024,chunk_overlap=20。 - 向量化:调用
Settings.embed_model将每个块转为向量。 - 存储:存入默认的
SimpleVectorStore(内存中,可替换为 FAISS/Chroma 等持久化存储)。
query_engine.query() 内部流程:
- 将用户问题向量化。
- 检索 top‑k 个最相似的块(默认 k=2)。
- 将检索结果与问题组合成提示词。
- 调用
Settings.llm生成答案。 - 返回
Response对象(包含答案文本和源节点)。
代码汇总
import os
from llama_index.core import Settings, VectorStoreIndex, SimpleDirectoryReader
from llama_index.llms.dashscope import DashScope
from llama_index.embeddings.dashscope import DashScopeEmbedding
# ========== 1. 设置 API Key ==========
os.environ["DASHSCOPE_API_KEY"] = "XXX" # 从阿里云百炼平台获取
# ========== 2. 配置国内模型(替换 OpenAI) ==========
# Settings.llm = DashScope(model_name="qwen-max") # 大语言模型
# Settings.embed_model = DashScopeEmbedding(model_name="text-embedding-v2",api_key=os.environ["DASHSCOPE_API_KEY"]) # 嵌入模型
Settings.llm = DashScope(
model_name="qwen-max",
api_key=os.environ["DASHSCOPE_API_KEY"] # 显式从环境变量读取并传入
)
Settings.embed_model = DashScopeEmbedding(
model_name="text-embedding-v2",
api_key=os.environ["DASHSCOPE_API_KEY"] # 嵌入模型也需显式传递
)
# ========== 3. 读取本地文档(优化 PDF 解析) ==========
# 只保留一个 reader,避免重复覆盖
reader = SimpleDirectoryReader(
input_dir="./ragdata",
required_exts=[".pdf"],
recursive=True
)
documents_origin = reader.load_data()
# 可选:打印文档内容(确保文本提取正常)
from pprint import pprint
for document in documents_origin:
pprint(document.text[:5]) # 只打印前500字符,避免过多输出
print('-'*130)
# ========== 4. 构建索引与查询 ==========
index = VectorStoreIndex.from_documents(documents_origin)
query_engine = index.as_query_engine()
response = query_engine.query("2022年实现营业收入?中文回答。")
print(response)
from llama_index.core import SimpleDirectoryReader
from llama_index.readers.file import PyMuPDFReader
from llama_index.readers.web import BeautifulSoupWebReader
# 本地文件加载器(扩展支持)
# 使用 SimpleDirectoryReader 读取本地目录中的文件
local_loader = SimpleDirectoryReader(
input_dir="./ragdata", # 指定要读取的目录路径
required_exts=[".pdf", ".docx", ".pptx", ".epub", ".md"], # 只处理这些扩展名的文件
file_extractor={
".pdf": PyMuPDFReader(), # 对 PDF 文件使用 PyMuPDFReader(保留文本坐标信息)
}
)
# 网页加载器:使用 BeautifulSoupWebReader 抓取网页内容
web_loader = BeautifulSoupWebReader()
# 混合加载:同时读取本地文件和网页内容
local_docs = local_loader.load_data() # 读取本地文件,返回 Document 对象列表
web_docs = web_loader.load_data(urls=[ # 抓取指定 URL 的网页并解析为 Document
"https://cloud.tencent.com/developer/article/2499999?fromSource=gwzcw.9358214.9358214.9358214&utm_medium=cpc&utm_id=gwzcw.9358214.9358214.9358214"
])
documents = local_docs + web_docs # 合并本地文档和网页文档
from pprint import pprint
for doc in local_docs: # 遍历每个本地文档
# pprint(doc.text) # 可选:打印完整文本(注释掉)
pprint(doc.text[:5]) # 只打印每个文档文本的前5个字符,用于快速预览
print('-'*130) # 打印分隔线,便于区分不同文档
import nest_asyncio # 用于解决 Jupyter 环境中事件循环冲突的问题
nest_asyncio.apply() # 应用 nest_asyncio 补丁,允许在已有事件循环中运行异步代码
from llama_cloud_services import LlamaParse # 导入 LlamaCloud 的文档解析服务
# 创建 LlamaParse 解析器实例
parser = LlamaParse(
api_key="llx-XXX", # 替换为你的 LlamaCloud API Key
result_type="markdown", # 输出格式:markdown(也可选 "text")
num_workers=3, # 并行处理文件时的工作线程数
verbose=True, # 输出详细日志
language="ch_sim", # 文档语言:简体中文(默认 en)
)
# 配置文件提取器:对于 .pdf 扩展名,使用上面创建的 parser
file_extractor = {".pdf": parser}
# 使用 SimpleDirectoryReader 读取 ./ragdata 目录中的所有文件,
# 遇到 .pdf 文件时自动调用 LlamaParse 解析,其他文件使用默认读取器
documents_cloud = SimpleDirectoryReader(
"./ragdata", file_extractor=file_extractor
).load_data()
from pprint import pprint
for doc in documents_cloud: # 遍历每个解析后的文档
# pprint(doc.text) # 可选:打印完整文本内容(注释掉)
pprint(doc.text[:5]) # 打印每个文档文本的前 5 个字符(预览)
print('-' * 130) # 打印分隔线,便于区分不同文档
index = VectorStoreIndex.from_documents(documents_origin)
#步骤三,构建查询引擎
query_engine = index.as_query_engine()
#步骤四,得到结果
response = query_engine.query("2022年实现营业收入?中文回答。")
print(response)
五、Data Connectors 深度解析
数据连接器是 LlamaIndex 的“触角”,负责从各种数据源读取数据并标准化为 Document 对象。
5.1 支持的数据源
| 数据源类型 | 常用加载器 | 说明 |
|---|---|---|
| 本地文件 | SimpleDirectoryReader, PDFReader, PyMuPDFReader |
支持 PDF, DOCX, PPTX, EPUB, MD, TXT 等 |
| 数据库 | SQLDatabase |
通过 SQLAlchemy 连接 PostgreSQL, MySQL 等 |
| Web 爬取 | BeautifulSoupWebReader, NotionPageReader |
静态网页、Notion、Google Drive、Slack |
| API | 自定义(requests + Document) |
任意 REST API 或 GraphQL |
5.2 Llama Hub 与 Llama Cloud
- Llama Hub:官方集成中心,提供上百种现成数据加载器。通过
download_loader一键安装。from llama_index.core import download_loader GoogleDocsReader = download_loader("GoogleDocsReader") loader = GoogleDocsReader() docs = loader.load_data(document_ids=["..."]) - Llama Cloud:托管式文档解析服务,专攻复杂 PDF(扫描件、多栏、表格)。使用
LlamaParse调用。from llama_parse import LlamaParse parser = LlamaParse(api_key="your_key", result_type="markdown") documents = parser.load_data("./complex_report.pdf")
5.3 PDF 解析全流程(4 步详解)
| 步骤 | 核心任务 | 常见工具/方法 | 难点与解决方案 |
|---|---|---|---|
| 1. 输入与预处理 | 读取 PDF 文件,解密(如有密码),确定页面范围 | pdfplumber.open(), PyMuPDF.open() |
处理加密 PDF 需提供密码 |
| 2. 内容分类与识别 | 提取文本、图片、表格 | - 文本:pypdf, pdfplumber, PyMuPDF- 表格: pdfplumber.extract_table(), camelot- OCR: pytesseract + pdf2image |
扫描件需 OCR,表格需保留结构 |
| 3. 版面布局分析 | 恢复阅读顺序,处理多栏、跨页、连字符 | - 坐标排序(pdfplumber.extract_words())- 跨页表格拼接 |
多栏文本需按列重组;跨页段落需合并 |
| 4. 内容整合与输出 | 将处理后的文本、表格、元数据打包为 Document |
输出为纯文本、Markdown 或 JSON | 保留元数据(页数、位置框)便于溯源 |
核心要点:
- 使用
PyMuPDFReader可获取文本位置信息,适合需要引用原文的场景。 - 对于扫描件或复杂排版,优先考虑
LlamaParse云端解析。
六、常见问题与优化建议
| 问题 | 原因 | 解决方案 |
|---|---|---|
| API Key 无效(401) | 环境变量未正确传递或 Key 已失效 | 显式传入 api_key 参数;检查阿里云百炼控制台 |
PDF 读取乱码(输出 %PDF-1.4...) |
缺少 PDF 解析依赖或文档为扫描件 | pip install pypdf pdfplumber;扫描件使用 LlamaParse |
| 嵌入模型调用超时 | 网络问题或批次过大 | 减小 chunk_size,设置 embed_batch_size=10 |
| 查询结果不相关 | 分块不合理或检索 top‑k 太小 | 调整 chunk_size(512~1024),增大 similarity_top_k=5 |
混合加载时 document 未定义错误 |
代码笔误(document 应为 doc) |
使用正确的变量名,如 doc.text |
七、总结
本文完整演示了如何基于 LlamaIndex + 阿里云 DashScope 搭建一个国产化 RAG 系统,并深入解析了数据连接器的设计哲学与 PDF 解析的底层细节。核心步骤回顾:
- 配置 LLM 和 Embedding 模型(替换 OpenAI)。
- 混合加载本地文件和网页,合并为统一文档列表。
- 构建向量索引(自动分块、向量化、存储)。
- 执行自然语言查询,获得基于文档内容的答案。
- 理解 Data Connectors 的多种数据源,掌握 Llama Hub 和 Llama Cloud 的使用场景。
- 掌握 PDF 解析的 4 个核心步骤,能处理复杂排版和扫描件。
通过本文的学习,你应该能够独立构建一个适用于企业知识库、个人文档库、在线资讯监控等场景的 RAG 应用。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)