
先說一個我印象很深的場景。工藝車間的同事打電話問我“手冊里這個物料的閃點到底是多少安全閥設(shè)定值有沒有出處”我眼前擺著一本2599頁的化工手冊他問的那一頁我不知道但我確信手冊里一定有。于是我把當時剛做出來沒多久的“AI專家”對話窗口發(fā)給他讓他直接問。他半信半疑地敲了一句話進去十幾秒后它不光給出了數(shù)值還標了“根據(jù)手冊第X頁”和對應(yīng)章節(jié)。同事愣了半天說了一句“這玩意兒比我翻書快多了?!边@就是這個項目的由來把一本2599頁的化工手冊通過知識蒸餾的思路轉(zhuǎn)化成相當于企業(yè)私有的AI專家。這篇文章我會把從PDF解析、文本切分、向量檢索到微調(diào)蒸餾的完整過程都交代清楚包括踩過的坑和調(diào)優(yōu)時掉過的頭發(fā)。如果你手頭也有一堆又厚又難查的規(guī)范、手冊、標準庫想做成內(nèi)部AI問答助手這篇文章可以直接當操作手冊看。1. 項目目標拆解先搞清楚“AI專家”到底要會什么1.1 為什么通用AI答不了化工手冊的問題在做這個項目之前我們內(nèi)部其實已經(jīng)有人試過把化工問題直接拋給市面上那些通用大模型。結(jié)果很典型問“甲苯的沸點是多少”它能回答得八九不離十但問“本廠手冊里關(guān)于該物料儲存溫度的上限是多少”它就完全抓瞎了。因為通用模型壓根沒看過你那本手冊它只能憑訓(xùn)練數(shù)據(jù)里那些“泛泛的常識”來編?;み@種行業(yè)憑印象給數(shù)據(jù)的后果相當嚴重輕則被工藝員罵重則出事。另外還有一個原因化工手冊里的信息形態(tài)和普通文章差別非常大。里面有大量物性數(shù)據(jù)表、CAS登記號、單位換算、工藝參數(shù)區(qū)間、安全注釋。通用模型即使讀到了一段相關(guān)文字也很難保證它引用的數(shù)據(jù)來自正確版本、正確條目。我們要的不是一個“會聊天的化工愛好者”而是一個“能查資料、能給依據(jù)、能標出處”的工具。1.2 成功標準不是“答得快”而是“說得清查得有據(jù)”項目啟動前我和使用方對齊了三個驗收標準這里可以直接分享給你參考回答準確率針對手冊內(nèi)高頻問題答案關(guān)鍵數(shù)據(jù)必須與原文一致不接受“大概其”。引用可溯源回答中必須能給出對應(yīng)頁碼或章節(jié)查不到出處的答案視為不合格。覆蓋率從手冊目錄隨機抽取100個知識點系統(tǒng)至少能答對八成以上。定這幾個標準不是為了顯得專業(yè)而是防止項目做到一半跑偏。技術(shù)團隊天然會被“用最新的框架”“加個Agent”這類事情吸引但用戶要的只是“我得快速查到準確的數(shù)據(jù)并且能跟別人說清楚依據(jù)”。明確了邊界之后后面每一步都能往回收不會越做越散。2. 第一步把2599頁PDF變成“機器能讀”的知識2.1 解析PDF的坑雙欄、表格和那些需要人工“合體”的段落拿到手冊的PDF文件之后第一反應(yīng)可能是直接丟給LangChain抽取文本。但這里有個前提問題這個PDF是文字版還是掃描版。如果是掃描版你得先過一遍OCR否則后面全是空白。我這次拿到的文字版還算幸運但依然踩了三個非常典型的坑。第一個坑是雙欄排版。化工手冊很多頁面是雙欄印刷直接按閱讀順序抽文本會把左欄后半句和右欄前半句拼到一起讀起來完全不通。我的處理方式是先用PyMuPDF把頁面按坐標切分出左右區(qū)域再按區(qū)域分別提取文本。這個動作看起來不起眼但對后續(xù)切分質(zhì)量影響巨大。第二個坑是表格跨頁。手冊里很多物性表橫跨兩三頁如果按“一頁一切”的思路去做會把一個完整表格切成好幾截。后來我們改成PDF解析階段就識別表格區(qū)域把跨頁表格按“表頭表項”合并重建再單獨存成一個Markdown表格塊這個問題才算解決。第三個坑是頁眉頁腳混入正文。頁眉頁碼、公司名、章節(jié)名反復(fù)出現(xiàn)會讓后續(xù)檢索時匹配到大量噪聲。我的做法是做一輪清洗規(guī)則去掉PDF抽取文本中距離頁面邊緣過近的短行再用正則濾掉重復(fù)出現(xiàn)的頁眉文字。這個過程不復(fù)雜但能顯著提升Chunk的質(zhì)量。2.2 切分策略為什么不能像切西瓜一樣一刀切文本切分是決定RAG效果最核心的一步。很多人習(xí)慣直接設(shè)一個“每500個字切一塊”的固定長度這在化工手冊上會出大問題。我給你舉個例子。有一頁講某原料的儲存條件前半部分是閃點數(shù)據(jù)后半部分是“泄漏處理建議”中間被一個固定長度切斷了。結(jié)果用戶問“這種物質(zhì)泄漏了怎么處理”的時候檢索系統(tǒng)找到的那塊文本里只有閃點參數(shù)沒有泄漏步驟答案自然答非所問。所以我的策略是“先按結(jié)構(gòu)切再按語義補”。流程大概是先解析出目錄和章節(jié)標題建立一個層級樹在每個章節(jié)內(nèi)部再根據(jù)段落語義、表格邊界、列表結(jié)構(gòu)做切分對于過長的章節(jié)再用遞歸字符切分作為兜底。這樣切出來的塊大部分保持“一個話題一塊”而不是“500個字一塊”。2.3 父子分塊與表格的單獨處理在化工手冊里數(shù)據(jù)表格是問答的高頻對象。用戶經(jīng)常問“某某物質(zhì)的沸點、閃點、爆炸極限分別是多少”這類問題天然適合查表格。但表格很難和正文塞在同一切塊里因為表格的信息密度太高和正文混在一起互相稀釋。我的處理方式是“父子分塊”每個章節(jié)保留一個較長的父塊用于提供上下文在此基礎(chǔ)上再細分出若干專注某個話題的子塊用于檢索匹配。當子塊被命中時把整個父塊內(nèi)容一起送入大模型這樣既能精準匹配到“閃點”這個關(guān)鍵詞又能讓模型結(jié)合前后文生成答案。表格則獨立成塊并給它單獨打一個“table”標簽在向量檢索時可以做類型過濾。我建議你親測一下“固定長度切分”和“父子分塊”的差距同樣的100道測試題前者答對率可能在60%左右后者能到80%以上。切分的工程量雖然大但它是整個RAG里最值得花時間打磨的地方。3. 第二步混合檢索 重排讓AI先學(xué)會“查資料”3.1 Embedding和向量庫怎么選切分完成后下一步是把文本塊向量化存入向量庫讓AI能“查資料”。這里有兩個選型問題Embedding模型和向量數(shù)據(jù)庫。Embedding模型我選的是BAAI的bge-large-zh-v1.5。原因很簡單它對中文支持好、在MTEB中文榜單上成績穩(wěn)定、開源可離線部署、單張消費級顯卡或者CPU都能跑。OpenAI的embedding確實強大但一來有數(shù)據(jù)合規(guī)問題二來每次調(diào)用都要走網(wǎng)絡(luò)在化工這種對數(shù)據(jù)安全敏感的行業(yè)里不太合適。向量數(shù)據(jù)庫我對比過Chroma、Qdrant和Milvus。Chroma適合原型驗證裝好就能用但數(shù)據(jù)量大之后性能一般。Milvus功能全、適合生產(chǎn)環(huán)境但部署和運維成本偏高。最后我用了Qdrant因為它支持過濾條件、支持MMR去重性能也夠用。如果你只是自己折騰一個小知識庫Chroma完全夠如果要做成多用戶服務(wù)可以認真考慮Qdrant。3.2 混合檢索化工數(shù)據(jù)吃字面匹配光靠語義檢索不夠這里我要重點說一個很多新手會漏掉的關(guān)鍵點化工手冊里的高頻查詢很多是“精確匹配”而非“語義匹配”。比如用戶輸入“CAS號 108-95-2”這串數(shù)字字母組合必須完全命中靠向量檢索的“語義相似”并不好使。再比如“請查一下規(guī)格牌號PH-3”這種查詢詞面匹配遠比語義相似靠譜。如果只做向量檢索遇到這類問題召回率會很低。我的方案是混合檢索向量檢索負責“語義相似”的召回BM25關(guān)鍵詞檢索負責“字面精確”的召回最后用RRFReciprocal Rank Fusion把兩路結(jié)果合并排序。實際效果是混合檢索比純向量檢索的召回率能提升10到15個百分點。尤其是在化工這種縮寫、代號、CAS號密集的場景混合檢索幾乎是必需品。3.3 加入重排與引文溯源向量檢索初篩出來的候選塊可能有幾十條直接一股腦塞給大模型既浪費token又容易被噪聲干擾。這時候最好加一個重排環(huán)節(jié)。我用了bge-reranker-v2-m3先把向量召回的前20條輸入重排模型讓模型逐對計算相關(guān)性再取前5條送入生成階段。重排之后的答案質(zhì)量提升非常明顯尤其是那些“多個相似段落混在一起”的場景重排能幫你把最相關(guān)的那一段挑出來。引文溯源也是在生成階段做。我給每個切塊都存了元數(shù)據(jù)包括起始頁碼、章節(jié)號、小節(jié)標題。生成Prompt里明確要求回答必須基于給定資料并標注“手冊第X頁”如果資料中沒有明確依據(jù)要直接說“手冊中未找到明確表述”不允許編造。輸出之后我還會跑一個校驗?zāi)_本檢查模型給出的頁碼是否在合理范圍內(nèi)防止它亂吐頁碼。這里有一個經(jīng)驗可以分享讓大模型“基于頁碼生成”是可行的但前提是你把頁碼作為元數(shù)據(jù)拼進了上下文。如果你只是讓模型“回憶”頁碼它一定會編。所以我會在發(fā)送給模型前把切塊的元數(shù)據(jù)拼成一串固定格式的引用前綴模型只需要把前綴里的頁碼復(fù)制進回答即可。4. 第三步知識蒸餾把手冊“壓進”模型里4.1 這里的“蒸餾”到底在干什么到了這一節(jié)才真正回應(yīng)標題里的“知識蒸餾”。需要先澄清概念傳統(tǒng)意義上的知識蒸餾是把一個大模型的能力遷移到一個小模型屬于模型壓縮的范疇。但我在這個項目里做的事更貼近“數(shù)據(jù)蒸餾”的思路就是把2599頁手冊里那些高價值的問答知識通過構(gòu)造訓(xùn)練數(shù)據(jù)的方式提煉出來再用LoRA微調(diào)注入到一個開源底座模型里。為什么要做這一步因為光靠RAG檢索AI的回答雖然準但語言風(fēng)格總有一種“拼湊感”讀起來不像一個真正懂化工的專家在說話。微調(diào)的目的正是讓模型學(xué)會手冊的表述習(xí)慣、單位習(xí)慣和安全提示用語。舉個例子檢索出來的原材料文字是“本品遇熱分解放出有毒氣體”。RAG模式下的回答可能是“本品遇熱分解放出有毒氣體。根據(jù)手冊第X頁”。微調(diào)之后模型會自然地補一句“操作時應(yīng)注意通風(fēng)并避免高溫環(huán)境”就像手冊編寫者真的在旁邊提醒你。4.2 蒸餾數(shù)據(jù)集的構(gòu)建寧可少不可錯知識蒸餾成敗的關(guān)鍵不在模型而在數(shù)據(jù)。我這次沒有盲目追求數(shù)量而是追求質(zhì)量最終用了約400條指令數(shù)據(jù)完成微調(diào)。數(shù)據(jù)構(gòu)建流程是這樣的先從手冊目錄里篩選出高頻知識點覆蓋物性數(shù)據(jù)、儲運條件、泄漏處理、安全防護幾大類然后針對每個知識點用大模型生成多個用戶角度的問法再從原文提取標準答案要求答案必須引用原文內(nèi)容不允許模型自由發(fā)揮最后請化工工程師做抽檢和修訂抽檢比例不低于20%。這里有一條血淚教訓(xùn)用大模型自動生成問答對時它很擅長一本正經(jīng)地編答案即使你喂了原文給它它也可能把數(shù)據(jù)改一個單位、換一個小數(shù)點。我后來嚴格要求生成腳本必須從原文模板中“填空式”抽取數(shù)值不允許逐字重寫才把數(shù)據(jù)準確性拉上去。數(shù)據(jù)集格式我用了Alpaca格式{ instruction: 查詢甲苯的閃點并給出安全操作建議, input: , output: 根據(jù)手冊第274頁甲苯的閃點為4.4℃閉杯為易燃液體操作時應(yīng)遠離明火并保持通風(fēng)。安全操作建議詳見手冊第275頁儲運注意事項。 }注意上面的頁碼和數(shù)值僅用于展示格式。做成真實數(shù)據(jù)集時每個數(shù)據(jù)項都必須經(jīng)過人工核對寧缺毋濫。4.3 LoRA微調(diào)實操參數(shù)與效果微調(diào)工具我用了LLaMA-Factory底座模型選了Qwen2.5-7B-Instruct。為什么用7B而不是更大的模型因為4090單卡跑LoRA很從容效果也夠用14B雖然更強但推理延遲和顯存壓力都會增加對于內(nèi)部工具來說沒有必要。關(guān)鍵參數(shù)如下照著跑基本沒問題參數(shù)配置lora_rank64lora_alpha128lora_dropout0.1learning_rate1e-4batch_size4gradient_accumulation_steps8epochs3最大序列長度2048訓(xùn)練時長大約三四個小時。微調(diào)完成之后我并沒有讓微調(diào)模型脫離RAG單獨使用而是讓它和RAG搭配檢索回來的資料拼進上下文模型用自己的語言整合輸出。這一套組合下來效果比“純RAG”或“純微調(diào)”都好。我的總結(jié)是RAG負責提供證據(jù)微調(diào)負責讓模型“像行家一樣說話”兩者是互補關(guān)系。5. 實測記錄哪些問題翻車了怎么修好的5.1 效果還不錯的時候先報喜。上線前的壓力測試里我拿高頻問題去問典型回答質(zhì)量已經(jīng)相當能打。比如問“某原料的爆炸極限是多少”系統(tǒng)先通過BM25精準定位到物性表那塊文本再經(jīng)過重排選中正確那一行最后生成回答時引用表格里的“爆炸上限”“爆炸下限”數(shù)值全部和手冊一致。再比如問“手冊里關(guān)于該物質(zhì)溢灑處理是怎么寫的”系統(tǒng)能準確地引用“截斷泄漏源”“使用惰性吸收材料覆蓋”等原話并把頁碼標得很清楚。整個回答結(jié)構(gòu)很干凈沒有多余的廢話。這讓我確認了“混合檢索父子切分重排”這套組合是可靠的基礎(chǔ)設(shè)施。5.2 翻車實錄五個事故現(xiàn)場當然能拿得出手的案例是一輪輪修出來的這里把印象最深的五個坑列出來供你排查時對照。第一個坑是表格被切碎。早期按固定長度切分把一個“物質(zhì)安全數(shù)據(jù)總表”切成了兩截用戶問“閃點”時檢索只命中了下半截沒有“閃點”列名模型就從別的地方胡編了一個數(shù)。后來我把表格整體保留為一個塊并在元數(shù)據(jù)中標記“table”這問題才消失。第二個坑是返回內(nèi)容重復(fù)。多個相近的切塊同時被檢索出來大模型把三段重復(fù)內(nèi)容拼在一起顯得很啰嗦。解決方案是在重排后加MMR去重保證送入模型的切塊之間盡可能不重復(fù)。第三個坑是頁碼幻覺。模型回答里給出一個手冊根本不存在的頁碼。原因是早期Prompt沒有強制它基于元數(shù)據(jù)標注頁碼。后來我把元數(shù)據(jù)拼進上下文并在輸出層加了校驗凡是不符合“手冊第X頁”格式的引用一律攔截重試問題基本解決。第四個坑是單位錯亂。有些表格列印的是kPa模型整合時自動幫用戶“換算”成MPa結(jié)果錯了三個數(shù)量級。這個比較難防我最后的方案是做一個后處理腳本把所有數(shù)字和單位的組合提取出來與原表核對一旦發(fā)現(xiàn)量級不一致就打回重生成。第五個坑是檢索漏召回。用戶問的是“操作溫度”手冊原文寫的是“工作溫度”向量檢索找不到完全匹配BM25又沒有同義詞擴展。后來我在查詢端加了一步“查詢改寫”先讓大模型把口語問題轉(zhuǎn)換成包含同義詞的檢索詞集合比如“操作溫度”改寫為“操作溫度 工作溫度 使用溫度”召回率立刻上來了。5.3 上線前必做的評估我把上面的測試整理成一套固定評估集從手冊中抽取100道有標準答案的問題每道題標注對應(yīng)頁碼。每次改完系統(tǒng)配置或Prompt就重跑一遍記錄三個指標。指標計算方式合格線答案正確率關(guān)鍵數(shù)據(jù)與史料一致的比例85%以上引用準確率頁碼可溯源且頁碼內(nèi)容相關(guān)的比例90%以上覆蓋率100道題中能答上來的比例80%以上這套評估集是整個項目最值錢的資產(chǎn)。后續(xù)任何人改了代碼、換了模型、調(diào)了切分參數(shù)跑一遍就知道有沒有變差不用依賴“感覺”。6. 成本、設(shè)備與后續(xù)還能怎么玩6.1 一個月的開發(fā)周期和硬件清單很多朋友關(guān)心做這么一套東西貴不貴。我大概算了一筆賬純?nèi)肆ν度虢馕龊颓蟹旨s一天數(shù)據(jù)構(gòu)造和人工審核約兩周微調(diào)和評測調(diào)優(yōu)約一周剩余時間在打磨Prompt和寫校驗?zāi)_本??傊芷诓畈欢嘁粋€月而且這一個月不是滿負荷是穿插著做別的事的情況下完成的。硬件方面Embedding和BM25檢索可以在普通CPU服務(wù)器上跑重排環(huán)節(jié)需要一張帶CUDA的顯卡我用的是4090。微調(diào)階段也用同一張4090Qwen2.5-7B的LoRA訓(xùn)練沒有壓力。如果只做推理不需要那么強的顯卡如果想把底座換成14B模型建議上雙卡或者48GB顯存的卡。這里再說一個成本上的真誠建議如果你只是想快速見效可以先只做“解析切分混合檢索RAG”這四步半天就能搭出來效果已經(jīng)能超過大多數(shù)通用問答。微調(diào)是錦上添花不是雪中送炭。6.2 從“會答問題”到“會干活”接Agent和更多擴展項目做完之后我思考了下這個問題還能往哪走。最簡單的擴展方式是把它接入聊天機器人或Agent讓工藝員不用面對一個問答窗口而是直接說“幫我查一下這批原料的存儲條件如果庫房溫度超過35℃該怎么辦”。系統(tǒng)先拆解任務(wù)再檢索再生成帶依據(jù)的回答。這就是典型的知識庫Agent場景。更遠一點的擴展方向是多手冊合并?;て髽I(yè)往往不止一本手冊可能還有國標、行標、內(nèi)部臺賬。多本手冊合并時要重點解決“同一數(shù)據(jù)在不同手冊中不一致”的問題。我的做法是給每個切塊增加“來源手冊”元數(shù)據(jù)回答時同時展示多手冊信息并標注不一致讓使用者自己判斷優(yōu)先級而不是讓AI強行統(tǒng)一。還可以做增量更新。手冊不定期修訂修訂頁面需要重新解析和向量化同時保留歷史版本。Qdrant支持按collection隔離版本替換時用新版collection切換即可運維成本不高。項目做下來我最大的體會是把精力花在“數(shù)據(jù)治理”和“評估集建設(shè)”上遠比花在換模型、調(diào)框架上值得。我們一度糾結(jié)要不要換一個更大的底座模型后來發(fā)現(xiàn)瓶頸根本不在模型而在切分粒度不夠細、檢索召回不夠全。這些問題解決之后7B模型已經(jīng)表現(xiàn)得很體面了。最后再分享一個小技巧上線前一定要讓實際使用者提20個他們?nèi)粘U鏁柕膯栴}拿去系統(tǒng)里測。因為他們問出來的話和開發(fā)時想象出來的問題差很遠。我第一次讓同事測的時候幾個高頻問法全是口語化的比如“這東西存?zhèn)}庫要注意啥”而不是標準術(shù)語。把這批口語問法加進評估集之后系統(tǒng)才真正算是在真實場景里站穩(wěn)了。