2.7 實踐:生成文字嵌入
用一小段 Python,把句子轉成向量,並且實際算出哪些句子意思相近。
下面直接用一個開源的多語言嵌入模型,把幾句中文轉成向量,計算句子之間的相似度,再拿問題找出最接近的內容。
這個範例我實際跑過,下面的輸出就是真實的執行結果。
準備
用 Python,安裝兩個套件:
pip install sentence-transformers numpy
如果你用 uv,也可以不裝,直接執行:
uv run --with sentence-transformers --with numpy embed_demo.py
第一次執行會自動下載嵌入模型,需要一點時間。
程式
from sentence_transformers import SentenceTransformer
import numpy as np
# 一個支援中文的小型嵌入模型(第一次執行會自動下載)
model = SentenceTransformer("paraphrase-multilingual-MiniLM-L12-v2")
sentences = [
"特休假要工作滿半年才會開始計算",
"員工年資滿六個月,就可以請特別休假",
"今天台北的天氣很好,適合出去走走",
"F1 賽車的輪胎有軟胎、中性胎和硬胎",
]
# 1. 把每句話轉成向量
vectors = model.encode(sentences)
print("向量形狀:", vectors.shape) # (句子數, 向量維度)
print("第一句的前 5 個數字:", vectors[0][:5])
# 2. 算餘弦相似度:向量長度先正規化,再做內積
unit = vectors / np.linalg.norm(vectors, axis=1, keepdims=True)
similarity = unit @ unit.T
for i in range(1, len(sentences)):
print(f"第 1 句 vs 第 {i + 1} 句:{similarity[0][i]:.3f}")
# 3. 拿一個問題去找最相近的句子
query = "新進員工什麼時候可以請年假?"
q = model.encode([query])[0]
q = q / np.linalg.norm(q)
scores = unit @ q
for idx in np.argsort(-scores):
print(f"{scores[idx]:.3f} {sentences[idx]}")
執行結果
向量形狀: (4, 384)
第一句的前 5 個數字: [-0.00596078 -0.00016462 -0.00075696 -0.01818132 0.05555712]
第 1 句 vs 第 2 句:0.849
第 1 句 vs 第 3 句:0.064
第 1 句 vs 第 4 句:0.054
0.601 員工年資滿六個月,就可以請特別休假
0.590 特休假要工作滿半年才會開始計算
0.121 今天台北的天氣很好,適合出去走走
-0.055 F1 賽車的輪胎有軟胎、中性胎和硬胎
注意 在 Windows 上第一次執行,可能會看到關於 symlink 的警告,這只是快取方式的提醒,不影響結果。
逐段解讀
1. 轉成向量
model.encode(sentences) 把 4 句話各轉成一個向量。(4, 384) 的意思是:4 句話,每句是 384 個數字。這個 384 是這個模型的維度,換一個模型就會不一樣。
2. 算相似度
第 1 句「特休假要工作滿半年才會開始計算」和第 2 句「員工年資滿六個月,就可以請特別休假」,字面幾乎不一樣,一個說「半年」一個說「六個月」,但意思是同一件事,相似度高達 0.849。
第 1 句和天氣、F1 輪胎那兩句,相似度只有 0.06、0.05,接近 0,代表沒什麼關係。
這就是 2.1 說的:嵌入看的是意思,不是字。
3. 用問題去搜尋
問題「新進員工什麼時候可以請年假?」跟那些句子的字面幾乎沒有重疊,但排在最前面的就是兩句特休假相關的句子,分數約 0.6。天氣那句 0.12,F1 輪胎那句甚至是負數。
這個過程,就是檢索器在做的事:把問題轉成向量,和知識庫的每一筆比較,取分數最高的。
觀察與思考
- 分數是相對的。 這裡「相關」的分數是 0.6 左右,不是 0.9。不同模型的分數範圍不一樣,所以通常看排名,要設門檻時也要用自己的資料測試。
- 一個負數也沒問題。 餘弦相似度範圍是 -1 到 1,負數代表方向相反。
自己試試看
- 把句子換成你自己的資料,看看哪些句子會被判斷成相近。
- 問一個問題,故意用跟句子完全不同的說法,看看還找不找得到。
- 換成英文的模型(例如
all-MiniLM-L6-v2)來處理中文句子,看看結果會差多少。 - 試試看把四句話改成一整個段落,看相似度怎麼變。
這四句只用來驗證流程。真實文件可能有幾千、幾萬句,必須先用固定規則載入、清理和分塊,再批次建立向量。