📚 1. LlamaIndex 介绍
官网标题:「 Build AI Knowledge Assistants over your enterprise data 」
LlamaIndex 是一个为开发「知识增强」的大语言模型应用的框架。知识增强,泛指任何在私有或特定领域数据基础上应用大语言模型的情况。例如:
在这里补充一张图。
- 💬Question-Answering Chatbots(也就是 RAG)
- 📄Document Understanding and Extraction(文档理解与信息抽取)
- 🤖Autonomous Agentsthat can perform research and take actions (智能体应用)
- 🔄Workflow orchestratingsingle and multi-agent (编排单个或多个智能体形成工作流)
LlamaIndex 有 Python 和 Typescript 两个版本,Python 版的文档相对更完善。
- 🐍Python 文档地址 :docs.llamaindex.ai/en/stable/
- 📚Python API 接口文档 :docs.llamaindex.ai/en/stable/a...
- 📘TS 文档地址 :ts.llamaindex.ai/
- 🔗Github 链接 :github.com/run-llama
LlamaIndex 的核心模块

💻 2. 安装 LlamaIndex
bash
pip install llama-index
💡 2.1 核心概念
在深入学习 LlamaIndex 之前,我们先了解几个核心概念:
- 📄Document(文档):
LlamaIndex 中的基本数据单元,代表一个完整的文档(如 PDF、网页、文本文件等)。每个 Document 包含文本内容以及可选的元数据(metadata)。
- 📝Node(节点):
Document 被切分后的文本片段,是检索和索引的基本单位。每个 Node 包含文本内容、元数据以及与其他 Node 的关系信息。
- 📊Index(索引):
为了快速检索而构建的数据结构。LlamaIndex 支持多种索引类型,如向量索引、关键词索引等。
- 🔍Retriever(检索器):
负责从索引中检索相关 Node 的组件,根据查询返回最相关的文档片段。
- 🤖Query Engine(查询引擎):
结合检索器和 LLM,根据检索到的上下文生成最终答案。
- 💬Chat Engine(对话引擎):
支持多轮对话的查询引擎,能够维护对话历史上下文。
数据流转过程:
📄 Document → 📝 Node → 📊 Index → 🔍 Retriever → 🤖 Query/Chat Engine → 💬 Response
📥 3. 数据加载(Loading)
📂 3.1、加载本地数据
SimpleDirectoryReader是一个简单的本地文件加载器。它会遍历指定目录,并根据文件扩展名自动加载文件(文本内容)。
支持的文件类型:
.csv- comma-separated values.docx- Microsoft Word.epub- EPUB ebook format.hwp- Hangul Word Processor.ipynb- Jupyter Notebook.jpeg,.jpg- JPEG image.mbox- MBOX email archive.md- Markdown.mp3,.mp4- audio and video.pdf- Portable Document Format.png- Portable Network Graphics.ppt,.pptm,.pptx- Microsoft PowerPoint
python
# 辅助函数:用于格式化展示 JSON 数据
import json
from pydantic.v1 import BaseModel
def show_json(data):
"""用于展示json数据"""
if isinstance(data, str):
obj = json.loads(data)
print(json.dumps(obj, indent=4, ensure_ascii=False))
elif isinstance(data, dict) or isinstance(data, list):
print(json.dumps(data, indent=4, ensure_ascii=False))
elif issubclass(type(data), BaseModel):
print(json.dumps(data.dict(), indent=4, ensure_ascii=False))
def show_list_obj(data):
"""用于展示一组对象"""
if isinstance(data, list):
for item in data:
show_json(item)
else:
raise ValueError("Input is not a list")
python
from llama_index.core import SimpleDirectoryReader
# 创建目录读取器
# input_dir: 要读取的目录路径
# recursive: 是否递归读取子目录(True/False)
# required_exts: 可选,指定只读取特定扩展名的文件
reader = SimpleDirectoryReader(
input_dir="./data",
recursive=False,
required_exts=[".pdf"]
)
# 加载文档,返回 Document 对象列表
documents = reader.load_data()
python
print(documents[0].text)
show_json(documents[0].json())
⚠️注意:对图像、视频、语音类文件,默认不会自动提取其中文字。如需提取,参考下面介绍的Data Connectors。
默认的PDFReader效果并不理想,我们可以更换文件加载器
LlamaParse
首先,登录并从 cloud.llamaindex.ai ↗ 注册并获取 api-key 。
然后,安装该包:
bash
pip install llama-cloud-services
python
# 在系统环境变量里配置 LLAMA_CLOUD_API_KEY=XXX
# 或使用 .env 文件配置(推荐)
from llama_cloud_services import LlamaParse
from llama_index.core import SimpleDirectoryReader
import nest_asyncio
from dotenv import load_dotenv
# 只在 Jupyter 环境中需要,解决异步事件循环问题
nest_asyncio.apply()
# 从 .env 文件加载环境变量
load_dotenv()
# 创建 LlamaParse 解析器
# result_type: 输出格式,"markdown" 或 "text"
parser = LlamaParse(result_type="markdown")
# 将 PDF 文件的解析器指定为 LlamaParse
file_extractor = {".pdf": parser}
# 使用自定义解析器加载文档
documents = SimpleDirectoryReader(
input_dir="./data",
required_exts=[".pdf"],
file_extractor=file_extractor
).load_data()
print(documents[0].text)
🔌 3.2、Data Connectors
用于处理更丰富的数据类型,并将其读取为Document的形式。
例如:直接读取网页
bash
pip install llama-index-readers-web
python
from llama_index.readers.web import SimpleWebPageReader
documents = SimpleWebPageReader(html_to_text=True).load_data(
["https://edu.guangjuke.com/tx/"]
)
print(documents[0].text)
💡更多 Data Connectors📁 内置的文件加载器🔌 连接三方服务的数据加载器,例如数据库🌐 更多加载器可以在 LlamaHub 上找到
✂️ 4. 文本切分与解析(Chunking)
为方便检索,我们通常把Document切分为Node。
在 LlamaIndex 中,Node被定义为一个文本的「chunk」。
✂️ 4.1、使用 TextSplitters 对文本做切分
例如:TokenTextSplitter按指定 token 数切分文本
python
from llama_index.core import Document
from llama_index.core.node_parser import TokenTextSplitter
# 创建文本切分器
# chunk_size: 每个 chunk 的最大 token 数(建议 256-1024,根据模型上下文窗口调整)
# chunk_overlap: chunk 之间的重叠 token 数(建议为 chunk_size 的 10-20%,保证上下文连续性)
node_parser = TokenTextSplitter(
chunk_size=512,
chunk_overlap=200
)
# 将 Document 切分为 Node 列表
# show_progress: 是否显示进度条(处理大量文档时有用)
nodes = node_parser.get_nodes_from_documents(
documents,
show_progress=False
)
# 查看切分后的 Node 结构
show_json(nodes[1].json())
show_json(nodes[2].json())
LlamaIndex 提供了丰富的TextSplitter,例如:
SentenceSplitter:在切分指定长度的 chunk 同时尽量保证句子边界不被切断;CodeSplitter:根据 AST(编译器的抽象句法树)切分代码,保证代码功能片段完整;SemanticSplitterNodeParser:根据语义相关性对将文本切分为片段。
📄 4.2、使用 NodeParsers 对有结构的文档做解析
例如:HTMLNodeParser解析 HTML 文档
python
from llama_index.core.node_parser import HTMLNodeParser
from llama_index.readers.web import SimpleWebPageReader
documents = SimpleWebPageReader(html_to_text=False).load_data(
["https://www.baidu.com/"]
)
# 默认解析 ["p", "h1", "h2", "h3", "h4", "h5", "h6", "li", "b", "i", "u", "section"]
parser = HTMLNodeParser(tags=["span"]) # 可以自定义解析哪些标签
nodes = parser.get_nodes_from_documents(documents)
for node in nodes:
print(node.text+"\n")
更多的NodeParser包括MarkdownNodeParser,JSONNodeParser等等。
📌 4.3 文本切分最佳实践
Chunk Size 选择建议:
- 小文档(< 1000 字):
chunk_size=256-512,chunk_overlap=50-100
- 中等文档(1000-10000 字):
chunk_size=512-1024,chunk_overlap=100-200
- 大文档(> 10000 字):
chunk_size=1024-2048,chunk_overlap=200-400
注意事项:
- Chunk size 需要根据 LLM 的上下文窗口大小调整(如 GPT-4 支持 128K,但实际使用时建议单个 chunk 不超过 2048 tokens)
- Overlap 过小可能导致上下文断裂,过大则增加存储和计算成本
- 对于代码文档,建议使用
CodeSplitter保持代码块完整性 - 对于结构化文档(HTML、Markdown),优先使用对应的
NodeParser而非简单切分
🔍 5. 索引(Indexing)与检索(Retrieval)
基础概念:
在「检索」相关的上下文中,「索引」即index, 通常是指为了实现快速检索而设计的特定「数据结构」。
索引的具体原理与实现不是本课程的教学重点,感兴趣的同学可以参考:传统索引、向量索引
🔍 5.1、向量检索
VectorStoreIndex直接在内存中构建一个 Vector Store 并建索引
python
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader
from llama_index.core.node_parser import TokenTextSplitter, SentenceSplitter
# 1. 加载 PDF 文档
documents = SimpleDirectoryReader(
"./data",
required_exts=[".pdf"],
).load_data()
# 2. 定义 Node Parser 用于切分文档
node_parser = TokenTextSplitter(chunk_size=512, chunk_overlap=200)
# 3. 将文档切分为 Node
nodes = node_parser.get_nodes_from_documents(documents)
# 4. 构建向量索引(默认在内存中,适合小规模数据)
# 构建过程会自动调用 Embedding 模型为每个 Node 生成向量
index = VectorStoreIndex(nodes)
# 方式二:直接从 Document 构建(会自动应用 transformations)
# index = VectorStoreIndex.from_documents(
# documents=documents,
# transformations=[SentenceSplitter(chunk_size=512)]
# )
# 5. 持久化索引到本地(可选,用于后续复用)
# index.storage_context.persist(persist_dir="./doc_emb")
# 6. 创建检索器
# similarity_top_k: 返回最相似的前 k 个结果(建议 3-10,根据需求调整)
vector_retriever = index.as_retriever(
similarity_top_k=2
)
# 7. 执行检索
# 检索过程:将查询文本转换为向量 → 在向量空间中搜索相似 Node → 返回结果
results = vector_retriever.retrieve("deepseek v3数学能力怎么样?")
# 8. 查看检索结果
print(results[0].text)
- 使用自定义的 Vector Store,以
Qdrant为例:
bash
pip install llama-index-vector-stores-qdrant
python
from llama_index.core.indices.vector_store.base import VectorStoreIndex
from llama_index.vector_stores.qdrant import QdrantVectorStore
from llama_index.core import StorageContext
from qdrant_client import QdrantClient
from qdrant_client.models import VectorParams, Distance
# 1. 创建 Qdrant 客户端
# location=":memory:": 内存模式(重启后数据丢失)
# location="./qdrant_db": 持久化到本地目录(推荐生产环境使用)
client = QdrantClient(location=":memory:")
# 2. 创建向量集合(Collection)
collection_name = "demo"
# size: 向量维度,需与 Embedding 模型输出维度一致(如 OpenAI text-embedding-3-small 为 1536)
# distance: 距离度量方式,COSINE(余弦相似度)适合文本检索
collection = client.create_collection(
collection_name=collection_name,
vectors_config=VectorParams(size=1536, distance=Distance.COSINE)
)
# 3. 创建 Qdrant Vector Store
vector_store = QdrantVectorStore(client=client, collection_name=collection_name)
# 4. 创建存储上下文,关联自定义的 Vector Store
storage_context = StorageContext.from_defaults(vector_store=vector_store)
# 5. 使用自定义 Vector Store 创建索引
# 数据会存储在 Qdrant 中,而非内存
index = VectorStoreIndex(nodes, storage_context=storage_context)
# 6. 创建检索器
vector_retriever = index.as_retriever(similarity_top_k=1)
# 7. 执行检索
results = vector_retriever.retrieve("deepseek v3数学能力怎么样")
print(results[0])
🔎 5.2、更多索引与检索方式
LlamaIndex 内置了丰富的检索机制,例如:
- 关键字检索
- RAG-Fusion
QueryFusionRetriever - 还支持 KnowledgeGraph、SQL、Text-to-SQL 等等
🔄 5.3、检索后处理
LlamaIndex 的Node Postprocessors提供了一系列检索后处理模块。
例如:我们可以用不同模型对检索后的Nodes做重排序
python
# 获取 retriever
vector_retriever = index.as_retriever(similarity_top_k=5)
# 检索
nodes = vector_retriever.retrieve("deepseek v3有多少参数?")
for i, node in enumerate(nodes):
print(f"[{i}] {node.text}\n")
python
from llama_index.core.postprocessor import LLMRerank
postprocessor = LLMRerank(top_n=2)
nodes = postprocessor.postprocess_nodes(nodes, query_str="deepseek v3有多少参数?")
for i, node in enumerate(nodes):
print(f"[{i}] {node.text}")
更多的 Rerank 及其它后处理方法,参考官方文档:Node Postprocessor Modules
📌 5.4 索引与检索最佳实践
内存 vs 持久化存储选择:
- 内存存储:适合小规模数据(< 1000 文档)、快速原型开发、一次性查询
- 持久化存储:适合生产环境、大规模数据、需要长期保存索引的场景
检索策略选择:
- 向量检索:适合语义搜索、相似度查询、多语言场景
- 关键词检索(BM25):适合精确匹配、术语查询、代码搜索
- 混合检索 :结合向量和关键词检索,通常效果最好(可用
QueryFusionRetriever)
Embedding 模型选择:
- 中文场景 :推荐使用支持中文的模型,如
text-embedding-v3(DashScope)、bge-large-zh-v1.5(HuggingFace) - 多语言场景 :推荐
text-embedding-3-small/large(OpenAI)、multilingual-e5-large - 成本考虑:开源模型可本地部署,API 模型按调用次数收费
💬 6. 生成回复(QA & Chat)
💬 6.1 单轮问答(Query Engine)
python
# 创建查询引擎(单轮问答)
# Query Engine 内部流程:检索相关 Node → 构建 Prompt → 调用 LLM 生成回答
qa_engine = index.as_query_engine()
# 执行查询
response = qa_engine.query("deepseek v3数学能力怎么样?")
# 输出结果
print(response)
流式输出
python
# 启用流式输出,适合实时交互场景
qa_engine = index.as_query_engine(streaming=True)
response = qa_engine.query("deepseek v3数学能力怎么样?")
# 方式一:使用内置方法打印流式输出
response.print_response_stream()
# 方式二:手动控制输出(更灵活)
# for token in response.response_gen:
# print(token, end="", flush=True)
💭 6.2 多轮对话(Chat Engine)
python
chat_engine = index.as_chat_engine()
response = chat_engine.chat("deepseek v3数学能力怎么样?")
print(response)
python
response = chat_engine.chat("代码能力呢?")
print(response)
流式输出
python
chat_engine = index.as_chat_engine()
# 流式对话,逐 token 输出
streaming_response = chat_engine.stream_chat("deepseek v3数学能力怎么样?")
# 方式一:使用内置方法
# streaming_response.print_response_stream()
# 方式二:手动控制输出(推荐,可自定义格式)
for token in streaming_response.response_gen:
print(token, end="", flush=True)
🔄 6.3 Query Engine vs Chat Engine
Query Engine(单轮问答):
- 每次查询都是独立的,不保留历史对话
- 适合:一次性问答、文档查询、信息检索
- 性能:更快,资源消耗更少
Chat Engine(多轮对话):
- 维护对话历史,支持上下文理解
- 适合:交互式对话、需要理解前文的问题(如"它呢?"、"详细说明一下")
- 性能:需要存储历史,资源消耗更多
选择建议:
- 简单问答场景 → Query Engine
- 需要上下文理解 → Chat Engine
- 生产环境建议根据实际需求选择,避免不必要的资源消耗
⚙️ 7. 底层接口:Prompt、LLM 与 Embedding
📝 7.1 Prompt 模板
PromptTemplate定义提示词模板
python
from llama_index.core import PromptTemplate
# 创建提示词模板,使用 {变量名} 作为占位符
prompt = PromptTemplate("写一个关于{topic}的笑话")
# 格式化模板,替换占位符
result = prompt.format(topic="小明")
print(result)
# 输出:'写一个关于小明的笑话'
ChatPromptTemplate定义多轮消息模板
python
from llama_index.core.llms import ChatMessage, MessageRole
from llama_index.core import ChatPromptTemplate
chat_text_qa_msgs = [
ChatMessage(
role=MessageRole.SYSTEM,
content="你叫{name},你必须根据用户提供的上下文回答问题。",
),
ChatMessage(
role=MessageRole.USER,
content=(
"已知上下文:\n" \
"{context}\n\n" \
"问题:{question}"
)
),
]
text_qa_template = ChatPromptTemplate(chat_text_qa_msgs)
print(
text_qa_template.format(
name="小明",
context="这是一个测试",
question="这是什么"
)
)
system: 你叫小明,你必须根据用户提供的上下文回答问题。 user: 已知上下文: 这是一个测试
问题:这是什么 assistant:
🤖 7.2 语言模型
python
from llama_index.llms.openai import OpenAI
llm = OpenAI(temperature=0, model="gpt-4o")
python
response = llm.complete(prompt.format(topic="小明"))
print(response.text)
python
response = llm.complete(
text_qa_template.format(
name="小明",
context="这是一个测试",
question="你是谁,我们在干嘛"
)
)
print(response.text)
连接DeepSeek
bash
pip install llama-index-llms-deepseek
python
import os
from llama_index.llms.deepseek import DeepSeek
llm = DeepSeek(model="deepseek-chat", api_key=os.getenv("DEEPSEEK_API_KEY"), temperature=1.5)
response = llm.complete("写个笑话")
print(response)
设置全局使用的语言模型
python
from llama_index.core import Settings
Settings.llm = DeepSeek(model="deepseek-chat", api_key=os.getenv("DEEPSEEK_API_KEY"), temperature=1.5)
除 OpenAI 外,LlamaIndex 已集成多个大语言模型,包括云服务 API 和本地部署 API,详见官方文档:Available LLM integrations
🧮 7.3 Embedding 模型
python
from llama_index.embeddings.openai import OpenAIEmbedding
from llama_index.core import Settings
# 全局设定 Embedding 模型
# model: 模型名称
# dimensions: 向量维度(可选,某些模型支持自定义维度以节省成本)
Settings.embed_model = OpenAIEmbedding(
model="text-embedding-3-small",
dimensions=512 # 降低维度可节省存储和计算成本,但可能影响精度
)
LlamaIndex 同样集成了多种 Embedding 模型,包括云服务 API 和开源模型(HuggingFace)等,详见官方文档。
📌 7.4 模型配置最佳实践
LLM 选择建议:
- 开发测试:使用成本较低的模型(如 GPT-3.5-turbo、DeepSeek)
- 生产环境:根据任务复杂度选择,简单任务用轻量模型,复杂任务用强模型
- 本地部署:考虑使用开源模型(如 Llama、Qwen)降低成本
Temperature 参数调整:
- 0-0.3:确定性输出,适合事实性问答、代码生成
- 0.5-0.7:平衡创造性和准确性,适合一般对话
- 0.8-1.5:高创造性,适合创意写作、头脑风暴
Embedding 模型选择:
- 确保向量维度与向量数据库配置一致
- 中文场景优先选择支持中文的模型
- 考虑成本:开源模型可本地部署,API 模型按调用收费
🏗️ 8. 基于 LlamaIndex 实现一个功能较完整的 RAG 系统
功能要求:
- 加载指定目录的文件
- 支持 RAG-Fusion
- 使用 Qdrant 向量数据库,并持久化到本地
- 支持检索后排序
- 支持多轮对话
python
from qdrant_client import QdrantClient
from qdrant_client.models import VectorParams, Distance
EMBEDDING_DIM = 1536
COLLECTION_NAME = "full_demo"
PATH = "./qdrant_db"
client = QdrantClient(path=PATH)
python
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader, get_response_synthesizer
from llama_index.vector_stores.qdrant import QdrantVectorStore
from llama_index.core.node_parser import SentenceSplitter
from llama_index.core.response_synthesizers import ResponseMode
from llama_index.core.ingestion import IngestionPipeline
from llama_index.core import Settings
from llama_index.core import StorageContext
from llama_index.core.postprocessor import LLMRerank, SimilarityPostprocessor
from llama_index.core.retrievers import QueryFusionRetriever
from llama_index.core.query_engine import RetrieverQueryEngine
from llama_index.core.chat_engine import CondenseQuestionChatEngine
from llama_index.llms.dashscope import DashScope, DashScopeGenerationModels
from llama_index.embeddings.dashscope import DashScopeEmbedding, DashScopeTextEmbeddingModels
import os
# ========== 第一步:配置全局模型 ==========
# 1. 设置 LLM(用于生成回答)
Settings.llm = DashScope(
model_name=DashScopeGenerationModels.QWEN_MAX,
api_key=os.getenv("DASHSCOPE_API_KEY")
)
# 2. 设置 Embedding 模型(用于生成向量)
Settings.embed_model = DashScopeEmbedding(
model_name=DashScopeTextEmbeddingModels.TEXT_EMBEDDING_V1
)
# 3. 设置全局文档处理管道(自动应用于所有文档)
Settings.transformations = [
SentenceSplitter(chunk_size=512, chunk_overlap=200)
]
# ========== 第二步:加载和索引文档 ==========
# 4. 加载本地文档
documents = SimpleDirectoryReader("./data").load_data()
# 5. 清理已存在的集合(可选,用于重新构建索引)
if client.collection_exists(collection_name=COLLECTION_NAME):
client.delete_collection(collection_name=COLLECTION_NAME)
# 6. 创建 Qdrant 集合
client.create_collection(
collection_name=COLLECTION_NAME,
vectors_config=VectorParams(size=EMBEDDING_DIM, distance=Distance.COSINE)
)
# 7. 创建 Vector Store 并关联到 Qdrant
vector_store = QdrantVectorStore(client=client, collection_name=COLLECTION_NAME)
storage_context = StorageContext.from_defaults(vector_store=vector_store)
# 8. 构建索引(会自动应用 Settings.transformations 切分文档)
index = VectorStoreIndex.from_documents(
documents,
storage_context=storage_context
)
# ========== 第三步:配置检索和排序 ==========
# 9. 定义检索后处理器
# LLMRerank: 使用 LLM 对检索结果重新排序,提高准确性(但会增加延迟和成本)
reranker = LLMRerank(top_n=2)
# SimilarityPostprocessor: 过滤相似度低于阈值的文档(未使用,仅作示例)
# sp = SimilarityPostprocessor(similarity_cutoff=0.6)
# 10. 创建 RAG-Fusion 检索器
# RAG-Fusion 原理:将原始查询扩展为多个相关查询,分别检索后合并结果
fusion_retriever = QueryFusionRetriever(
[index.as_retriever()], # 可以传入多个检索器进行融合
similarity_top_k=5, # 每个查询返回 top 5 结果
num_queries=3, # 生成 3 个扩展查询
use_async=False, # 是否异步执行(True 可提升速度)
)
# ========== 第四步:构建查询引擎 ==========
# 11. 构建单轮查询引擎
# ResponseMode.REFINE: 先基于第一个 chunk 生成回答,再用其他 chunk 逐步优化
query_engine = RetrieverQueryEngine.from_args(
fusion_retriever,
node_postprocessors=[reranker], # 应用重排序
response_synthesizer=get_response_synthesizer(
response_mode=ResponseMode.REFINE # 其他模式:COMPACT, TREE_SUMMARIZE, SIMPLE_SUMMARIZE
)
)
# ========== 第五步:构建对话引擎 ==========
# 12. 创建多轮对话引擎
# CondenseQuestionChatEngine: 将历史对话压缩为独立查询,适合长对话
chat_engine = CondenseQuestionChatEngine.from_defaults(
query_engine=query_engine,
# 可以自定义问题压缩的 prompt 模板
# condense_question_prompt="..."
)
python
# 测试多轮对话
# User: deepseek v3有多少参数
# User: 每次激活多少
while True:
question=input("User:")
if question.strip() == "":
break
response = chat_engine.chat(question)
print(f"AI: {response}")
❓ 9. 常见问题 FAQ
📥 9.1 数据加载相关问题
Q: 如何处理大文件或大量文件?
A: 有几种策略:
- 使用
recursive=True递归读取子目录 - 分批加载文件,避免一次性加载所有文件到内存
- 使用流式处理(Streaming),边读边处理
- 对于超大文件,考虑先预处理,提取关键部分
python
# 示例:分批加载
files = ["file1.pdf", "file2.pdf", "file3.pdf"]
for file in files:
documents = SimpleDirectoryReader(input_files=[file]).load_data()
# 处理 documents
Q: PDF 文件解析效果不好怎么办?
A: 可以尝试以下方法:
- 使用
LlamaParse替代默认的 PDFReader(效果更好但需要 API key) - 对于扫描版 PDF,先使用 OCR 工具提取文字
- 检查 PDF 是否包含可提取的文本层(非纯图片)
Q: 如何处理图像、视频、音频文件中的文字?
A: 需要使用专门的 Data Connectors:
- 图像 OCR:使用
ImageReader或集成 OCR 服务 - 视频字幕:提取视频中的字幕文件
- 音频转文字:使用语音识别服务(如 Whisper)
✂️ 9.2 文本切分相关问题
Q: Chunk size 应该设置多大?
A: 需要根据以下因素综合考虑:
- LLM 上下文窗口:确保 chunk + 查询 + 回答不超过模型限制
- 文档类型:代码文档建议 512-1024,自然语言建议 256-512
- 检索精度:chunk 太小可能丢失上下文,太大可能包含无关信息
- 经验值:大多数场景下,512-1024 tokens 是比较好的选择
Q: Chunk overlap 设置多少合适?
A: 一般建议:
- 设置为 chunk_size 的 10-20%(如 chunk_size=512,overlap=50-100)
- 对于长文档或需要保持上下文连续性的场景,可以适当增大
- 注意:overlap 过大会增加存储和计算成本
Q: 为什么切分后的结果不理想?
A: 可能的原因和解决方案:
- 问题 :在句子中间切断 →解决 :使用
SentenceSplitter而非TokenTextSplitter - 问题 :代码块被破坏 →解决 :使用
CodeSplitter - 问题 :语义不完整 →解决 :使用
SemanticSplitterNodeParser - 问题 :结构化文档解析错误 →解决 :使用对应的
NodeParser(如HTMLNodeParser、MarkdownNodeParser)
🔍 9.3 检索相关问题
Q: 检索效果不好,返回的结果不相关怎么办?
A: 可以尝试以下优化方法:
- 调整 chunk size:太大或太小都可能影响效果
- 尝试不同的 TextSplitter :
SentenceSplitter通常比TokenTextSplitter效果更好 - 使用 Rerank :使用
LLMRerank对检索结果重新排序 - 检查 Embedding 模型:确保使用的模型适合你的数据(如中文数据使用中文模型)
- 使用混合检索:结合向量检索和关键字检索(如 RAG-Fusion)
- 调整 similarity_top_k:适当增大返回结果数量,然后通过 Rerank 筛选
Q: 检索速度太慢怎么办?
A: 优化建议:
- 使用持久化向量数据库(如 Qdrant)而非内存存储
- 减少
similarity_top_k的值 - 使用异步检索(
use_async=True) - 考虑使用更快的 Embedding 模型(如本地部署的轻量模型)
- 对于大规模数据,考虑使用专业的向量数据库服务(如 Pinecone)
Q: 向量检索和关键字检索应该选哪个?
A: 选择建议:
- 向量检索:适合语义搜索、理解同义词、多语言场景
- 关键字检索(BM25):适合精确匹配、术语查询、代码搜索
- 混合检索:结合两者优势,通常效果最好(推荐)
🇨🇳 9.4 中文文档处理问题
Q: 如何处理中文文档?
A: 关键点:
- 使用支持中文的 Embedding 模型:
- 使用适合中文的 TextSplitter:
- 确保 LLM 支持中文:
python
# 中文场景推荐配置
from llama_index.embeddings.dashscope import DashScopeEmbedding
from llama_index.core.node_parser import SentenceSplitter
Settings.embed_model = DashScopeEmbedding(
model_name=DashScopeTextEmbeddingModels.TEXT_EMBEDDING_V3
)
Settings.transformations = [SentenceSplitter(chunk_size=512, chunk_overlap=100)]
⚡ 9.5 性能和成本问题
Q: 如何降低 API 调用成本?
A: 优化策略:
- 使用开源模型:本地部署开源 LLM 和 Embedding 模型(如 Llama、Qwen、BGE)
- 缓存机制:对相同查询结果进行缓存
- 减少 Rerank 调用:只在必要时使用 LLMRerank(会增加成本)
- 优化 chunk 数量:减少不必要的 chunk,降低 Embedding 调用次数
- 选择合适的模型:简单任务使用轻量模型,复杂任务再用强模型
Q: 内存占用太大怎么办?
A: 解决方案:
- 使用持久化存储(Qdrant、Chroma 等)而非内存存储
- 分批处理文档,不要一次性加载所有数据
- 使用流式处理,边处理边释放内存
- 考虑使用更轻量的 Embedding 模型
Q: 索引构建速度慢怎么办?
A: 优化方法:
- 使用异步处理(
use_async=True) - 批量处理文档而非逐个处理
- 使用更快的 Embedding 模型
- 对于大规模数据,考虑分布式处理
🏭 9.6 部署和生产环境问题
Q: 如何持久化索引以便后续复用?
A: 两种方式:
- 使用向量数据库(推荐):
python
# 使用 Qdrant 等向量数据库,数据自动持久化
client = QdrantClient(path="./qdrant_db")
- 使用本地文件存储:
python
# 保存索引到本地
index.storage_context.persist(persist_dir="./doc_emb")
# 后续加载
from llama_index.core import load_index_from_storage
storage_context = StorageContext.from_defaults(persist_dir="./doc_emb")
index = load_index_from_storage(storage_context)
Q: 如何更新已构建的索引?
A: 更新策略:
- 增量更新 :使用
index.insert()添加新文档 - 全量重建:删除旧索引,重新构建(适合文档经常变化的情况)
- 版本管理:为不同版本的索引创建不同的 collection
Q: 生产环境应该注意什么?
A: 关键点:
- 使用持久化存储:避免数据丢失
- 错误处理:添加异常捕获和重试机制
- 监控和日志:记录 API 调用、检索性能等
- 限流和缓存:避免 API 调用过频
- 安全性:保护 API key,避免敏感数据泄露
- 性能优化:使用异步、批量处理等技术
✨ 10. 总结
本文全面介绍了 LlamaIndex 框架的核心功能和使用方法,帮助读者快速上手构建 RAG 应用。
核心流程回顾
一个完整的 RAG 系统通常包含以下步骤:
- 📥数据加载(Loading)
- ✂️文本切分与解析(Chunking)
- 📊构建索引(Indexing)
- 🔍检索(Retrieval)
- 💬生成回答(QA & Chat)
关键要点
- ✂️Chunk 策略:选择合适的 chunk size 和 overlap 是 RAG 系统成功的关键
- 💾存储选择:根据数据规模和场景选择内存存储或持久化存储
- 🔍检索策略:向量检索适合语义搜索,关键字检索适合精确匹配,混合检索通常效果最好
- 🤖模型选择:根据任务需求和数据特点选择合适的 LLM 和 Embedding 模型
- 🇨🇳中文支持:处理中文文档时,务必使用支持中文的 Embedding 模型和合适的 TextSplitter
最佳实践建议
- 🚀开发阶段:使用内存存储和简单配置快速验证想法
- 🏭生产环境:使用持久化向量数据库,添加错误处理和监控
- ⚡性能优化:合理设置参数,使用异步处理,考虑缓存机制
- 💰成本控制:根据任务复杂度选择模型,考虑使用开源模型降低成本
下一步学习
- 📚深入学习:LlamaIndex 官方文档
- 🔌探索连接器:LlamaHub 上找到更多 Data Connectors
- 🤖高级功能:了解 Agent 和 Workflow 的用法
- 💡实践项目:尝试构建自己的 RAG 应用,解决实际问题
- 🎯社区支持:加入 LlamaIndex 社区,获取帮助和分享经验
希望本文能帮助你快速掌握 LlamaIndex,构建出强大的知识增强应用!如有问题,欢迎参考上面的常见问题部分,或查阅官方文档。
🎉END
如果你觉得本文有帮助,欢迎点赞👍、在看👀、转发📤,也欢迎留言💬分享你的经验!