语义分块先守住长度约束:一个可复核的边界切分器 长文档分块最容易混淆两件事在哪里切比较自然以及一块究竟能装多少内容。前者可以用向量相似度辅助后者必须由明确的计数规则兜底。一个语义分数再漂亮的分块器只要把超长表格原样塞进去就没有满足窗口约束。Kimi Code 的 10 月 21 日更新把忙碌时的/compact改为排队执行。它提醒我上下文维护也有生命周期不能把压缩当作随时都能安全调用的文本函数。下面只讨论离线文档预处理不模拟客户端压缩行为。更新说明先写下能够检查的契约本文的最小实现按字符计量保留原始字符和标点逐句装箱。超过上限的单句先拆成硬片段句子装不进当前块时再开新块。它是贪心算法不求全局最优也不把字符数叫作 Token 数。三个断言比“语义绝对完整”更有用每块不超过上限所有非重叠块拼接后等于原文重叠只是额外的检索上下文不能改变原始块的身份。真实接入时应把len换成目标模型的分词计数并给请求模板留出开销。图中数字表示抽象单元每组只装两个单元也满足最大三个单元的约束。它不是性能结果。下面代码处理实际字符串二者的计量单位不要混用。import re def split_document(text, max_chars): if max_chars 0: raise ValueError(max_chars must be positive) sentences re.findall(r[^。]*[。]|[^。]$, text) units [s[i:i max_chars] for s in sentences for i in range(0, len(s), max_chars)] chunks, current [], for unit in units: if current and len(current) len(unit) max_chars: chunks.append(current) current current unit if current: chunks.append(current) return chunks def retrieval_windows(chunks, overlap_chars): if overlap_chars 0: raise ValueError(negative overlap) return [{id: i, original: chunk, prefix: chunks[i-1][-overlap_chars:] if i and overlap_chars else } for i, chunk in enumerate(chunks)] text 甲方提交报告。乙方复核。 长 * 13 尾句 chunks split_document(text, 8) assert .join(chunks) text assert all(0 len(c) 8 for c in chunks) assert split_document(, 8) [] windows retrieval_windows(chunks, 2) assert .join(x[original] for x in windows) text assert windows[0][prefix] print(reconstruction, size limit, empty input, overlap: PASS)语义边界应该放在哪里工程上可以把相邻句子的相似度低谷作为候选切点但它只能影响“优先在哪里切”不能取消硬上限。表格、代码块和标题还有各自的结构边界。若一个代码块超过窗口应该返回“需要专门处理”的状态或者按语法节点切分而不是保证它永远不会断。vLLM 的前缀缓存设计还说明了一个相关区别缓存身份包含前序块检索内容切得相同并不表示推理 KV 状态也相同。分块ID、文档偏移和推理缓存键应各自管理。这个例子已在本地 Python 标准库环境验证重建和长度边界没有加载嵌入模型也没有跑检索准确率实验。要比较语义切分与固定窗口应固定语料、问题和召回标准再统计切断结构的次数、重复字符开销以及答案证据覆盖没有这些记录就不写准确率提高了多少。