数据截至 (上游 commit 30e759af1f0f)
LlamaIndex 灌库与切块 — 从文档到 Node
这章讲什么: 离线阶段——一份
Document怎么变成一批可检索的Node。先看「切块」(SentenceSplitter怎么在保住句子边界的前提下控制块大小),再看「转换流水线」(run_transformations/IngestionPipeline)如何把切块、抽元数据、嵌入串起来,以及它的两大省钱机制:transformation 缓存 和 基于哈希的去重/更新。
2.1 一步直觉:灌库 = 跑一串「转换」
VectorStoreIndex.from_documents(docs) 看着是一个方法,内部其实是:
Documents ─▶ run_transformations(默认 [SentenceSplitter(), embed_model]) ─▶ Nodes(带嵌入)
─▶ 存进 vector store / docstore
源码:indices/base.py:111-129——先把每个 doc 的 hash 记进 docstore,再 run_transformations(documents, transformations, ...) 得到 nodes,最后用这批 nodes 构造索引。默认 transformations 来自 Settings.transformations(indices/base.py:109)。
转换的统一接口 TransformComponent(schema.py:191-204)只有一个抽象方法:
# 示意,非源码:任何「一步变换」都是 nodes → nodes
def __call__(self, nodes: Sequence[BaseNode], **kw) -> Sequence[BaseNode]: ...
切块器、元数据抽取器、嵌入模型全都实现这个签名,于是能任意串联。
2.2 SentenceSplitter:控制块大小,但别切碎句子
切块的两难:块太大 → 检索不精准、塞不进上下文;块太小 → 语义破碎。SentenceSplitter 的取法是**「尽量按完整句子凑到目标 token 数,带少量重叠」**。