中華心法問答系統
- 一、研究背景
- 1. 研究意義
- 2. 研究目的
- 3. 信息檢索技術
- 二、主要研究內容
- 三、相關技術介紹
- 1. Flask框架技術
- 2. BERT模型
- (1)基本概念
- (2)BERT解決的問題
- (3)BERT的核心結構
- a. 模型結構
- b. 預訓練任務( MLM+NSP)
- 3. 信息檢索技術
- (1)混合檢索框架
- (4)激活函數校準
- 四、中華心法問答系統需求分析與設計
- 1. 系統需求分析
- 2. 模塊的劃分和設計
- (1)查詢模塊
- (2)智能檢索模塊
- (3)錄入模塊
- 3. 前端和后端的交互邏輯
- 4. 后端運作邏輯
- 五、中華心法問答系統的實現
- 1. BERT模型的運用
- 2. 混合檢索算法的實現
- (1)動態校準策略(語義相似度校準)
- (2)關鍵詞增強機制(文本相似度補充)
- (3)總結對比
- 3. 去重模塊的實現
- (1)文本清洗部分
- (2)去重機制(三重過濾)
- 4. 實驗不同參數對比的結論
- 六、運行代碼
- 七、總結感受
一、研究背景
1. 研究意義
-
幫助我們更好地認識自己,掌握自己的情緒和思維,提高自我控制和自我調
節的能力。 -
可以更好地應對生活中的挑戰和困難,保持內心的平靜和穩定,從而更好地發揮自己的潛力和才能。
2. 研究目的
設計并開發一個基于信息檢索的中華心法問答系統。
3. 信息檢索技術
信息檢索技術是指通過計算機及相關技術,從文本、圖像、音頻等多種形式的信息中快速有效地尋找出與用戶需求相匹配的信息。
二、主要研究內容
針對心法問答系統中對于語義理解問題以及匹配準確度問題,基于BERT模型,設計了融合語義向量和關鍵詞匹配的算法。
三、相關技術介紹
①整體框架主要采用了Flask框架技術,用于前后端之間數據傳輸;
②語義理解主要是采用BERT模型,用于計算問句的語義向量;
③相似度匹配是用混合檢索技術,主要是用于計算問句的相似度。
1. Flask框架技術
Flask 是一個非常小的PythonWeb框架,被稱為微型框架;只提供了一個穩健的核心,其他功能全部是通過擴展實現的,以 “微核心+可擴展” 的設計哲學著稱
本系統的前端采用了 Flask 框架實現。
2. BERT模型
(1)基本概念
自然語言處理主要對輸入語句進行語義理解。
BERT 是 Google 在 2018 年提出的一個基于 Transformer 的預訓練語言模型。
核心特點:①基于 Transformer 編碼器架構 ②雙向建模,同時考慮上下文左右兩邊的信息 ③ 預訓練 + 微調,先用海量文本預訓練,再根據具體任務微調。
(2)BERT解決的問題
在 BERT 出現之前,很多語言模型(如 GPT、ELMo)是:
-
單向的:只能從左到右或從右到左理解句子(上下文信息不完整)
-
任務特定的:每個任務都要單獨設計模型
BERT的突破
-
使用 雙向 Transformer 捕捉上下文全局語義
-
使用 預訓練的通用語言理解模型,然后對下游任務進行微調,顯著提升性能
(3)BERT的核心結構
a. 模型結構
BERT 采用 Transformer Encoder 堆疊結構。
b. 預訓練任務( MLM+NSP)
-
掩碼語言模型 Masked Language Model(MLM)
隨機遮住句子中15%的詞,讓模型預測它們
如:“I have a [MASK] dog.” → 預測 “cute” -
下句預測 Next Sentence Prediction(NSP)
給定句子 A 和句子 B,預測 B 是否是 A 的下一個句子
學習句與句之間的邏輯關系
BERT 是一種通過預訓練獲得語言理解能力的深度學習模型,能夠廣泛用于各種自然語言處理任務,具有上下文雙向理解的優勢。
3. 信息檢索技術
(1)混合檢索框架
混合檢索架構,指的是將多種檢索方法結合起來的系統架構,用于提高信息檢索的效果和準確性。
它通常結合了以下兩種主流方法:
(1)稀疏檢索(Sparse Retrieval)
(2)稠密檢索(Dense Retrieval)
a. 兩種檢索方法的介紹
- 稀疏檢索(BM25):傳統基于關鍵詞匹配的檢索方法,具有快速、解釋性強、依賴關鍵詞的特點。
- 稠密檢索(BERT向量):將文本轉為向量,通過語義相似度進行匹配,具有能理解語義、擴展性強、計算較重的特點。
b. 為什么要 “混合”
- 單一檢索的缺陷:稀疏檢索只能匹配關鍵詞,可能錯過語義相近但詞不同的結果。稠密檢索計算成本高,可能錯過精確匹配關鍵詞的內容。
- 混合檢索可以兼顧精確性和語義性,提升召回率和準確率,適應多樣的查詢需求。
c. 流程圖
混合檢索架構就是將關鍵詞匹配和語義理解 (BERT向量相似度)兩種技術融合起來,提高搜索/問答的準確性和覆蓋率,是現代智能信息檢索系統的關鍵技術。
(4)激活函數校準
a. 為什么要使用 “激活函數校準”
- 在很多任務中(如推薦系統、問答匹配、語義檢索),我們會計算兩個向量之間的相似度(通常使用余弦相似度,值域為 [-1, 1]),然后根據這個相似度來判斷匹配程度。
- 但在實際中:余弦相似度分布在高分段(比如 0.88 ~ 1.0)時,差距非常小,模型難以區分,所以需要一種變換手段,把這些相似度變換成更有區分度的分值——這就是 “激活函數校準” 的用意。
b. 多維相似度計算模型
- 指的是將輸入向量投影到多個子空間中,計算多個相似度,然后進行融合;與單一余弦計算相比,多維可以捕捉更復雜的語義信息。
c. 引入Sigmoid 函數進行非線性變換
- 目的是:將原始余弦值(如0.88 ~ 0.99)非線性映射到更加集中的區間(如0.9 ~ 1.0),讓差距放大;
- 本質上是一種 非線性壓縮+拉伸操作
d. Sigmoid 的飽和特性
- Sigmoid函數的飽和特性:當輸入(x-0.88)的絕對值增大時,輸出趨近于0 或1
- 在 x 趨近正負無窮時,sigmoid 的值逼近 1 或 0;
- 中間部分是最陡的(在 x=0 附近),表示對接近“中心值”的輸入更敏感,容易放大差異;
- 這里設置中心點為 0.88,其實是人為 “對齊” 高相似度部分,使其更容易分出誰更相似。
四、中華心法問答系統需求分析與設計
1. 系統需求分析
主要目的:回答用戶有關心法的問題,直觀給用戶展示答案。
數據庫:收集專家們對于心法問題的解答
2. 模塊的劃分和設計
系統總體設計了三個模塊:查詢模塊、算法模塊和錄入模塊。
查詢模塊:用戶可以直接使用查詢模塊,在首頁直接進行心法問題的查詢;對于想針對細分領域進行查找的用戶,系統還設計了通過問答分類標簽進行篩選的功能,可以讓用戶自由選擇看到指定標簽的問題與答案。
算法模塊:算法模塊里含有對知識庫里的問答對進行信息檢索,包括文本清洗去重、算法計算等.
錄入模塊:為了知識庫的可擴充性,系統設計了錄入模塊,用戶可以根據自己的需求選擇是否新錄入問題與答案。
(1)查詢模塊
(前端)向用戶展示搜索結果 + 標簽篩選功能
標簽篩選功能:將含有對應標簽的結果保留,不含有對應標簽的結果將不在界面展示,用戶可以自由選擇細分領域。
工作原理:
- 前端收到用戶輸入的問題后,采用Flask 的 POST /search 接口將問題和標簽數據送入后臺
- 過后臺智能檢索模塊檢索到匹配問答對
- 經過標簽過濾后,以JSON格式結果,返回匹配結果
- 將結果顯示在前端頁面上
(2)智能檢索模塊
算法模塊主要分為去重模塊和相似度計算模塊
a. 去重模塊(針對于一個問題的)
目的:消除知識庫中內容重復或相似度過高的問題。
步驟:
-
文本清洗
系統首先會把每個問題的文本做“清洗處理”,比如:
(1)刪除特殊符號(如“@”、“#”、“!” 等);
(2)去掉停用詞(像“的”、“是”、“了”、“和”等對語義沒有實質作用的詞);
(3)只保留關鍵語義信息(問題的核心詞)。
這一步的目的是把問題簡化為最有意義的部分。 -
分詞處理
接下來系統會對處理過的問題做分詞。分詞用的是一個叫 Jieba 的中文分詞工具,并且配合了一個特別定制的 “心法”領域詞典。
jieba: 是一個非常常用的 中文分詞工具,它的名字來源于“結巴”(諧音),意思是“把句子切開”。
為什么要用領域詞典呢?
因為普通分詞工具可能會把一些專有名詞、術語(比如“內功心法”)錯誤地切成幾個詞,導致語義被拆散。加了領域詞典后,能更準確地保留這些專有詞匯,避免出現“語義碎片化”的問題。 -
相似度計算后去重
處理后的問題會進行“相似度判斷”:
先做哈希去重:把完全一模一樣的兩個問題去掉一個。
然后進行更細致的判斷:把每個問題轉成向量(可以理解為數學上的一個點),計算它們之間的余弦相似度。
如果兩個問題的余弦相似度 > 93%,就說明它們在語義上幾乎一樣,這時候也會去掉其中一個,避免重復回答。
通過文本清洗 + 分詞優化 + 相似度判斷,系統能有效地識別并去除語義重復或過于相似的問題,提高問答系統的效率和準確性。
b. 相似度計算模塊(針對兩個問題在語義上的相似度)
目的:判斷兩個問題在語義上的相似程度,以便識別重復、相似的問題,提高問答系統的準確率和響應質量。
步驟:
-
問題向量化:用BERT表示語義
系統首先使用 BERT 模型(一個強大的預訓練語言模型)將文本問題轉換為向量表示。
具體方法是:
① 取出 BERT 輸出的 最后四層的 CLS 向量(CLS 表示整個句子的語義信息);
② 給這四層分別賦予權重:0.15, 0.25, 0.35, 0.25
這些權重的意義是:
倒數第四層(最淺層)表示的是字面含義;
倒數第二層(更深層)更能捕捉抽象語義;
因為“心法”領域涉及很多抽象術語(如經絡、氣機等),所以系統提高了抽象層的權重,降低了字面層的比重。
這樣做是為了讓系統更“理解”用戶的問題語義,而不僅僅是表面詞匯。 -
向量歸一化:消除長度影響
因為不同句子長度不同,向量的模長也不同,這會影響余弦相似度的計算。
所以在融合完各層向量之后,系統對向量做了歸一化處理(也就是把向量拉到相同長度),確保比較時更公平、更準確。 -
計算余弦相似度:衡量兩個向量的夾角
系統用余弦相似度來計算兩個句子的語義相近程度,公式如下:
其中:
𝐴, 𝐵 是兩個句子的向量;
點積(A · B)表示它們的相似程度;
模長(∥A∥)表示它們的長度。
值域范圍是 0 到 1,值越大表示越相似。 -
引入 Sigmoid 函數:增強高相似度區間的分辨率
問題:很多句子之間的相似度都集中在 0.88 ~ 0.92,這樣差距太小,人眼不容易區分。
解決方法:
使用 Sigmoid 函數,將原始余弦相似度進行非線性映射,提升這個“高相似區間”的區分度。
公式如下:
這可以把 0.88 ~ 0.92 之間的值“拉開”,讓相近的問題得分差別更明顯。 -
混合相似度:原始值 + 校準值結合
因為 Sigmoid 會造成一定的偏差,為了防止誤差過大,系統采用了混合策略:
最終語義相似度= 0.2·原始余弦值+0.8·校準后值
這樣既保留了余弦值的“整體趨勢”,又增強了高相似區域的細節辨別能力。 -
關鍵詞增強:捕捉顯性特征
除了語義相似度,系統還使用了關鍵詞匹配作為 “顯性特征” 的補充。方法是:
① 用 Jieba 分詞 提取每個問題中的 名詞、動詞、形容詞;
② 利用 TF-IDF 思想 篩選重要詞;
③ 計算關鍵詞重疊率,得到一個“關鍵詞相似度”。
這個模塊用于捕捉那些直接表達意思的關鍵詞,彌補深層語義模型可能忽視的部分。 -
最終融合:語義 + 關鍵詞的加權相似度
最后系統將兩種相似度進行融合:
α=0.7:語義相似度占比 70%
1?α=0.3:關鍵詞相似度占比 30%
融合后的結果再經過一些補償機制,得出最終的綜合相似度分數。
這個相似度模塊通過 BERT + Sigmoid + 關鍵詞融合的方式,綜合考慮深層語義和關鍵詞重合度,實現了更加準確的問句相似度判斷,特別適合處理“心法”這種抽象領域的問題。
(3)錄入模塊
目的:給用戶用來添加新的“心法”問題和對應答案的。每當用戶有新的內容想加入系統,就可以:
-
輸入一個新問題;
-
提供對應答案;
-
為這個問題打上一級標簽和二級標簽(用于分類管理,比如“心法理論 / 調息方法”)。
重復問題怎么處理?
在用戶添加時,可能會不小心添加:
-
一模一樣的問題;
-
或者和已有問題意思非常相近(相似度很高)的問題。
為了避免:
-
問答重復
-
系統里有很多雷同問題
-
輸出時出現重復答案
系統在錄入時會自動進行三步去重處理。
三步去重機制
(1)文本清洗
-
刪除特殊符號;
-
去掉“的、是、了”等停用詞;
-
保留問題的核心關鍵詞。
-
目的是讓系統專注于識別問題的“本質”。
(2)哈希去重
-
用哈希算法判斷新問題是否和之前某個問題完全一樣;
-
如果是,就不再錄入。
(3)語義向量去重
-
把新問題轉換成向量(用 BERT 模型);
-
計算它和已有問題之間的語義相似度;
-
如果相似度很高(比如大于 93%),說明問題太像,就不錄入。
實時更新機制
系統在內存中用 np.vstack()(NumPy 的一個函數)動態地擴展保存向量的矩陣,相當于把新的問題“實時加進去”,不需要重啟系統。
這就實現了:
-
實時錄入;
-
實時查找;
-
用戶錄完問題,可以馬上在首頁搜索到這個新問題。
錄入模塊讓用戶可以方便地添加新的心法問題和答案,同時系統通過文本清洗 + 哈希去重 + 語義判斷三重機制,自動去除重復或過度相似的問題,并支持熱更新,錄入后立即生效。
3. 前端和后端的交互邏輯
(1)前端設計——頁面交互界面
-
使用 HTML 設計用戶界面,也就是你在瀏覽器里看到的頁面;
-
用戶可以在前端界面中輸入問題(比如:“如何修煉心法?”);
-
前端頁面通過 JavaScript、表單或按鈕等方式,與后端服務器交互。
(2)前后端交互方式 —— Flask 框架 + RESTful API
-
本系統后端使用 Python 的 Flask 框架;
-
前后端是分離式架構(即用戶界面和業務邏輯分開);
-
前端通過 RESTful API 與后端通信:
-
發送數據:如用戶提交的問題;
-
接收數據:如后端返回的相似問題列表。
-
RESTful API 是一種設計接口的規范,它讓前端能方便地“問”后端:“你能給我哪些相似的問題?”、“我能不能錄入一個新問題?”等。
(3)查詢問題的流程(搜索接口)
當用戶在前端輸入一個問題并提交后:
-
前端把這個問題發送到后端 API 接口;
-
后端調用 BERT 模型,把用戶輸入轉換為語義向量;
-
系統在知識庫中進行語義相似度計算和檢索;
-
找到與該問題最相似的問題列表(比如Top5);
-
返回給前端一個按相似度排序的問答對列表,每項包含:
-
匹配的問題;
-
問題對應的答案;
-
一級/二級標簽;
-
相似度得分。
-
舉例:
用戶問“如何練氣功?”
系統返回:“氣功入門的方法有哪些?(相似度:92.6%)”
(4)提交新問題的流程(錄入接口)
當用戶希望添加一個新問題+答案時:
-
用戶填寫“問題 + 答案 + 一級標簽 + 二級標簽”;
-
前端將這些信息通過 API 發送到后端;
-
后端執行兩步驗證:
-
校驗合法性(如字段是否為空);
-
檢查是否已存在相似問題(防止重復);
-
-
校驗通過后,后端將新數據寫入 CSV 文件(你當前的知識庫存儲方式);
-
并對內存中的數據結構做 熱更新(不用重啟服務器就能實時加入新問題);
-
最終返回結果給前端:
-
若成功:提示“提交成功,問題已錄入”;
-
若失敗:前端顯示提示(比如“問題重復”或“請填寫完整內容”)。
-
4. 后端運作邏輯
(1)系統初始化階段
加載模型與數據,后端一啟動就會加載以下內容:
-
預訓練好的 BERT 模型(用于語義理解);
-
分詞器(配合 Jieba 或 BERT Tokenizer 用于預處理文本);
-
已有問答對數據(知識庫中的所有問題 + 答案 + 標簽等)
(2)知識庫數據預處理
清洗問答對文本
-
去掉特殊符號、空格、停用詞;
-
保留關鍵信息,防止語義碎片。
三重去重機制
為了避免知識庫中存在重復問題或高度相似問題,系統對問答對做如下處理:
-
哈希去重:判斷完全重復的問答對;
-
語義相似度去重:將問句轉成向量,若余弦相似度 > 0.93,就認為太相似,去掉一個;
-
動態閾值擴展機制:
-
如果匹配結果太少,系統會自動降低相似度標準(比如從0.93放寬到0.88),保證至少能返回一些合理結果。
-
這樣兼顧了“結果準確”和“結果充足”。
-
(3)向量預計算與歸一化存儲
-
所有問答對在系統啟動時就提前用 BERT 向量化;
-
對每個向量做 歸一化處理(確保計算余弦值時不受向量長度影響);
-
存在內存里,方便后續快速檢索。
優點:查詢時就不用每次都重新計算知識庫向量,節省用戶等待時間,提高系統響應速度。
(4)接口設計(通過Flask)
-
后端使用 Flask 的路由機制,把不同的 HTTP 請求(如 POST /search)對應到具體的功能代碼;
-
例如:
-
/search 用于搜索問題;
-
/submit 用于錄入新問題。
-
(5)用戶使用查詢功能時
前端將用戶輸入的問題打包成 JSON 格式 發送給后端(例如:{“question”: “心法如何修煉?”});
后端使用 request.json 獲取數據,并提取出 question 字段;
然后:
-
清洗文本;
-
用 BERT 向量化(加權融合最后四層,提升語義理解);
-
使用 Sigmoid 函數放大高相似度之間的區分度;
-
進行與知識庫中向量的相似度匹配(比如取Top5相似的問題)。
如果用戶還選擇了標簽篩選:
-
前端把選擇的標簽傳給后端;
-
后端只返回含有該標簽的問題和答案。
(6)用戶使用錄入功能時
前端先校驗數據格式(是否填寫完整);
后端收到數據后,執行:
-
文本清洗;
-
哈希查重;
-
語義查重;
-
如果問題通過查重檢測,寫入知識庫文件(如 CSV);
-
使用 np.vstack() 對向量矩陣進行動態擴展(熱更新);
-
無需重啟服務器,新問題立即可查詢。
如果錄入成功:
-
返回結果給前端;
-
前端展示“提交成功”的提示。
如果不符合要求:
-
返回出錯原因;
-
例如“問題為空”、“語義重復”;
-
前端負責展示提示信息。
五、中華心法問答系統的實現
1. BERT模型的運用
(1)整體思路解釋
目標:將用戶輸入的問題(或知識庫中的問題)轉化為一個語義向量,用于后續的語義相似度計算。
使用BERT的原因:BERT 是預訓練的大規模語言模型,能夠捕捉句子的深層語義和上下文信息。
(2)為什么使用BERT的最后四層
BERT 的輸出由多個 Transformer 層組成(默認是 12 層);
不同層表達的語義信息不同:
-
淺層(如第9層):更關注詞法、局部語法;
-
深層(如第11層):更關注整體句意、抽象語義;
心法領域中的問句具有高度抽象性,所以更看重深層含義;
因此采用一種加權融合策略,對最后四層的輸出按重要程度賦予不同的權重。
權重示例(從第9層到第12層):[0.15, 0.25, 0.35, 0.25]
- 第11層(倒數第2層)占比最高,強調抽象語義;
- 第9層占比最低,僅保留必要的詞法信息
(3)為什么歸一化向量
-
向量歸一化的目的是讓每個向量的長度為1;
-
這樣可以避免因為句子長短不同而造成的向量模長差異對余弦相似度計算的干擾;
-
所以最后一步使用如下代碼進行歸一化:
fused_vector / np.linalg.norm(fused_vector)
(4)關鍵代碼解釋
①
def _get_embedding(self, text: str) -> np.ndarray:
- 這是定義一個函數,用來獲取輸入 text 的向量表示。
函數的目的:將輸入的一句話,如 “如何修煉內功?”,通過 BERT 模型編碼成一個語義向量(長度為 768),用于后續的相似度計算。
② 分詞與編碼
inputs = self.tokenizer(text, return_tensors="pt", truncation=True, max_length=512).to(DEVICE)
-
self.tokenizer(…) 是 BERT 模型自帶的分詞器,它將自然語言句子轉化為模型可接受的格式。
-
return_tensors= “pt” 表示使用 PyTorch 張量格式;
-
truncation=True 說明如果太長就截斷,最多不超過 512 字;
-
.to(DEVICE) 把張量送到 GPU 或 CPU 上運行。
以 “如何修煉內功?” 為例:
① 調用分詞器后,會得到
tokens = [‘[CLS]’, ‘如何’, ‘修煉’, ‘內功’, ‘?’, ‘[SEP]’]
② 這些 token 會被轉化為 ID,例如:
input_ids = [101, 2128, 3299, 3782, 8043, 102]
(說明:101 是 [CLS],102 是 [SEP],其他數字是詞的詞表編號)
目的:將文字轉成模型可以處理的數字表示
例如:
text = “如何修煉內功?”
tokens = [‘[CLS]’, ‘如何’, ‘修煉’, ‘內功’, ‘?’, ‘[SEP]’]
token_ids = [101, 2128, 3299, 3782, 8043, 102]
模型看到的就是這些 token ID
③ 輸入BERT模型(輸出所有隱藏狀態)
with torch.no_grad():outputs = self.model(**inputs)
-
with torch.no_grad() 表示推理階段不計算梯度(即不訓練,只推理),節省內存;
-
self.model(…) 運行 BERT 模型
-
outputs.hidden_states:模型每一層的輸出
得到的 outputs.hidden_states 是 13 層隱藏狀態(1層輸入 + 12層Transformer)
每層是一個形如:
[1, 6, 768] # batch_size=1, sequence_len=6, hidden_size=768
每層都是6個 token(句子長度)每個 token 是768維的向量。
(其中 [CLS] 是每一層第一個 token 的表示,即 layer[:, 0, :])
④ 提取最后四層的 [CLS] 向量
hidden_states = outputs.hidden_states[-4:]
- 獲取 BERT 最后的 4 層隱藏狀態(每層是一個 [batch_size, seq_len, hidden_dim] 的張量);
cls_vectors = torch.stack([layer[:, 0, :] for layer in hidden_states])
-
對每層,取出 [CLS] 位置的向量(即 layer[:, 0, :]),它代表整句含義;
-
將四個 [CLS] 向量堆疊成一個新張量,形狀為 [4, hidden_dim]。
最終會得到:
cls_vectors.shape = [4, 768]
例如:
cls_vectors = [
[0.01, 0.02, …, 0.05], # 第9層
[0.04, 0.01, …, 0.06], # 第10層
[0.10, 0.09, …, 0.08], # 第11層(抽象)
[0.08, 0.04, …, 0.07], # 第12層
]
⑤ 加權融合四層向量
fused_vector = torch.sum(cls_vectors * self.config.LAYER_WEIGHTS, dim=0)
-
對四個 [CLS] 向量按預設權重 LAYER_WEIGHTS 進行加權求和;
-
得到融合后的語義向量 fused_vector。
假設 LAYER_WEIGHTS 為[0.15, 0.25, 0.35, 0.25],以第100維為例:
第100維的融合計算:
= 0.15×0.05(第9層) + 0.25×0.06(第10層) + 0.35×0.08(第11層) + 0.25×0.07(第12層)
= 0.0075 + 0.015 + 0.028 + 0.0175 = 0.068
所以融合后的 fused_vector 是一個長度為 768 的向量:
fused_vector = [0.045, 0.067, …, 0.068] # 共768維
⑥ 歸一化處理
return (fused_vector / np.linalg.norm(fused_vector)).cpu().numpy()
- 將向量歸一化(單位化),然后轉為 CPU 并轉成 NumPy 格式;
假設:向量的模長為||fused_vector|| = 1.872
則:
normalized[0] = 0.045 / 1.872 ≈ 0.024
normalized[1] = 0.067 / 1.872 ≈ 0.036
最終出的 normalized 向量仍然是一個長度為 768 的向量,但所有數值已壓縮到單位球面。
- 返回最終的語義向量表示。
最終結果:
array([
0.0241, -0.0357, 0.0159, …, 0.0687
]) # 長度為768
這個就是“如何修煉內功?”的語義向量表示。
它現在可以與其他問題的向量做余弦相似度計算,來判斷語義是否接近。
2. 混合檢索算法的實現
(1)動態校準策略(語義相似度校準)
① 核心思想:用 BERT 語義相似度 + Sigmoid 非線性變換 + 原始余弦相似度補償 的方式,對高相似度區域(如 0.88~0.93 區間)進行更敏感的區分,從而提升相似問句的辨別能力。
② 實現過程:
# 1. 原始語義相似度(由BERT余弦計算得到)
raw_similarities = cosine_similarity(query_vector, knowledge_base_vectors)# 2. 對高相似度區間進行Sigmoid校準
calibrated = 1 / (1 + np.exp(-25*(raw_similarities - 0.88)))# 3. 加權融合(混合相似度)
similarities = 0.2 * raw_similarities + 0.8 * calibrated
③ 舉例說明
句子編號:A
原始余弦值 raw_similarities:0.85
校準后 calibrated:0.3775
最終 similarities:0.2×0.85 + 0.8×0.3775 = 0.477
④ 好處
- Sigmoid 增大了 0.88~0.93 的區分度(原本余弦值之間差距小,現在差距更明顯)
- 補償機制(0.2×原始 + 0.8×校準)使得整個值域不會偏離原始相似度太多,保持語義分布的整體穩定性。
(2)關鍵詞增強機制(文本相似度補充)
① 核心思想
彌補 BERT 對 “關鍵詞(尤其是專業術語)” 不敏感的問題,利用 TF-IDF + 共現匹配,提取關鍵詞后做共現率計算。
什么是TF-IDF
TF-IDF 是一種用于衡量一個詞對于某篇文檔在整個語料庫中有多重要的常用方法.
它由兩部分組成:
- ① TF:某個詞在當前文檔中出現的頻率(出現越多越重要)
- ② IDF:某個詞在所有文檔中出現的頻率的“反比”(出現越少越重要)
直觀解釋:
- 如果某個詞在某篇文章中出現很多次(高 TF),那它可能是這篇文章的關鍵詞。
- 但如果這個詞在所有文章中都很常見(低 IDF,例如“的”“是”),那它的區分度就低。
- TF-IDF 就是要找那些:在該文檔中出現頻繁,但在其他文檔中很少出現的詞,也就是具有代表性的關鍵詞。
② 實現過程
# 1. 文本清洗 → 分詞
query_keywords = set(jieba.lcut(cleaned_query))# 2. 關鍵詞共現度
keyword_intersection = query_keywords & doc_keywords
keyword_weights = len(keyword_intersection) / max(len(query_keywords), 1)# 3. 混合最終相似度(語義 + 文本)
final_similarity = 0.7 * semantic_similarity + 0.3 * keyword_weights
③ 舉例說明
假設:
- 用戶問句分詞后關鍵詞:{“內功”, “修煉”}
- 某知識庫問句關鍵詞:{“內功”, “呼吸”, “吐納”}
則關鍵詞交集為 {“內功”},共現度:keyword_weights = 1 / 2 = 0.5
如果BERT 相似度為 0.8:final = 0.7 * 0.8 + 0.3 * 0.5 = 0.56 + 0.15 = 0.71
(3)總結對比
模塊 | 功能 | 技術 | 舉例說明 |
---|---|---|---|
動態校準策略 | 強化高相似度區域劃分 | 域區分 BERT余弦 + Sigmoid + 加權補償 | 將 0.88、0.90、0.93 差異拉大 |
關鍵詞增強機制 | 彌補語義遺漏關鍵詞問題 | jieba分詞+TF-IDF共現 | {“修煉”, “內功”} 與 {“內功”, “吐納”} 匹配1個關鍵詞,權重0.5 |
最終融合 | 平衡語義和關鍵詞 | 0.7 * 語義 + 0.3 * 關鍵詞 | 相似度提升更合理,兼顧句意和字面 |
3. 去重模塊的實現
問答系統中文本清洗和去重機制的具體實現方式。
(1)文本清洗部分
① 目的
去除“虛詞”(如:的、了、是、在等),保留“實詞”(名詞、動詞、形容詞、人名、地名等),提升語義向量的準確性。
② 代碼解釋
def clean_text(text): keep_pos = {'n','v','a','nr','ns'} # n=名詞, v=動詞, a=形容詞, nr=人名, ns=地名return " ".join([word for word, flag in words if flag[0] in keep_pos])
- words 是使用jieba分詞并帶詞性標注后的結果
例如:words = pseg.cut(“如何修煉內功”)
輸出: [(‘如何’, ‘r’), (‘修煉’, ‘v’), (‘內功’, ‘n’)] - flag[0] in keep_pos 表示我們只保留詞性以 ‘n’, ‘v’, ‘a’, ‘nr’, ‘ns’ 開頭的詞。
③ 舉例說明
- 輸入原始句子:
“我應該如何修煉內功?” - jieba分詞結果(含詞性):
詞 | 詞性 | 是否保留 |
---|---|---|
我 | r(代詞) | 否 |
應該 | d(副詞) | 否 |
如何 | r(代詞) | 否 |
修煉 | v(動詞) | 是 |
內功 | n(名詞) | 是 |
- 清洗結果為:
“修煉 內功”
(2)去重機制(三重過濾)
① 目的
在回答相似問題時,去掉重復的或語義高度重合的答案,提升用戶體驗。
② 去重策略包括三重過濾
- 內容哈希去重(防止重復內容)
content_hash = hash(data["cleaned_question"] + data["answer"][:20])
if content_hash in seen_hashes:continue
-
利用 Python 的 hash() 對問題 + 答案前20字符進行哈希值計算。
-
如果已經出現相同的哈希,就跳過,避免輸出完全重復的內容。
- 語義相似度去重(防止“換句話說”的重復)
if any(np.dot(self.question_vectors[idx], self.question_vectors[r["index"]]) > 0.93 for r in results):continue
-
使用向量點積(近似等價于歸一化后的余弦相似度)判斷:
- 當前回答與已有回答是否語義過于接近(>0.93)
-
避免輸出內容不同但意思雷同的回答。
- 動態閾值篩選(控制輸出質量)
if sim < self.config.MIN_SIMILARITY:continue
-
如果當前問題與知識庫的相似度小于設定閾值(如 0.7),則跳過。
-
如果系統發現返回結果太少,會自動 降低閾值,放寬匹配限制,以保證有足夠回答輸出。
③ 舉例說明
假設用戶輸入:
“如何修煉內功?”
知識庫中有以下問句:
問句ID | 問題內容 | 語義相似度 | 哈希是否重復 | 向量相似度>0/93 |
---|---|---|---|---|
Q1 | “修煉內功的方法?” | 0.95 | 是 | 是 |
Q2 | “怎么練好內功?” | 0.92 | 否 | 是 |
Q3 | “內功要如何突破?” | 0.89 | 否 | 否 |
系統處理邏輯:
- Q1:哈希重復 + 向量太相似 → 剔除
- Q2:雖然哈希不同,但語義相似度過高 → 剔除
- Q3:符合相似度要求、內容不重復 → 保留
這個模塊的作用:對用戶輸入的問句進行文本清洗、向量語義判斷和關鍵詞增強,使用三重過濾機制(哈希去重、語義相似度去重、動態閾值控制),避免問答內容重復、提高相似度計算的精度,從而提升系統的智能性和用戶體驗。
4. 實驗不同參數對比的結論
結論:在中華心法問答系統中,語義理解與關鍵詞匹配采用 0.7:0.3 的融合權重能獲得更準確、更符合用戶語義意圖的相似度匹配結果。
六、運行代碼
Window系統上
(1)創建虛擬環境
python -m venv naodian-env
- 創建了一個名為 naodian-env 的虛擬環境
(2)激活虛擬環境
naodian-env\Scripts\activate
- 激活虛擬環境
(3)安裝各種功能包
# 安裝 jieba
pip install jieba# 安裝 numpy
pip install numpy# 安裝 torch(即 PyTorch)庫
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu# 安裝 transformers
pip install transformers# 安裝 Flask
pip install flask
(4)運行代碼
python xinfa_QA.py
登錄網頁 http://127.0.0.1:5000
七、總結感受
通過深入學習論文中所提出的“中華心法問答系統”設計方案,我對智能問答系統的整體構建流程與核心技術有了更全面的認識。尤其是在系統中采用語義理解與關鍵詞匹配相結合的混合策略,使我意識到,在實際應用中,單一的匹配機制往往難以兼顧準確性與靈活性,合理分配權重(如0.7:0.3)才能更有效地提升問答質量。
論文中對語義相似度的處理方式也讓我印象深刻。通過引入Sigmoid函數對原始余弦相似度進行非線性變換,不僅優化了高相似度樣本的區分能力,也體現了對實際使用場景的精細化考量。這種從 “模型輸出” 到 “實際需求” 之間的橋接過程,是我在以往學習中較少接觸但極具啟發性的部分。
此外,在知識錄入、去重、相似問題推薦等模塊中,運用語義向量去重與分類方法構建知識庫,不僅增強了系統擴展性,也使我更加理解了如何將理論與工程實現相結合。
總體而言,這次學習讓我不僅掌握了相關的技術路線(如BERT模型、語義匹配、知識管理),也培養了我用系統思維看待問答系統設計的能力。
通過本次對“中華心法問答系統”相關代碼的運行與學習,我對該系統的整體框架和實現流程有了初步的認識。在本周學習中,我主要聚焦于論文具體知識點的學習和代碼的整體運行效果,初步了解了語義匹配、關鍵詞權重分配、相似度計算等核心部分的作用。接下來,我將進一步深入閱讀和分析源代碼,結合論文內容深入理解各個模塊的設計思路與算法實現邏輯。