AI知識庫:解析、分塊與RAG實戰(zhàn))
這幾年做企業(yè)知識庫項目我接觸最多的不是各種炫酷的 AI 框架而是散落在共享盤、郵箱附件和桌面文件夾里的 Office 文檔。Word 里的方案、Excel 里的報價、PPT 里的匯報這些文件占了企業(yè)知識的絕大部分。很多團隊上來就想著買大模型、搭平臺結(jié)果卡在第一步——怎么把幾千份 docx、xlsx、pptx 變成 AI 能讀、能查、能從里面找出答案的數(shù)據(jù)。先說結(jié)論用 Office 文檔直接構(gòu)建企業(yè) AI 知識庫完全可行核心不是模型而是文檔解析和數(shù)據(jù)清洗。RAG 這條技術(shù)路線之所以被廣泛采用正是因為它能繞過微調(diào)的成本先把文檔切塊、向量化再在問答時檢索相關(guān)內(nèi)容丟給大模型。Dify、RAGFlow、FastGPT 這些開源平臺以及 Qdrant、Milvus 這類向量庫都能把整條鏈路串起來。這篇文章我會把從 Office 原始文件到可問答知識庫的完整過程拆開講包括格式轉(zhuǎn)換、分塊策略、向量化方案、權(quán)限設(shè)計以及我實際踩過的坑。適合正在做企業(yè)知識庫的研發(fā)、運維和產(chǎn)品同學也適合想用工具搭建內(nèi)部問答系統(tǒng)的業(yè)務團隊。1. 為什么不能直接把 Office 文檔扔給大模型1.1 問題先從兩種“格式世界觀”談起Office 文檔在本質(zhì)上分為兩類。一類是 docx、xlsx、pptx它們從 Office 2007 開始采用 OOXML 標準本質(zhì)是一個 Zip 壓縮包里面有若干 XML 文件描述文檔結(jié)構(gòu)、樣式、批注、修訂記錄。另一類是 doc、xls、ppt 老格式屬于 OLE 復合文檔亂一點但也不是不能解析。問題在于文件對你來說是文檔對模型來說是“二進制流”。把 50 頁的方案書直接拼進 Prompt送入模型的上下文窗口這既不現(xiàn)實也很浪費。模型上下文長度是有限的幾百萬 token 的上下文窗口產(chǎn)品也存在但企業(yè)文檔動輒幾百上千頁全量塞進去的成本極高。更重要的是模型回答問題的前提是“找得到證據(jù)”不是“背誦全文”。這也正是 RAG 的意義。RAG 是 Retrieval-Augmented Generation檢索增強生成的縮寫先把你所有的 Office 文檔切成小塊轉(zhuǎn)成向量存儲到向量數(shù)據(jù)庫用戶提問時系統(tǒng)在向量庫里檢索最相關(guān)的幾個片段再讓大模型基于這些片段生成答案。這樣既突破上下文長度限制也能在回答里附上出處讓答案有據(jù)可查。1.2 直接把文檔喂給模型的三個硬傷如果跳過解析清洗直接拿原始文檔做向量化通常會出現(xiàn)三種情況。第一文本提取不全。Word 里文字在文本框、頁眉頁腳、批注里PPT 里的內(nèi)容散落在各種形狀、備注、圖表數(shù)據(jù)源中Excel 里的數(shù)據(jù)藏在多個 Sheet、合并單元格、透視表結(jié)果里。常規(guī)的簡單提取方案會漏掉大量內(nèi)容導致檢索時找不到答案。第二多級信息折疊。Word 的標題層級標題 1、標題 2、正文、Excel 的單元格坐標邏輯、PPT 的頁面順序這些結(jié)構(gòu)信息在簡單提取后全部丟失。檢索時能拼出來的都是“詞語碎片”沒法形成上下文。第三掃描件的問題。如果這些 Office 文檔是從紙質(zhì)文件掃描成 PDF 后轉(zhuǎn)成 Word 的那么文檔里根本沒有文本層全是圖片。不經(jīng)過 OCR光學字符識別就入庫AI 能看到的只是“一張圖”檢索自然失敗。所以構(gòu)建 AI 知識庫的第一課不是學大模型而是先處理文檔格式。用一句行業(yè)里的話說垃圾進垃圾出。文檔解析的質(zhì)量決定了知識庫回答的上限。2. 文檔解析是知識庫質(zhì)量的第一道閘門2.1 工具選型別在這上面盲目造輪子解析 Office 文檔的成熟方案很多我的建議是優(yōu)先用現(xiàn)成工具只有特殊需求才自己寫代碼。工具適用場景優(yōu)勢注意點LibreOffice全格式轉(zhuǎn)換批量 docx 轉(zhuǎn) docx / PDF / HTML免費開源、命令行支持、自帶過濾規(guī)則轉(zhuǎn)換效果依賴原文檔排版習慣需配置字體環(huán)境pandocWord 轉(zhuǎn) Markdown、HTML輕量、保留標題層級和列表結(jié)構(gòu)對復雜表格、批注支持有限會丟樣式Apache Tika服務化解析支持 docx、xlsx、pptx、PDF自動識別格式REST API 易集成對中文支持不錯但表格結(jié)構(gòu)提取比較粗糙python-docx / openpyxl / python-pptx編程方式細粒度控制可以按段落、單元格、形狀逐一路由處理需要自己處理邊界情況代碼量相對大MarkItDown微軟開源的文檔轉(zhuǎn) Markdown 工具對 Office 系列友好適合做 RAG 預處理依賴外部的轉(zhuǎn)換器首次使用需完整安裝個人使用比較多的是 LibreOffice python-docx 的組合。批量處理時用 LibreOffice 把 doc 統(tǒng)一轉(zhuǎn)成 docx再用 python-docx 按段落級別結(jié)構(gòu)提取如果文檔排版很亂就先用 LibreOffice 轉(zhuǎn) PDF再用解析庫從 PDF 提取版面。這樣能通過轉(zhuǎn) PDF 獲得相對穩(wěn)定的布局再按頁面切塊適合保真要求高的場景。如果項目工期緊直接用 Dify 或 RAGFlow 內(nèi)置的文檔解析器也能跑通。但現(xiàn)在很多平臺對 Office 的解析深度一般復雜表格和文本框照樣歪。用來做 demo 可以生產(chǎn)環(huán)境建議至少抽幾個復雜文檔做對比測試。2.2 從 Word 文檔里提取“有結(jié)構(gòu)”的文本W(wǎng)ord 提取的核心是結(jié)構(gòu)不是字符。下面是一段我用 python-docx 提取標題層級和正文的簡化代碼可以處理標題 13、正文、表格單元格內(nèi)的文字。from docx import Document from docx.table import Table from docx.text.paragraph import Paragraph def iter_block_items(parent): 按文檔順序遍歷段落和表格 from docx.oxml.ns import qn parent_elm parent.element.body for child in parent_elm.iterchildren(): if child.tag qn(w:p): yield Paragraph(child, parent) elif child.tag qn(w:tbl): yield Table(child, parent) doc Document(方案書.docx) for block in iter_block_items(doc): if isinstance(block, Paragraph): style block.style.name if block.style else text block.text.strip() if not text: continue if style.startswith(Heading 1): print(f# {text}) elif style.startswith(Heading 2): print(f## {text}) elif style.startswith(Heading 3): print(f### {text}) else: print(text) else: # 表格塊逐行逐單元格提取并在前面加 markdown 表格分隔 print(| | .join(cell.text.strip() for cell in block.rows[0].cells) |) print(| |.join([---] * len(block.rows[0].cells)) |) for row in block.rows[1:]: print(| | .join(cell.text.strip() for cell in row.cells) |)注意這里兩個細節(jié)一是用iter_block_items按文檔實際順序遍歷而不是先遍歷所有段落再遍歷所有表格否則文檔里的圖表順序會錯亂二是把 Word 表格直接轉(zhuǎn)成 Markdown 表格格式這樣后續(xù)分塊時能保持單元格之間的對應關(guān)系。我見過不少項目用doc.paragraphs提取結(jié)果表格里的關(guān)鍵數(shù)據(jù)全部丟光問答系統(tǒng)對著合同“告訴我有多少金額”直接答不出來。另外頁碼和標題信息建議拼進文本開頭作為文檔來源標記例如在每段前面加“第 3 節(jié)項目預算”這樣的前綴。這樣檢索結(jié)果里能直接知道引文出處也方便做引用溯源。2.3 Excel 數(shù)據(jù)要按“語義塊”而不是按行切Excel 的處理思路和 Word 不一樣。Word 是流式閱讀的Excel 是表格式的每一行只是一個記錄單獨切一行檢索往往沒有意義。比如一張銷售明細表第一行是“客戶名稱、產(chǎn)品、金額、日期”單獨把“北京公司 100 萬”做成向量丟失了“這是哪個項目的收入”這個上下文。更合理的做法是按 Sheet 和表格區(qū)域聚合。我的做法是先提取 Sheet 名稱和表頭再把表格轉(zhuǎn)成行列結(jié)構(gòu)按“Sheet 名 表頭 若干行”作為一個語義塊。如果表格特別長比如上千行的臺賬可以按 100200 行切一塊同時把表頭和 Sheet 名拼到每塊前面。import openpyxl wb openpyxl.load_workbook(報價明細.xlsx, data_onlyTrue) for ws in wb.worksheets: rows list(ws.iter_rows(values_onlyTrue)) if not rows: continue header | .join([str(c) if c else for c in rows[0]]) block_lines [fSheet: {ws.title}, f表頭: {header}] chunk_size 100 for i in range(1, len(rows), chunk_size): chunk rows[i:ichunk_size] lines block_lines [ | .join(str(c) if c else for c in row) for row in chunk] chunk_text \n.join(lines) # 這里把 chunk_text 交給 embedding 入庫即可data_onlyTrue很關(guān)鍵它會返回緩存的計算結(jié)果而不是公式字符串。如果你的 Excel 里有大量公式不加這個參數(shù)提取出來的一堆“SUM(A1:A10)”對 AI 毫無意義。另外合并單元格會讓某些行出現(xiàn) None提取時可以把上一條非空值前向填充當然你也可以用 openpyxl 的merged_cells屬性在提取時精確處理。2.4 PPT 內(nèi)容要同時抓幻燈片和備注PPT 是企業(yè)知識庫里最容易被忽略又最“痛”的格式。它的文本分布在標題框、內(nèi)容框、圖表、SmartArt 內(nèi)部和備注區(qū)尤其備注區(qū)的演講者提示往往藏著真正的干貨比如項目背景、口徑說明、關(guān)鍵結(jié)論這些才是問答系統(tǒng)里價值很高的素材。python-pptx 提取時要注意遍歷所有slide.shapes對shape.has_text_frame的取文本對shape.shape_type MSO_SHAPE_TYPE.TABLE的取表格對shape.has_chart的取圖表系列名稱和值。每張幻燈片建議單獨作為一個塊并加上頁碼和標題作為前綴。from pptx import Presentation from pptx.enum.shapes import MSO_SHAPE_TYPE def extract_slide_text(shape): texts [] if shape.shape_type MSO_SHAPE_TYPE.TABLE: for row in shape.table.rows: texts.append( | .join(cell.text.strip() for cell in row.cells)) elif shape.has_text_frame: texts.append(shape.text_frame.text.strip()) return \n.join(t for t in texts if t) prs Presentation(季度匯報.pptx) for idx, slide in enumerate(prs.slides, 1): slide_texts [] for shape in slide.shapes: t extract_slide_text(shape) if t: slide_texts.append(t) full_text f[Slide {idx}]\n \n.join(slide_texts) if slide.has_notes_slide: notes slide.notes_slide.notes_text_frame.text.strip() full_text f\n[備注]\n{notes} # full_text 進入分塊流程這條代碼在實際項目中幫了不少忙。很多匯報 PPT 的標題是“公司戰(zhàn)略”備注里卻寫“此處強調(diào)要聚焦三大業(yè)務線”如果沒有備注知識庫永遠回答不了“公司戰(zhàn)略的重點是什么”。當然后續(xù)要給不同來源的內(nèi)容打標簽比如在 metadata 里記錄source_typeslide或source_typenotes便于權(quán)限控制和過濾。2.5 掃描 PDF 轉(zhuǎn)來的“假 Word”要先過 OCR再強調(diào)一次如果文檔是掃描件轉(zhuǎn)的不管它是 PDF 還是 Word里面基本沒有文本層。這時候必須接 OCR。OCR 工具的選擇我體驗下來比較推薦 PaddleOCR中文識別效果在開源方案里比較能打如果團隊里有人力做調(diào)優(yōu)也可以試試 Tesseract但中文模型的效果需要自己標注。在知識庫場景里OCR 建議做得“穩(wěn)”不追求把每個字符都認準而是把版面結(jié)構(gòu)認出來標題、段落、表格區(qū)域。這樣后續(xù)分塊才能保留閱讀順序。實操時我習慣先把掃描 PDF 按頁面轉(zhuǎn)成圖片再用 PaddleOCR 的ocr接口識別并把每行結(jié)果按 y 坐標排序從上到下拼成文本塊。這里有個細節(jié)表格行容易被識別成“一條橫線”要單獨把表格區(qū)域的識別結(jié)果按單元格坐標重組否則表格數(shù)據(jù)會徹底亂掉。如果你的掃描件數(shù)量不大直接人工校對幾個關(guān)鍵表格比在代碼里調(diào)半天正則靠譜得多。3. 分塊、向量化與入庫搭起知識庫的骨架3.1 分塊策略別照抄網(wǎng)上參數(shù)先看文檔類型解析完成之后下一步是分塊。網(wǎng)上到處是“chunk_size512, overlap50”的建議直接照抄往往效果一般。分塊的本質(zhì)是找到一個平衡點塊太小檢索時上下文不夠模型看不懂說的是什么塊太大一個塊里混著好幾個主題檢索召回相關(guān)性下降大模型的注意力也被稀釋。我自己的實踐經(jīng)驗是分三類處理一是段落式內(nèi)容如 Word 方案、合同條款、制度文件按標題層級天然劃分先按標題 1標題 2 切塊如果某個二級標題下的內(nèi)容過長再按 8001000 字拆分子塊并讓重疊部分包含前一個子塊的結(jié)尾通常 overlap 設(shè)在 10%15%。二是表格型內(nèi)容如 Excel 報價單、臺賬表頭和 Sheet 名必須跟數(shù)據(jù)塊綁定再按行數(shù)切塊塊與塊之間不需要 overlap否則重復記錄會干擾精確檢索。三是 PPT 型內(nèi)容按幻燈片整頁作為塊備注頁和正文合并。如果某頁文字特別多可以按內(nèi)容框拆成兩到三個子塊但仍保留頁碼信息。一段合格的塊看起來長這樣 來源方案書_v3.docx 章節(jié)項目總體架構(gòu)標題1 內(nèi)容本方案建議采用微服務架構(gòu)將系統(tǒng)拆分為用戶服務、訂單服務、支付服務等核心模塊。各服務通過消息隊列異步通信......后續(xù)正文這段文本里既有來源信息又有結(jié)構(gòu)標題還有正文檢索時能直接理解為“這句話來自方案的哪個章節(jié)”問答中就能帶著出處返回。還要提醒一個隱藏問題中文和英文字符的 chunk 計算方式不一樣。很多國外框架的 tokenizer 是按英文單詞估算的Chinese 一句話可能十幾個字就算成十幾個 token。建議用真實驗證不要把理論 chunk_size 當成硬性指標而是看塊內(nèi)的實際 token 數(shù)超過模型 token 上限就要縮小。3.2 向量化模型選型中文場景下優(yōu)先級要調(diào)整分完塊之后就要對每個塊做向量化。這一步把文本變成一串浮點數(shù)向量檢索時通過余弦相似度計算哪個塊跟用戶問題最接近。Embedding 模型的選型我認為要考慮三個維度中文語義理解能力、向量維度、部署成本?,F(xiàn)在常見的選擇包括模型中文效果維度說明BGE-M3優(yōu)秀1024 / 512 可配支持中英混合適合知識庫本地部署可控text-embedding-3-small良好1536云端服務接入簡單成本較低text-embedding-3-large更好3072強語義理解但存儲開銷和費用更高M3E / bge-large-zh良好1024中文優(yōu)化離線可用老牌選擇Ollama embedding 模型一般不定本地部署友好但中文詞典覆蓋有限需測試實戰(zhàn)中文檔量大、中文為主、又對數(shù)據(jù)隱私有要求的企業(yè)優(yōu)先考慮 BGE-M3 或 bge-large-zh本地部署接入 Dify 或 LangChain 都很順。如果對云端不敏感先用 text-embedding-3-small 跑通再根據(jù)實際效果升級。向量維度的選擇不只是模型本身的參數(shù)還影響向量庫的存儲和檢索性能維度太高單條查詢變慢索引內(nèi)存也膨脹。向量庫選型方面小規(guī)模知識庫少于 100 萬塊用 Qdrant 或 pgvector 就夠支持 Docker 部署配置簡單。百萬級別以上再考慮 Milvus。如果團隊已經(jīng)有 Elasticsearch 基礎(chǔ)設(shè)施也可以直接用它存向量利用已有的權(quán)限和運維生態(tài)。3.3 用 Dify 搭建知識庫流水線不要覺得只有寫代碼才能搭知識庫。現(xiàn)在到了 2025 年Dify、RAGFlow、FastGPT 這類開源平臺把鏈路做得很完整。下面是我比較推薦的一個 Dify 搭建路徑。第一步創(chuàng)建一個知識庫應用。第二步接入文檔源把第二步解析好的文本或其他格式文件傳進去。第三步在設(shè)置里選好 Embedding 模型。第四步設(shè)置分塊規(guī)則Dify 支持自定義 Segmentation 模式直接填 chunk_size 和 overlap。第五步綁定到 Chatflow讓用戶提問時先檢索知識庫再調(diào)對話模型。需要注意一點在 Dify 里不要偷懶把 Office 文件直接上傳它的內(nèi)置解析器雖然方便但對復雜版式和表格處理能力一般。更穩(wěn)的做法是保證自己在外部完成了解析清洗再導入寧可靠前一步優(yōu)化也別讓知識庫出現(xiàn)壞數(shù)據(jù)。如果你追求數(shù)據(jù)庫級可控“連接外部知識庫”也是 Dify 支持的方向??梢园?Qdrant 或 pgvector 作為外部向量庫Dify 做編排檢索時先查外部庫再拼裝上下文。這樣便于已有業(yè)務的團隊復用現(xiàn)有數(shù)據(jù)也可以避免頻繁遷庫。3.4 Metadata 設(shè)計決定你能不能做權(quán)限和溯源分塊之后每一塊一定要帶上 metadata 字段元數(shù)據(jù)是知識庫的靈魂。沒有 metadata你的知識庫就是一堆無差別文本后續(xù)想做權(quán)限隔離、引用溯源、更新時間過濾全都做不了。推薦至少包含這些字段doc_id文檔唯一編碼建議用哈希值便于底層查重doc_name便于展示的來源名source_typeword/excel/ppt/pdfsection_path章節(jié)路徑例如“項目總體架構(gòu) / 技術(shù)方案”page_no如果有頁碼則保留chunk_index塊序號便于按順序重排updated_at文檔更新時間permission_tags部門標簽或密級標簽用于權(quán)限過濾權(quán)限這塊很多企業(yè)會犯一個錯誤向量庫只做檢索權(quán)限放在應用層。但權(quán)限必須同時落在文檔級別和 chunk 級別。簡單做法是給每個塊打上dept標簽檢索時把用戶所屬部門作為過濾條件傳給向量庫做filter參數(shù)而不僅僅是返回結(jié)果后再過濾否則底層數(shù)據(jù)泄露誰都攔不住。3.5 增量更新與知識庫的“新陳代謝”企業(yè)文檔每天都在變昨天上傳的方案第二天就更新了達成了一個錯誤版本。如果不處理知識庫永遠“活在昨天”。增量更新的常見方案是在文檔入庫時記錄文檔的doc_id和content_hash每次掃描文件時先比哈希哈希變了就刪除舊 chunks重新解析入庫完全新增的文檔直接入庫。這個邏輯可以用 Airflow、Prefect 或者定時腳本實現(xiàn)。還有一個容易忽略的操作清理已刪除文檔。共享盤里文件可能移動了路徑、改了名字如果只按“新增”邏輯跑舊版本殘留會讓檢索結(jié)果重復甚至沖突。我建議每次同步前先遍歷一遍源頭目錄生成當前文件清單跟庫里的 doc_id 對比把缺席文檔的所有 chunks 一次性刪除。這步雖然簡單卻能讓知識庫保持干凈的狀態(tài)避免用戶搜到半年前的過時信息。4. 實操過程從 Office 文件到可問答知識庫的完整鏈路4.1 環(huán)境準備與依賴安裝基于常見實踐的補充這里給出一個可復現(xiàn)的最小方案使用 Python Dify Qdrant 或本地向量模型。假設(shè)你有基礎(chǔ) Python 環(huán)境建議用 conda 或 venv 建一個獨立環(huán)境。mkdir office-kb cd office-kb python -m venv venv source venv/bin/activate # Windows 使用 venv\Scripts\activate需要安裝的庫見下面的 requirements.txt都是常用庫版本號建議根據(jù)網(wǎng)絡(luò)實際可用情況安裝最新穩(wěn)定版。libreoffice-convert # 如果需要批量轉(zhuǎn)格式可自行安裝對應轉(zhuǎn)換器 python-docx openpyxl python-pptx pandas pypdf2 paddleocr # OCR 需要則裝對依賴較高請注意libreoffice-convert依賴系統(tǒng)安裝 LibreOffice。裝完以后可以用一個簡單的命令行測試libreoffice --headless --convert-to pdf 方案書.docx --outdir ./pdf_output4.2 從文件目錄批量解析入庫的核心代碼下面這段代碼可以算是一個迷你版的文檔入庫腳本骨架基于我平時的處理習慣整理。它做三件事遍歷目錄、按擴展名分流解析、組裝 metadata 交給后面分塊。import hashlib from pathlib import Path from docx import Document from pptx import Presentation import openpyxl def get_file_hash(path: Path) - str: h hashlib.sha256() with open(path, rb) as f: for chunk in iter(lambda: f.read(8192), b): h.update(chunk) return h.hexdigest() def extract_docx(path: Path): doc Document(path) blocks [] # 這里復用前面 iter_block_items 的邏輯輸出按結(jié)構(gòu)拼接的文本 return \n.join(blocks) def extract_pptx(path: Path): prs Presentation(path) slides [] # 復用前面的逐頁提取邏輯記錄 slide 序號和備注 return \n.join(slides) def extract_xlsx(path: Path): wb openpyxl.load_workbook(path, data_onlyTrue) sheets [] # 這里復用前文 Sheet 表頭 數(shù)據(jù)塊 的邏輯 return \n.join(sheets) def process_folder(folder: Path): for ext, func in {.docx: extract_docx, .pptx: extract_pptx, .xlsx: extract_xlsx}.items(): for file in folder.rglob(f*{ext}): # 1. 計算哈希 content_hash get_file_hash(file) # 2. 解析文本 text func(file) # 3. 分塊和向量化這里暫用占位邏輯 yield { doc_id: content_hash, doc_name: file.name, source_type: ext.replace(., ), text: text, updated_at: file.stat().st_mtime, } for item in process_folder(Path(企業(yè)文檔)): # 接入向量庫或 Dify API 的寫入函數(shù) pass這段代碼的真正價值是幫你把“文件系統(tǒng)”和“知識庫”建立映射。后續(xù)不管用了多少次、改了多少文件都能通過 doc_id 精準刪除重建而不是簡單清空重來。如果你的團隊更喜歡低代碼方式Dify 的文檔導入功能可以省掉這段 Python。把解析腳本作為前置清洗模塊也是后面做生產(chǎn)級知識庫的必經(jīng)之路我建議兩者結(jié)合低代碼平臺跑流程Python 腳本做特殊文檔的精處理。4.3 RAG 問答驗證不只看“答得出來”還要看“引用對沒有”知識庫搭好后別急著宣告成功。先用指定測試集驗證效果。我的習慣是從三個角度出題事實查詢類“2024 年第二季度華東區(qū)的銷售額是多少”對應表格型知識要求答案有準確的數(shù)字和出處。總結(jié)歸納類“公司今年的三大戰(zhàn)略重點分別是什么”對應 PPT 和 Word 標題體系需要模型跨多個塊綜合。流程制度類“報銷流程需要哪些審批節(jié)點”對應制度文檔需要引用原文條款。把這三類問題分別跑一遍按照回答準確率、引用正確率、拒絕回答率三個指標打分。正常來說準確率低于 60% 說明文檔解析或分塊有明顯問題先不要急著換模型而是回去看是不是表格丟了、標題層級壞了、OCR 亂碼了。調(diào)試時我推薦一個“檢索前置”的小技巧在 Dify 或 LangChain 的調(diào)試界面里先不看大模型的最終回答先看檢索返回了哪些 chunk。如果返回的 chunk 本身不是相關(guān)內(nèi)容那后面大模型回答不可能靠譜如果 chunk 相關(guān)但回答不對那是 Prompt 或語義理解的問題。這條經(jīng)驗基本能定位 80% 的知識庫問題。4.4 從“能答”到“答得好”的 Prompt 調(diào)優(yōu)不要迷信模型能力Prompt 往往決定知識庫的最終體驗。下面是一個比較實用的 RAG 問答提示詞模板適合在 Chatflow 里使用你是企業(yè)內(nèi)部知識庫助手。請僅根據(jù)下面提供的【參考資料】回答問題。 如果參考資料中沒有明確信息請直接回復“知識庫中未找到相關(guān)信息”不要猜測。 【參考資料】 {context} 【用戶問題】 {question} 要求 1. 答案中涉及的制度條款、數(shù)字、流程步驟必須在回答末尾標注來源文件名和段落標題。 2. 如果問題與參考資料無關(guān)回復“這個問題不在我的知識范圍內(nèi)”。這個模板看起來很簡單但它強制模型“沒有資料就承認不知道”可以避免一本正經(jīng)地胡說八道。實際使用中你還可以根據(jù)企業(yè)特點追加“如果涉及金額必須保留兩位小數(shù)”“回答時先給出結(jié)論再給出依據(jù)”等約束。Prompt 是在知識庫數(shù)據(jù)質(zhì)量過關(guān)之后性價比最高的調(diào)優(yōu)手段。5. 常見問題與排查技巧實錄5.1 明明有答案檢索卻一直召回不到出現(xiàn)這個現(xiàn)象十有八九是分塊粒度或結(jié)構(gòu)信息丟了。我遇到過最典型的例子客戶上線一個合同知識庫測試問“違約金條款是什么”模型總是答不上來。排查后發(fā)現(xiàn)原合同的章節(jié)被排版成分頁符隔開解析時把“違約責任”和正文拆成了兩個塊檢索時“違約金”這三個字只在標題塊里出現(xiàn)正文塊沒有關(guān)鍵詞兩個塊都只能算低相關(guān)最終被 Top-K 截斷。解決辦法一是讓分塊把標題和正文放在同一個塊里可以通過 Python 解析時對上游塊做“標題繼承”遇到標題 1 時把它存為當前 section直到遇到下一個標題才替換。在分塊時把這個 section 拼到每個 chunk 的前綴里。這樣每個子塊都能帶著章節(jié)上下文檢索召回會穩(wěn)很多。另一個原因是 Embedding 模型對長文本概括能力一般。檢索詞集中在某個段落但那個段落被截斷到另一個塊里。這時可以適度提高 chunk_size或者調(diào)整 overlap。我的經(jīng)驗是overlap 最少要有百字級別的語義銜接不能只重復最后兩句話。5.2 Excel 表格“看得見字但一回答問題就是錯的”Excel 入庫經(jīng)常出現(xiàn)三種問題一是列頭丟了分塊時只取數(shù)據(jù)行不取表頭二是合并單元格沒處理導致數(shù)據(jù)對應錯列三是多 Sheet 之間共享一個表頭但語義完全不同比如“一月數(shù)據(jù)”和“二月數(shù)據(jù)”結(jié)構(gòu)相同單獨檢索時模型不知道數(shù)字屬于哪個月。給這些表格數(shù)據(jù)加“字段前綴”是個好做法。我在 excel 塊生成文本時會把“Sheet 名 表頭 日期范圍”放在每塊的最前面例如數(shù)據(jù)來源2024年銷售臺賬.xlsx / Sheet華東大區(qū) 表頭客戶名稱 | 產(chǎn)品 | 金額(元) | 合同日期 | 負責人 數(shù)據(jù)杭州某某公司 | A系列 | 120000 | 2024-03-05 | 張三這樣模型看到每行數(shù)據(jù)時就知道它的字段語義。如果表頭和數(shù)據(jù)行被分塊切開這個前綴還能在多個塊里重復出現(xiàn)保證塊之間信息一致。5.3 PPT 記錄了很多內(nèi)容但檢索時“看不到重點”PPT 這類版式文檔最大的問題是“一句話被拆在多個文本框里”比如標題是一個文本框副標題是另一個文本框旁邊還有個圖標里的文字。如果只按文本框逐個提取原本一個完整觀點被拆成三四個塊檢索時每個塊都很短相關(guān)性得分不高。解決辦法是把同一頁內(nèi)所有文本框的內(nèi)容合并成一個塊通過形狀的坐標left、top判斷閱讀順序再按位置排序拼接。還有一種更省事的辦法利用 PPT 的分頁符天然切塊把一頁的全部文本作為一個塊。這樣即使頁面里有多個形狀也可以保證信息完整。多年的經(jīng)驗提醒做 PPT 知識庫時不要把“頁標題”當成塊的唯一索引。很多企業(yè) PPT 標題習慣寫成“項目概覽”“核心亮點”這類雷同詞如果檢索只看標題多個塊高度相似無法區(qū)分。必須在塊內(nèi)附帶一兩句頁面正文的關(guān)鍵詞讓檢索命中正文內(nèi)容。5.4 大量文件入庫時檢索結(jié)果出現(xiàn)重復或沖突如果你發(fā)現(xiàn)同一個知識點被返回了好幾份而且內(nèi)容互相矛盾基本可以斷定庫里存在舊版本殘留。前面提到的內(nèi)容哈希方案就是為解決這個問題而設(shè)的。掃描時比對每個文檔的 SHA-256只要文件內(nèi)容變了就把舊 doc_id 對應的所有 chunks 刪掉再用新的文本重新生成向量。這個方案也有條件解析前的“原始文本”和入庫后的“向量塊”必須能通過 doc_id 做反查。所以建議在上游就維護一個簡易的 document registry 表記錄 doc_id、文件路徑、content_hash、pages、chunk_count。任何同步任務跑完先檢查這個表有沒有異常再調(diào)問答測試。5.5 權(quán)限泄露是知識庫的高危場景很多企業(yè)覺得 RAG 知識庫是個內(nèi)部應用不設(shè)防。但實際中除非文檔都是全公司公開級否則一定要帶權(quán)限控制。這里再強調(diào)一遍權(quán)限一定要下推到 chunk 層不是只在業(yè)務層過濾。以 Dify 為例如果直接用外部知識庫 API可以在檢索參數(shù)里加入filter比如dept in [tech, hr]。這樣每個用戶的查詢請求都帶過濾條件檢索階段就排除無權(quán)訪問的塊。如果用戶想通過越權(quán)提問套取其他部門的東西向量庫返回的結(jié)果天然不含高密級內(nèi)容安全面就小了很多。至于權(quán)限標簽怎么來文件系統(tǒng)里通常有文件夾結(jié)構(gòu)或文件命名規(guī)則合理映射到部門標簽即可。寫在最后的一點體會做了這么多企業(yè)知識庫項目我的一個強烈感受是技術(shù)本身已經(jīng)不是瓶頸瓶頸在于團隊是否愿意在文檔治理上花功夫。Office 文檔構(gòu)建 AI 知識庫最容易出彩的環(huán)節(jié)不是大模型選了多強而是解析清洗做到位分塊設(shè)計貼合業(yè)務。我自己也多次被現(xiàn)實教育剛開始總覺得模型聰明一點就能解決一切后來發(fā)現(xiàn)讓結(jié)構(gòu)化的 Office 文檔以正確的姿勢進入知識庫遠比切換更貴的模型更有效。如果你正在設(shè)計新的知識庫系統(tǒng)我建議先找一個最小的業(yè)務場景試點挑一個目錄幾百份合同或幾十份項目總結(jié)從解析到問答完整跑通再慢慢擴大到全公司。別一上來就想把共享盤幾萬份文件一股腦灌進去那樣既難以保證質(zhì)量也難以及時發(fā)現(xiàn)數(shù)據(jù)問題。先拿一套“能答對有出處的問題”作為驗收標準再逐步擴展覆蓋范圍這是我認為最穩(wěn)妥、也最容易出效果的實施路徑。