From 2c681bcdd1f9fed3ab3caa576239606407cd3449 Mon Sep 17 00:00:00 2001 From: Archer <545436317@qq.com> Date: Mon, 17 Nov 2025 12:30:56 +0800 Subject: [PATCH] fix: text split (#5933) * fix: text split * remove test --- document/content/docs/upgrading/4-14/4142.mdx | 1 + document/data/doc-last-modified.json | 6 +-- packages/global/common/string/textSplitter.ts | 7 ++- test/cases/global/common/string/test.md | 5 +++ .../global/common/string/textSplitter.test.ts | 44 ++++++++++++++++--- 5 files changed, 52 insertions(+), 11 deletions(-) create mode 100644 test/cases/global/common/string/test.md diff --git a/document/content/docs/upgrading/4-14/4142.mdx b/document/content/docs/upgrading/4-14/4142.mdx index 930d2268b..9910f251e 100644 --- a/document/content/docs/upgrading/4-14/4142.mdx +++ b/document/content/docs/upgrading/4-14/4142.mdx @@ -13,6 +13,7 @@ description: 'FastGPT V4.14.2 更新说明' ## ⚙️ 优化 1. 30 分钟模板市场缓存时长。 +2. 自定义分隔符块大小采用最大块大小。 ## 🐛 修复 diff --git a/document/data/doc-last-modified.json b/document/data/doc-last-modified.json index e7d850644..66d2ef55c 100644 --- a/document/data/doc-last-modified.json +++ b/document/data/doc-last-modified.json @@ -31,7 +31,7 @@ "document/content/docs/introduction/development/modelConfig/ppio.mdx": "2025-09-29T11:52:39+08:00", "document/content/docs/introduction/development/modelConfig/siliconCloud.mdx": "2025-08-05T23:20:39+08:00", "document/content/docs/introduction/development/openapi/app.mdx": "2025-09-26T13:18:51+08:00", - "document/content/docs/introduction/development/openapi/chat.mdx": "2025-09-29T11:34:11+08:00", + "document/content/docs/introduction/development/openapi/chat.mdx": "2025-11-14T13:21:17+08:00", "document/content/docs/introduction/development/openapi/dataset.mdx": "2025-09-29T11:34:11+08:00", "document/content/docs/introduction/development/openapi/intro.mdx": "2025-09-29T11:34:11+08:00", "document/content/docs/introduction/development/openapi/share.mdx": "2025-08-05T23:20:39+08:00", @@ -101,7 +101,7 @@ "document/content/docs/protocol/terms.en.mdx": "2025-08-03T22:37:45+08:00", "document/content/docs/protocol/terms.mdx": "2025-08-03T22:37:45+08:00", "document/content/docs/toc.en.mdx": "2025-08-04T13:42:36+08:00", - "document/content/docs/toc.mdx": "2025-11-13T13:36:41+08:00", + "document/content/docs/toc.mdx": "2025-11-14T13:21:17+08:00", "document/content/docs/upgrading/4-10/4100.mdx": "2025-08-02T19:38:37+08:00", "document/content/docs/upgrading/4-10/4101.mdx": "2025-09-08T20:07:20+08:00", "document/content/docs/upgrading/4-11/4110.mdx": "2025-08-05T23:20:39+08:00", @@ -116,7 +116,7 @@ "document/content/docs/upgrading/4-13/4132.mdx": "2025-10-21T11:46:53+08:00", "document/content/docs/upgrading/4-14/4140.mdx": "2025-11-06T15:43:00+08:00", "document/content/docs/upgrading/4-14/4141.mdx": "2025-11-12T12:19:02+08:00", - "document/content/docs/upgrading/4-14/4142.mdx": "2025-11-13T20:49:04+08:00", + "document/content/docs/upgrading/4-14/4142.mdx": "2025-11-14T13:21:17+08:00", "document/content/docs/upgrading/4-8/40.mdx": "2025-08-02T19:38:37+08:00", "document/content/docs/upgrading/4-8/41.mdx": "2025-08-02T19:38:37+08:00", "document/content/docs/upgrading/4-8/42.mdx": "2025-08-02T19:38:37+08:00", diff --git a/packages/global/common/string/textSplitter.ts b/packages/global/common/string/textSplitter.ts index 5563562c6..65fb24be3 100644 --- a/packages/global/common/string/textSplitter.ts +++ b/packages/global/common/string/textSplitter.ts @@ -176,7 +176,7 @@ const commonSplit = (props: SplitProps): SplitResponse => { const stepReges: { reg: RegExp | string; maxLen: number }[] = [ ...customReg.map((text) => ({ reg: text.replace(/\\n/g, '\n'), - maxLen: chunkSize + maxLen: maxSize })), ...markdownHeaderRules, @@ -250,7 +250,10 @@ const commonSplit = (props: SplitProps): SplitResponse => { .map((text) => { const matchTitle = isMarkdownSplit ? text.match(reg)?.[0] || '' : ''; // 如果一个分块没有匹配到,则使用默认块大小,否则使用最大块大小 - const chunkMaxSize = text.match(reg) === null ? chunkSize : maxLen; + const chunkMaxSize = (() => { + if (isCustomStep) return maxLen; + return text.match(reg) === null ? chunkSize : maxLen; + })(); return { text: isMarkdownSplit ? text.replace(matchTitle, '') : text, diff --git a/test/cases/global/common/string/test.md b/test/cases/global/common/string/test.md new file mode 100644 index 000000000..5688fd21c --- /dev/null +++ b/test/cases/global/common/string/test.md @@ -0,0 +1,5 @@ +[ + "这是一个测试的内容,包含代码块快速了解FastGPTFastGPT的能力与优势FastGPT是一个基于LLM大语言模型的知识库问答系统,提供开箱即用的数据处理、模型调用等能力。同时可以通过Flow可视化进行工作流编排,从而实现复杂的问答场景!FastGPT在线使用:https://fastgpt.ioFastGPT能力1.专属AI客服通过导入文档或已有问答对进行训练,让AI模型能根据你的文档以交互式对话方式回答问题。2.简单易用的可视化界面FastGPT采用直观的可视化界面设计,为各种应用场景提供了丰富实用的功能。通过简洁易懂的操作步骤,可以轻松完成AI客服的创建和训练流程。~~~jsimport{defaultMaxChunkSize}from'../../core/dataset/training/utils';import{getErrText}from'../error/utils';constgetOneTextOverlapText=({text,step}:{text:string;step:number}):string=>{constforbidOverlap=checkForbidOverlap(step);constmaxOverlapLen=chunkSize*0.4;//step>=stepReges.length:Donotoverlapincompletesentencesif(forbidOverlap||overlapLen===0||step>=stepReges.length)return'';constsplitTexts=getSplitTexts({text,step});letoverlayText='';for(leti=splitTexts.length-1;i>=0;i--){constcurrentText=splitTexts[i].text;constnewText=currentText+overlayText;constnewTextLen=newText.length;if(newTextLen>overlapLen){if(newTextLen>maxOverlapLen){consttext=getOneTextOverlapText({text:newText,step:step+1});returntext||overlayText;}returnnewText;}overlayText=newText;}returnoverlayText;};constgetOneTextOverlapText=({text,step}:{text:string;step:number}):string=>{constforbidOverlap=checkForbidOverlap(step);constmaxOverlapLen=chunkSize*0.4;//step>=stepReges.length:Donotoverlapincompletesentencesif(forbidOverlap||overlapLen===0||step>=stepReges.length)return'';constsplitTexts=getSplitTexts({text,step});letoverlayText='';for(leti=splitTexts.length-1;i>=0;i--){constcurrentText=splitTexts[i].text;constnewText=currentText+overlayText;constnewTextLen=newText.length;if(newTextLen>overlapLen){if(newTextLen>maxOverlapLen){consttext=getOneTextOverlapText({text:newText,step:step+1});returntext||overlayText;}returnnewText;}overlayText=newText;}returnoverlayText;};constgetOneTextOverlapText=({text,step}:{text:string;step:number}):string=>{constforbidOverlap=checkForbidOverlap(step);constmaxOverlapLen=chunkSize*0.4;//step>=stepReges.length:Donotoverlapincompletesentencesif(forbidOverlap||overlapLen===0||step>=stepReges.length)return'';constsplitTexts=getSplitTexts({text,step});letoverlayText='';for(leti=splitTexts.length-1;i>=0;i--){constcurrentText=splitTexts[i].text;constnewText=currentText+overlayText;constnewTextLen=newText.length;if(newTextLen>overlapLen){if(newTextLen>maxOverlapLen){consttext=getOneTextOverlapText({text:newText,step:step+1});returntext||overlayText;}returnnewText;}overlayText=newText;}returnoverlayText;};constgetOneTextOverlapText=({text,step}:{text:string;step:number}):string=>{constforbidOverlap=checkForbidOverlap(step);constmaxOverlapLen=chunkSize*0.4;//step>=stepReges.length:Donotoverlapincompletesentencesif(forbidOverlap||overlapLen===0||step>=stepReges.length)return'';constsplitTexts=getSplitTexts({text,step});letoverlayText='';for(leti=splitTexts.length-1;i>=0;i--){constcurrentText=splitTexts[i].text;constnewText=currentText+overlayText;constnewTextLen=newText.length;if(newTextLen>overlapLen){if(newTextLen>maxOverlapLen){consttext=getOneTextOverlapText({text:newText,step:step+1});returntext||overlayText;}returnnewText;}overlayText=newText;}returnoverlayText;};constgetOneTextOverlapText=({text,step}:{text:string;step:number}):string=>{constforbidOverlap=checkForbidOverlap(step);constmaxOverlapLen=chunkSize*0.4;//step>=stepReges.length:Donotoverlapincompletesentencesif(forbidOverlap||overlapLen===0||step>=stepReges.length)return'';constsplitTexts=getSplitTexts({text,step});letoverlayText='';for(leti=splitTexts.length-1;i>=0;i--){constcurrentText=splitTexts[i].text;constnewText=currentText+overlayText;constnewTextLen=newText.length;if(newTextLen>overlapLen){if(newTextLen>maxOverlapLen){consttext=getOneTextOverlapText({text:newText,step:step+1});returntext||overlayText;}returnnewText;}overlayText=newText;}returnoverlayText;};~~~", + "3.自动数据预处理提供手动输入、直接分段、LLM自动处理和CSV等多种数据导入途径,其中“直接分段”支持通过PDF、WORD、Markdown和CSV文档内容作为上下文。FastGPT会自动对文本数据进行预处理、向量化和QA分割,节省手动训练时间,提升效能。4.工作流编排基于Flow模块的工作流编排,可以帮助你设计更加复杂的问答流程。例如查询数据库、查询库存、预约实验室等。5.强大的API集成FastGPT对外的API接口对齐了OpenAI官方接口,可以直接接入现有的GPT应用,也可以轻松集成到企业微信、公众号、飞书等平台。FastGPT特点项目开源FastGPT遵循附加条件ApacheLicense2.0开源协议,你可以Fork之后进行二次开发和发布。FastGPT社区版将保留核心功能,商业版仅在社区版基础上使用API的形式进行扩展,不影响学习使用。独特的QA结构针对客服问答场景设计的QA结构,提高在大量数据场景中的问答准确性。可视化工作流通过Flow模块展示了从问题输入到模型输出的完整流程,便于调试和设计复杂流程。无限扩展基于API进行扩展,无需修改FastGPT源码,也可快速接入现有的程序中。", + "便于调试提供搜索测试、引用修改、完整对话预览等多种调试途径。支持多种模型支持GPT、Claude、文心一言等多种LLM模型,未来也将支持自定义的向量模型。知识库核心流程FastGPTAI相关参数配置说明在FastGPT的AI对话模块中,有一个AI高级配置,里面包含了AI模型的参数配置,本文详细介绍这些配置的含义。返回AI内容(高级编排特有)这是一个开关,打开的时候,当AI对话模块运行时,会将其输出的内容返回到浏览器(API响应);如果关闭,AI输出的内容不会返回到浏览器,但是生成的内容仍可以通过【AI回复】进行输出。你可以将【AI回复】连接到其他模块中。最大上下文代表模型最多容纳的文字数量。" +] \ No newline at end of file diff --git a/test/cases/global/common/string/textSplitter.test.ts b/test/cases/global/common/string/textSplitter.test.ts index 2df9c3db5..3d92243c9 100644 --- a/test/cases/global/common/string/textSplitter.test.ts +++ b/test/cases/global/common/string/textSplitter.test.ts @@ -295,10 +295,8 @@ it(`Test splitText2Chunks 6`, () => { 这是测试文本 2,长的。 FastGPT是一款基于大语言模型(LLM)的智能问答系统,专为提供高效、准确的知识库问答服务而设计。它支持多种数据导入方式,包括手动输入、PDF、WORD、Markdown和CSV等格式,能够自动进行数据预处理、向量化和QA分割,大幅提升数据处理效率。FastGPT的可视化界面设计简洁直观,用户可以通过Flow模块进行工作流编排,轻松实现复杂的问答场景。此外,FastGPT支持多种LLM模型,如GPT、Claude、文心一言等,未来还将支持自定义的向量模型。其强大的API集成能力使得用户可以轻松将其接入现有的GPT应用或其他平台,如企业微信、公众号、飞书等。FastGPT的开源项目遵循Apache License 2.0协议,用户可以进行二次开发和发布。其独特的QA结构设计提高了在大量数据场景中的问答准确性,而可视化工作流则展示了从问题输入到模型输出的完整流程,便于调试和设计复杂流程。FastGPT还提供了多种调试途径,如搜索测试、引用修改和完整对话预览等,方便用户进行调试。其知识库核心流程包括AI相关参数配置说明,如返回AI内容、最大上下文、函数调用、温度、回复上限、系统提示词、引用模板和引用提示词等。通过这些配置,用户可以更好地控制和优化AI模型的表现。FastGPT的引用模板和提示词设计使得用户可以根据具体需求进行灵活配置,从而提高问答的准确性和效率。总之,FastGPT是一款功能强大、易于使用的智能问答系统,适用于各种应用场景,帮助用户实现高效、准确的知识库问答服务。FastGPT的设计理念是通过先进的技术手段简化用户的操作流程,使得即便是没有技术背景的用户也能轻松上手。其多样化的数据导入方式确保了用户可以根据自身需求选择最合适的方式进行数据输入,而自动化的数据预处理功能则大大减少了用户的工作量。通过对数据的向量化处理,FastGPT能够更好地理解和分析用户的问题,从而提供更为精准的回答。`, result: [ - `这是测试文本 1,短的`, - `这是测试文本 2,长的。 -FastGPT是一款基于大语言模型(LLM)的智能问答系统,专为提供高效、准确的知识库问答服务而设计。它支持多种数据导入方式,包括手动输入、PDF、WORD、Markdown和CSV等格式,能够自动进行数据预处理、向量化和QA分割,大幅提升数据处理效率。FastGPT的可视化界面设计简洁直观,用户可以通过Flow模块进行工作流编排,轻松实现复杂的问答场景。此外,FastGPT支持多种LLM模型,如GPT、Claude、文心一言等,未来还将支持自定义的向量模型。其强大的API集成能力使得用户可以轻松将其接入现有的GPT应用或其他平台,如企业微信、公众号、飞书等。FastGPT的开源项目遵循Apache License 2.0协议,用户可以进行二次开发和发布。其独特的QA结构设计提高了在大量数据场景中的问答准确性,而可视化工作流则展示了从问题输入到模型输出的完整流程,便于调试和设计复杂流程。FastGPT还提供了多种调试途径,如搜索测试、引用修改和完整对话预览等,方便用户进行调试。其知识库核心流程包括AI相关参数配置说明,如返回AI内容、最大上下文、函数调用、温度、回复上限、系统提示词、引用模板和引用提示词等。`, - `FastGPT还提供了多种调试途径,如搜索测试、引用修改和完整对话预览等,方便用户进行调试。其知识库核心流程包括AI相关参数配置说明,如返回AI内容、最大上下文、函数调用、温度、回复上限、系统提示词、引用模板和引用提示词等。通过这些配置,用户可以更好地控制和优化AI模型的表现。FastGPT的引用模板和提示词设计使得用户可以根据具体需求进行灵活配置,从而提高问答的准确性和效率。总之,FastGPT是一款功能强大、易于使用的智能问答系统,适用于各种应用场景,帮助用户实现高效、准确的知识库问答服务。FastGPT的设计理念是通过先进的技术手段简化用户的操作流程,使得即便是没有技术背景的用户也能轻松上手。其多样化的数据导入方式确保了用户可以根据自身需求选择最合适的方式进行数据输入,而自动化的数据预处理功能则大大减少了用户的工作量。通过对数据的向量化处理,FastGPT能够更好地理解和分析用户的问题,从而提供更为精准的回答。` + '这是测试文本 1,短的', + '这是测试文本 2,长的。\nFastGPT是一款基于大语言模型(LLM)的智能问答系统,专为提供高效、准确的知识库问答服务而设计。它支持多种数据导入方式,包括手动输入、PDF、WORD、Markdown和CSV等格式,能够自动进行数据预处理、向量化和QA分割,大幅提升数据处理效率。FastGPT的可视化界面设计简洁直观,用户可以通过Flow模块进行工作流编排,轻松实现复杂的问答场景。此外,FastGPT支持多种LLM模型,如GPT、Claude、文心一言等,未来还将支持自定义的向量模型。其强大的API集成能力使得用户可以轻松将其接入现有的GPT应用或其他平台,如企业微信、公众号、飞书等。FastGPT的开源项目遵循Apache License 2.0协议,用户可以进行二次开发和发布。其独特的QA结构设计提高了在大量数据场景中的问答准确性,而可视化工作流则展示了从问题输入到模型输出的完整流程,便于调试和设计复杂流程。FastGPT还提供了多种调试途径,如搜索测试、引用修改和完整对话预览等,方便用户进行调试。其知识库核心流程包括AI相关参数配置说明,如返回AI内容、最大上下文、函数调用、温度、回复上限、系统提示词、引用模板和引用提示词等。通过这些配置,用户可以更好地控制和优化AI模型的表现。FastGPT的引用模板和提示词设计使得用户可以根据具体需求进行灵活配置,从而提高问答的准确性和效率。总之,FastGPT是一款功能强大、易于使用的智能问答系统,适用于各种应用场景,帮助用户实现高效、准确的知识库问答服务。FastGPT的设计理念是通过先进的技术手段简化用户的操作流程,使得即便是没有技术背景的用户也能轻松上手。其多样化的数据导入方式确保了用户可以根据自身需求选择最合适的方式进行数据输入,而自动化的数据预处理功能则大大减少了用户的工作量。通过对数据的向量化处理,FastGPT能够更好地理解和分析用户的问题,从而提供更为精准的回答。' ] }; @@ -326,6 +324,41 @@ it(`Test splitText2Chunks 7`, () => { expect(chunks).toEqual(mock.result); }); +// 自定义分隔符测试:使用 maxSize 而非 chunkSize 进行分割 +it(`Test splitText2Chunks 7.5 - Custom separator uses maxSize for splitting`, () => { + const mock = { + text: `第一段内容。FastGPT 是一个基于 LLM 大语言模型的知识库问答系统,提供开箱即用的数据处理、模型调用等能力。它支持多种数据导入方式,包括手动输入、PDF、WORD、Markdown 和 CSV 等格式,能够自动进行数据预处理、向量化和 QA 分割,大幅提升数据处理效率。FastGPT 的可视化界面设计简洁直观,用户可以通过 Flow 模块进行工作流编排,轻松实现复杂的问答场景。补充几个字,hello!!! +---- +第二段内容。FastGPT 支持多种 LLM 模型,如 GPT、Claude、文心一言等,未来还将支持自定义的向量模型。其强大的 API 集成能力使得用户可以轻松将其接入现有的 GPT 应用或其他平台,如企业微信、公众号、飞书等。FastGPT 的开源项目遵循 Apache License 2.0 协议,用户可以进行二次开发和发布。,轻松实现复杂的问答场景。补充几个字,hello!!!,轻松实现复杂的问答场景。补充几个字,hello!!!`, + chunkSize: 200, // 设置较小的 chunkSize + maxSize: 2000 // maxSize 远大于 chunkSize + }; + + const { chunks } = splitText2Chunks({ + text: mock.text, + chunkSize: mock.chunkSize, + maxSize: mock.maxSize, + customReg: ['----'] + }); + + // 应该分成 2 个块(通过 ---- 分隔符分割) + expect(chunks.length).toBe(2); + + // 验证第一个块大于 chunkSize(200),说明使用的是 maxSize + expect(chunks[0].length).toBeGreaterThan(mock.chunkSize); + expect(chunks[0].length).toBeLessThanOrEqual(mock.maxSize); + + // 验证第二个块大于 chunkSize(200),说明使用的是 maxSize + expect(chunks[1].length).toBeGreaterThan(mock.chunkSize); + expect(chunks[1].length).toBeLessThanOrEqual(mock.maxSize); + + // 验证包含完整内容(去除分隔符和空白后) + expect(chunks[0]).toContain('第一段内容'); + expect(chunks[0]).toContain('FastGPT 是一个基于 LLM 大语言模型'); + expect(chunks[1]).toContain('第二段内容'); + expect(chunks[1]).toContain('FastGPT 支持多种 LLM 模型'); +}); + // 长代码块分割 it(`Test splitText2Chunks 8`, () => { const mock = { @@ -545,8 +578,7 @@ FastGPT AI 相关参数配置说明 const { chunks } = splitText2Chunks({ text: mock.text, chunkSize: 500, - maxSize: 100000, - customReg: ['----'] + maxSize: 100000 }); const normalizedChunks = simpleChunks(chunks);