สวัสดีครับ วันนี้ผมจะมาสอนเทคนิคการประเมินระบบ RAG (Retrieval-Augmented Generation) อย่างละเอียด สำหรับคนที่เพิ่งเริ่มต้นและยังไม่เคยใช้ API เลย ผมจะอธิบายทุกอย่างแบบง่ายๆ ไม่มีศัพท์เทคนิคยากๆ แน่นอนครับ
RAG คืออะไร? ทำไมต้องประเมิน?
ลองนึกภาพว่าคุณมีห้องสมุดขนาดใหญ่ และคุณจ้างบรรณารักษ์ AI มาช่วยค้นหาข้อมูล RAG ก็เหมือนกับระบบที่ทำให้ AI สามารถเปิดหนังสือในห้องสมุดของคุณได้ แทนที่จะตอบจากความรู้ทั่วไปเท่านั้น
การประเมินระบบ RAG มี 2 ส่วนหลัก:
- Retrieval Metrics (การประเมินการค้นหา): วัดว่าระบบค้นหาเอกสารที่ถูกต้องมาได้ดีแค่ไหน
- Generation Quality (การประเมินคุณภาพคำตอบ): วัดว่าคำตอบที่สร้างมามีคุณภาพดีแค่ไหน
เมตริกส์สำคัญในการประเมินการค้นหา
1. Precision@K - ความแม่นยำของผลลัพธ์
Precision@K บอกเราว่า ในจำนวน K ผลลัพธ์แรกที่ระบบค้นหามา มีกี่อันที่เกี่ยวข้องจริงๆ
ตัวอย่างง่ายๆ: ถ้าคุณถามว่า "วิธีทำกาแฟ" และระบบค้นหาได้ 5 ผลลัพธ์ แต่มี 4 อันที่เกี่ยวกับการทำกาแฟจริงๆ Precision@5 ก็จะเป็น 4/5 = 0.8 หรือ 80%
2. Recall@K - ความครบถ้วนของผลลัพธ์
Recall@K บอกเราว่า ระบบค้นหาเอาเอกสารที่เกี่ยวข้องมาได้กี่เปอร์เซ็นต์จากทั้งหมดที่มี
3. NDCG (Normalized Discounted Cumulative Gain)
NDCG เป็นเมตริกส์ที่ซับซ้อนขึ้นอีกนิด เพราะมันคำนึงถึงลำดับด้วย ถ้าเอกสารที่เกี่ยวข้องมากอยู่อันดับ 1 จะดีกว่าอยู่อันดับ 10
เมตริกส์สำคัญในการประเมินคุณภาพคำตอบ
1. BLEU Score
BLEU เปรียบเทียบคำตอบที่ AI สร้างกับคำตอบตัวอย่างที่ถูกต้อง ยิ่งมีคำซ้ำกันมาก คะแนนยิ่งสูง
2. ROUGE Score
ROUGE เน้นดูว่ามีส่วนของข้อความที่ทับซ้อนกันหรือไม่ เช่น n-gram หรือ sequence
3. BERT Score
BERT Score ใช้เทคโนโลยี AI มาช่วยวัดว่าความหมายของคำตอบใกล้เคียงกับคำตอบตัวอย่างแค่ไหน ซึ่งจะดีกว่าแค่เช็คคำซ้ำ
เริ่มต้นเขียนโค้ดประเมินระบบ RAG ด้วย Python
ในส่วนนี้ผมจะสอนทีละขั้นตอน ให้คุณ copy โค้ดไปรันได้เลยครับ ผมจะใช้ HolySheep AI เป็น API หลัก เพราะมีความเร็วต่ำกว่า 50ms และราคาถูกมาก (DeepSeek V3.2 เพียง $0.42 ต่อล้าน token)
ขั้นตอนที่ 1: ติดตั้งโปรแกรมที่จำเป็น
เปิด Command Prompt หรือ Terminal แล้วพิมพ์คำสั่งนี้:
pip install openai scikit-learn numpy pandas torch transformers rouge-score bert-score sentence-transformers
ขั้นตอนที่ 2: สร้างไฟล์สำหรับทดสอบ
สร้างไฟล์ชื่อ rag_evaluation.py แล้ว copy โค้ดด้านล่างไปวางครับ:
import os
from openai import OpenAI
import numpy as np
from sklearn.metrics import precision_score, recall_score, ndcg_score
from sentence_transformers import SentenceTransformer
from rouge_score import rouge_scorer
from bert_score import score as bert_score
import pandas as pd
ตั้งค่า HolySheep API - อย่าลืมใส่ API Key ของคุณ
client = OpenAI(
api_key="YOUR_HOLYSHEEP_API_KEY",
base_url="https://api.holysheep.ai/v1"
)
โหลดโมเดลสำหรับวัดความเหมือนของประโยค
embedder = SentenceTransformer('all-MiniLM-L6-v2')
def get_embedding(text):
"""ดึง embedding จาก HolySheep API"""
response = client.embeddings.create(
input=text,
model="text-embedding-3-small"
)
return response.data[0].embedding
def calculate_retrieval_metrics(retrieved_docs, relevant_docs, k_values=[1, 3, 5]):
"""คำนวณเมตริกส์การค้นหา"""
results = {}
for k in k_values:
# Precision@K
retrieved_k = set(retrieved_docs[:k])
relevant_set = set(relevant_docs)
precision = len(retrieved_k & relevant_set) / k
recall = len(retrieved_k & relevant_set) / len(relevant_set) if relevant_set else 0
results[f'precision@{k}'] = precision
results[f'recall@{k}'] = recall
return results
def calculate_similarity_metrics(candidate, references):
"""คำนวณเมตริกส์ความเหมือน"""
scorer = rouge_scorer.RougeScorer(['rouge1', 'rouge2', 'rougeL'], use_stemmer=True)
rouge_scores = []
for ref in references:
score = scorer.score(ref, candidate)
rouge_scores.append({
'rouge1': score['rouge1'].fmeasure,
'rouge2': score['rouge2'].fmeasure,
'rougeL': score['rougeL'].fmeasure
})
# หาค่าเฉลี่ย
avg_rouge = {
'rouge1': np.mean([s['rouge1'] for s in rouge_scores]),
'rouge2': np.mean([s['rouge2'] for s in rouge_scores]),
'rougeL': np.mean([s['rougeL'] for s in rouge_scores])
}
return avg_rouge
ตัวอย่างการใช้งาน
if __name__ == "__main__":
# ข้อมูลทดสอบ
test_query = "วิธีทำกาแฟสด"
retrieved_documents = ["วิธีทำกาแฟ", "วิธีทำชา", "สูตรกาแฟ", "วิธีทำน้ำส้ม", "กาแฟคั่ว"]
relevant_documents = ["วิธีทำกาแฟ", "สูตรกาแฟ", "กาแฟคั่ว", "กาแฟเย็น"]
# ทดสอบการค้นหา
print("=" * 50)
print("การประเมินการค้นหา (Retrieval Metrics)")
print("=" * 50)
retrieval_results = calculate_retrieval_metrics(retrieved_documents, relevant_documents)
for metric, value in retrieval_results.items():
print(f"{metric}: {value:.4f}")
# ทดสอบคุณภาพคำตอบ
print("\n" + "=" * 50)
print("การประเมินคุณภาพคำตอบ (Generation Quality)")
print("=" * 50)
generated_answer = "วิธีทำกาแฟสด ให้เริ่มจากการคั่วเมล็ดกาแฟ บดให้ละเอียด แล้วชงด้วยน้ำร้อน"
reference_answers = [
"การทำกาแฟสดต้องเริ่มจากการคั่วเมล็ดกาแฟก่อน จากนั้นบดเมล็ดให้ละเอียดแล้วชงด้วยน้ำร้อน",
"ขั้นตอนทำกาแฟสด: 1. คั่วเมล็ด 2. บดกาแฟ 3. ชงด้วยน้ำร้อน"
]
similarity = calculate_similarity_metrics(generated_answer, reference_answers)
print("ROUGE Scores:")
for metric, value in similarity.items():
print(f" {metric}: {value:.4f}")
print("\nเสร็จสิ้นการประเมิน!")
ขั้นตอนที่ 3: รันโค้ดและดูผลลัพธ์
พิมพ์คำสั่งนี้ใน Terminal:
python rag_evaluation.py
คุณจะเห็นผลลัพธ์ประมาณนี้:
==================================================
การประเมินการค้นหา (Retrieval Metrics)
==================================================
precision@1: 1.0000
precision@3: 0.6667
precision@5: 0.6000
recall@1: 0.2500
recall@3: 0.7500
recall@5: 1.0000
==================================================
การประเมินคุณภาพคำตอบ (Generation Quality)
==================================================
ROUGE Scores:
rouge1: 0.6523
rouge2: 0.4521
rougeL: 0.5218
เสร็จสิ้นการประเมิน!
ขั้นตอนที่ 4: ทดสอบกับ API จริง
สร้างไฟล์ใหม่ชื่อ rag_api_test.py สำหรับทดสอบกับเอกสารจริง:
import os
from openai import OpenAI
import json
ตั้งค่า HolySheep API
client = OpenAI(
api_key="YOUR_HOLYSHEEP_API_KEY",
base_url="https://api.holysheep.ai/v1"
)
def retrieve_documents(query, document_corpus, top_k=3):
"""
ค้นหาเอกสารที่เกี่ยวข้องจาก corpus
ใช้ embedding similarity แบบง่าย
"""
# ดึง embedding ของ query
query_embedding = client.embeddings.create(
input=query,
model="text-embedding-3-small"
).data[0].embedding
# ดึง embedding ของทุกเอกสาร
similarities = []
for i, doc in enumerate(document_corpus):
doc_embedding = client.embeddings.create(
input=doc,
model="text-embedding-3-small"
).data[0].embedding
# คำนวณ cosine similarity
similarity = sum(q * d for q, d in zip(query_embedding, doc_embedding))
similarities.append((i, doc, similarity))
# เรียงตามความเหมือน และเลือก top_k
similarities.sort(key=lambda x: x[2], reverse=True)
return similarities[:top_k]
def generate_answer(query, retrieved_docs):
"""สร้างคำตอบจากเอกสารที่ค้นหาได้"""
context = "\n".join([f"- {doc}" for doc in retrieved_docs])
response = client.chat.completions.create(
model="gpt-4.1",
messages=[
{"role": "system", "content": "คุณคือผู้ช่วยตอบคำถามจากเอกสารที่ให้ไว้"},
{"role": "user", "content": f"อ้างอิงจากเอกสารต่อไปนี้:\n{context}\n\nคำถาม: {query}"}
],
temperature=0.3,
max_tokens=500
)
return response.choices[0].message.content
def evaluate_rag_system():
"""ประเมินระบบ RAG แบบครบวงจร"""
# คลังเอกสารตัวอย่าง
documents = [
"กาแฟอาราบิกา มีรสชาติอ่อนนุ่ม ปลูกในพื้นที่สูง",
"กาแฟโรบัสตา มีรสชาติเข้มกว่า คาเฟอีนสูงกว่า",
"วิธีชงกาแฟแบบ French Press: ใส่กาแฟบดหยาบ แล้วเทน้ำร้อน",
"วิธีชงกาแฟแบบ Pour Over: ค่อยๆ เทน้ำร้อนทีละน้อย",
"กาแฟคั่วอ่อน มีกลิ่นหอม ไม่ขมมาก",
"กาแฟคั่วเข้ม มีรสขมมากขึ้น น้ำมันกาแฟเยอะ"
]
test_queries = [
"วิธีชงกาแฟแบบไหนที่ให้รสชาติดี?",
"กาแฟอาราบิกากับโรบัสตาแตกต่างกันยังไง?"
]
print("=" * 60)
print("การประเมินระบบ RAG ด้วย HolySheep API")
print("=" * 60)
for i, query in enumerate(test_queries, 1):
print(f"\nทดสอบที่ {i}: {query}")
print("-" * 50)
# ค้นหาเอกสาร
retrieved = retrieve_documents(query, documents, top_k=3)
print(f"เอกสารที่ค้นหาได้:")
for idx, doc, sim in retrieved:
print(f" {idx+1}. {doc[:30]}... (ความเหมือน: {sim:.3f})")
# สร้างคำตอบ
retrieved_docs = [doc for idx, doc, sim in retrieved]
answer = generate_answer(query, retrieved_docs)
print(f"\nคำตอบที่สร้างได้:\n{answer}")
print("-" * 50)
if __name__ == "__main__":
evaluate_rag_system()
print("\n✅ การประเมินเสร็จสมบูรณ์!")
print("💡 คุณสามารถนำโค้ดนี้ไปดัดแปลงใช้กับเอกสารจริงของคุณได้")
วิธีอ่านผลลัพธ์การประเมิน
หลังจากรันโค้ดแล้ว คุณจะเห็นตัวเลขหลายตัว นี่คือวิธีตีความ:
- Precision สูง (0.8-1.0): ระบบค้นหาได้ผลลัพธ์ที่ถูกต้อง ไม่มีเอกสารแปลกปลอม
- Recall สูง (0.8-1.0): ระบบค้นหาเจอเอกสารที่เกี่ยวข้องเกือบหมด
- ROUGE สูง (0.5 ขึ้นไป): คำตอบที่สร้างมีคำศัพท์ใกล้เคียงกับตัวอย่าง
- ROUGE ต่ำ (ต่ำกว่า 0.3): คำตอบอาจไม่ตรงประเด็น หรือใช้คำอื่นที่มีความหมายเดียวกัน
เคล็ดลับการปรับปรุงระบบ RAG
จากประสบการณ์ที่ผมใช้งานมา มีวิธีที่ช่วยให้ระบบ RAG ทำงานได้ดีขึ้น:
- ใช้ Chunking ที่เหมาะสม: เอกสารควรถูกแบ่งเป็นส่วนๆ ประมาณ 500-1000 ตัวอักษร
- เพิ่ม Metadata: ใส่ข้อมูลเพิ่มเติมเช่น หัวข้อ วันที่ ผู้เขียน ช่วยให้การค้นหาแม่นยำขึ้น
- ทดสอบหลายๆ ครั้ง: ใช้คำถามหลายแบบ แล้วดูว่าเมตริกส์เฉลี่ยเป็นเท่าไหร่
- เลือก Embedding Model ที่เหมาะสม: text-embedding-3-small เป็นตัวเลือกที่คุ้มค่า
ข้อผิดพลาดที่พบบ่อยและวิธีแก้ไข
กรณีที่ 1: "Authentication Error" หรือ "Invalid API Key"
สาเหตุ: API Key ไม่ถูกต้องหรือหมดอายุ
วิธีแก้ไข:
# ตรวจสอบว่าคุณคัดลอก API Key ถูกต้อง
ไม่มีช่องว่าง หรือตัวอักษรพิเศษติดมา
วิธีตรวจสอบ: ลอง print API Key ออกมาดู (เฉพาะตอนทดสอบ)
print(f"API Key length: {len('YOUR_HOLYSHEEP_API_KEY')}")
ถ้ายังไม่ได้ ลองสร้าง API Key ใหม่ที่ https://www.holysheep.ai/register
กรณีที่ 2: "Rate Limit Exceeded" หรือ "Too Many Requests"
สาเหตุ: ส่งคำขอเร็วเกินไป หรือเกินโควต้าที่กำหนด
วิธีแก้ไข:
import time
เพิ่ม delay ระหว่างการเรียก API
def call_api_with_retry(client, max_retries=3, delay=1):
for attempt in range(max_retries):
try:
response = client.chat.completions.create(
model="gpt-4.1",
messages=[{"role": "user", "content": "ทดสอบ"}]
)
return response
except Exception as e:
if "rate limit" in str(e).lower():
wait_time = delay * (2 ** attempt) # Exponential backoff
print(f"รอ {wait_time} วินาที...")
time.sleep(wait_time)
else:
raise e
raise Exception("เกินจำนวนครั้งที่ลองใหม่สูงสุด")
หรือใช้ rate limiter
from collections import defaultdict
request_times = defaultdict(list)
def rate_limited_call(client, max_requests_per_minute=60):
current_time = time.time()
# ลบคำขอที่เก่ากว่า 1 นาที
request_times[client] = [t for t in request_times[client] if current_time - t < 60]
if len(request_times[client]) >= max_requests_per_minute:
sleep_time = 60 - (current_time - request_times[client][0])
time.sleep(sleep_time)
request