LlamaIndex — 架构与原理
30 秒导读: LlamaIndex 是一个「数据框架」,帮你把私有数据(PDF、网页、SQL……)接到 LLM 上做问答。核心是一条流水线:把文档切成带关系的小块(Node),灌进索引/向量库;查询时先检索出相关 Node,再让 LLM 在有限的上下文窗口内把它们合成成答案。本文按「数据砖 → 灌库 → 检索 → 合成」四步,带你读透
llama-index-core的真实源码。
1. 这是什么(零基础也能懂)
-
一句话定义: LlamaIndex 是 RAG(Retrieval-Augmented Generation,检索增强生成)框架——让 LLM 「带着你的资料」回答问题,而不是只靠它预训练时记住的东西。
-
解决什么问题 / 给谁用: 假设你有一堆公司内部文档,想做个「问它任何问题、它从文档里找答案」的机器人。直接把全部文档塞进 LLM 不现实(上下文窗口装不下、也贵)。LlamaIndex 帮你:把文档切块、建索引、查询时只捞最相关的几块、再让 LLM 据此作答。给 RAG 应用开发者用。
-
它能做什么(功能):
- 读入 300+ 种数据源(connectors / readers)。
- 把文档切成块、抽元数据、算嵌入(ingestion)。
- 多种索引:向量索引、关键词表、树、知识图谱 / 属性图。
- 多种检索 + 重排 + 多路融合。
- 多种答案合成策略(refine / tree summarize / compact……)。
- 之上还能搭 chat engine、agent、workflow。
-
用起来什么样: 经典「5 行代码」:
# 示意,非源码(贴近 README 的标准用法)
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader
docs = SimpleDirectoryReader("data").load_data() # 1) 读文档
index = VectorStoreIndex.from_documents(docs) # 2) 切块+嵌入+建索引
qe = index.as_query_engine() # 3) 变成问答引擎
print(qe.query("作者上大学前做了什么?")) # 4) 提问 → 检索 → 合成答案
- 一句话直觉 / 类比: 把它想成图书馆 + 研究助理。建索引 = 把书拆成卡片、按内容贴上「相似度坐标」归档;查询 = 助理先按主题抽出最相关的几张卡片(检索),再读着卡片给你写一段答案(合成)。LLM 只是那个「会读卡片写答 案」的助理,真正的知识在卡片(Node)里。
2. 顶层全景(它大概怎么转)
RAG 分两个阶段:离线灌库(把数据变成可检索的 Node)和 在线查询(检索 + 合成)。一张图看全:
离线:灌库(index time)
Documents ──切块/抽元数据/嵌入──▶ Nodes ──存──▶ ┌─ vector store(向量+文本)
(Reader) (transformations) ├─ docstore(Node 正本)
└─ index_store(索引结构)
在线:查询(query time)
query ─▶ Retriever ─▶ NodeWithScore[] ─▶ NodePostprocessor ─▶ ResponseSynthesizer ─▶ Response
(向量召回) (带分数的Node) (重排/过滤,可选) (refine/tree…喂给LLM)
主要部件一句话职责:
| 部件 | 干什么 | 在哪个文件(符号) |
|---|---|---|
Document / Node | 数据的「砖」:一段文本 + 元数据 + 关系 + 嵌入 | schema.py(BaseNode/TextNode/Document) |
TransformComponent | 对一批 Node 做一步变换(切块、抽元数据、嵌入) | schema.py(TransformComponent) |
IngestionPipeline | 串起若干 transformation + 去重 + 缓存 | ingestion/pipeline.py(IngestionPipeline) |
BaseIndex | 索引基类:from_documents / as_query_engine / insert | indices/base.py(BaseIndex) |
VectorStoreIndex | 最常用索引:把 Node 嵌入后存进向量库 | indices/vector_store/base.py(VectorStoreIndex) |
BaseRetriever | 给 query 召回一批 NodeWithScore | base/base_retriever.py(BaseRetriever) |
RetrieverQueryEngine | 把「检索 → 后处理 → 合成」编排成一次 query() | query_engine/retriever_query_engine.py |
BaseSynthesizer | 把召回的 Node 文本喂给 LLM 生成答案 | response_synthesizers/base.py |
PromptHelper | 算 token 预算、repack/truncate 文本块 | indices/prompt_helper.py(PromptHelper) |
StorageContext | 三件套存储:docstore + index_store + vector_store | storage/storage_context.py |
Settings | 全局默认(llm / embed_model / node_parser…) | settings.py(_Settings) |
主线走一遍(高层):
-
灌库:
VectorStoreIndex.from_documents(docs)→ 跑run_transformations(默认SentenceSplitter+embed_model)把 Document 切成带嵌入的 Node → 存进 vector store(文本随之存),Node 关系/正本视情况存进 docstore(indices/base.py:111-129、indices/vector_store/base.py:286-309)。 -
查询:
index.as_query_engine().query(q)→as_query_engine把 retriever 包进RetrieverQueryEngine(indices/base.py:491-516);_query先retrieve(q)召回 Node、过 postprocessor,再synthesize让 LLM 作答(query_engine/retriever_query_engine.py:202-215)。
-
检索内部:
VectorIndexRetriever把 query 嵌入 → 查向量库拿 top-k → 必要时回 docstore 取正本 → 返回NodeWithScore(indices/vector_store/retrievers/retriever.py:227-246)。 -
合成内部:
Refine/CompactAndRefine/TreeSummarize先用PromptHelper.repack把多块文本塞满上下文窗口,再决定调几次 LLM(response_synthesizers/*)。