構(gòu)化表格的RAG架構(gòu):從文本檢索到精準(zhǔn)查詢(xún)的實(shí)戰(zhàn)解析)
1. 項(xiàng)目緣起當(dāng)大模型遇上結(jié)構(gòu)化表格最近在做一個(gè)企業(yè)內(nèi)部的數(shù)據(jù)智能問(wèn)答項(xiàng)目遇到了一個(gè)非常典型且棘手的問(wèn)題客戶(hù)手里有大量歷史積累的Excel、CSV表格里面存放著銷(xiāo)售數(shù)據(jù)、庫(kù)存清單、產(chǎn)品規(guī)格參數(shù)等。他們希望用一個(gè)對(duì)話界面讓業(yè)務(wù)人員能像問(wèn)同事一樣直接提問(wèn)“上季度華東區(qū)A產(chǎn)品的銷(xiāo)售額是多少”或者“庫(kù)存低于安全線的SKU有哪些”并立刻得到準(zhǔn)確的答案。一開(kāi)始我們很自然地想到了RAG檢索增強(qiáng)生成。畢竟讓大模型直接“記住”所有表格數(shù)據(jù)既不現(xiàn)實(shí)上下文長(zhǎng)度限制、成本高也不可靠存在幻覺(jué)。RAG的思路很清晰用戶(hù)提問(wèn)時(shí)先從外部知識(shí)庫(kù)這里就是那些表格里檢索出最相關(guān)的信息片段再把問(wèn)題和這些片段一起喂給大模型讓它基于這些“證據(jù)”來(lái)生成答案。然而當(dāng)我們把經(jīng)典的、為文本文檔如PDF、網(wǎng)頁(yè)設(shè)計(jì)的RAG流水線直接套用到結(jié)構(gòu)化表格上時(shí)立刻撞得頭破血流。你會(huì)發(fā)現(xiàn)模型經(jīng)常答非所問(wèn)或者給出的數(shù)字完全對(duì)不上。比如你問(wèn)“哪個(gè)區(qū)域的利潤(rùn)最高”它可能根據(jù)一段描述性文字瞎猜一個(gè)而不是去計(jì)算表格中“利潤(rùn)”列的實(shí)際數(shù)值。問(wèn)題的核心在于表格是一種二維的、行列交叉的結(jié)構(gòu)化數(shù)據(jù)而傳統(tǒng)的RAG處理的是線性的、非結(jié)構(gòu)化的文本。直接把表格單元格里的文字抽出來(lái)打成碎片再去做向量檢索會(huì)徹底丟失行與列之間的關(guān)聯(lián)關(guān)系、計(jì)算邏輯和上下文語(yǔ)義。這正是“面向結(jié)構(gòu)化表格的RAG”要解決的核心痛點(diǎn)。它不是一個(gè)簡(jiǎn)單的技術(shù)疊加而是一套針對(duì)表格數(shù)據(jù)特性重新設(shè)計(jì)的技術(shù)架構(gòu)。經(jīng)過(guò)一段時(shí)間的摸索和實(shí)踐我們搭建了一套相對(duì)穩(wěn)定、高效的方案。今天我就來(lái)詳細(xì)拆解一下這套架構(gòu)的核心設(shè)計(jì)思想、關(guān)鍵技術(shù)組件以及我們?cè)趯?shí)踐中總結(jié)出的那些“坑”和應(yīng)對(duì)技巧。無(wú)論你是正在考慮將大模型能力接入企業(yè)數(shù)據(jù)系統(tǒng)的架構(gòu)師還是對(duì)RAG技術(shù)如何落地具體場(chǎng)景感興趣的開(kāi)發(fā)者相信這些來(lái)自一線的實(shí)戰(zhàn)經(jīng)驗(yàn)都能給你帶來(lái)一些啟發(fā)。2. 核心挑戰(zhàn)為什么表格是RAG的“硬骨頭”在深入架構(gòu)之前我們必須先理解處理表格數(shù)據(jù)時(shí)傳統(tǒng)RAG流水線到底在哪里“失靈”了。只有看清了這些挑戰(zhàn)我們后面的技術(shù)選型和架構(gòu)設(shè)計(jì)才有依據(jù)。2.1 信息孤島與語(yǔ)義割裂這是最致命的問(wèn)題。假設(shè)我們有一個(gè)簡(jiǎn)單的銷(xiāo)售記錄表日期銷(xiāo)售員區(qū)域產(chǎn)品銷(xiāo)售額元利潤(rùn)元2024-01-15張三華東產(chǎn)品A1000020002024-01-16李四華北產(chǎn)品B80001200傳統(tǒng)的文本RAG處理流程可能會(huì)按行或按單元格進(jìn)行“切片”Chunking。例如它可能生成這樣幾個(gè)文本片段“2024-01-15, 張三, 華東, 產(chǎn)品A, 10000, 2000”“2024-01-16, 李四, 華北, 產(chǎn)品B, 8000, 1200”或者更糟糕地它可能把表頭單獨(dú)切出來(lái)“日期, 銷(xiāo)售員, 區(qū)域, 產(chǎn)品, 銷(xiāo)售額元, 利潤(rùn)元”。當(dāng)用戶(hù)提問(wèn)“張三在華東區(qū)的銷(xiāo)售額是多少”時(shí)檢索系統(tǒng)會(huì)計(jì)算這個(gè)問(wèn)題與每個(gè)文本片段的向量相似度。片段“2024-01-15, 張三, 華東, 產(chǎn)品A, 10000, 2000”可能因?yàn)榘皬埲焙汀叭A東”而獲得較高分?jǐn)?shù)被檢索出來(lái)。這看起來(lái)還行。但是如果用戶(hù)問(wèn)的是“華東區(qū)的總銷(xiāo)售額是多少”麻煩就來(lái)了。沒(méi)有一個(gè)文本片段直接包含這個(gè)答案10000元。模型需要理解“華東區(qū)”對(duì)應(yīng)“區(qū)域”列并且要對(duì)所有“區(qū)域”為“華東”的行的“銷(xiāo)售額”列進(jìn)行求和計(jì)算。然而檢索系統(tǒng)返回的可能只是孤立的、一行行的數(shù)據(jù)片段模型無(wú)法從這些片段中重建出“求和”這個(gè)操作所需的完整數(shù)據(jù)集和列關(guān)聯(lián)關(guān)系。這就是語(yǔ)義的割裂檢索階段丟失了表格的結(jié)構(gòu)化查詢(xún)能力。2.2 數(shù)值與計(jì)算的“失語(yǔ)”大語(yǔ)言模型LLM在理解和生成自然語(yǔ)言方面表現(xiàn)出色但其“數(shù)學(xué)能力”和“精確計(jì)算能力”相對(duì)較弱尤其是面對(duì)多位數(shù)字和復(fù)雜運(yùn)算時(shí)。在傳統(tǒng)RAG中即使我們幸運(yùn)地檢索到了所有相關(guān)的行比如把上面兩行數(shù)據(jù)都給了模型然后提問(wèn)“華東區(qū)和華北區(qū)的平均利潤(rùn)是多少”。模型需要做的是(2000 1200) / 2 1600。但模型可能會(huì)犯各種錯(cuò)誤它可能錯(cuò)誤地識(shí)別數(shù)字把10000看成利潤(rùn)可能用錯(cuò)公式甚至可能直接“幻覺(jué)”出一個(gè)看似合理的數(shù)字。我們不能依賴(lài)LLM作為可靠的計(jì)算器。對(duì)于表格問(wèn)答尤其是涉及聚合求和、平均、計(jì)數(shù)、比較、排序的問(wèn)題必須將計(jì)算邏輯下推到更可靠的系統(tǒng)中。2.3 表頭、多表關(guān)聯(lián)與動(dòng)態(tài)查詢(xún)一個(gè)表格的價(jià)值一半在于其表頭列名。表頭定義了數(shù)據(jù)的語(yǔ)義。在檢索時(shí)問(wèn)題“哪個(gè)產(chǎn)品利潤(rùn)最高”本質(zhì)上是在問(wèn)“在‘產(chǎn)品’列中找到‘利潤(rùn)’列數(shù)值最大的那一行所對(duì)應(yīng)的產(chǎn)品”。如果檢索時(shí)丟失了表頭信息模型就無(wú)從理解“利潤(rùn)”指的是哪一列的數(shù)據(jù)。現(xiàn)實(shí)中的數(shù)據(jù)很少是單表存在的。我們可能有“銷(xiāo)售表”、“產(chǎn)品信息表”、“客戶(hù)表”它們通過(guò)“產(chǎn)品ID”、“客戶(hù)ID”等鍵關(guān)聯(lián)。用戶(hù)的問(wèn)題可能是跨表的例如“顯示利潤(rùn)超過(guò)10%的產(chǎn)品的詳細(xì)信息包括產(chǎn)品名稱(chēng)和供應(yīng)商”。這要求RAG系統(tǒng)能理解這種關(guān)聯(lián)關(guān)系并生成相應(yīng)的聯(lián)合查詢(xún)。此外用戶(hù)的問(wèn)題往往是動(dòng)態(tài)的、模糊的。他們不會(huì)說(shuō)“請(qǐng)執(zhí)行一個(gè)SQL語(yǔ)句SELECT 產(chǎn)品 FROM sales WHERE 利潤(rùn) (SELECT MAX(利潤(rùn)) FROM sales)”。他們會(huì)用自然語(yǔ)言說(shuō)“賣(mài)得最好的產(chǎn)品是哪個(gè)”。這就要求系統(tǒng)具備將自然語(yǔ)言問(wèn)題NLQ轉(zhuǎn)換為結(jié)構(gòu)化查詢(xún)語(yǔ)言如SQL、Pandas操作的能力。3. 技術(shù)架構(gòu)設(shè)計(jì)從“檢索文本”到“理解結(jié)構(gòu)”基于上述挑戰(zhàn)我們?cè)O(shè)計(jì)的面向結(jié)構(gòu)化表格的RAG架構(gòu)其核心思想是將“檢索”升級(jí)為“理解與查詢(xún)”。我們不再僅僅是尋找相似的文本片段而是試圖理解用戶(hù)問(wèn)題的意圖并將其映射到對(duì)結(jié)構(gòu)化數(shù)據(jù)的精確操作上。整個(gè)架構(gòu)可以劃分為四個(gè)核心層次。3.1 數(shù)據(jù)預(yù)處理與表示層讓表格“會(huì)說(shuō)話”這一層的目標(biāo)是將原始的、靜態(tài)的表格文件轉(zhuǎn)化為既能保留完整結(jié)構(gòu)信息又能被下游檢索和LLM理解的知識(shí)表示。1. 結(jié)構(gòu)化信息提取與增強(qiáng)描述我們不會(huì)簡(jiǎn)單地把表格存成CSV字符串。相反我們會(huì)為每個(gè)表格生成一份豐富的“元數(shù)據(jù)描述”。這個(gè)過(guò)程通常是自動(dòng)化的提取表模式Schema包括表名、所有列名、列數(shù)據(jù)類(lèi)型字符串、整數(shù)、浮點(diǎn)數(shù)、日期等。這是最基礎(chǔ)的信息。生成統(tǒng)計(jì)摘要對(duì)數(shù)值列計(jì)算均值、中位數(shù)、最大值、最小值、標(biāo)準(zhǔn)差對(duì)分類(lèi)列統(tǒng)計(jì)唯一值數(shù)量、樣例值。例如為“銷(xiāo)售額”列生成摘要“該列存儲(chǔ)銷(xiāo)售金額單位為元平均值為15000最大值為50000主要分布在10000-30000區(qū)間”。分析行列關(guān)系識(shí)別可能的主鍵列、外鍵列通過(guò)列名模式或數(shù)據(jù)一致性推斷為多表關(guān)聯(lián)打下基礎(chǔ)。編寫(xiě)自然語(yǔ)言描述利用LLM基于表頭、前幾行數(shù)據(jù)樣例和統(tǒng)計(jì)信息為整個(gè)表格生成一段易于理解的自然語(yǔ)言概述。例如“本表為2024年第一季度銷(xiāo)售記錄包含每次銷(xiāo)售的日期、負(fù)責(zé)人、所屬區(qū)域、產(chǎn)品名稱(chēng)、銷(xiāo)售額及利潤(rùn)。數(shù)據(jù)共約1000行主要涉及華東、華北兩個(gè)區(qū)域產(chǎn)品線包括A、B、C三類(lèi)。”最終每個(gè)表格在系統(tǒng)中會(huì)有一個(gè)“身份檔案”包含其原始數(shù)據(jù)存儲(chǔ)在數(shù)據(jù)庫(kù)或?qū)ο蟠鎯?chǔ)中和這份增強(qiáng)后的描述文件。這份描述文件將成為后續(xù)檢索和問(wèn)題理解的關(guān)鍵輸入。2. 雙路索引的構(gòu)建這是與傳統(tǒng)RAG最大的區(qū)別之一。我們同時(shí)構(gòu)建兩種索引語(yǔ)義向量索引將上一步生成的表格自然語(yǔ)言描述、重要的列名和列注釋進(jìn)行高質(zhì)量的文本嵌入Embedding存入向量數(shù)據(jù)庫(kù)如Chroma, Weaviate, Pinecone。這部分用于處理用戶(hù)問(wèn)題中概念性、描述性的查詢(xún)例如“幫我找一下關(guān)于銷(xiāo)售業(yè)績(jī)的表格”、“有哪些表格記錄了產(chǎn)品信息”。結(jié)構(gòu)索引/元數(shù)據(jù)索引將表格的Schema信息表名、列名、數(shù)據(jù)類(lèi)型、統(tǒng)計(jì)信息、關(guān)聯(lián)關(guān)系等存入一個(gè)便于精確過(guò)濾和查找的數(shù)據(jù)庫(kù)中例如關(guān)系數(shù)據(jù)庫(kù)或Elasticsearch。這部分用于處理精確的、條件性的查詢(xún)例如“在‘銷(xiāo)售表’里找‘區(qū)域’是‘華東’的數(shù)據(jù)”、“哪個(gè)表有‘利潤(rùn)’這個(gè)列”。3.2 查詢(xún)理解與路由層聽(tīng)懂用戶(hù)的“弦外之音”當(dāng)用戶(hù)提出一個(gè)問(wèn)題時(shí)系統(tǒng)需要先判斷這個(gè)問(wèn)題到底想問(wèn)什么以及應(yīng)該用什么方式去回答。1. 意圖分類(lèi)與查詢(xún)類(lèi)型識(shí)別我們訓(xùn)練或使用提示工程引導(dǎo)一個(gè)輕量級(jí)的分類(lèi)器或直接用小模型/大模型API對(duì)用戶(hù)問(wèn)題進(jìn)行分類(lèi)。常見(jiàn)的類(lèi)別包括事實(shí)型查詢(xún)?cè)儐?wèn)表格中某個(gè)具體的、已存在的值。例如“張三一月份的銷(xiāo)售額是多少”答案可能直接存在于某一行。聚合型查詢(xún)需要計(jì)算如求和、平均、計(jì)數(shù)、最大值、最小值。例如“華東區(qū)的總利潤(rùn)是多少”、“銷(xiāo)量最高的產(chǎn)品是什么”。篩選型查詢(xún)根據(jù)條件過(guò)濾出行。例如“列出所有利潤(rùn)低于1000的記錄。”描述型/解釋型查詢(xún)?cè)儐?wèn)表格的含義或內(nèi)容。例如“‘銷(xiāo)售表’是干什么用的”、“‘毛利率’這一列是怎么算的”多表關(guān)聯(lián)查詢(xún)問(wèn)題涉及多個(gè)表格。例如“顯示購(gòu)買(mǎi)了‘產(chǎn)品A’的客戶(hù)的公司名稱(chēng)和聯(lián)系方式。”需要關(guān)聯(lián)‘訂單表’和‘客戶(hù)表’。2. 查詢(xún)?cè)鰪?qiáng)與分解對(duì)于復(fù)雜問(wèn)題直接映射可能很困難。這里會(huì)利用LLM進(jìn)行問(wèn)題重寫(xiě)或分解。重寫(xiě)將口語(yǔ)化問(wèn)題轉(zhuǎn)化為更規(guī)范、包含關(guān)鍵實(shí)體和操作的表述。例如將“賣(mài)得最火的是啥”重寫(xiě)為“查詢(xún)銷(xiāo)售額最高的產(chǎn)品名稱(chēng)”。分解將復(fù)雜問(wèn)題拆解為多個(gè)子問(wèn)題。例如“華東和華北哪個(gè)區(qū)的平均利潤(rùn)高”可以分解為1) 計(jì)算華東區(qū)的平均利潤(rùn)2) 計(jì)算華北區(qū)的平均利潤(rùn)3) 比較兩個(gè)數(shù)值。3. 路由決策根據(jù)意圖分類(lèi)和增強(qiáng)后的查詢(xún)系統(tǒng)決定執(zhí)行路徑如果是描述型查詢(xún)直接走語(yǔ)義向量索引檢索相關(guān)的表格描述讓LLM綜合描述信息生成答案。如果是涉及具體數(shù)據(jù)操作的查詢(xún)事實(shí)、聚合、篩選則進(jìn)入下一層——結(jié)構(gòu)查詢(xún)生成層。同時(shí)系統(tǒng)會(huì)利用結(jié)構(gòu)索引快速定位到最可能包含答案的目標(biāo)表格。3.3 結(jié)構(gòu)查詢(xún)生成與執(zhí)行層讓機(jī)器“自己查表”這是整個(gè)架構(gòu)的技術(shù)核心也是精度保障的關(guān)鍵。目標(biāo)是將自然語(yǔ)言問(wèn)題轉(zhuǎn)化為可執(zhí)行的結(jié)構(gòu)化查詢(xún)語(yǔ)句。1. 文本到SQL/代碼生成Text-to-SQL/Code這是目前最主流和有效的技術(shù)路徑。我們利用LLM的強(qiáng)大代碼生成能力在提供了目標(biāo)表格的詳細(xì)Schema列名、類(lèi)型、樣例、關(guān)系以及少量示例Few-shot后讓它生成查詢(xún)代碼。SQL路徑如果數(shù)據(jù)本身存儲(chǔ)在SQL數(shù)據(jù)庫(kù)中直接生成SQL語(yǔ)句如SELECT product, SUM(sales) FROM sales_table WHERE region ‘華東’ GROUP BY product。然后由系統(tǒng)安全地執(zhí)行這條SQL獲取精確結(jié)果。這里的“安全”包括防止SQL注入、設(shè)置查詢(xún)超時(shí)和行數(shù)限制。Pandas/DataFrame路徑如果數(shù)據(jù)是以文件形式CSV, Excel或已加載到內(nèi)存的DataFrame中則生成Pandas操作代碼。這種方式更靈活尤其適合復(fù)雜的數(shù)據(jù)清洗和轉(zhuǎn)換操作。關(guān)鍵實(shí)踐心得Schema描述的質(zhì)量決定生成SQL的準(zhǔn)確率。我們不僅提供干巴巴的列名還會(huì)在提示詞Prompt中加入列的業(yè)務(wù)含義注釋、數(shù)值范圍、常見(jiàn)值枚舉以及這個(gè)表和其他表的關(guān)系。例如描述“客戶(hù)ID”列時(shí)會(huì)加上“該列關(guān)聯(lián)到‘客戶(hù)維度表’的主鍵用于獲取客戶(hù)詳細(xì)信息”。這能極大提升LLM對(duì)業(yè)務(wù)邏輯的理解。2. 混合檢索與上下文構(gòu)建有時(shí)用戶(hù)的問(wèn)題不能完全通過(guò)生成的查詢(xún)解決或者生成的查詢(xún)需要額外的上下文信息。這時(shí)我們會(huì)采用混合策略首先通過(guò)結(jié)構(gòu)索引精確定位目標(biāo)表和列。同時(shí)通過(guò)語(yǔ)義向量索引檢索與問(wèn)題相關(guān)的表格描述、業(yè)務(wù)規(guī)則文檔或其他注釋信息。將目標(biāo)表的Schema、檢索到的相關(guān)文本上下文和用戶(hù)問(wèn)題三者一起喂給LLM讓它生成更準(zhǔn)確的查詢(xún)代碼。例如用戶(hù)問(wèn)“計(jì)算毛利率”如果表中只有“銷(xiāo)售額”和“成本”LLM需要知道“毛利率 (銷(xiāo)售額 - 成本) / 銷(xiāo)售額”這個(gè)業(yè)務(wù)規(guī)則這個(gè)規(guī)則就可能從檢索到的業(yè)務(wù)文檔中獲得。3. 安全執(zhí)行與后處理生成的查詢(xún)代碼不會(huì)直接在生產(chǎn)環(huán)境裸跑。沙箱環(huán)境代碼會(huì)在一個(gè)隔離的、資源受限的沙箱中執(zhí)行例如使用pandas在子進(jìn)程中操作數(shù)據(jù)副本。結(jié)果驗(yàn)證與格式化執(zhí)行得到的結(jié)果通常是一個(gè)數(shù)字、一個(gè)字符串或一個(gè)小表格會(huì)進(jìn)行格式化處理使其更適合放入最終的答案模板中。同時(shí)會(huì)檢查結(jié)果的合理性例如銷(xiāo)售額不應(yīng)為負(fù)數(shù)。3.4 答案合成與呈現(xiàn)層給出“人話”答案拿到了精確的查詢(xún)結(jié)果最后一步是生成自然、流暢的最終答案。1. 答案合成LLM在這一步的角色是“翻譯官”和“報(bào)告撰寫(xiě)者”。我們將原始用戶(hù)問(wèn)題、系統(tǒng)生成的查詢(xún)語(yǔ)句可選用于增加透明度、查詢(xún)執(zhí)行得到的精確結(jié)果一起交給LLM。Prompt會(huì)指示它“基于以下問(wèn)題和查詢(xún)結(jié)果生成一個(gè)通順、直接的自然語(yǔ)言答案。”例如輸入問(wèn)題“華東區(qū)銷(xiāo)售額最高的產(chǎn)品是什么” 結(jié)果{‘product’: ‘產(chǎn)品A’, ‘total_sales’: 50000}。LLM輸出“根據(jù)查詢(xún)結(jié)果華東區(qū)銷(xiāo)售額最高的產(chǎn)品是‘產(chǎn)品A’總銷(xiāo)售額為50,000元。”2. 溯源與解釋可解釋性為了增加用戶(hù)信任答案中可以附上來(lái)源信息例如“該數(shù)據(jù)來(lái)源于‘2024銷(xiāo)售明細(xì)表’”甚至可以展示簡(jiǎn)化后的查詢(xún)邏輯如“系統(tǒng)篩選了區(qū)域?yàn)椤A東’的記錄并按產(chǎn)品匯總了銷(xiāo)售額”。這對(duì)于調(diào)試和用戶(hù)驗(yàn)證非常有用。3. 處理“未知”與“不確定”如果查詢(xún)結(jié)果為空或者LLM在生成查詢(xún)或答案時(shí)置信度很低系統(tǒng)應(yīng)坦誠(chéng)回應(yīng)而不是胡編亂造。例如“在當(dāng)前的數(shù)據(jù)表中未找到符合‘張三在華南區(qū)銷(xiāo)售額’條件的記錄。”或者“您的問(wèn)題可能涉及多個(gè)表格的關(guān)聯(lián)目前系統(tǒng)無(wú)法完全處理請(qǐng)嘗試更具體的問(wèn)題。”4. 關(guān)鍵特性與優(yōu)化策略解析在搭建和迭代這套架構(gòu)的過(guò)程中我們總結(jié)出幾個(gè)至關(guān)重要的特性和優(yōu)化點(diǎn)它們直接決定了系統(tǒng)的可用性和準(zhǔn)確性。4.1 動(dòng)態(tài)上下文管理少即是多傳統(tǒng)文檔RAG中我們總擔(dān)心檢索到的上下文不夠所以?xún)A向于返回多個(gè)片段。但在表格RAG中過(guò)多的、無(wú)關(guān)的表格行列信息作為上下文會(huì)嚴(yán)重干擾LLM生成正確查詢(xún)。我們的策略是動(dòng)態(tài)、精準(zhǔn)地提供上下文核心是Schema而非數(shù)據(jù)在Text-to-SQL的Prompt中我們主要提供目標(biāo)表的列名、類(lèi)型、注釋以及可能涉及的相關(guān)表的Schema。通常不提供具體的表數(shù)據(jù)行除非是極少數(shù)作為“示例”的行。按需提供統(tǒng)計(jì)信息只有當(dāng)問(wèn)題涉及“最大值”、“平均值”等概念時(shí)才在Prompt中附上相關(guān)列的統(tǒng)計(jì)摘要如“銷(xiāo)售額列的范圍在1000-50000之間”這能幫助LLM更好地理解數(shù)據(jù)尺度。列篩選如果通過(guò)初步分析能確定問(wèn)題只涉及某幾個(gè)列例如問(wèn)題中有“銷(xiāo)售額”和“利潤(rùn)”那么在提供給LLM的Schema描述中可以突出顯示這些列甚至?xí)簳r(shí)隱藏其他不相關(guān)的列減少干擾。4.2 混合檢索策略語(yǔ)義與結(jié)構(gòu)的交響樂(lè)我們強(qiáng)調(diào)“雙路索引”在實(shí)際檢索時(shí)它們是協(xié)同工作的首輪語(yǔ)義粗篩。用用戶(hù)問(wèn)題去查詢(xún)語(yǔ)義向量索引找到最相關(guān)的幾個(gè)表格通過(guò)它們的描述文件。次輪結(jié)構(gòu)精篩。在語(yǔ)義粗篩的結(jié)果集里再利用結(jié)構(gòu)索引進(jìn)行精確過(guò)濾。例如用戶(hù)問(wèn)題包含“利潤(rùn)”我們就在粗篩出的表格中查找哪些表格的列名里包含“利潤(rùn)”或同義詞如“收益”、“盈利”。最終確定結(jié)合兩輪分?jǐn)?shù)選出最可能的目標(biāo)表。這種“語(yǔ)義找領(lǐng)域結(jié)構(gòu)找字段”的混合策略比單一檢索方式要穩(wěn)健得多。4.3 查詢(xún)生成的穩(wěn)定性保障Prompt工程與自我修正Text-to-SQL的生成并非百分百可靠。我們通過(guò)多層機(jī)制來(lái)保障穩(wěn)定性標(biāo)準(zhǔn)化Prompt模板設(shè)計(jì)包含清晰指令、格式示例、約束條件如“只使用存在的列名”、“不要用DELETE或DROP語(yǔ)句”的Prompt模板。在模板中固定思考過(guò)程Chain-of-Thought要求LLM先分析問(wèn)題涉及的表和列再生成SQL。Few-shot示例在Prompt中提供3-5個(gè)針對(duì)當(dāng)前表格的、從簡(jiǎn)單到復(fù)雜的“問(wèn)題-SQL”配對(duì)示例。這是提升準(zhǔn)確率最有效的手段之一。自我驗(yàn)證與重試生成SQL后系統(tǒng)可以在沙箱中進(jìn)行一個(gè)輕量級(jí)的驗(yàn)證檢查SQL語(yǔ)法是否正確檢查引用的表名、列名是否真實(shí)存在。如果驗(yàn)證失敗可以將錯(cuò)誤信息反饋給LLM要求它修正SQL。我們通常設(shè)置1-2次重試機(jī)會(huì)。多候選生成與投票讓LLM生成3條不同的SQL查詢(xún)?nèi)缓髨?zhí)行它們。如果多條查詢(xún)返回的結(jié)果一致那么這個(gè)結(jié)果的可信度就非常高。如果不一致可以選取出現(xiàn)頻率高的結(jié)果或者觸發(fā)人工審核流程。4.4 針對(duì)表格特性的切片Chunking策略雖然我們?nèi)趸藶闄z索而做的數(shù)據(jù)切片但在為向量索引構(gòu)建表格的“描述”時(shí)仍然涉及對(duì)表格信息的“切片”或“分塊”表達(dá)以應(yīng)對(duì)不同粒度的問(wèn)題。表級(jí)描述整個(gè)表格的概述用于回答“這個(gè)表是什么”這類(lèi)問(wèn)題。列級(jí)描述對(duì)每個(gè)重要列單獨(dú)生成描述名稱(chēng)、類(lèi)型、業(yè)務(wù)含義、值域用于回答“這個(gè)列是什么意思”或涉及特定列的查詢(xún)。行列切片謹(jǐn)慎使用對(duì)于特別寬列多或特別長(zhǎng)行多的表可以考慮按業(yè)務(wù)主題將列分組描述或按時(shí)間、區(qū)域等關(guān)鍵維度將行分組描述。例如將銷(xiāo)售表按“季度”分組生成“2024年Q1銷(xiāo)售數(shù)據(jù)概況”的描述。這主要用于輔助語(yǔ)義檢索而不是作為生成查詢(xún)的主要依據(jù)。5. 實(shí)戰(zhàn)中的“坑”與應(yīng)對(duì)之道理論架構(gòu)很美好但實(shí)際落地時(shí)我們踩過(guò)不少坑。這里分享幾個(gè)印象深刻的。坑一列名歧義與業(yè)務(wù)同義詞。表格里的列名可能是技術(shù)性的如sales_amt而用戶(hù)提問(wèn)用“銷(xiāo)售額”。直接匹配會(huì)失敗。應(yīng)對(duì)在建結(jié)構(gòu)索引時(shí)我們?yōu)槊總€(gè)列名維護(hù)了一個(gè)“同義詞詞典”。這個(gè)詞典可以手動(dòng)維護(hù)也可以用LLM基于列的業(yè)務(wù)描述自動(dòng)擴(kuò)展。例如將sales_amt映射到[“銷(xiāo)售額” “銷(xiāo)售金額” “營(yíng)收”]。在檢索和查詢(xún)理解階段進(jìn)行同義詞擴(kuò)展匹配。坑二LLM的“數(shù)學(xué)幻覺(jué)”。即使生成了正確的SQL并拿到了結(jié)果[1500, 1800, 2200]讓LLM口頭回答“平均值是多少”它有時(shí)會(huì)瞎算一個(gè)數(shù)而不是老實(shí)地說(shuō)(150018002200)/3 1833.33。應(yīng)對(duì)絕對(duì)禁止LLM進(jìn)行數(shù)值計(jì)算。在答案合成階段Prompt里必須嚴(yán)格指令“答案中涉及的所有數(shù)值必須直接、原樣使用‘查詢(xún)結(jié)果’部分提供的數(shù)據(jù)不得自行計(jì)算或更改。” 對(duì)于需要展示計(jì)算過(guò)程的情況如平均值由系統(tǒng)后端計(jì)算好再將計(jì)算結(jié)果作為“事實(shí)”提供給LLM去組織語(yǔ)言。坑三復(fù)雜嵌套查詢(xún)與性能。用戶(hù)可能會(huì)問(wèn)“找出那些銷(xiāo)售額高于該產(chǎn)品平均銷(xiāo)售額的記錄”。這需要生成帶子查詢(xún)的SQL。LLM有時(shí)能生成但生成的查詢(xún)可能效率低下甚至導(dǎo)致數(shù)據(jù)庫(kù)超時(shí)。應(yīng)對(duì)設(shè)定查詢(xún)復(fù)雜度閾值。對(duì)于識(shí)別出的復(fù)雜查詢(xún)可以采取兩種策略1) 將其分解為多個(gè)順序執(zhí)行的簡(jiǎn)單查詢(xún)由中間層代碼進(jìn)行結(jié)果整合2) 直接告知用戶(hù)“您的問(wèn)題過(guò)于復(fù)雜請(qǐng)嘗試簡(jiǎn)化例如先查詢(xún)某產(chǎn)品的平均銷(xiāo)售額再進(jìn)行比較”。同時(shí)對(duì)生成的SQL進(jìn)行基本的執(zhí)行計(jì)劃評(píng)估如是否包含全表掃描并設(shè)置嚴(yán)格的執(zhí)行時(shí)間限制。坑四數(shù)據(jù)更新與索引同步。業(yè)務(wù)表格是會(huì)更新的。今天導(dǎo)入新數(shù)據(jù)后昨天的統(tǒng)計(jì)摘要和向量索引就過(guò)時(shí)了。應(yīng)對(duì)建立數(shù)據(jù)變更監(jiān)聽(tīng)機(jī)制。對(duì)于數(shù)據(jù)庫(kù)表可以通過(guò)監(jiān)聽(tīng)binlog或時(shí)間戳來(lái)觸發(fā)增量更新。對(duì)于文件可以監(jiān)控文件修改時(shí)間。更新時(shí)需要重新生成受影響表格的描述和統(tǒng)計(jì)信息并更新雙路索引。這個(gè)過(guò)程最好是自動(dòng)化的、異步的避免影響線上查詢(xún)。6. 技術(shù)棧選型參考與迭代方向最后聊聊具體的技術(shù)選型。這不是一套固定的組合而是一個(gè)靈活的生態(tài)。LLM核心閉源模型如GPT-4、Claude-3在查詢(xún)生成、意圖識(shí)別的準(zhǔn)確性上表現(xiàn)最佳但成本高、數(shù)據(jù)隱私需考慮。開(kāi)源模型如Qwen、Llama 3系列通過(guò)微調(diào)使用LlamaFactory等工具在特定領(lǐng)域可以達(dá)到接近閉源的效果且可私有化部署是很多企業(yè)的選擇。我們的經(jīng)驗(yàn)是對(duì)于查詢(xún)生成這類(lèi)“關(guān)鍵任務(wù)”初期可以用GPT-4 API快速驗(yàn)證效果穩(wěn)定后逐步遷移到微調(diào)好的開(kāi)源模型上控制成本和安全。向量數(shù)據(jù)庫(kù)Chroma輕量易用適合原型和中小規(guī)模Weaviate、Qdrant功能更強(qiáng)大支持混合搜索和過(guò)濾適合生產(chǎn)環(huán)境Pinecone是托管服務(wù)省心但成本較高。結(jié)構(gòu)索引/元數(shù)據(jù)存儲(chǔ)簡(jiǎn)單的可以用SQLite或PostgreSQL如果需要更靈活的搜索如對(duì)列描述的全文搜索可以用Elasticsearch。Text-to-SQL框架LangChain、LlamaIndex都提供了相關(guān)的鏈Chain和工具Tool可以快速搭建原型。但在生產(chǎn)環(huán)境中我們往往需要更精細(xì)的控制最終可能會(huì)基于它們的思路自研更貼合業(yè)務(wù)的數(shù)據(jù)處理管道和Prompt管理模塊。計(jì)算引擎如果數(shù)據(jù)量不大Pandas足以應(yīng)對(duì)如果數(shù)據(jù)量大或需要實(shí)時(shí)查詢(xún)那么將數(shù)據(jù)存入OLAP數(shù)據(jù)庫(kù)如ClickHouse、Doris或數(shù)據(jù)倉(cāng)庫(kù)讓生成的SQL直接在這些高性能引擎上執(zhí)行是更優(yōu)的選擇。未來(lái)的迭代方向我們關(guān)注幾點(diǎn)一是多模態(tài)表格理解直接處理掃描版PDF或圖片中的表格二是更復(fù)雜的推理鏈Agentic RAG讓系統(tǒng)能通過(guò)多輪思考、調(diào)用工具計(jì)算器、搜索引擎來(lái)解決更復(fù)雜的問(wèn)題三是Graph RAG的探索將表格中的實(shí)體和關(guān)系抽取出來(lái)構(gòu)建知識(shí)圖譜從另一個(gè)維度增強(qiáng)對(duì)數(shù)據(jù)關(guān)系的理解能力。面向結(jié)構(gòu)化表格的RAG本質(zhì)上是將大語(yǔ)言模型的語(yǔ)義理解能力與傳統(tǒng)數(shù)據(jù)處理系統(tǒng)的精確計(jì)算能力相結(jié)合。它不是一個(gè)“開(kāi)箱即用”的解決方案而是一個(gè)需要根據(jù)具體數(shù)據(jù)形態(tài)和業(yè)務(wù)問(wèn)題精心設(shè)計(jì)的架構(gòu)。希望這次的技術(shù)架構(gòu)與特性解析能為你打開(kāi)一扇門(mén)在讓大模型真正“讀懂”企業(yè)數(shù)據(jù)價(jià)值的道路上少走一些我們?cè)?jīng)走過(guò)的彎路。