方法节里「20 μL、60°C、3 只小鼠」经常被切在两段:检索只命中前半,生成就编造后半。LlamaIndex 的 NodeParser 把 Document 切成 TextNode,默认 SentenceSplitter 先按句切开再打包到 chunk_size,并用 chunk_overlap 让边界句出现在相邻两块里。
段末注释:NodeParser =
list[Document] → list[Node]的切分器;chunk_size按 token 计(默认 tiktoken),不是字符数。

1. 一句话定位
| 维度 | 内容 |
|---|---|
| 角色 | 知识层的切分:来源正文 → 可嵌入、可引用的块 |
| 输入 → 输出 | list[Document] → list[TextNode](继承 metadata,挂 SOURCE / PREV / NEXT) |
| 典型调用入口 | SentenceSplitter(...).get_nodes_from_documents();或 Settings.text_splitter / from_documents(transformations=...) |
| 与 LangChain / LangGraph | 近邻是 langchain-text-splitters;LangGraph 不切块 |
出现背景:裸按字符 text[i:i+n] 会切断术语与数字。SentenceSplitter 在「不超过 token 预算」的约束下尽量在句号处断开,并把 Document 的 metadata / 排除键拷到每个子 Node。
切分策略(层级、语义切分、评测口径)见 RAG 目录;本篇只讲 LlamaIndex 怎么把剂量拧到 API 上。
2. 前置依赖与环境
1 | pip install -U llama-index-core |
- Python 3.10+;
llama-index-core0.14.x - 本篇不调 LLM。
SemanticSplitterNodeParser才需要 embedding,此处不展开。 from_documents若未传transformations且未改Settings.text_splitter,会用全局默认 splitter。
3. 实现逻辑
1 | 1. 准备 Document(text + metadata + 稳定 doc_id) |
字段级变形:
1 | Document.text = "句A。句B。句C。句D。" # 假设每句约 20 token,chunk_size=45, overlap≈20 |
4. 原理说明
主轴是:parser 不改 Document,只派生 Node;token 预算决定打包,句子边界决定刀口。
1 | 1. get_nodes_from_documents 取出每个 Document.text |
SentenceSplitter(类,llama_index.core.node_parser)出现在步骤 2。功能:句感知打包。默认 chunk_size=1024,chunk_overlap=20。
get_nodes_from_documents(documents, show_progress=False)(方法)出现在步骤 1。输入非空 list[Document];输出 list[TextNode],长度 ≥1(极短文可能 1 块)。
Settings.text_splitter 出现在索引构建:VectorStoreIndex.from_documents 未传 transformations 时读它。局部覆盖:
1 | index = VectorStoreIndex.from_documents( |
其它 parser(按需,不在本篇示例展开):
| 类 | 刀口 | 适用 |
|---|---|---|
TokenTextSplitter |
纯 token 窗 | 无标点日志 |
HierarchicalNodeParser |
多尺寸父子块 | 先宽召回再精读子块 |
SentenceWindowNodeParser |
一句 + 左右窗口 | 后续 auto-merging |
SemanticSplitterNodeParser |
嵌入相似度断点 | 段落主题切换;要 embedding |
5. 最小可运行示例
1 | pip install -U llama-index-core |
1 | from llama_index.core import Document |
把 chunk_overlap 改成 0 再跑一遍,比较「20 μL」是否与「60°C」分家——这就是 overlap 的可观测差。
6. 重要配置参数
| 参数(API 名) | 类型 / 默认值 | 功能说明 | 作用与影响 | 参考起点 / 常用范围 | 配置指导 |
|---|---|---|---|---|---|
chunk_size |
int,默认 1024 | 每块目标 token 上限 | 过大混入噪声、挤上下文;过小切断方法句、块数暴涨 | 方法节 256~512;综述 512~1024 | 按生成模型窗口与 top_k 反算 |
chunk_overlap |
int,默认 20 | 相邻块重叠的 token 预算 | 过小跨句指代丢失;过大重复占检索位 | 约为 chunk_size 的 10%~20% |
与 size 成对调,不要只拧一个 |
separator |
str,默认 " " |
句子再细拆时的分隔 | 中文空格少,主要靠句号/换行 | 保持默认 | 不要改成空串 |
paragraph_separator |
str,默认 "\n\n\n" |
段边界 | 与你的文件实际空行数不一致则整段当一句 | Markdown 常用 "\n\n" |
先 print 原文里的换行再设 |
include_metadata |
bool,默认 True |
是否把 Document.metadata 拷到 Node | False 则引用丢页码/物种 |
保持 True |
几乎总开 |
include_prev_next_rel |
bool,默认 True |
是否写 PREVIOUS/NEXT | False 则窗口扩展/邻块拼接做不了 |
层级/窗口检索保持 True |
省一点存储可关,默认开 |
Settings.chunk_size |
int | 不换 splitter 类、只改全局默认块长 | 与显式 SentenceSplitter(chunk_size=...) 谁后生效看调用点 |
与上表同源 | 索引构建处显式传 transformations 更不易踩 |
7. 适用 / 不适用
| 维度 | 适用 | 不适用 |
|---|---|---|
| 任务形态 | 叙事/方法段落、句边界清晰 | 超长无标点表、纯代码——改 TokenTextSplitter 或按标题切 |
| 集成约束 | 默认 tiktoken 计数与 OpenAI 系接近 | 本地 tokenizer 与 tiktoken 差很大时,块长体感会偏 |
| 工程阶段 | 任何 from_documents 之前 |
已按标题/HTML 树切好——直接造 TextNode,跳过 parser |
需要父子层级时用 HierarchicalNodeParser,不要把 chunk_size 拧到 64 冒充层级。
8. 易踩坑
- 把
chunk_size当字符数:中文 1024 token 远不是 1024 字,块会比直觉大或小。用len(nodes)和每块text目测。 overlap=0切方法句:剂量与条件分家,看起来像幻觉,其实是召回半句。- 改了 parser 却走
from_documents默认:忘记传transformations/Settings.text_splitter,索引仍是旧刀口。 - 切完丢掉
start_char_idx:后面做引用高亮时无法对齐 PDF 原文。
小结
- SentenceSplitter:按句打包到 token 预算,overlap 保跨句条件。
- 子 Node 继承 metadata,并挂 SOURCE / PREV / NEXT。
- 接到索引时用
transformations=或Settings.text_splitter,不要假设默认值等于你设过的数字。 - 切分策略对错用 RAG 评测看,本篇只保证 API 剂量拧在刀口上。