LlamaIndex:将你的数据接入 LLM
认识 LlamaIndex:连接你的数据与大语言模型
无论是构建一个能够回答你公司内部文档问题的聊天机器人,还是想用大语言模型(LLM)分析你的个人笔记,核心挑战都是:如何让 LLM 理解、利用那些它从未见过的私有数据。LlamaIndex 正是为解决这一问题而生的数据框架。它像一座桥梁,将你的结构化、半结构化和非结构化数据(PDF、网页、数据库、API 等)无缝接入 LLM,让模型能够基于这些知识进行推理、问答和生成。
本教程将从零开始,带你理解 LlamaIndex 的核心思想、安装配置、数据加载、索引构建以及如何发起查询。即使你只具备基础的 Python 知识,也能跟着完成一个可以实际运行的 “知识问答” 应用。
为什么需要 LlamaIndex?—— 超越 Prompt 的局限
你可能已经尝试过直接向 ChatGPT 粘贴一段文本并提问。这种方式对于简单、短小的文档有效,但面临明显瓶颈:
- 上下文窗口有限:你无法把一整本 500 页的手册放进 Prompt。
- 结构丢失:表格、树状分类、多轮对话等复杂关系难以仅通过文本传递。
- 检索效率低:每次提问都需要 LLM 读取全部上下文,成本和延迟都很高。
LlamaIndex 引入了一套“数据框架”,它首先将你的数据加工成 LLM 易于消费的形式,然后提供一套检索与合成机制,让 LLM 精准地拿到回答问题所需的最小上下文,而不是囫囵吞枣。
LlamaIndex 的核心概念:从数据到答案的流水线
在 LlamaIndex 的世界里,你的数据会经历一个清晰的流水线:加载 → 解析 → 索引 → 查询。
| 阶段 | 做什么 | 关键角色 |
|---|---|---|
| 加载 | 从各种数据源读取原始数据 | Reader / Loader |
| 解析 | 将原始数据拆分成更小的“节点”(Node) | Node Parser |
| 索引 | 为节点构建便于快速检索的数据结构 | Index |
| 查询 | 接收自然语言问题,检索相关节点并合成答案 | Retriever + Response Synthesizer |
其中索引是 LlamaIndex 的心脏。常用的索引类型包括针对文本摘要的 SummaryIndex、擅长检索特定事实的 VectorStoreIndex 以及处理树状结构的 TreeIndex 等。对于新手,我们首先需要掌握的是最通用、最常见的 VectorStoreIndex。
环境准备与安装
在开始前,请确保你的系统已安装 Python 3.8 以上版本。我们使用 pip 安装核心包:
pip install llama-index
如果你希望使用 OpenAI 的模型,还需设置 API 密钥。你也可以自由更换 LLM(如使用 Ollama 在本地运行开源模型),本教程为便于演示,将采用 OpenAI 的 gpt-3.5-turbo。
import os
os.environ["OPENAI_API_KEY"] = "你的-api-密钥" # 请替换为真实密钥
从加载数据开始
LlamaIndex 内置了近百种数据加载器,可以轻松读取不同来源的数据。最简单的开始是直接加载一个目录下的所有文本文件。
from llama_index.core import SimpleDirectoryReader
# 加载当前目录下 './data' 文件夹内的所有 .txt 文件
documents = SimpleDirectoryReader('./data').load_data()
documents 是一个列表,其中每个元素都是一个 Document 对象,包含了文本内容和一些元数据(如文件名、创建日期等)。如果你只有一段纯文本,也可以手动创建:
from llama_index.core import Document
doc = Document(text="LlamaIndex 是一个连接数据和 LLM 的框架。")
将文档拆分成“节点”
原始文档往往包含很长的段落,直接作为检索单位效果不佳。我们需要将其拆分成大小合适的节点(Node)。每个节点都是一小段文本,通常是完整的一句话或一小段落,并附带与原始文档的关联信息。
from llama_index.core.node_parser import SimpleNodeParser
parser = SimpleNodeParser.from_defaults(chunk_size=512, chunk_overlap=50)
nodes = parser.get_nodes_from_documents(documents)
chunk_size:每个文本块的最大 token 数(大约为 512 个单词/子词)。chunk_overlap:相邻两个块之间的重叠长度,防止关键信息恰好在分割处被截断。
构建索引:把数据变成可检索的“知识库”
有了节点之后,我们就可以构建索引了。这里使用 VectorStoreIndex,它会为每个节点生成一个称为嵌入向量(embedding)的数值表示,并将它们存储在内存中。查询时,向量相似度搜索能够快速召回与问题最相关的节点。
from llama_index.core import VectorStoreIndex
index = VectorStoreIndex(nodes)
在后台,LlamaIndex 会调用嵌入模型(默认是 text-embedding-ada-002)将文本转化为向量。如果是首次运行,可能需要一点时间。
如果你的数据量很大,建议使用持久化向量存储(如 Chroma、Pinecone、Qdrant),但入门阶段直接用内存存储完全够用。
创建查询引擎:用自然语言提问
索引构建完成后,我们可以通过它生成一个查询引擎(Query Engine)。查询引擎封装了一次完整的问答流程:它会自动进行检索、将检索到的节点与问题一起发给 LLM,并生成最终答案。
query_engine = index.as_query_engine()
现在,你可以像与 ChatGPT 对话一样,针对你刚刚加载的数据进行提问:
response = query_engine.query("什么是 LlamaIndex?")
print(response)
查询引擎还支持流式输出、设置返回源节点以及自定义提示词。例如,我们可以要求引擎用中文回答并列出参考来源:
from llama_index.core import get_response_synthesizer
from llama_index.core.retrievers import VectorIndexRetriever
from llama_index.core.query_engine import RetrieverQueryEngine
# 自定义检索器,每次取回3个最相关节点
retriever = VectorIndexRetriever(index=index, similarity_top_k=3)
# 自定义响应合成器,可以修改生成答案时的提示词
response_synthesizer = get_response_synthesizer(
response_mode="compact",
verbose=True
)
custom_engine = RetrieverQueryEngine(
retriever=retriever,
response_synthesizer=response_synthesizer
)
response = custom_engine.query("请用中文解释 LlamaIndex 的主要组件。")
print(response)
深入理解:检索与合成的内部机制
当你执行 query 时,发内部生了两个关键步骤:
-
检索(Retrieval)
查询引擎将你的问题转换成嵌入向量,在索引的向量空间中寻找最相似的k个节点。这保证 LLM 最终看到的只是与你问题高度相关的那一小部分数据,而不是全部文档。 -
响应合成(Response Synthesis)
将检索到的节点文本放入一个精心设计的 Prompt 模板,模板告诉 LLM:“仅使用下面的文本片段来回答问题,如果无法从片段中获得答案,就说不知道,不要编造事实。” LLM 生成答案后返回。
这种设计模式常被总结为 RAG(检索增强生成) ,LlamaIndex 提供了高度可定制化的 RAG 实现。
持久化索引,避免重复计算
每次运行程序都重新构建索引(尤其是生成嵌入向量)既耗时又浪费计算资源。LlamaIndex 支持将索引直接保存到硬盘,下次直接加载。
# 保存索引
index.storage_context.persist(persist_dir="./my_index")
# 之后加载索引
from llama_index.core import StorageContext, load_index_from_storage
storage_context = StorageContext.from_defaults(persist_dir="./my_index")
loaded_index = load_index_from_storage(storage_context)
# 使用加载的索引继续提问
query_engine = loaded_index.as_query_engine()
print(query_engine.query("之前我们讨论过什么?"))
常见问题与进阶方向
1. 我想使用免费的本地模型,而不是 OpenAI?
LlamaIndex 支持几乎任何 LLM。可以使用 Ollama 或 HuggingFaceLLM 等集成。例如,配置 Ollama 的 llama3 模型:
from llama_index.llms.ollama import Ollama
llm = Ollama(model="llama3", request_timeout=120.0)
# 然后在构建索引或查询引擎时将 llm 传入
Settings.llm = llm
2. 数据量非常大时该怎么办?
推荐使用外部向量数据库配合 VectorStoreIndex,比如 ChromaVectorStore、PineconeVectorStore 等。它们能够高效管理海量向量,并支持分区、元数据过滤等高级操作。
3. 我该如何处理表格、图片或者混合文档?
LlamaIndex 提供了 SimpleDirectoryReader 的多格式支持(PDF、Word 等),对于复杂文档还可以使用 Unstructured.io 读取器。对于表格数据,可以使用 PandasQueryEngine 或专门的 SQLJoinQueryEngine 进行结构化查询。多模态(图片+文字)的支持也在快速发展中。
结语:你刚刚踏出了数据框架的第一步
通过这篇教程,你已经掌握了使用 LlamaIndex 将私有数据接入大语言模型的核心流程:加载文档 → 分割成节点 → 构建向量索引 → 用自然语言查询。这让你能够构建出基于自有知识库的智能问答应用,完全脱离传统搜索的约束。
接下来,你可以尝试将公司手册、个人笔记、研究论文放入 LlamaIndex,并用不同的查询参数去感受回答质量的变化。当基础应用跑通后,LlamaIndex 的代理(Agent) 能力将带你进入更智能的自主任务处理世界——让 LLM 不仅能回答,还能调用工具、查询数据库,成为你真正的“数据管家”。
现在就动手试试吧:用你手边的任何文本文件,构建属于自己的第一个知识助手。