微信扫码
添加专属顾问
我要投稿
文档分段是智能问答与知识检索的基础,掌握分段技巧能大幅提升检索精度与回答质量。 核心内容: 1. 文档分段的重要性及其对检索精度的影响 2. 五种文本分段方法的实现与优劣分析 3. 从基础字符分段到智能进阶的完整解决方案
在之前介绍包含知识库检索Agent的推文发布之后,不少同学追问:为啥文档处理这么重要的内容不介绍呢?
(PS:文档处理,尤其是文档分段,是整个智能问答与知识检索流程中至关重要的基础环节。)
为了响应同学们的号召,从本期起,我们将结合 dify 中的实际处理逻辑,用几期内容把这块讲明白、说透彻。
第一期,我们聚焦在最核心的步骤上:文档分段(Text Chunking)。它看似只是“把长文本切开”,却直接决定了后续检索的精度与回答的质量。
我们在这部分将手搓实现几类文本分段的代码,现在有那么多的成熟框架(比如Langchain)不用,为什么偏要自己从头造轮子呢?
因为成熟框架虽好,但高度封装的特性的确会带来一些局限。而亲自动手实现,能为我们带来三大核心优势:灵活、稳健、出错了排查快。
我们实现了五种文本分段的方法,下面我们将分类详细介绍每种文本分段的实现方法。
字符级的分段是最简单的一种方法,但是缺点十分明显,直接按照chunk字符数量上限分段破坏了文件内容的逻辑连贯和语义,增加了rag的检索难度。所以这种方法并不常用。
def segment_by_char_count(text: str, max_chars: int = 500, overlap: int = 0) -> list[str]: chunks = [] start = 0 while start < len(text): end = start + max_chars chunks.append(text[start:end]) start = end - overlap return chunks
--- 下面是我们对字符级分段的测试结果 ---
待分段文本:
在过去的十年中,人工智能经历了爆发式的增长。从最初的图像识别、语音识别,到如今的大语言模型(Large Language Models),AI 的能力已经远远超出了人们的预期。它不仅能够生成文本、理解语义,还能进行逻辑推理、编写代码,甚至参与艺术创作。然而,AI 的发展也带来了新的挑战。数据安全、隐私保护、模型可解释性,这些议题正在成为研究者和监管机构关注的重点。For example, when a model generates a medical diagnosis, how can we ensure that its reasoning process is transparent and trustworthy? This question is not only technical but also deeply ethical.未来的人工智能将不再仅仅依赖模型的规模,而是更关注“智能的组织结构”。换句话说,AI 将像人类一样学会“协作”和“记忆”。一个智能体(agent)可以调用另一个智能体的能力,共同完成复杂任务。这正是当前 Agentic AI 研究的方向。
---- Chunk 0 ----在过去的十年中,人工智能经历了爆发式的增长。从最初的图像识别、语音识别,到如今的大语言模型(Large Language Models),AI 的能力已经远远超出了人们的预期。它不仅能够生成文本、理解语义,还能进行逻辑推理、编写代码,甚至参与艺术创作。然而,AI 的发展也带来了新的挑战。数据安全、隐私保护、模型可解释性,这些议题正在成为研究者和监管机构关注的重点。For example, when a model generates a medical diagnosis, how can we ensure that its reasoning proce---- Chunk 1 ----ss is transparent and trustworthy? This question is not only technical but also deeply ethical.未来的人工智能将不再仅仅依赖模型的规模,而是更关注“智能的组织结构”。换句话说,AI 将像人类一样学会“协作”和“记忆”。一个智能体(agent)可以调用另一个智能体的能力,共同完成复杂任务。这正是当前 Agentic AI 研究的方向。
按照句子分段是字符级分段的进阶版,这种方法考虑到了句子完整对于检索的重要性,所以首先将文本内容按照标点符号分割,然后在满足chunk大小的基础上将句子添加到chunk内,同时考虑到了单个句子长度超过chunk限制的情况,采用滑动窗口的方法进行字符级的切分。
import refrom typing import Listdef split_sentences_multilang(text: str) -> List[str]:# 中文标点 + 英文句号/问号/感叹号 + 换行段落sentence_endings = r"([。!?!?]|(?<!\w)\.(?=\s|$)|\n{2,})"parts = re.split(sentence_endings, text)sentences, buffer = [], ""for p in parts:if not p:continuebuffer += p# 如果是句子终结或段落if re.match(sentence_endings, p):sentences.append(buffer.strip())buffer = ""if buffer.strip():sentences.append(buffer.strip())return sentencesdef segment_by_sentence_multilang(text: str, max_chars: int = 500, overlap: int = 0) -> List[str]:sentences = split_sentences_multilang(text)chunks = []buffer = ""for sent in sentences:sent = sent.strip()if not sent:continue# 单句过长,回退到字符滑窗切分if len(sent) > max_chars:if buffer:chunks.append(buffer)buffer = ""start = 0while start < len(sent):end = start + max_charschunks.append(sent[start:end])start = max(end - overlap, start + 1) # 保证前进continueif len(buffer) + len(sent) <= max_chars:buffer += sentelse:chunks.append(buffer)buffer = sentif buffer:chunks.append(buffer)# overlap 处理if overlap > 0:overlapped = []for i, c in enumerate(chunks):if i == 0:overlapped.append(c)else:ov_text = chunks[i-1][-overlap:] if overlap < len(chunks[i-1]) else chunks[i-1]overlapped.append(ov_text + c)chunks = overlappedreturn chunks
--- 下面是我们对字符级分段的测试结果 ---
待分段文本:
在过去的十年中,人工智能经历了爆发式的增长。从最初的图像识别、语音识别,到如今的大语言模型(Large Language Models),AI 的能力已经远远超出了人们的预期。它不仅能够生成文本、理解语义,还能进行逻辑推理、编写代码,甚至参与艺术创作。然而,AI 的发展也带来了新的挑战。数据安全、隐私保护、模型可解释性,这些议题正在成为研究者和监管机构关注的重点。For example, when a model generates a medical diagnosis, how can we ensure that its reasoning process is transparent and trustworthy? This question is not only technical but also deeply ethical.未来的人工智能将不再仅仅依赖模型的规模,而是更关注“智能的组织结构”。换句话说,AI 将像人类一样学会“协作”和“记忆”。一个智能体(agent)可以调用另一个智能体的能力,共同完成复杂任务。这正是当前 Agentic AI 研究的方向。
分段结果如下,可以看到句子级的分段避免了句子或者英文单词被截断的风险:
---- Chunk 0 ----在过去的十年中,人工智能经历了爆发式的增长。从最初的图像识别、语音识别,到如今的大语言模型(Large Language Models),AI 的能力已经远远超出了人们的预期。它不仅能够生成文本、理解语义,还能进行逻辑推理、编写代码,甚至参与艺术创作。然而,AI 的发展也带来了新的挑战。数据安全、隐私保护、模型可解释性,这些议题正在成为研究者和监管机构关注的重点。---- Chunk 1 ----For example, when a model generates a medical diagnosis, how can we ensure that its reasoning process is transparent and trustworthy?This question is not only technical but also deeply ethical.未来的人工智能将不再仅仅依赖模型的规模,而是更关注“智能的组织结构”。换句话说,AI 将像人类一样学会“协作”和“记忆”。一个智能体(agent)可以调用另一个智能体的能力,共同完成复杂任务。---- Chunk 2 ----这正是当前 Agentic AI 研究的方向。
句子级别的分段就可以实现高召回率和精准度吗?当然不够,句子级别的分段没有考虑句子之间的关系,一股脑儿的都装进一个chunk内部,最终的目标只有不截断句子和尽可能接近chunk字符上限。这样就增加了召回chunk的噪声,无关的内容增多,浪费token不说,还给了LLM“胡说八道”足够的内容。
因此,我们在句子级别的分段上计算句子之间的语义相似度,实现基于语义相似度的分段。根据我们测试来看语义分段可以满足大部分的文件内容了。
为了保证数据安全,我们使用本地部署的embedding模型,代码实现如下:
from sklearn.metrics.pairwise import cosine_similarityXINFERENCE_MODEL = "bge-large-zh-v1.5"XINFERENCE_API_URL = "http://localhost:9997/v1/embeddings"def get_xinference_embeddings(texts, model=XINFERENCE_MODEL, api_url=XINFERENCE_API_URL): """调用 Xinference 获取文本向量""" payload = {"model": model, "input": texts} headers = {"Content-Type": "application/json"} response = requests.post(api_url, headers=headers, json=payload) response.raise_for_status() data = response.json() # 确保兼容返回格式 embeddings = [item["embedding"] for item in data.get("data", [])] return np.array(embeddings)def segment_by_semantic(text: str, threshold: float = 0.7, max_chars: int = 500, overlap: int = 0): """ 基于语义相似度分段,同时控制 chunk 最大长度 """ sentences = segment_by_sentence_multilang(text) # 使用多语言句子分割 embeddings = get_xinference_embeddings(sentences) chunks, buffer = [], [sentences[0]] buffer_len = len(sentences[0]) for i in range(1, len(sentences)): sim = cosine_similarity([embeddings[i-1]], [embeddings[i]])[0][0] # 当前句子长度 sent_len = len(sentences[i]) # 超长句子单独处理 if sent_len > max_chars: # 先输出当前 buffer if buffer: chunks.append("".join(buffer)) buffer = [] buffer_len = 0 # 字符滑窗切分超长句 start = 0 s = sentences[i] while start < len(s): end = start + max_chars chunks.append(s[start:end]) start = max(end - overlap, start + 1) continue # 判断是否与前一句语义相似且长度不超 max_chars if sim > threshold and buffer_len + sent_len <= max_chars: buffer.append(sentences[i]) buffer_len += sent_len else: # 输出当前 buffer if buffer: chunks.append("".join(buffer)) buffer = [sentences[i]] buffer_len = sent_len if buffer: chunks.append("".join(buffer)) # overlap 处理(可选) if overlap > 0: overlapped = [] for i, c in enumerate(chunks): if i == 0: overlapped.append(c) else: prev = overlapped[-1] ov_text = prev[-overlap:] if overlap < len(prev) else prev overlapped.append(ov_text + c) chunks = overlapped return [c for c in chunks if c]--- 下面是语义分割的结果 ---
待分段文本:
在过去的十年中,人工智能经历了爆发式的增长。从最初的图像识别、语音识别,到如今的大语言模型(Large Language Models),AI 的能力已经远远超出了人们的预期。它不仅能够生成文本、理解语义,还能进行逻辑推理、编写代码,甚至参与艺术创作。然而,AI 的发展也带来了新的挑战。数据安全、隐私保护、模型可解释性,这些议题正在成为研究者和监管机构关注的重点。For example, when a model generates a medical diagnosis, how can we ensure that its reasoning process is transparent and trustworthy? This question is not only technical but also deeply ethical.未来的人工智能将不再仅仅依赖模型的规模,而是更关注“智能的组织结构”。换句话说,AI 将像人类一样学会“协作”和“记忆”。一个智能体(agent)可以调用另一个智能体的能力,共同完成复杂任务。这正是当前 Agentic AI 研究的方向。
---- Chunk 0 ----在过去的十年中,人工智能经历了爆发式的增长。从最初的图像识别、语音识别,到如今的大语言模型(Large Language Models),AI 的能力已经远远超出了人们的预期。它不仅能够生成文本、理解语义,还能进行逻辑推理、编写代码,甚至参与艺术创作。然而,AI 的发展也带来了新的挑战。数据安全、隐私保护、模型可解释性,这些议题正在成为研究者和监管机构关注的重点。For example, when a model generates a medical diagnosis, how can we ensure that its reasoning process is transparent and trustworthy?This question is not only technical but also deeply ethical.未来的人工智能将不再仅仅依赖模型的规模,而是更关注“智能的组织结构”。换句话说,AI 将像人类一样学会“协作”和“记忆”。一个智能体(agent)可以调用另一个智能体的能力,共同完成复杂任务。---- Chunk 1 ----这正是当前 Agentic AI 研究的方向。
讨论完常见的文件,我们来看一下自带规范结构的文件,例如markdown、html、代码脚本等。一般我们就按照文本自身结构进行分段就可以了,下面我们看一下markdown格式文件的分段代码:
import redef segment_markdown(text: str,max_chars: int = 1000,overlap: int = 100) -> list[str]:"""Args:text (str): Markdown 文本max_chars (int): 每个 chunk 的最大字符长度overlap (int): 上一个 chunk 尾部在下一个 chunk 中重叠的字符数(防止上下文割裂)Returns:list[str]: 分段后的 Markdown 文本列表"""lines = text.splitlines()chunks, current_chunk = [], []current_length = 0for line in lines:# 遇到标题(H1-H6)时,强制开始一个新的块if re.match(r"^#{1,6}\s", line):if current_chunk:chunk_text = "\n".join(current_chunk).strip()chunks.append(chunk_text)current_chunk = [line]current_length = len(line)else:# 普通文本行if current_length + len(line) + 1 > max_chars:# 达到 chunk 上限,切分chunk_text = "\n".join(current_chunk).strip()chunks.append(chunk_text)# 处理 overlap:取上一个 chunk 的尾部部分作为新起点if overlap > 0 and len(chunk_text) > overlap:overlap_text = chunk_text[-overlap:]current_chunk = [overlap_text, line]current_length = len(overlap_text) + len(line)else:current_chunk = [line]current_length = len(line)else:current_chunk.append(line)current_length += len(line) + 1# 追加最后的chunkif current_chunk:chunks.append("\n".join(current_chunk).strip())return [c for c in chunks if c]
--- 下面是我们关于markdown格式分段的测试结果 ---
待分段文件内容:
# 人工智能的起源与发展人工智能(Artificial Intelligence, AI)这一概念最早诞生于20世纪50年代。最初的研究者们试图让计算机模拟人类思考的过程,例如推理、学习与决策。然而,受限于算力与数据的匮乏,这一阶段的AI发展相对缓慢。## 机器学习的崛起进入21世纪后,机器学习(Machine Learning)成为AI的核心方向。它不再依赖人工设定规则,而是通过数据驱动模型的自我学习。这标志着AI从“编程智能”迈向了“学习智能”。# 现实挑战与伦理思考AI的发展带来了巨大的社会影响。隐私泄露、算法歧视、虚假信息传播等问题,正在成为亟需解决的现实挑战。与此同时,AI的应用边界也在被不断讨论——它是否应该参与教育、医疗甚至法律判断?## 可解释性与安全性一个重要议题是模型的可解释性(Explainability)。人类希望理解模型为何得出某个结论,尤其是在关键领域如医学诊断或司法判决。因此,提高AI的可解释性与安全性,是未来研究的重点方向。## 人机协作与未来愿景未来的AI不会取代人类,而会成为人类的协作者。人机协同(Human-AI Collaboration)将推动知识创造、科学研究乃至社会治理的新模式。这种“共智”模式,或许才是人工智能的真正终极形态。
---- Chunk 0 ----# 人工智能的起源与发展人工智能(Artificial Intelligence, AI)这一概念最早诞生于20世纪50年代。最初的研究者们试图让计算机模拟人类思考的过程,例如推理、学习与决策。然而,受限于算力与数据的匮乏,这一阶段的AI发展相对缓慢。---- Chunk 1 ----## 机器学习的崛起进入21世纪后,机器学习(Machine Learning)成为AI的核心方向。它不再依赖人工设定规则,而是通过数据驱动模型的自我学习。这标志着AI从“编程智能”迈向了“学习智能”。---- Chunk 2 ----# 现实挑战与伦理思考AI的发展带来了巨大的社会影响。隐私泄露、算法歧视、虚假信息传播等问题,正在成为亟需解决的现实挑战。与此同时,AI的应用边界也在被不断讨论——它是否应该参与教育、医疗甚至法律判断?---- Chunk 3 ----## 可解释性与安全性一个重要议题是模型的可解释性(Explainability)。人类希望理解模型为何得出某个结论,尤其是在关键领域如医学诊断或司法判决。因此,提高AI的可解释性与安全性,是未来研究的重点方向。---- Chunk 4 ----## 人机协作与未来愿景未来的AI不会取代人类,而会成为人类的协作者。人机协同(Human-AI Collaboration)将推动知识创造、科学研究乃至社会治理的新模式。这种“共智”模式,或许才是人工智能的真正终极形态。
基于LLM实现的分段让大模型先理解内容语义再决定如何分块。模型不只是看句号或者行数来分段,而是理解哪几句话在讲一个主题,哪个小标题下的内容属于同一个语义单元。
import reimport jsonbase_url = "http://localhost:8977/v1/chat/completions"api_key = "xxxxxxx"def segment_by_llm(text: str, max_chars: int = 800, overlap: int = 0) -> list[str]:"""使用大模型理解文本语义后进行分块。"""headers = {"Content-Type": "application/json","Authorization": f"Bearer {api_key}"}system_prompt = """你是一个文本分块专家,请将输入文本分成语义完整、长度适中的段落。每个段落应尽量保持上下文连贯。请输出 JSON 格式,如:[{"chunk_id": 1, "content": "第一段文本"},{"chunk_id": 2, "content": "第二段文本"}]"""user_prompt = f"以下是要分块的文本(建议每块不超过 {max_chars} 字):\n{text[:6000]}" # 限制输入长度避免超限messages = []if system_prompt:messages.append({"role": "system", "content": system_prompt})messages.append({"role": "user", "content": user_prompt})payload = {"model": "Qwen3-32B","messages": messages,"temperature": 0.6}response = requests.post(base_url, headers=headers, json=payload)result = response.json()content = result["choices"][0]["message"]["content"]# 尝试提取 JSONjson_match = re.search(r"\[.*\]", content, re.S)if not json_match:return [text] # fallbacktry:chunks_data = json.loads(json_match.group(0))chunks = [c["content"].strip() for c in chunks_data if "content" in c]except Exception:chunks = [text]return chunks
--- 下面是LLM Chunking的测试结果 ---
待分段文本:
# 人工智能的起源与发展人工智能(Artificial Intelligence, AI)这一概念最早诞生于20世纪50年代。最初的研究者们试图让计算机模拟人类思考的过程,例如推理、学习与决策。然而,受限于算力与数据的匮乏,这一阶段的AI发展相对缓慢。# 现实挑战与伦理思考AI的发展带来了巨大的社会影响。隐私泄露、算法歧视、虚假信息传播等问题,正在成为亟需解决的现实挑战。与此同时,AI的应用边界也在被不断讨论——它是否应该参与教育、医疗甚至法律判断?
---- Chunk 0 ----# 人工智能的起源与发展人工智能(Artificial Intelligence, AI)这一概念最早诞生于20世纪50年代。最初的研究者们试图让计算机模拟人类思考的过程,例如推理、学习与决策。然而,受限于算力与数据的匮乏,这一阶段的AI发展相对缓慢。---- Chunk 1 ----# 现实挑战与伦理思考AI的发展带来了巨大的社会影响。隐私泄露、算法歧视、虚假信息传播等问题,正在成为亟需解决的现实挑战。与此同时,AI的应用边界也在被不断讨论——它是否应该参与教育、医疗甚至法律判断?
虽然LLM Chunking相较于之前传统的基于规则分段的任务对于语义和逻辑的理解更透彻,但是存在一些挑战:
1. 每个文档都要调用模型,成本较高;
2. 可能会出现chunk太大或者太碎的情况;
3. 难以调试或者标准化;
以上就是我们本期关于文档分段的全部内容,我们从可精准控制的基于规则的基础方法,一路探讨到大模型时代更为智能、理解上下文的进阶分段策略,希望能为大家构建高效的检索问答系统打下坚实基础。
53AI,企业落地大模型首选服务商
产品:场景落地咨询+大模型应用平台+行业解决方案
承诺:免费POC验证,效果达标后再合作。零风险落地应用大模型,已交付160+中大型企业
2025-10-30
Cursor 2.0的一些有趣的新特性
2025-10-30
Anthropic 发布最新研究:LLM 展现初步自省迹象
2025-10-30
让Agent系统更聪明之前,先让它能被信任
2025-10-30
Rag不行?谷歌DeepMind同款,文档阅读新助手:ReadAgent
2025-10-29
4大阶段,10个步骤,助你高效构建企业级智能体(Agent)
2025-10-29
DocReward:让智能体“写得更专业”的文档奖励模型
2025-10-29
沃尔沃RAG实战:企业级知识库,早就该放弃小分块策略
2025-10-29
大模型的Funcation Calling是什么?
2025-08-21
2025-08-21
2025-08-19
2025-09-16
2025-10-02
2025-09-08
2025-09-17
2025-08-19
2025-09-29
2025-08-20
2025-10-29
2025-10-29
2025-10-28
2025-10-28
2025-10-27
2025-10-26
2025-10-25
2025-10-23