iT邦幫忙

2025 iThome 鐵人賽

DAY 5
0
DevOps

30 天帶你實戰 LLMOps:從 RAG 到觀測與部署系列 第 5

Day05 - 向量模型(Embedding)- 四種 Embedding 模型實測與選型

  • 分享至 

  • xImage
  •  

🔹 前言

昨天 (Day 4) 我們比較了 向量資料庫,解決了「知識要存在哪裡,怎麼檢索」的問題。
但在 RAG (Retrieval-Augmented Generation) 裡,還有另一個同等重要的環節:

要怎麼把文字轉成向量 (Embedding)

因為如果 Embedding 模型效果不好,「請假」可能會和「旅行」比對在一起,而不是和「休假」相近。這樣檢索到的文件就完全錯了,RAG pipeline 也就失敗。

https://ithelp.ithome.com.tw/upload/images/20250919/20120069nEUKC6RdjD.png
RAG 流程(此為缺少文檔預處理以及回覆後處理的簡化版)

所以今天,我們要比較幾種常見的 Embedding 模型(OpenAI、HuggingFace、BGE、Cohere),
看誰能在「語意檢索」這件事上表現最好。


🔹 為什麼 Embedding 重要?

Embedding 就像是「文字的座標化」。
例如下面三句話:

  • 「我今天請假」
  • 「我要休假」
  • 「我想去旅行」

Embedding 模型是透過大量語料訓練,把語意相近的詞句投影到相近的向量位置。這樣系統才能用 數學運算 - 餘弦相似度(cosine similarity) 取代傳統的 字串比對。以上述舉的例子來說,理想的向量空間應該要讓「請假」和「休假」的距離很近,而「旅行」稍微遠一點,這樣檢索出來的結果才符合語意。

在實務場景裡,這種語意對齊格外重要。

例如一個 FAQ Bot,當使用者問「怎麼申請休假?」時,系統應該要能檢索到「請假流程」的文件;又或者在 客服知識庫 裡,不同人可能會使用「薪水」「薪資」「工資」等不同說法,Embedding 必須能理解這些詞語其實指向相同概念,才能確保檢索結果符合用戶需求。


🔹 四種常見選項比較

這裡我們挑選了四種常見 Embedding 模型:OpenAI、HuggingFace、BGE、Cohere,並針對語言支援、效果 (相似度示例)、硬體需求、收費與適合場景進行比較。

模型 公司/國家 語言支援 硬體需求 收費 適合場景
OpenAI (text-embedding-3-small/large) OpenAI(美國) 多語言(中/英/日等) 雲端 API,無需本機硬體 Token 計價,需付費 快速 MVP、多語言應用
HuggingFace MiniLM (all-MiniLM-L6-v2) Microsoft Research + HuggingFace(美國) 英文最佳,中文一般 CPU 可跑,GPU 更快 免費 (開源)[註3] 個人專案、英文知識檢索
BGE (BAAI/bge-small-zh-v1.5) BAAI 北京智源人工智能研究院(中國) 中文特化[註1] 本機可跑:GPU 建議,本機可跑[註2] 免費 (開源) 中文 QA、企業知識庫
Cohere (embed-english-v3.0) Cohere (加拿大) 英文最佳,支援跨語言 雲端 API,無需本機硬體 Token 計價,需付費 英文知識庫、商用 SaaS

[註1] 泛指簡體中文。
[註2] 需要依據最大輸入 tokens / context window / 向量維度 / 延遲吞吐等因素而定。
[註3] 延伸閱讀:這裡單指模型本身是不需要付費的,但實際上使用會需要考慮更多面向,比如轉換和儲存成本,Day 26 我們會提到這塊。


🔹 Demo 四種 Embedding 模型

完整可執行專案 已經放在 GitHub

📋 環境準備

一樣用 conda 啟動環境:

conda env create -f environment.yaml
conda activate day05_embedding

📋 Demo 1:OpenAI Embeddings

from openai import OpenAI
from dotenv import load_dotenv
import numpy as np
import os


# 載入 .env
load_dotenv()

# 讀取金鑰
api_key = os.getenv("OPENAI_API_KEY")
if not api_key:
    raise RuntimeError("❌ 找不到 OPENAI_API_KEY,請確認 .env 或環境變數設定")
client = OpenAI()

texts = ["我今天請假", "我要休假", "我想去旅行"]
embs = [client.embeddings.create(model="text-embedding-3-small", input=t).data[0].embedding for t in texts]

sim = np.dot(embs[0], embs[1]) / (np.linalg.norm(embs[0]) * np.linalg.norm(embs[1]))
print("請假 vs 休假 相似度:", sim)
sim = np.dot(embs[1], embs[2]) / (np.linalg.norm(embs[1]) * np.linalg.norm(embs[2]))
print("休假 vs 旅行 相似度:", sim)
sim = np.dot(embs[0], embs[2]) / (np.linalg.norm(embs[0]) * np.linalg.norm(embs[2]))
print("請假 vs 旅行 相似度:", sim)

結果:

❯ python openai_embedding_demo.py
請假 vs 休假 相似度: 0.7618106440094277
休假 vs 旅行 相似度: 0.5885526266358054
請假 vs 旅行 相似度: 0.4865730089098357

📋 Demo 2:HuggingFace MiniLM

from sentence_transformers import SentenceTransformer
import numpy as np

model = SentenceTransformer('sentence-transformers/all-MiniLM-L6-v2')

texts = ["我今天請假", "我要休假", "我想去旅行"]
embs = model.encode(texts)

sim = np.dot(embs[0], embs[1]) / (np.linalg.norm(embs[0]) * np.linalg.norm(embs[1]))
print("請假 vs 休假 相似度:", sim)
sim = np.dot(embs[1], embs[2]) / (np.linalg.norm(embs[1]) * np.linalg.norm(embs[2]))
print("休假 vs 旅行 相似度:", sim)
sim = np.dot(embs[0], embs[2]) / (np.linalg.norm(embs[0]) * np.linalg.norm(embs[2]))
print("請假 vs 旅行 相似度:", sim)

結果:

❯ python huggingface_minilm_demo.py
請假 vs 休假 相似度: 0.8110042
休假 vs 旅行 相似度: 0.8215162
請假 vs 旅行 相似度: 0.73472106

📋 Demo 3:BGE

from sentence_transformers import SentenceTransformer
import numpy as np

model = SentenceTransformer('BAAI/bge-small-zh-v1.5')

texts = ["我今天請假", "我要休假", "我想去旅行"]
embs = model.encode(texts, normalize_embeddings=True)

sim = np.dot(embs[0], embs[1])
print("請假 vs 休假 相似度:", sim)
sim = np.dot(embs[1], embs[2])
print("休假 vs 旅行 相似度:", sim)
sim = np.dot(embs[0], embs[2])
print("請假 vs 旅行 相似度:", sim)

結果:

❯ python bge_demo.py
請假 vs 休假 相似度: 0.7691307
休假 vs 旅行 相似度: 0.57563287
請假 vs 旅行 相似度: 0.49289015

👉 BGE 系列(base、large)在簡體中文 QA、知識檢索的效果特別好。[註1]

[註1] C-MTEB: BAAI/bge--small-zh-v1.5 Benchmark

📋 Demo 4:Cohere

import cohere
import numpy as np
import os
from dotenv import load_dotenv

# 載入 .env 檔案,讀取環境變數(例如 API Key)
load_dotenv()

# 從環境變數取得 Cohere API Key
api_key = os.getenv("COHERE_API_KEY")
if not api_key:
    # 若沒有設定金鑰就直接中斷
    raise RuntimeError("❌ 找不到 COHERE_API_KEY,請確認 .env 或環境變數設定")

# 初始化 Cohere Client
co = cohere.Client(api_key)

# 測試用的三個句子
texts = ["我今天請假", "我要休假", "我想去旅行"]

# 呼叫 Cohere 的 Embed API
# - model="embed-english-v3.0":使用 Cohere 最新的英文向量模型(多語言也有一定支援)
# - input_type:可設定 "search_document"(文件庫向量)或 "search_query"(查詢向量)
resp = co.embed(
    texts=texts,
    model="embed-english-v3.0",
    input_type="search_document"
)

# 取得向量結果,轉成 numpy array
# shape: (3, 1024) → 三個句子,每個句子轉成 1024 維向量
embs = np.array(resp.embeddings)

print(f"Embeddings shape: {embs.shape[0]} x {embs.shape[1]}")

# 定義 cosine similarity 計算函式
def cos(a, b):
    return float(np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b)))

# 計算相似度
print("請假 vs 休假 相似度:", round(cos(embs[0], embs[1]), 3))
print("休假 vs 旅行 相似度:", round(cos(embs[1], embs[2]), 3))
print("請假 vs 旅行 相似度:", round(cos(embs[0], embs[2]), 3))

結果:

❯ python cohere_demo.py
Embeddings shape: 3 x 1024
請假 vs 休假 相似度: 0.802
休假 vs 旅行 相似度: 0.882
請假 vs 旅行 相似度: 0.731

📋 比較結果

模型 請假 vs 休假 請假 vs 旅行 休假 vs 旅行 分離度(↑佳)[註1]
OpenAI (text-embedding-3-small) 0.762 0.487 0.589 0.275
HuggingFace MiniLM (all-MiniLM-L6-v2) 0.811 0.735 0.822 0.076
BGE (bge-small-zh-v1.5) 0.769 0.493 0.576 0.276
Cohere (embed-english-v3.0) 0.802 0.731 0.882 0.071

這組中文例句下,BGE ≈ OpenAI 的分離度表現最佳,能把「旅行」明顯拉遠。MiniLM、Cohere 對「旅行」距離偏近(特別是 Cohere 的「休假 vs 旅行」很高),顯示中文語意分離較弱。

🧐 為什麼看「分離度」?

不是只有「請假 vs 休假」要接近,更重要的是「請假/休假」要和「旅行」保持距離,才能避免檢索錯誤。分離度就反映了模型在「相似要近、不同要遠」的平衡能力。

這張比較表只是極小的樣本對比,實務建議要用更多的語料,並透過 RAG 檢索評測指標(例如 HitRate、MRR、nDCG)來做量化比較[註2],再決定要用哪個 embedding 模型

[註1] 分離度(Separation) =(請假 vs 休假)− min(請假 vs 旅行, 休假 vs 旅行),越高代表越能把「旅行」和請/休假區分開)
[註2]📊 常見檢索評測指標
HitRate@k:Top-k 命中率,查詢的正確答案是否出現在前 k 筆結果中。
MRR (Mean Reciprocal Rank):平均倒數排名,命中的越靠前分數越高。
nDCG (Normalized Discounted Cumulative Gain):考慮多個答案的排序合理性,越前面的正確答案分數越高。


🔹 小結

今天我們比較了四種 Embedding 模型,並得到以下結論:

  • OpenAI → 穩定、多語言支援,商用方便,但要付費。
  • HuggingFace → 免費、社群多,但需要硬體支援。
  • BGE → 中文 QA 效果不錯,適合企業知識庫。
  • Cohere → 英文強勢[註1],API 好上手,但需付費。(Trial Free 有每個月呼叫一千次的額度)

明天 (Day 6),我們會實作第一個 Minimal RAG QA Bot,到時候我們會用今天挑的 embedding 模型 + Day04 的向量資料庫,拼湊出第一個最小可行的 RAG Pipeline。

[註1] Cohere - Introducing Embed v3


📚 引用來源 / 延伸閱讀


上一篇
Day04 - 向量資料庫(Vector Database)- 常見選項與實務比較
下一篇
Day06 - 初探 RAG(Retrieval-Augmented Generation)
系列文
30 天帶你實戰 LLMOps:從 RAG 到觀測與部署7
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言