National Central University
Uedu Main Site
Explore Uedu
Student Console
Register as Member/Login
Research Informed Consent Center
Survey Center
Educational Big Data Challenge
Claim or create a course
Try an AI Scenario Task
Support & Messages
Uptime Data

UeduGPTs

--

Jupyters

3

Local AI

--

Uedu Code

--

中央大學 AQI 80 24°C PM2.5 21
AI Reply Desktop Notifications

Show a desktop notification when the AI TA finishes replying

Chat Message Notifications

Notify me when classmates post messages in the forum

Sound notification

Play an alert sound whenever there is a new notification

Unit 10

Embedding 與語意相似度

文字變成向量,用餘弦相似度比較意思
Interaction實作 25 minute(s)

Learning Objectives

  • 說明 embedding 是什麼,並呼叫 API 取得一段文字的向量
  • 用 numpy 算餘弦相似度,說明內積與長度正規化的關係
  • 讀懂相似度矩陣,說明相似度數字只能比較、沒有絕對意義
  • 舉出相似度高但意思相反的例子,說明 embedding 不能用來判斷語意是否正確

讓程式比較兩段文字的意思

使用者問「圖書館幾點關門?」,手冊裡寫的是「閉館時間」。兩邊沒有共同的詞,字串比對找不到,人卻一眼看得出在講同一件事。

Embedding(嵌入向量) 把一段文字變成一串數字,也就是一個向量。訓練的目標是讓意思相近的文字得到方向相近的向量,所以「比較兩段文字的意思」就變成「比較兩個向量」,這件事程式很擅長。後面幾課的向量搜尋與 RAG,都建立在這個動作上。

和前幾課一樣,右邊的程式和真實環境寫法相同,向量是我們事先呼叫 text-embedding-3-small 錄下來的真實結果(2026-11-03)。

逐步看:取得文字的向量

請注意 input 可以一次放很多段文字,回傳的 data 依序對應;還有每個向量有幾個數字。

餘弦相似度比的是方向

兩個向量的餘弦相似度(cosine similarity) 是它們夾角的餘弦值:

cos = 內積 ÷(a 的長度 × b 的長度)
  • 內積(dot product):對應位置相乘再加總。
  • 同方向得 1,垂直得 0,反方向得 −1。
  • 除以長度之後,只剩方向的差別,向量長短不影響結果。

text-embedding-3-small 回傳的向量已經正規化為長度 1,所以內積就是餘弦相似度,算起來少一步(OpenAI Embeddings 指南 也建議用餘弦相似度)。但別家的模型不一定這樣,自己截短向量之後長度也不是 1 了。不確定時用完整公式,或先正規化一次,結果不會錯。本課的向量四捨五入到小數 4 位存放,長度會有 0.001 以內的誤差,範例裡都會先正規化。

先用二維的小向量算一次,比較容易看出來。

逐步看:內積與長度正規化

a 和 b 方向相同,只是 b 比較長。比較它們的內積和餘弦值。

逐步看:六個句子的相似度矩陣

六個句子裡有換句話說、換成英文、相關但問不同的事,還有完全無關的。先猜猜看哪一對最高。所有向量排成矩陣 V(每一列一段文字),V @ V.T 一次算出每一對的內積,第 i 列第 j 欄就是第 i 句和第 j 句的相似度。

相似度只能拿來比較

從這個矩陣可以看到幾件事:

  • 「0.7 算不算像」沒有標準答案。 這個數字的分布依模型、維度、文字長短與語言而不同,換一個模型整批都會變。所以我們說「A 比 B 更像」,不說「0.7 就是相似」。
  • 主題相同就會偏高。「圖書館幾點關門」和「圖書館可以借幾本書」問的是不同的事,相似度 0.679,只比換句話說的 0.788 低一點。
  • 不同模型的向量不能互相比較。 維度相同也不行,它們是不同的空間。換模型時所有向量要全部重算。

dimensions 參數可以縮短向量,省下儲存空間;縮得太短可能分不清相近的內容。本軌一律用 128 維,是為了讓範例小,實際專案請用自己的資料試過再決定。

逐步看:相似度高不等於意思對

比較「意思相反」和「意思相同但換句話說」,哪一邊的相似度比較高?

Embedding 量的是「在談什麼」

上面的結果很值得記住:意思相反的兩句(0.92、0.824)比真正的換句話說(0.788、0.502)還要像。

Embedding 擅長判斷兩段文字是否在談同一件事,不擅長判斷細節是否相符,例如否定、誰對誰做了什麼、數字大小。對應用的影響:

  • 拿它來找資料很合適:把可能相關的段落找出來。
  • 不能拿它來判斷對錯:相似度高不表示這段文字支持使用者的說法。找到的內容是否真的回答了問題,要留給後面的步驟檢查(第 13、14 課)。

接下來用小工具親手試試。

互動練習:點兩句,看真實的相似度

每個點是一段文字。圖上的位置是把 128 維投影到平面的結果,會失真;數字則是 128 維向量算出來的真實餘弦相似度。「手冊」這組是下一課要用的教材,內容是虛構的《優學大學學生手冊》,不是任何學校的規定。

從小工具看到的事

  • 短句這組裡最像的一對,就是意思相反的那兩句。
  • 手冊各節的相似度普遍比短句低:最高的一對是舊制 grade-2 與新制 grade-3,只有 0.697,而它們的內容互相衝突。這正是第 14 課要處理的問題。
  • fee-1 和 health-1 在平面上幾乎相鄰,真實相似度只有 0.281,在 276 對裡排第 242。短句這組的前兩個主成分保留了 45.5% 的變異,手冊這組只有 24.2%,其餘的資訊都在投影時丟掉了。平面圖適合用來看大致分布,不能當成相似度的證據。

實作:餘弦相似度與排序

完成兩個函數:

  • cosine_similarity(a, b):回傳兩個 numpy 向量的餘弦相似度。向量長度不一定是 1,所以要用完整公式。
  • rank(query_vec, vectors):回傳 vectors 的索引串列,依和 query_vec 的相似度由高到低排列。

這裡的向量已經錄好,只要不改 docs 和查詢句子,就對得上錄音。

你的輸出
預期輸出

小測驗:Embedding 與相似度

1.

下面這段程式會印出什麼?

import numpy as np
a = np.array([1.0, 0.0])
b = np.array([5.0, 0.0])
print(round(float(a @ b / (np.linalg.norm(a) * np.linalg.norm(b))), 1))
2.

檢索系統找到一段和問題相似度很高的文字。可以由此確定什麼?

3.

原本用模型 A 存了一批向量,改用模型 B 算新查詢的向量(維度也設成一樣),會怎樣?

4.

散布圖上兩個點幾乎重疊,這表示什麼?

5.

同事說:「相似度 0.5 以上就算相關。」這句話的問題在哪裡?

第 1 次作答

重點整理

  • Embedding 把文字變成向量;意思相近的文字,向量方向相近。
  • 餘弦相似度 = 內積 ÷ 兩個長度的乘積;向量長度都是 1 時,內積就是餘弦相似度。
  • 相似度只能拿來比較:數字的分布依模型和資料而不同,不同模型的向量也不能互相比較。
  • Embedding 量的是「在談什麼」。意思相反的句子可以比換句話說更像,所以它適合找資料,不能判斷對錯。

下一課: 有了向量,就能在一整份手冊裡找出和問題最相關的段落。下一課用 numpy 寫向量搜尋,並和關鍵字搜尋比較。

這一課完成了!
Next lesson:向量搜尋
你目前沒有登入,學習進度只存在這個瀏覽器。 Login 後,進度會跟著帳號,換電腦也看得到。