RAG系列:切分優化 - 基于 Markdown 語法的文檔切分
引言
在RAG系列:解析優化 - 不同文件類型統一轉換成Markdown一文中我們介紹了將不同文件類型統一解析轉換成 Markdown 文件的好處。本文我們接著這篇文章解析轉換后的 Markdown 文件,介紹下基于 Markdown 語法的文檔切分方法。
關于指標
在RAG系列:系統評估 - 五個主流評估指標詳解一文中我們介紹了評估 RAG 系統的五個主流指標,從本文開始,我會根據不同優化階段來選擇要重點關注的指標,不必要每次都關注五個指標的表現,這樣可以讓我們的優化更聚焦,通過優化每個階段的重點指標,從而逐步優化系統的各個環節。
在不同優化階段需要重點關注的指標:
- 問題優化:上下文召回率、答案正確性;
- 切分優化:上下文召回率、上下文相關性、答案正確性;
- 檢索優化:上下文召回率、上下文相關性、答案正確性;
- 生成優化:答案忠實度、答案相關性、答案正確性。
代碼實踐
本文完整代碼地址[1]
基于換行符&空格等字符切分
在之前的示例中,我們用的切分方法是 langchainjs
的 RecursiveCharacterTextSplitter
,這是默認推薦(常用)的切分方法。與簡單的基于字符計數或固定分隔符的分割方法不同,RecursiveCharacterTextSplitter
使用一種遞歸的方法來嘗試在多個級別的分隔符上進行分割,從而盡量保持文本的語義完整性。
RecursiveCharacterTextSplitter
默認分隔符序列是 ["\n\n", "\n", " ", ""]
,意味著它會先嘗試按段落分割,然后是句子,接著是單詞,最后是逐字符處理。
代碼實現:
async function splitDocuments_v50(docs) {
const textSplitter = new RecursiveCharacterTextSplitter({
chunkSize: 500, // 文本切分大小
chunkOverlap: 50, // 文本切分重疊大小
});
const documents = await textSplitter.splitDocuments(docs);
return documents;
}
使用該方法切分出來的文檔塊大小相對比較均勻,都比較接近設置的 chunkSize(500):
[379,425,396,376,425,206,495,400,248,299,304,335,314,484,485,425,474,479,352,378,441,443,460,400,398,211,481,346,307,476,414,358,494,480,412,367,383,485,421,407,494,487,334,448,493,397,443,410,400,388,460,492,423,55,484,498,488,422,485,414,382,361,431,157,482,485,192,271,332,424,150,456,410,427,491,477,379,202,461,456,48,39,494,235,474,407,405,248,472,473,134,351,407,102,491,413,486,478,210,495,476,163,383,421,406,486,431,224,488,488,93,487,442,388,496,169,487,485,361,412,468,357,421,362,489,445,468,251,495,477,101,202,498,211,494,328,470,422,332,246,295,393,264]
以下是我們用該方法對 《2024少兒編程教育行業發展趨勢報告.md》文件進行切分后的結果:
[
{
"pageContent":"# 少兒編程教育行業發展趨勢報告\n\n\n\n多鯨教育研究院/ 2024 年 1 月\n\n## 少兒編程教育行業圖譜\n\n### To B / To G\n\n",
},
{
"pageContent":"\n\n## 專家觀點\n\n### 【童程童美 CEO/孫瀅】\n\n? 當前,素質教育市場比較分散,但包括少兒編程教育在內的市場規模仍將繼續擴大。人工智能浪潮越大,人們越可能認識到通過素質教育發展孩子其他能力的重要性,包括體育、藝術、編程等,因此素質教育將會繼續蓬勃發展。 \n? 鑒于提升學科成績的剛需長期持續存在,優質的教師資源將始終都是稀缺資源。有實力的大品牌和大公司會在素質教育發展的過程當中獲得更大的優勢。與此同時,市場里具有個性化特點的小公司也會蓬勃發展,最終呈現巨頭和小而美并存的共榮局面。\n\n### 【點貓科技創始人兼 CEO/李天馳】",
},
{
"pageContent":"### 【點貓科技創始人兼 CEO/李天馳】\n\n? 點貓科技將以“為下一代提供更有價值的教育”為使命,持續聚焦工具和內容研發,培養青少年的計算思維以及用數字化的方法和手段解決實際問題的能力,幫助更多地區和學校開展人工智能編程教育服務,不斷為科技教育事業添磚加瓦,并為振興鄉村教育、助力教育公平貢獻自己的力量。\n\n### 【核桃編程創始人兼 CEO/曾鵬軒】\n\n? 未來教育的趨勢是以實操為主的教育方式。少兒編程是學習的工具,一種能夠實現主動學習的教育方式,也是一種未來教育的理念。核桃編程讓孩子通過編程來學習,而不是學習編程,而實操是對編程最有效的學習方式,也是核桃編程的核心理念。我們希望通過核桃編程帶來一種正向的學習理念,不只是為了學而學,而是為了用而學。我們要培養的孩子,是對科學充滿好奇、擁有無限創造力,最重要的是具有獨立思考與自主學習的能力。\n\n### 【斯坦星球 CEO/崔顯耿】",
}
...
]
然后對此進行評測,將該評測結果(v5.0)作為本文的基準:
基于 Markdown 語法切分
要基于 Markdown 語法進行切分,我們采用的是 langchainjs
提供的MarkdownTextSplitter
。MarkdownTextSplitter
是RecursiveCharacterTextSplitter
的子類,也就是在RecursiveCharacterTextSplitter
默認分隔符序列的基礎上添加了一些 Markdown 特有的分隔符['\n## ', '\n### ','\n#### ', '\n##### ','\n###### ', '```\n\n','\n\n***\n\n', '\n\n---\n\n','\n\n___\n\n' ]
,這樣就意味著它會先嘗試按 Markdown 標題 分割,然后是代碼塊、接著是分割線,最后是按 RecursiveCharacterTextSplitter
方法切分,這樣就能夠識別并考慮 Markdown 文本中的不同元素(如標題、段落、列表項、代碼塊等),從而進行更加合理的切分。
代碼實現:
async function splitDocuments_v51(docs, config) {
const textSplitter = new MarkdownTextSplitter({
chunkSize: 500, // 文本切分大小
chunkOverlap: 50, // 文本切分重疊大小
});
const documents = await textSplitter.splitDocuments(docs);
return documents;
}
使用該方法切分出來的文檔塊大小分布的比較分散,最小的文檔塊大小只有 10:
[192,340,402,378,387,400,495,381,225,273,275,314,281,435,485,245,350,302,387,411,378,383,445,451,32,463,398,143,359,359,484,359,39,490,271,437,420,308,28,441,443,436,465,25,407,494,487,334,14,432,148,343,182,437,145,72,410,400,388,172,29,255,492,423,55,484,498,28,458,168,252,451,32,477,225,419,392,37,118,482,485,192,19,250,332,424,150,19,27,481,242,487,491,175,300,36,462,35,10,461,456,48,27,10,494,235,14,458,32,206,380,387,27,22,472,473,134,339,10,407,102,412,407,27,13,486,478,210,14,467,129,412,30,31,350,170,206,29,492,71,263,378,253,488,88,440,487,353,38,279,432,170,34,133,487,485,361,392,468,357,243,31,474,203,28,484,203,127,32,460,37,31,12,495,477,101,14,142,30,10,498,211,327,404,36,393,183,453,448,277,393,264]
我們再看下用該方法對 《2024少兒編程教育行業發展趨勢報告.md》文件進行切分的結果:
[
{
"pageContent":"# 少兒編程教育行業發展趨勢報告\n\n\n\n多鯨教育研究院/ 2024 年 1 月",
},
{
"pageContent":"## 少兒編程教育行業圖譜\n\n### To B / To G\n\n\n\n",
},
{
"pageContent":"### 【極客晨星創始人、CTO/張軍彪】\n\n? 2023 年以 AIGC 和大模型為代表的 AI 技術迅猛發展,如何為中小學生提供更加優質的科學教育、全面提高科學素質,成為一個急迫的時代命題,編程作為鏈接 AI 時代和創新人才的“鑰匙”越來越剛需,整個青少年編程市場也進入活躍期。編程教育的目標是要培養個性化、創新性人才。 \n? 編程教育最根本的是要立足課程體系,用科技加持的方法教好科技的課程,打造好的平臺和工具,為孩子們提供更加優質的教育資源,激發好奇心、培養創造力,實現個性化、創新性人才的培養,在助力科學教育做加法中的作用越來越突出。",
},
...
{
"pageContent":"#### 各地積極響應國家政策號召,推動編程教育與人工智能的融合及普及國家戰略政策利好,少兒編程教育重要性逐步提升\n\n國家政策支持\n\n從教育部到各地方教育主管部門陸續出臺多項政策支持少兒編程教育普及推廣\n\n- 2018 -2019 年\n\n? 河南省建議在中小學開設 Scratch、Python 等程序設計課程,培養編程思維,普及編程教育。 \n? 天津市政府招生辦發布的《 2018 年天津科技特長生招生計劃》中,多所中學將信息學奧賽、信息技術、人工智能等納入了招生范疇。 \n? 重慶市教委發布《關于加強中小學編程教育的通知》,將編程列為重慶中小學必修課,要求小學三年級開始學編程。 \n? 北京市教育委員會將人工智能納入北京中小學社會實踐,明確了人工智能與教育融合發展在教育各學段主要任務。 \n? 山東省教育廳整合人工智能、編程教育、機器人教育等創客資源,著力打造創客教育課程體系。\n\n- 2020 -2021 年",
},
{
"pageContent":"- 2020 -2021 年\n\n? 新疆烏魯木齊市教育局通知將在小學初中和高中年級里分別開展圖形化編程和 Python 課程,并附對課程及課時安排的具體要求,要求對老師進行線上與線下結合的編程培訓。 \n? 浙江省發布消息,八年級新增 Python 內容,五六年級按照教材規劃開始接觸大數據、人工智能、程序設計與算法。 \n? 北京市海淀區明確指出:將信息技術(包含編程)納入初中學業水平測試,考試不通過不予畢業。 \n? 上海市教委提出推進人工智能、編程技術等課程進中小學課堂,支持高校人工智能相關專業建設,提升師生信息素養。 \n? 長沙市發改委等部門指出,中小學新增“人工智能教育”和“編程教育”。 \n? 廣州市將“信息技術”列入初中學業水平考試錄取參考科目之一,示范性普通高中投檔考生的錄取參考科目成績均須達到 C 級及以上。\n\n- 2022 年",
}
]
該切分方法的評測結果(v5.1)如下:
從評測結果來看,該方法對各項指標有提升但不是很明顯,因此我們進一步分析下原因并優化。
合并過小的文檔塊
在使用 MarkdownTextSplitter
進行切分文檔的時候,我們可以看到切分后的文檔塊大小分布是比較分散的,最小的文檔塊大小只有 10,由于 MarkdownTextSplitter
切分方法的特性,這些小的文檔塊可能就是一個標題,比如:["##### 業務模式", "##### 課程體系", "##### 產品優勢"]
。由于我們是根據向量距離檢索相關文檔的,由于更大的文本塊,其所涵蓋的信息量也增大,可能導致向量表示變得更加稀疏,往往我們檢索出來的是這些更小的文檔,但這些文檔往往不包含或包含很少答案所需的關鍵信息,從而影響到上下文召回率
。
因此我們需要將這些過小的文檔塊進行合并,由于這些過小的文檔塊是標題,所以簡單的方法就是將過小的文檔塊直接合并到下一個文檔塊上,代碼實現:
async functionsplitDocuments_v52(docs) {
// 在 splitDocuments_v51 的結果上進行處理
const documents = awaitsplitDocuments_v51(docs);
for (let i = 0; i < documents.length; i++) {
const doc = documents[i];
// 長度小于100的文檔
if (doc.pageContent.length < 100) {
// 如果不是最后一個元素,則合并到下一個元素
if (i < documents.length - 1) {
console.log('合并內容:', doc.pageContent, '到下一個');
documents[i + 1].pageContent =
doc.pageContent + '\n' + documents[i + 1].pageContent;
}
// 刪除當前元素
documents.splice(i, 1);
i--; // 回退索引以適應數組縮短的情況
}
}
return documents;
}
通過這樣的優化,我們看下評測結果(v5.2)如下:
此時我們可以看到,上下文召回率
較 v5.1 有了比較明顯的提升。
給文檔塊補充標題
之所有要把不同的文件轉換成 Markdown 文件,其中的好處是 Markdown 文件能夠以純文本形式保留文檔的基本結構(標題、列表、代碼塊、表格),其中的標題提供了文檔的關鍵詞和上下文信息,能來用來幫助快速理解文檔內容,并在檢索時更準確地定位到與用戶提問相關的信息,這可以提高上下文相關性
,因此給每個文檔塊補充標題是非常有必要的。
MarkdownTextSplitter
切分后的結果:
[
{
"pageContent":"# 少兒編程教育行業發展趨勢報告\n\n\n\n多鯨教育研究院/ 2024 年 1 月",
},
{
"pageContent":"## 少兒編程教育行業圖譜\n\n### To B / To G\n\n\n\n",
},
{
"pageContent":"### 【極客晨星創始人、CTO/張軍彪】\n\n? 2023 年以 AIGC 和大模型為代表的 AI 技術迅猛發展,如何為中小學生提供更加優質的科學教育、全面提高科學素質,成為一個急迫的時代命題,編程作為鏈接 AI 時代和創新人才的“鑰匙”越來越剛需,整個青少年編程市場也進入活躍期。編程教育的目標是要培養個性化、創新性人才。 \n? 編程教育最根本的是要立足課程體系,用科技加持的方法教好科技的課程,打造好的平臺和工具,為孩子們提供更加優質的教育資源,激發好奇心、培養創造力,實現個性化、創新性人才的培養,在助力科學教育做加法中的作用越來越突出。",
},
...
{
"pageContent":"#### 各地積極響應國家政策號召,推動編程教育與人工智能的融合及普及國家戰略政策利好,少兒編程教育重要性逐步提升\n\n國家政策支持\n\n從教育部到各地方教育主管部門陸續出臺多項政策支持少兒編程教育普及推廣\n\n- 2018 -2019 年\n\n? 河南省建議在中小學開設 Scratch、Python 等程序設計課程,培養編程思維,普及編程教育。 \n? 天津市政府招生辦發布的《 2018 年天津科技特長生招生計劃》中,多所中學將信息學奧賽、信息技術、人工智能等納入了招生范疇。 \n? 重慶市教委發布《關于加強中小學編程教育的通知》,將編程列為重慶中小學必修課,要求小學三年級開始學編程。 \n? 北京市教育委員會將人工智能納入北京中小學社會實踐,明確了人工智能與教育融合發展在教育各學段主要任務。 \n? 山東省教育廳整合人工智能、編程教育、機器人教育等創客資源,著力打造創客教育課程體系。\n\n- 2020 -2021 年",
},
{
"pageContent":"- 2020 -2021 年\n\n? 新疆烏魯木齊市教育局通知將在小學初中和高中年級里分別開展圖形化編程和 Python 課程,并附對課程及課時安排的具體要求,要求對老師進行線上與線下結合的編程培訓。 \n? 浙江省發布消息,八年級新增 Python 內容,五六年級按照教材規劃開始接觸大數據、人工智能、程序設計與算法。 \n? 北京市海淀區明確指出:將信息技術(包含編程)納入初中學業水平測試,考試不通過不予畢業。 \n? 上海市教委提出推進人工智能、編程技術等課程進中小學課堂,支持高校人工智能相關專業建設,提升師生信息素養。 \n? 長沙市發改委等部門指出,中小學新增“人工智能教育”和“編程教育”。 \n? 廣州市將“信息技術”列入初中學業水平考試錄取參考科目之一,示范性普通高中投檔考生的錄取參考科目成績均須達到 C 級及以上。\n\n- 2022 年",
}
]
我們通過看 MarkdownTextSplitter
切分后的結果,可以看到文檔塊所在的每一層級的標題是有缺失的,理想狀態下,該文檔塊需要有它所在的一級標題、二級標題、三級標題等等,所以在這里我們將對每個文檔塊的標題進行補充,實現代碼如下:
async functionsplitDocuments_v53(docs, config) {
// 在 splitDocuments_v52 的結果上進行處理
const documents = awaitsplitDocuments_v52(docs, config);
// 獲取每個文檔塊的標題并添加到元數據中
for (let i = 0; i < documents.length; i++) {
const doc = documents[i];
const lines = doc.pageContent.split('\n');
const headers = [
{
key: 'header5',
value: '##### ',
},
{
key: 'header4',
value: '#### ',
},
{
key: 'header3',
value: '### ',
},
{
key: 'header2',
value: '## ',
},
{
key: 'header1',
value: '# ',
},
];
headers.forEach((header) => {
const { key, value } = header;
doc.metadata[key] = [];
// 提取每一行的標題
for (const line of lines) {
if (line.startsWith(value)) {
doc.metadata[key].push(
line.replace(newRegExp(`/^${value}/`), '').trim()
);
}
}
// 如果當前文檔沒有對應標題,則取前一個文檔的對應標題的第一個,并加入到當前文檔中
if (i > 0) {
if (doc.metadata[key].length === 0) {
const preHeader = documents[i - 1].metadata[key][0];
if (preHeader) {
doc.pageContent = preHeader + '\n\n' + doc.pageContent;
doc.metadata[key] = [preHeader];
}
}
}
});
}
return documents;
}
這樣處理后,我們可以看到每個文檔塊都補充了每一級的標題:
[
{
"pageContent":"# 少兒編程教育行業發展趨勢報告\n\n\n\n多鯨教育研究院/ 2024 年 1 月",
},
{
"pageContent":"# 少兒編程教育行業發展趨勢報告\n\n## 少兒編程教育行業圖譜\n\n### To B / To G\n\n\n\n",
},
{
"pageContent":"# 少兒編程教育行業發展趨勢報告\n\n## 專家觀點\n\n### 【極客晨星創始人、CTO/張軍彪】\n\n? 2023 年以 AIGC 和大模型為代表的 AI 技術迅猛發展,如何為中小學生提供更加優質的科學教育、全面提高科學素質,成為一個急迫的時代命題,編程作為鏈接 AI 時代和創新人才的“鑰匙”越來越剛需,整個青少年編程市場也進入活躍期。編程教育的目標是要培養個性化、創新性人才。 \n? 編程教育最根本的是要立足課程體系,用科技加持的方法教好科技的課程,打造好的平臺和工具,為孩子們提供更加優質的教育資源,激發好奇心、培養創造力,實現個性化、創新性人才的培養,在助力科學教育做加法中的作用越來越突出。",
},
...
{
"pageContent":"# 少兒編程教育行業發展趨勢報告\n\n## 少兒編程教育行業 十大趨勢\n\n### 01 國家戰略政策利好,少兒編程教育重要性逐步提升\n\n#### 各地積極響應國家政策號召,推動編程教育與人工智能的融合及普及國家戰略政策利好,少兒編程教育重要性逐步提升\n\n國家政策支持\n\n從教育部到各地方教育主管部門陸續出臺多項政策支持少兒編程教育普及推廣\n\n- 2018 -2019 年\n\n? 河南省建議在中小學開設 Scratch、Python 等程序設計課程,培養編程思維,普及編程教育。 \n? 天津市政府招生辦發布的《 2018 年天津科技特長生招生計劃》中,多所中學將信息學奧賽、信息技術、人工智能等納入了招生范疇。 \n? 重慶市教委發布《關于加強中小學編程教育的通知》,將編程列為重慶中小學必修課,要求小學三年級開始學編程。 \n? 北京市教育委員會將人工智能納入北京中小學社會實踐,明確了人工智能與教育融合發展在教育各學段主要任務。 \n? 山東省教育廳整合人工智能、編程教育、機器人教育等創客資源,著力打造創客教育課程體系。\n\n- 2020 -2021 年",
},
{
"pageContent":"# 少兒編程教育行業發展趨勢報告\n\n## 少兒編程教育行業 十大趨勢\n\n### 01 國家戰略政策利好,少兒編程教育重要性逐步提升\n\n#### 各地積極響應國家政策號召,推動編程教育與人工智能的融合及普及國家戰略政策利好,少兒編程教育重要性逐步提升\n\n- 2020 -2021 年\n\n? 新疆烏魯木齊市教育局通知將在小學初中和高中年級里分別開展圖形化編程和 Python 課程,并附對課程及課時安排的具體要求,要求對老師進行線上與線下結合的編程培訓。 \n? 浙江省發布消息,八年級新增 Python 內容,五六年級按照教材規劃開始接觸大數據、人工智能、程序設計與算法。 \n? 北京市海淀區明確指出:將信息技術(包含編程)納入初中學業水平測試,考試不通過不予畢業。 \n? 上海市教委提出推進人工智能、編程技術等課程進中小學課堂,支持高校人工智能相關專業建設,提升師生信息素養。 \n? 長沙市發改委等部門指出,中小學新增“人工智能教育”和“編程教育”。 \n? 廣州市將“信息技術”列入初中學業水平考試錄取參考科目之一,示范性普通高中投檔考生的錄取參考科目成績均須達到 C 級及以上。\n\n- 2022 年",
}
]
通過這樣的優化,我們看下評測結果(v5.3)如下:
此時我們可以看到,上下文相關性
較 v5.2 有了比較明顯的提升。
結語
通過對比基于通用字符遞歸切分方法與基于 Markdown 語法的文檔切分方法,我們可以看到基于 Markdown 語法的文檔切分方法對 RAG 系統的各項指標是有一定的提升作用,然后我們通過合并過小的文檔塊提升了上下文召回率
,通過給文檔塊補充標題提升了上下文相關性
。
引用鏈接
[1]
本文完整代碼地址: https://github.com/laixiangran/ai-learn/blob/main/src/app/rag/05_document_split_optimize/route.ts