บทนำ: ทำไม BGE-M3 ถึงเป็นมาตรฐานใหม่ของวงการ Embedding
BGE-M3 (BAAI General Embedding-M3) คือโมเดล embedding หลายภาษาจาก BAAI ที่รองรับมากกว่า 100 ภาษา รวมถึงภาษาไทย ด้วยความสามารถในการสร้าง vector ขนาด 1,024 มิติที่มีความแม่นยำสูงในงาน semantic search, document retrieval และ RAG (Retrieval-Augmented Generation) บทความนี้จะพาคุณเข้าใจวิธีการต่อ BGE-M3 ผ่าน API แบบ step-by-step พร้อม case study จริงจากทีมที่ประสบความสำเร็จในการย้ายระบบ
กรณีศึกษา: ผู้ให้บริการอีคอมเมิร์ซในเชียงใหม่
บริบทธุรกิจ
ทีมสตาร์ทอัพ AI ในเชียงใหม่ที่ให้บริการแพลตฟอร์มค้นหาสินค้าอัจฉริยะสำหรับร้านค้าออนไลน์ SME ได้พัฒนาระบบ product search ด้วย embedding model เพื่อให้ลูกค้าสามารถค้นหาสินค้าด้วยคำบรรยายหรือรูปภาพแทนการพิมพ์ keyword แบบเดิม
จุดเจ็บปวดของผู้ให้บริการเดิม
ทีมเดิมใช้ OpenAI API สำหรับ text-embedding-3-large แต่เจอปัญหาหลายประการ:
- ความหน่วงสูงเกินไป: latency เฉลี่ย 420ms ต่อ request ทำให้ UX ของ product search ช้า
- ค่าใช้จ่ายสูงลิบ: บิลรายเดือน $4,200 สำหรับ embedding 2.8 ล้าน requests
- ไม่รองรับภาษาไทยอย่างมีประสิทธิภาพ: OpenAI embedding ให้คุณภาพไม่ดีนักกับภาษาไทยโดยเฉพาะคำภาษาไทยผสมอังกฤษ
- ฟีเจอร์จำกัด: ไม่สามารถทำ multilingual search ข้ามภาษาได้
การย้ายสู่ HolySheep AI
หลังจากทดสอบหลายเจ้าผู้ให้บริการ ทีมเลือก HolySheep AI เพราะ:
- รองรับ BGE-M3 อย่างเป็นทางการ ซึ่งเก่งเรื่อง multilingual embedding
- latency เฉลี่ยต่ำกว่า 50ms
- อัตราค่าบริการประหยัดกว่า 85% เมื่อเทียบกับ OpenAI
- รองรับการชำระเงินผ่าน WeChat Pay และ Alipay
- มีเครดิตฟรีเมื่อลงทะเบียน
ขั้นตอนการย้ายระบบ
การย้ายระบบใช้เวลาทั้งหมด 3 วัน แบ่งเป็น:
- วันที่ 1: เปลี่ยน base_url และ API key, ทดสอบ sandbox
- วันที่ 2: Canary deployment 10% ของ traffic
- วันที่ 3: ขยายเป็น 100% และ monitor ผลลัพธ์
ผลลัพธ์ 30 วันหลังการย้าย
| ตัวชี้วัด | ก่อนย้าย | หลังย้าย | การเปลี่ยนแปลง |
|---|---|---|---|
| Latency เฉลี่ย | 420ms | 180ms | ลดลง 57% |
| ค่าใช้จ่ายรายเดือน | $4,200 | $680 | ประหยัด 84% |
| ความแม่นยำ (NDCG@10) | 0.72 | 0.89 | เพิ่มขึ้น 24% |
| ความพึงพอใจลูกค้า | 3.2/5 | 4.6/5 | เพิ่มขึ้น 44% |
BGE-M3 คืออะไร และทำไมต้องใช้ผ่าน API
BGE-M3 พัฒนาโดย Beijing Academy of Artificial Intelligence (BAAI) มีความโดดเด่นในหลายด้าน:
- Multilingual: รองรับ 100+ ภาษา รวมถึงภาษาไทย ลาว เขมร พม่า
- Multi-function: รองรับทั้ง dense retrieval, sparse retrieval และ multi-vector colBERT
- Long-text: รองรับข้อความยาวสูงสุด 8,192 tokens
- High performance: ได้คะแนน MTEB leaderboard สูงในหลาย benchmark
การใช้ BGE-M3 ผ่าน API ช่วยให้คุณไม่ต้องดูแล infrastructure เอง ประหยัด GPU resource และได้รับการอัปเดตโมเดลอัตโนมัติ
การติดตั้งและตั้งค่าเบื้องต้น
ติดตั้ง Client Library
pip install requests huggingface-hub sentence-transformers
สำหรับการใช้งานผ่าน API เราจะใช้ requests library เพื่อควบคุมทุกอย่างได้อย่างละเอียด
สร้าง API Client พื้นฐาน
import requests
import numpy as np
from typing import List, Union
class BGE_M3_Client:
def __init__(self, api_key: str, base_url: str = "https://api.holysheep.ai/v1"):
self.api_key = api_key
self.base_url = base_url.rstrip("/")
self.embeddings_endpoint = f"{self.base_url}/embeddings"
def get_embedding(
self,
text: str,
model: str = "bge-m3",
dimensions: int = 1024
) -> List[float]:
"""สร้าง embedding จากข้อความเดียว"""
headers = {
"Authorization": f"Bearer {self.api_key}",
"Content-Type": "application/json"
}
payload = {
"model": model,
"input": text,
"dimensions": dimensions
}
response = requests.post(
self.embeddings_endpoint,
headers=headers,
json=payload,
timeout=30
)
if response.status_code != 200:
raise Exception(f"API Error: {response.status_code} - {response.text}")
result = response.json()
return result["data"][0]["embedding"]
def get_embeddings_batch(
self,
texts: List[str],
model: str = "bge-m3"
) -> List[List[float]]:
"""สร้าง embeddings จากหลายข้อความพร้อมกัน"""
headers = {
"Authorization": f"Bearer {self.api_key}",
"Content-Type": "application/json"
}
payload = {
"model": model,
"input": texts
}
response = requests.post(
self.embeddings_endpoint,
headers=headers,
json=payload,
timeout=60
)
if response.status_code != 200:
raise Exception(f"API Error: {response.status_code} - {response.text}")
result = response.json()
# เรียงลำดับตาม input ต้นฉบับ
embeddings_map = {item["index"]: item["embedding"] for item in result["data"]}
return [embeddings_map[i] for i in range(len(texts))]
ตัวอย่างการใช้งาน
client = BGE_M3_Client(api_key="YOUR_HOLYSHEEP_API_KEY")
Embedding ข้อความเดียว
embedding = client.get_embedding("ร้านกาแฟอร์จานาวาโด้ สาขาเชียงใหม่")
print(f"Embedding dimensions: {len(embedding)}")
Embedding หลายข้อความพร้อมกัน
texts = [
"เสื้อยืดผ้าฝ้าย สีดำ ขนาด M",
"Cotton t-shirt black size M",
"Chemise en coton noire taille M"
]
embeddings = client.get_embeddings_batch(texts)
print(f"Batch embeddings: {len(embeddings)} items")
การคำนวณความคล้ายคลึงและ Semantic Search
หลังจากได้ embedding แล้ว ขั้นตอนถัดไปคือการนำไปใช้ในงาน semantic search โดยใช้ cosine similarity
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity
class SemanticSearch:
def __init__(self, client: BGE_M3_Client):
self.client = client
self.document_embeddings = []
self.documents = []
def index_documents(self, documents: List[str]) -> None:
"""สร้าง index สำหรับเอกสารทั้งหมด"""
print(f"Indexing {len(documents)} documents...")
# เรียก API แบบ batch เพื่อประหยัด cost และเวลา
batch_size = 32
all_embeddings = []
for i in range(0, len(documents), batch_size):
batch = documents[i:i + batch_size]
batch_embeddings = self.client.get_embeddings_batch(batch)
all_embeddings.extend(batch_embeddings)
print(f" Processed {min(i + batch_size, len(documents))}/{len(documents)}")
self.document_embeddings = np.array(all_embeddings)
self.documents = documents
print(f"Indexing complete. Shape: {self.document_embeddings.shape}")
def search(
self,
query: str,
top_k: int = 5
) -> List[tuple]:
"""ค้นหาเอกสารที่เกี่ยวข้องมากที่สุด"""
# สร้าง embedding ของ query
query_embedding = np.array(self.client.get_embedding(query))
# คำนวณ cosine similarity
similarities = cosine_similarity(
[query_embedding],
self.document_embeddings
)[0]
# เรียงลำดับและเลือก top_k
top_indices = np.argsort(similarities)[::-1][:top_k]
results = [
(self.documents[i], similarities[i], i)
for i in top_indices
]
return results
ตัวอย่างการใช้งาน
search_engine = SemanticSearch(client)
สร้าง product catalog
products = [
"กาแฟอร์จานาวาโด้ ปิดท้าย ร้านกาแฟคลาสสิกในเชียงใหม่",
"Espresso เข้มข้นจากเมล็ดกาแฟอาราบิก้าคุณภาพสูง",
"Cold brew กาแฟเย็นสกัดเย็น 24 ชั่วโมง",
"Latte กาแฟนมร้อน สูตรอิตาเลียนแท้",
"Cappuccino กาแฟนมฟูเนื้อละเอียด",
"Americano กาแฟดำเข้มข้นรสชาติจัดจ้าน",
"Matcha latte ชาเขียวมัทฉะญี่ปุ่นผสมนมสด",
"Thai iced tea ชาชงเย็นรสหวานมัน"
]
search_engine.index_documents(products)
ทดสอบค้นหา
query = "กาแฟเย็นร้อนอะไรก็ได้ที่ทำจากเมล็ดคุณภาพ"
results = search_engine.search(query, top_k=3)
print(f"\nQuery: '{query}'")
print("-" * 60)
for doc, score, idx in results:
print(f"[{score:.4f}] {doc}")
การใช้งาน BGE-M3 สำหรับ RAG Pipeline
BGE-M3 เหมาะมากสำหรับ RAG (Retrieval-Augmented Generation) เพราะรองรับ multilingual query และสามารถค้นหาข้ามภาษาได้
import json
from datetime import datetime
class RAG_Pipeline:
def __init__(self, client: BGE_M3_Client, embedding_model: str = "bge-m3"):
self.client = client
self.embedding_model = embedding_model
self.chunks = []
self.chunk_embeddings = None
self.metadata = []
def add_documents(
self,
documents: List[dict],
chunk_size: int = 512,
overlap: int = 64
) -> None:
"""เพิ่มเอกสารและสร้าง chunks พร้อม embeddings"""
for doc in documents:
text = doc["content"]
doc_id = doc.get("id", hash(text) % 1000000)
source = doc.get("source", "unknown")
# แบ่งเอกสารเป็น chunks
chunks = self._chunk_text(text, chunk_size, overlap)
for i, chunk in enumerate(chunks):
self.chunks.append(chunk)
self.metadata.append({
"doc_id": doc_id,
"source": source,
"chunk_index": i,
"timestamp": datetime.now().isoformat