EN

2.7 實踐:生成文字嵌入

用一小段 Python,把句子轉成向量,並且實際算出哪些句子意思相近。

RAG

下面直接用一個開源的多語言嵌入模型,把幾句中文轉成向量,計算句子之間的相似度,再拿問題找出最接近的內容。

這個範例我實際跑過,下面的輸出就是真實的執行結果。

準備

用 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,負數代表方向相反。

自己試試看

  1. 把句子換成你自己的資料,看看哪些句子會被判斷成相近。
  2. 問一個問題,故意用跟句子完全不同的說法,看看還找不找得到。
  3. 換成英文的模型(例如 all-MiniLM-L6-v2)來處理中文句子,看看結果會差多少。
  4. 試試看把四句話改成一整個段落,看相似度怎麼變。

這四句只用來驗證流程。真實文件可能有幾千、幾萬句,必須先用固定規則載入、清理和分塊,再批次建立向量。

← 全部文章