做 RAG(检索增强生成)时,很多人第一反应是”把文档向量化丢进向量库”。但当文档变多、问答变复杂,你就会遇到切分策略、多路召回、重排序、可观测等一系列工程问题。LlamaIndex 正是为解决这个问题而生的数据框架:它把”文档加载→切分→建索引→检索→合成答案”整条链路标准化,让你用几十行代码就搭出可演进的生产级 RAG 应用。
一、为什么需要 LlamaIndex:它不只是向量库
向量数据库只负责”存向量、做相似度搜索”。而一个完整的 RAG 应用还需要:把 PDF/Word/网页读进来、按语义切分成节点、选择索引结构、在检索阶段做过滤与融合、把命中的上下文喂给大模型、最后把回答链路记录下来。LlamaIndex 把这些环节抽象成统一的 Document → Node → Index → Retriever → QueryEngine 管线,既能在本地用 Ollama 跑,也能接云端模型,还方便替换任意组件。
如果你已经在本地用 Ollama 部署了模型,LlamaIndex 可以无缝接管”知识检索”这一层,和你的私有化部署形成闭环。我们之前讲过用 Ollama + Open WebUI 搭建团队 AI 助手,本文则聚焦检索编排本身。
为什么不直接用 LangChain 或自己写一套?核心差异在于”数据抽象层级”:LlamaIndex 把”节点(Node)”作为一等公民,所有切分、索引、检索、重排都围绕节点展开,并内置了几十种数据源连接器与检索策略。对以”知识库问答”为目标的应用,它的开箱成本显著低于从零拼装;当你需要更复杂的工作流编排时,再叠加其他框架也不冲突。换句话说,LlamaIndex 解决的是”怎么把企业里散落的知识变成可被大模型精确调用的结构”,这正是 RAG 落地的主战场。
二、快速起步:一个最小可运行的 RAG
先安装核心包。LlamaIndex 0.10 之后拆分了核心与各集成,基础能力都在 llama-index 里。
pip install llama-index
下面 5 行就能构建一个基于本地文档的问答引擎:加载目录下的文件、建向量索引、转成查询引擎、提问。
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader
# 1. 加载数据:支持 pdf / docx / md / txt 等
documents = SimpleDirectoryReader("./data").load_data()
# 2. 建索引(默认会把文档切分并对每个节点做嵌入)
index = VectorStoreIndex.from_documents(documents)
# 3. 转查询引擎并提问
query_engine = index.as_query_engine()
response = query_engine.query("退货政策里支持七天无理由吗?")
print(response.response)
注意:默认会调用 OpenAI 的嵌入与对话接口。生产环境我们通常换成自托管模型,避免把敏感文档外发,这正是下一节要解决的。
三、文档加载与切分:数据接入的关键
RAG 质量的 70% 取决于切分。切得太长会引入噪声、超出上下文;切得太碎会丢失语义。LlamaIndex 的 SentenceSplitter 按句子边界切分,比按固定字符数更自然。
from llama_index.core.node_parser import SentenceSplitter
splitter = SentenceSplitter(chunk_size=512, chunk_overlap=64)
nodes = splitter.get_nodes_from_documents(documents)
# 用预先切好的节点建索引,行为完全可控
index = VectorStoreIndex(nodes)
切分时给每个节点打上元数据(来源、章节、分类),后续就能做”按分类过滤”的精准检索。这对多租户知识库尤其重要。
四、接入本地大模型:用 Ollama 替换默认接口
通过全局 Settings 把对话模型和嵌入模型都指向本地 Ollama,文档无需离开内网。这与用 Dify + Ollama 本地部署私有 AI 知识库的思路一致,只是把编排层换成了 LlamaIndex。
from llama_index.core import Settings
from llama_index.llms.ollama import Ollama
from llama_index.embeddings.ollama import OllamaEmbedding
Settings.llm = Ollama(model="qwen2.5:7b", base_url="http://localhost:11434")
Settings.embed_model = OllamaEmbedding(
model_name="bge-m3",
base_url="http://localhost:11434",
)
设置好 Settings 后,前面所有 from_documents / as_query_engine 调用都会自动走本地模型,无需逐处传参。
五、检索器与查询引擎:不止”相似度 TopK”
查询引擎底层依赖检索器(Retriever)。拿到检索器后,你可以直接观察召回结果、分数与原文,便于调试。
retriever = index.as_retriever(similarity_top_k=5)
nodes = retriever.retrieve("如何申请退款?")
for n in nodes:
print(round(n.score, 3), n.text[:80])
更进一步,用元数据过滤器把检索限定在特定分类或时间范围,避免”全局相似但答非所问”。
from llama_index.core.vector_stores import MetadataFilters, FilterCondition
filters = MetadataFilters.from_dicts(
[{"key": "category", "value": "refund", "operator": "=="}],
condition=FilterCondition.AND,
)
retriever = index.as_retriever(similarity_top_k=5, filters=filters)
LlamaIndex 提供多种索引结构,选型直接决定检索行为与成本:
| 索引类型 | 适用场景 | 检索方式 |
|---|---|---|
| VectorStoreIndex | 绝大多数 RAG 默认选择 | 向量相似度 TopK |
| ListIndex | 文档少、需要全量顺序或摘要 | 逐节点或 LLM 择优 |
| TreeIndex | 长文档分层总结 | 自底向上聚合 |
| KeywordTableIndex | 关键词特征明显、术语表 | 关键词映射表 |
六、生产级优化:混合检索、重排序与评估
单一路向量检索在术语密集或长尾问题上容易漏召。生产环境普遍采用混合检索(向量 + 关键词)与重排序优化:先用多路检索器召回候选,再用交叉编码器重排,把最相关的几条顶到前面。
from llama_index.core.retrievers import QueryFusionRetriever
from llama_index.core.query_engine import RetrieverQueryEngine
from llama_index.core.postprocessor import SentenceTransformerRerank
retriever = QueryFusionRetriever(
[index.as_retriever(similarity_top_k=5)],
mode="reciprocal_rerank",
similarity_top_k=5,
)
rerank = SentenceTransformerRerank(model="BAAI/bge-reranker-base", top_n=3)
query_engine = RetrieverQueryEngine.from_args(
retriever, node_postprocessors=[rerank]
)
上线前务必做量化评估,而不是凭感觉调参。可以参考向量检索评测:用 Recall@K 与 RAG 质量度量建立自动评测集,把每次改动都跑一遍回归。
七、可观测性:把链路接到 Langfuse
RAG 出问题往往不在模型,而在”哪段上下文被召回了”。接入Langfuse 做 LLM 应用链路与成本可观测,能看到每次提问实际检索了哪些节点、token 消耗与延迟,排障效率提升一个量级。
import llama_index.core.settings as settings
from llama_index.callbacks import LlamaDebugHandler, CallbackManager
debug = LlamaDebugHandler()
settings.callback_manager = CallbackManager([debug])
# 此后所有 query 的事件都会进入 debug 处理器,便于打印与上报
八、索引持久化:别让每次重启都重建
上面的示例每次运行都会重新切分并嵌入文档,文档量大时既慢又浪费算力。生产环境应当把索引持久化到磁盘或向量库,重启后直接加载。LlamaIndex 用 StorageContext 管理索引的存储位置,支持本地文件、Redis、PostgreSQL(pgvector)等多种后端。
from llama_index.core import StorageContext, load_index_from_storage
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader
# 首次:构建并持久化
documents = SimpleDirectoryReader("./data").load_data()
index = VectorStoreIndex.from_documents(documents)
index.storage_context.persist(persist_dir="./storage")
# 后续:直接加载,跳过重新嵌入
ctx = StorageContext.from_defaults(persist_dir="./storage")
index = load_index_from_storage(ctx)
如果团队已经在使用 PostgreSQL,建议直接把向量存进 pgvector,这样索引和业务的元数据可以共用一套备份与权限体系,扩容也更顺滑。持久化之后,文档更新只需增量重建变动节点,而不是全量重跑。
九、小结与落地清单
LlamaIndex 的价值在于把 RAG 从”调几个 API”升级成”可装配的数据应用”:切分、索引、检索、重排、观测各层解耦,任何一环都能单独替换优化。先用默认管线跑通,再按下面清单逐项加固。
| 环节 | 生产建议 |
|---|---|
| 切分 | chunk 256–512 字符,overlap 10–20% |
| 嵌入 | 本地 bge-m3 或云端 text-embedding-3-small |
| 检索 | top_k 4–8 + 元数据过滤缩小范围 |
| 重排 | bge-reranker 显著提升答案精度 |
| 评估 | Recall@K + 答案忠实度自动回归 |
| 可观测 | Langfuse 追踪检索链路与成本 |
当你把这套结构搭好,后续无论是接企业 Wiki、客服知识库还是研报分析,都只是”换数据源 + 调检索参数”的事。RAG 的真正门槛从来不是模型,而是这条被 LlamaIndex 理顺的数据管线。




