LlamaIndex (原名 GPT Index) 学习笔记
文档版本: 2025年6月
1. 什么是 LlamaIndex?
LlamaIndex (原名 GPT Index) 是一个数据框架 (Data Framework) ,旨在帮助开发者构建基于大型语言模型 (LLM) 的应用程序,特别是那些需要处理私有、专有或领域特定数据的应用程序。
核心问题:虽然 LLM 在通用领域展现了强大的能力,但它们通常无法直接访问最新的、内部的或特定领域的数据。当用户的问题涉及这些外部知识时,LLM 会因为训练数据的限制而"幻觉"(hallucinate)或给出错误答案。
LlamaIndex 的解决方案:
LlamaIndex 提供了一套工具,使得 LLM 能够 摄取 (ingest)、索引 (index) 和检索 (retrieve) 各种数据源,然后将这些数据注入到 LLM 的上下文中,从而使其能够基于这些外部知识进行回答。
关键理念:LlamaIndex 的核心在于连接你的数据和 LLM。它将你的非结构化数据(如文档、PDF、数据库记录)转化为 LLM 可以理解并利用的结构化表示,实现 LLM 的知识增强 (Knowledge Augmentation)。
2. LlamaIndex 的核心概念与工作流程
处理流程
文档预处理阶段:
- 支持多种格式文档加载(PDF/Word/Markdown等)
- 使用专用解析器提取结构化内容
- 创建带有元数据的文档节点
- 采用多种分块策略处理长文本
索引构建阶段:
- 使用嵌入模型生成向量表示
- 构建多种索引类型:
- 向量索引(稠密检索)
- 关键词索引(稀疏检索)
- 知识图谱索引(关系检索)
- 组合索引(混合检索)
查询处理阶段:
- 查询解析和意图识别
- 多策略检索:
- 向量相似度搜索
- 关键词匹配
- 混合检索策略
- 节点后处理(排序/过滤)
响应生成阶段:
- 多种结果合成模式:
- 紧凑模式(节省token)
- 树状汇总(层次化处理)
- 渐进式摘要(流式生成)
- 支持不同LLM后端
优化闭环:
- 持续评估检索效果
- 动态调整索引参数
- 支持在线更新索引
S5: 持续评估与优化 S4: 答案合成策略 S3: 查询理解与检索 S2: 索引类型与结构 S1: 数据预处理与加载 持续改进 支持格式 解析器 策略 模型 NLP处理 策略选择 模式 LLM 命中率分析 评估反馈 相关性评分 调整分块策略 索引优化 更新嵌入模型 索引结构调整 紧凑模式 响应合成 树状汇总 渐进式摘要 GPT-4/Claude等 意图识别 查询解析 关键词提取 向量相似度 检索策略 关键词匹配 混合检索 Top-k节点 节点检索 向量索引 索引构建 关键词索引 知识图谱索引 组合索引 PDF/PPT/Word/HTML等 文档加载 PDF解析器/Markdown解析器等 文档解析 节点属性设置 节点创建 固定大小/语义分割 文本分块 OpenAI/BGE/Sentence-Transformer 嵌入生成 用户输入 向量存储 查询输入 结果输出
LlamaIndex 的工作流程两个主要阶段分别为:索引构建 (Indexing) 和 查询 (Querying)。
2.1. 索引构建 (Indexing)
LlamaIndex 会将你的原始数据转化为可供 LLM 理解和检索的格式。
-
数据连接器 (
Data Connectors / Loaders
):LlamaIndex 提供了一系列预构建的数据连接器,用于从各种数据源加载数据。
- 文件系统:
SimpleDirectoryReader
(TXT, PDF, DOCX, CSV等) - 数据库: PostgreSQL, MongoDB, MySQL 等
- SaaS 应用: Notion, Slack, Google Docs, Confluence, Jira 等
- API: 各种自定义 REST API
- 更多: 社区贡献了大量的加载器,几乎可以覆盖所有常见数据源。
- 文件系统:
-
文档 (Documents): 加载器读取数据后,LlamaIndex 会将其表示为
Document
对象。一个Document
对象是 LlamaIndex 中的基本数据单元,包含原始文本内容和可选的元数据(如文件名、创建日期、作者等)。 -
节点 (Nodes):Document 通常非常大,不适合直接放入 LLM 的上下文窗口。因此,LlamaIndex 会将 Document
分割成更小的、可管理的块,称为 Node
-
分块策略 (Chunking Strategies):
如何分割 Document 非常关键,它决定了查询时能获取到的上下文质量。
- 固定大小分块: 最简单,按固定字符数或 Token 数分割。
- 递归字符文本分块 (RecursiveCharacterTextSplitter): 按段落、句子等语义边界递归分割,优先级高者优先。
- 基于语义的分块: 结合嵌入模型,确保分割后的块语义完整。
- 上下文增强: 可以配置
Node
包含前后段落、章节标题等额外上下文信息。
-
Node
是索引和检索的基本单位。每个Node
通常都会有其对应的嵌入向量 (Embedding Vector),用于语义相似度搜索。
-
-
索引 (Indexes):Node 被创建后,LlamaIndex 会组织这些 Node 以便高效检索。索引是 LlamaIndex 的核心。
- 向量存储索引 (Vector Store Index): 最常用。将每个 Node 的嵌入向量存储在向量数据库中。查询时,通过计算查询文本的嵌入向量与 Node 嵌入向量的相似度来查找最相关的 Node
- 支持的向量数据库: Chroma, Pinecone, Milvus, Weaviate, Qdrant, FAISS (本地) 等。
- 树索引 (Tree Index): 将
Node
构建成树状结构。叶节点是原始Node
,父节点是其子节点内容的总结。查询时可以从根节点开始遍历,向下钻取以获取更详细信息。 - 关键词表索引 (Keyword Table Index): 为每个
Node
提取关键词,并构建关键词到Node
的映射。查询时,通过匹配关键词来查找相关Node
。 - 文档摘要索引 (Summary Index): 将所有
Node
串联起来,形成一个完整的文档链。查询时,通常会对整个文档进行总结或顺序遍历。 - 知识图谱索引 (Knowledge Graph Index): 从
Node
中提取实体和关系,构建知识图谱。查询时,可以进行图遍历来获取结构化知识。
- 向量存储索引 (Vector Store Index): 最常用。将每个 Node 的嵌入向量存储在向量数据库中。查询时,通过计算查询文本的嵌入向量与 Node 嵌入向量的相似度来查找最相关的 Node
2.2. 查询 (Querying)
这是用户提问并获取答案的阶段,LlamaIndex 利用构建好的索引来增强 LLM 的能力。
-
查询引擎 (Query Engine): 这是用户与 LlamaIndex 交互的主要接口。它接收用户查询,并协调检索和 LLM 生成答案的过程。
-
检索器 (Retriever):
负责根据用户查询从索引中检索最相关的 Node。不同的索引类型会对应不同的检索策略。
- 向量检索: 计算查询嵌入与
Node
嵌入的相似度。 - 关键词检索: 匹配查询中的关键词。
- 混合检索 (Hybrid Retrieval): 结合多种检索策略(如关键词+向量)。
- 子查询检索: 将复杂查询分解为多个子查询。
- 向量检索: 计算查询嵌入与
-
节点后处理器 (Node Postprocessors):在检索到 Node后,但在发送给 LLM 之前,可以对这些 Node进行后处理,以优化上下文。
- 相似度排名过滤器: 过滤掉相似度低于阈值的
Node
。 - 重新排名器 (Re-ranker): 使用一个更小的、更精确的模型(如 Sentence Transformers)对检索到的
Node
进行二次排序,以找到最相关的Node
。 - 去重: 移除重复的
Node
。 - 上下文裁剪: 确保上下文不超过 LLM 的 Token 限制。
- 相似度排名过滤器: 过滤掉相似度低于阈值的
-
响应合成器 (Response Synthesizer):
接收检索到的 Node 和原始用户查询,将其打包成一个 Prompt,然后发送给 LLM,并解析 LLM 的响应。
refine
: 迭代地细化答案,尤其适用于处理大量Node
。compact
(默认): 将所有Node
压缩到单个 Prompt 中。tree_summarize
: 递归地总结Node
,生成一个摘要。simple_summarize
: 将所有Node
作为一个大文本块进行总结。
-
LLM (Large Language Model): LlamaIndex 支持多种 LLM,包括 OpenAI (GPT-3.5/4), Anthropic (Claude), Google (PaLM/Gemini), 以及通过 Hugging Face 或本地部署的开源 LLM (如 Llama2, Mistral, Qwen)。
-
嵌入模型 (Embedding Model): 用于将文本(文档、节点、查询)转换为数值向量(嵌入)。LlamaIndex 支持 OpenAI Embeddings, Hugging Face Embeddings, Sentence Transformers 等。
3. 核心代码示例 (基础 RAG 流程)
如何使用 LlamaIndex 构建一个简单的 RAG系统,从本地文档中回答问题。
python
import os
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader, ServiceContext, Settings
from llama_index.llms.openai import OpenAI # 或其他 LLM 提供商
from llama_index.embeddings.openai import OpenAIEmbedding # 或其他嵌入模型
# --- 配置环境 ---
# 确保设置了 OpenAI API 密钥,或者配置其他LLM和嵌入模型
# os.environ["OPENAI_API_KEY"] = "YOUR_OPENAI_API_KEY"
# LlamaIndex >= 0.10.0 版本推荐使用 Settings 配置
Settings.llm = OpenAI(model="gpt-3.5-turbo", temperature=0.1)
Settings.embed_model = OpenAIEmbedding(model="text-embedding-ada-002")
Settings.chunk_size = 1024 # 默认块大小
Settings.chunk_overlap = 20 # 块之间的重叠,提供更多上下文
# --- 1. 准备数据 ---
# 创建一个 'data' 文件夹,并在其中放入一些 .txt 或 .pdf 文件
# 例如:
# data/
# - my_document_1.txt
# - my_document_2.pdf
# 加载数据
print("Loading documents from './data'...")
documents = SimpleDirectoryReader("./data").load_data()
print(f"Loaded {len(documents)} documents.")
# --- 2. 构建索引 ---
# 最常用的是 VectorStoreIndex
# LlamaIndex 会自动分块、生成嵌入并存储到内存中的向量存储
print("Building VectorStoreIndex...")
index = VectorStoreIndex.from_documents(documents)
print("Index built successfully.")
# --- 3. 创建查询引擎 ---
# QueryEngine 是与索引交互的主要接口
query_engine = index.as_query_engine(
similarity_top_k=2 # 检索最相似的 2 个节点
)
# --- 4. 执行查询 ---
query = "What is the main topic of the documents?" # 替换为你想问的问题
print(f"\nQuerying: '{query}'")
response = query_engine.query(query)
# --- 5. 打印响应 ---
print("\n--- Response ---")
print(response)
# 打印源节点信息,查看LLM使用了哪些原文片段来生成答案
print("\n--- Source Nodes ---")
for source_node in response.source_nodes:
print(f"Node ID: {source_node.id_}")
print(f"Text (first 200 chars): {source_node.text[:200]}...")
print(f"Metadata: {source_node.metadata}")
print("-" * 20)
核心模块 (概念性) 代码解释:
-
SimpleDirectoryReader("./data").load_data()
:- 功能: 从指定目录加载所有支持格式的文档。
- 输出: 一个
list
,其中包含多个Document
对象。每个Document
存储原始文本及其元数据。
-
VectorStoreIndex.from_documents(documents)
:- 功能: 这是索引构建的核心。它负责将原始
Document
转换为可查询的索引。 - 内部流程:
- 分块 (Chunking): 将每个
Document
分割成多个较小的Node
(默认通过Settings.chunk_size
和Settings.chunk_overlap
控制)。 - 嵌入 (Embedding): 使用配置好的
Settings.embed_model
为每个Node
的文本内容生成一个高维向量(嵌入)。 - 存储 (Storage): 将
Node
对象(包括其文本、嵌入和元数据)存储在一个向量存储中。默认是内存中的 FAISS 向量存储。
- 分块 (Chunking): 将每个
- 输出: 一个
VectorStoreIndex
对象。
- 功能: 这是索引构建的核心。它负责将原始
-
index.as_query_engine(similarity_top_k=2)
:- 功能: 基于构建好的
index
创建一个QueryEngine
。 similarity_top_k
: 指定在检索阶段,从向量存储中查找与查询最相似的 K 个Node
。- 输出: 一个
QueryEngine
对象。
- 功能: 基于构建好的
-
query_engine.query(query)
:-
功能: 执行实际的查询操作。
-
内部流程:
-
查询嵌入: 将用户
query
通过Settings.embed_model
转换为嵌入向量。 -
检索 (Retrieval): 使用查询嵌入在
index
的向量存储中进行相似度搜索,找到similarity_top_k
个最相关的Node
。 -
响应合成 (Response Synthesis): 将检索到的 Node 的文本内容和原始用户查询打包成一个 Prompt。
-
Prompt
示例如下(LlamaIndex 会自动构建):
bash"Context information is below.\n" "---------------------\n" "{retrieved_node_1_text}\n" "{retrieved_node_2_text}\n" "---------------------\n" "Given the context information and not prior knowledge, answer the query.\n" "Query: {user_query}\n" "Answer:"
-
将此 Prompt 发送给
Settings.llm
。
-
-
LLM 推理: LLM 基于 Prompt 生成答案。
-
-
输出: 一个
Response
对象,包含 LLM 生成的答案以及用于生成答案的源节点信息。
-
4. LlamaIndex 的高级特性
LlamaIndex 提供了许多高级功能来应对更复杂的应用场景:
-
持久化存储 (Persistence):将索引保存到磁盘,避免每次运行时都重新构建。
python# 保存索引 index.storage_context.persist(persist_dir="./storage") # 加载索引 from llama_index.core import StorageContext, load_index_from_storage storage_context = StorageContext.from_defaults(persist_dir="./storage") index = load_index_from_storage(storage_context)
-
集成外部向量数据库 (Vector Stores):
- 除了内存中的 FAISS,LlamaIndex 可以轻松集成 Pinecone, Chroma, Milvus, Weaviate 等生产级向量数据库。
- 这对于大规模数据和高并发场景至关重要。
python# 示例:使用 ChromaDB 作为向量存储 from llama_index.vector_stores.chroma import ChromaVectorStore import chromadb # 创建或连接 Chroma 客户端 db = chromadb.PersistentClient(path="./chroma_db") chroma_collection = db.get_or_create_collection("my_documents") vector_store = ChromaVectorStore(chroma_collection=chroma_collection) # 构建索引时指定向量存储 index = VectorStoreIndex.from_documents( documents, vector_store=vector_store, # service_context=service_context # 旧版本用法,新版本用 Settings )
-
自定义分块策略 (Custom Chunking):
- LlamaIndex 允许使用不同的文本分割器,如
SentenceSplitter
,TokenTextSplitter
,MarkdownTextSplitter
等。 - 可以自定义
chunk_size
和chunk_overlap
。 - 高级分块:例如,为代码文件和普通文本使用不同的分块策略。
- LlamaIndex 允许使用不同的文本分割器,如
-
节点后处理器 (Node Postprocessors):
SimilarityPostprocessor
: 根据相似度阈值过滤。KeywordNodePostprocessor
: 基于关键词过滤。MetadataReplacementPostProcessor
: 动态替换节点元数据。LongContextReorder
: 在检索结果中,将最相关的节点放到中间,提升长上下文 LLM 的表现。LLMRerank
: 使用一个专门的 Re-ranker 模型(如 Cohere Rerank, BGE Rerank)对检索到的节点进行重新排序,进一步提高相关性。
Pythonfrom llama_index.core.postprocessor import SimilarityPostprocessor # 在 query_engine 中添加后处理器 query_engine = index.as_query_engine( similarity_top_k=5, node_postprocessors=[ SimilarityPostprocessor(similarity_cutoff=0.7) # 过滤掉相似度低于0.7的节点 ] )
-
多种查询引擎模式:
as_query_engine()
: 最常用,适用于标准 RAG。as_chat_engine()
: 用于构建有记忆的多轮对话机器人。as_retriever()
: 仅返回检索到的节点,不经过 LLM 合成答案,用于构建高级检索管道。
-
高阶查询引擎 (Advanced Query Engines):
- 路由查询引擎 (Router Query Engine): 根据用户查询的意图,动态地选择合适的索引或子查询引擎来处理查询。例如,文档查询去文档索引,数据库查询去数据库工具。
- 递归查询引擎 (Recursive Query Engine): 当查询需要多步骤推理时,可以递归地调用查询引擎。
- 子查询查询引擎 (SubQuery Query Engine): 将一个复杂问题分解为多个子问题,每个子问题由独立的查询引擎处理。
- SQL 查询引擎: 将自然语言查询转换为 SQL 查询,然后执行并利用结果。
- 知识图谱查询引擎: 利用知识图谱进行结构化推理。
-
代理 (Agents):
LlamaIndex 提供了构建 LLM Agents 的能力,这些 Agent 可以利用工具(包括查询引擎)来完成复杂任务。
- Agent 能够理解任务、分解步骤、调用工具、观察结果并迭代。
- 工具 (Tools): 可以将 LlamaIndex 的 QueryEngine 封装成一个工具,供 Agent 调用。
-
自定义 LLM 和嵌入模型:
- 除了 OpenAI,LlamaIndex 提供了丰富的
LLM
和Embedding
抽象接口,可以轻松集成 Hugging Face 上的任何模型、本地模型 (如ollama
,llama_cpp
) 或其他云服务提供商。
Pythonfrom llama_index.llms.huggingface import HuggingFaceLLM from llama_index.embeddings.huggingface import HuggingFaceEmbedding from transformers import AutoTokenizer, AutoModelForCausalLM # 加载本地/Hugging Face LLM # model_name = "mistralai/Mistral-7B-Instruct-v0.2" # llm_model = AutoModelForCausalLM.from_pretrained(model_name) # tokenizer_hf = AutoTokenizer.from_pretrained(model_name) # llm = HuggingFaceLLM( # model=llm_model, # tokenizer=tokenizer_hf, # max_new_tokens=512, # generate_kwargs={"temperature": 0.1, "do_sample": True}, # device_map="auto" # ) # Settings.llm = llm # 加载 Hugging Face 嵌入模型 # embed_model = HuggingFaceEmbedding(model_name="BAAI/bge-small-en-v1.5") # Settings.embed_model = embed_model
- 除了 OpenAI,LlamaIndex 提供了丰富的
-
可观测性 (Observability): 集成 LlamaIndex 的调用链到 Tracing 工具(如 LangChain's LangSmith, OpenAI Evals),便于调试和性能分析。
-
RAG Fusion / Multi-Query Retrieval: 生成多个查询,并行检索,然后合并结果。
-
知识图谱抽取与查询: 从非结构化文本中构建知识图谱,并进行结构化查询。
5. LlamaIndex 的架构原理 (更深层次)
LlamaIndex 内部维护着几个核心组件:
ServiceContext
(在 LlamaIndex 0.10.0+ 版本中被Settings
模块替代): 包含了 LLM 模型、嵌入模型、文本分割器、节点解析器等核心服务配置。它是 LlamaIndex 内部运行的基础。NodeParser
: 负责将Document
解析成Node
。可以配置分块大小、重叠、元数据提取等。Embedding
模型: 负责将文本转化为向量。LLM
模型: 负责文本生成。IndexStore
: 用于存储索引的元数据(如节点ID、文档ID)。VectorStore
: 存储Node
的嵌入向量,用于相似度搜索。GraphStore
: 存储知识图谱(如果使用知识图谱索引)。
这些组件协同工作,形成一个可插拔、可扩展的 RAG 管道。
6. LlamaIndex 与 LangChain 的比较
LlamaIndex 和 LangChain 都可以构建 LLM 应用的热门框架,这里做一下对比:
特性/框架 | LlamaIndex | LangChain |
---|---|---|
核心侧重 | 数据摄取、索引和查询 (RAG 核心) | 链式应用、代理和工具使用 (LLM 编排核心) |
数据管理 | 强大,提供丰富的加载器、索引类型和节点管理。 | 较弱,主要集中于 Retriever 抽象,数据管理不如 LlamaIndex 丰富。 |
检索增强 | 专注于此,提供多种高级检索器、节点处理器、响应合成器。 | RAG 只是其功能之一,但 Retriever 抽象也较完善。 |
LLM 编排 | 提供 Query Engine, Agent 等高级抽象,可调用工具。 | 极其强大,以 Chain、Agent 为核心,鼓励多步骤、多工具协作。 |
工具集成 | 主要通过 Tool 封装 QueryEngine ,供 Agent 使用。 |
丰富的工具集,易于定义和集成各种外部工具(API、计算器、Python REPL等)。 |
学习曲线 | 相对更直接,RAG 流程清晰。 | 抽象层级较多,灵活性强但也可能更复杂。 |
协作关系 | 1. LlamaIndex 构建索引; 2. LlamaIndex 提供数据增强能力。 | 1.LangChain 调用 LlamaIndex 的 QueryEngine 作为工具;2.LangChain 管理整体对话/代理流 |