การสร้างชุดเครื่องมือประเมินอัตโนมัติ
สร้างกระบวนการประเมินที่ทำซ้ำได้ โดยเรียกใช้ระบบ RAG ทั้งหมดกับชุดทดสอบ คำนวณตัวชี้วัดทั้งหมด และสร้างรายงานเพื่อให้ติดตามการปรับปรุงเมื่อเวลาผ่านไป
การสร้างชุดเครื่องมือประเมินอัตโนมัติ เป็นบทเรียน AI Engineering Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน AI Engineering Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส AI Engineering Academy มีบทเรียนทั้งหมด 4 บทเรียน
โครงทดสอบการประเมินคืออะไร
โครงทดสอบการประเมิน คือกระบวนการอัตโนมัติที่ทำซ้ำได้ ซึ่งเรียกใช้ระบบ RAG ทั้งหมดกับชุดการทดสอบมาตรฐาน คำนวณตัวชี้วัดทั้งหมด และสร้างรายงาน คำสำคัญคือ ทำซ้ำได้ กล่าวคือ ทุกครั้งที่คุณเปลี่ยนกลยุทธ์การแบ่งส่วนข้อมูล โมเดลเวกเตอร์ฝังตัว คำสั่ง หรือ LLM คุณจะเรียกใช้โครงทดสอบเดิมและเปรียบเทียบผลกับค่าพื้นฐาน การทำเช่นนี้เปลี่ยนการพัฒนา RAG จากการปรับไปเรื่อย ๆ ตามความรู้สึกให้เป็นวิศวกรรมที่ขับเคลื่อนด้วยข้อมูล
สถาปัตยกรรมของโครงทดสอบ
โครงทดสอบการประเมินที่ออกแบบมาอย่างดีมีสี่ชั้น ได้แก่ การจัดการข้อมูลการทดสอบ (โหลดและจัดการรุ่นของชุดข้อมูลมาตรฐาน) การเรียกใช้กระบวนการ (ส่งคำถามทดสอบแต่ละข้อผ่านกระบวนการ RAG ทั้งหมด) การคำนวณตัวชี้วัด (คำนวณตัวชี้วัดการค้นคืนและการสร้างคำตอบทั้งหมด) และ การสร้างรายงาน (บันทึกผลพร้อมข้อมูลรุ่นและสร้างส่วนต่างเทียบกับค่าพื้นฐานก่อนหน้า) แต่ละชั้นควรสามารถทดสอบและกำหนดค่าแยกจากกันได้
class RAGEvaluationHarness:
def __init__(self, retriever, llm_client, config):
self.retriever = retriever
self.llm_client = llm_client
self.config = config # chunk_size, top_k, model, threshold, etc.
self.results = []
def run(self, golden_dataset):
for item in golden_dataset:
result = self._evaluate_single(item)
self.results.append(result)
metrics = self._compute_metrics()
self._save_report(metrics)
return metricsเรียกใช้กรณีทดสอบแต่ละรายการ
สำหรับแต่ละคำถามในชุดข้อมูลมาตรฐาน ให้เรียกใช้กระบวนการ RAG ทั้งหมดและบันทึกผลลัพธ์ระหว่างทางทั้งหมด ได้แก่ รหัสและคะแนนของส่วนข้อมูลที่ดึงมา บริบทที่จัดรูปแบบ คำตอบที่สร้างขึ้น และจำนวนโทเคน การจัดเก็บค่าเหล่านี้มีความสำคัญต่อการแก้ไขข้อผิดพลาด เมื่อคำถามได้คะแนนต่ำ คุณจะตรวจสอบได้ทันทีว่าดึงส่วนข้อมูลใดมาและเพราะเหตุใดคำตอบจึงผิด โดยไม่ต้องเรียกใช้กระบวนการที่ใช้ทรัพยากรมากซ้ำ
import time
def _evaluate_single(self, item):
start = time.perf_counter()
query_vector = embed_query(item['question'])
chunks = self.retriever.retrieve(query_vector, top_k=self.config['top_k'])
filtered_chunks = filter_by_score(chunks, self.config['threshold'])
context = format_context(filtered_chunks)
answer_result = generate_answer(item['question'], context, self.llm_client)
latency_ms = (time.perf_counter() - start) * 1000
return {
'question': item['question'],
'expected_answer': item['answer'],
'generated_answer': answer_result['answer'],
'retrieved_chunk_ids': [c['id'] for c in filtered_chunks],
'retrieved_scores': [c['score'] for c in filtered_chunks],
'relevant_chunk_ids': item['relevant_chunk_ids'],
'context_texts': [c['text'] for c in filtered_chunks],
'tokens_used': answer_result['tokens_used'],
'latency_ms': round(latency_ms)
}คำนวณตัวชี้วัดทั้งหมดในการประมวลผลครั้งเดียว
หลังจากรวบรวมผลลัพธ์ของกรณีทดสอบทั้งหมดแล้ว ให้คำนวณชุดตัวชี้วัดทั้งหมดในการประมวลผลผลลัพธ์เพียงรอบเดียว แยกตัวชี้วัดการค้นคืน (คำนวณจากรหัสส่วนข้อมูล) ออกจากตัวชี้วัดการสร้างคำตอบ (คำนวณด้วยการเรียก LLM ผู้ประเมิน) จัดกลุ่มการเรียก LLM ผู้ประเมินเพื่อเพิ่มประสิทธิภาพ โดยรวมการประเมินความยึดมั่นตามข้อมูลแล้วส่งไปพร้อมกันด้วย asyncio แทนการส่งทีละรายการ โปรดบันทึกความคืบหน้า เนื่องจากตัวชี้วัดการสร้างคำตอบอาจใช้เวลาหลายนาทีเมื่อมีกรณีทดสอบมากกว่า 100 รายการ
def _compute_metrics(self):
# Retrieval metrics (no LLM calls needed)
hit_rates = []
mrr_scores = []
for r in self.results:
retrieved = r['retrieved_chunk_ids']
relevant = set(r['relevant_chunk_ids'])
hit = any(rid in relevant for rid in retrieved)
hit_rates.append(1.0 if hit else 0.0)
for rank, rid in enumerate(retrieved, 1):
if rid in relevant:
mrr_scores.append(1.0 / rank)
break
else:
mrr_scores.append(0.0)
metrics = {
'hit_rate_at_5': sum(hit_rates) / len(hit_rates),
'mrr': sum(mrr_scores) / len(mrr_scores),
'mean_latency_ms': sum(r['latency_ms'] for r in self.results) / len(self.results),
'mean_tokens': sum(r['tokens_used'] for r in self.results) / len(self.results)
}
return metricsบันทึกผลลัพธ์พร้อมข้อมูลรุ่น
ควรบันทึกการประเมินทุกครั้งพร้อมข้อมูลกำกับรุ่น เพื่อให้เปรียบเทียบผลระหว่างการกำหนดค่าต่าง ๆ ได้ ให้ระบุค่าแฮชการคอมมิตของโค้ด พารามิเตอร์การกำหนดค่า (โมเดลเวกเตอร์ฝังตัว ขนาดส่วนข้อมูล K เกณฑ์ และโมเดล LLM) เวลา และคำอธิบายการเรียกใช้ที่มนุษย์อ่านเข้าใจ บันทึกผลลัพธ์ในไฟล์ JSONL หรือในตารางฐานข้อมูล วิธีนี้จะสร้างประวัติถาวรว่าระบบของคุณพัฒนามาอย่างไร
import json
import subprocess
from datetime import datetime
def _save_report(self, metrics):
git_hash = subprocess.check_output(
['git', 'rev-parse', '--short', 'HEAD']
).decode().strip()
report = {
'run_id': datetime.utcnow().strftime('%Y%m%d_%H%M%S'),
'git_commit': git_hash,
'config': self.config,
'metrics': metrics,
'n_test_cases': len(self.results),
'timestamp': datetime.utcnow().isoformat()
}
with open('eval_history.jsonl', 'a') as f:
f.write(json.dumps(report) + '\n')
print(f'Saved evaluation run: {report["run_id"]}')
print(json.dumps(metrics, indent=2))เปรียบเทียบกับค่าพื้นฐาน
หลังจากการเรียกใช้แต่ละครั้ง ให้เปรียบเทียบกับค่าพื้นฐานก่อนหน้าโดยอัตโนมัติและทำเครื่องหมายการถดถอย การถดถอยคือกรณีที่ตัวชี้วัดใดลดลงเกินเกณฑ์ที่กำหนด (เช่น 2 จุดเปอร์เซ็นต์) ให้พิมพ์ตารางส่วนต่างที่แสดงการเปลี่ยนแปลงของตัวชี้วัด หากตัวชี้วัดใดถดถอยอย่างมีนัยสำคัญ การเรียกใช้การประเมินควรล้มเหลวด้วยรหัสออกที่ไม่ใช่ศูนย์ ซึ่งจะทำให้กระบวนการ CI/CD ระงับการนำการเปลี่ยนแปลงนั้นไปใช้งาน
def compare_to_baseline(current_metrics, baseline_file='best_eval.json'):
import json
from pathlib import Path
if not Path(baseline_file).exists():
print('No baseline yet. Saving current as baseline.')
Path(baseline_file).write_text(json.dumps(current_metrics, indent=2))
return True
baseline = json.loads(Path(baseline_file).read_text())
regressions = []
print('\nMetric comparison (current vs baseline):')
for metric, current_val in current_metrics.items():
baseline_val = baseline.get(metric, 0)
delta = current_val - baseline_val
status = 'OK' if delta >= -0.02 else 'REGRESSION'
print(f' {metric}: {current_val:.3f} vs {baseline_val:.3f} ({delta:+.3f}) {status}')
if status == 'REGRESSION':
regressions.append(metric)
return len(regressions) == 0ผสานรวมเข้ากับ CI/CD
โครงทดสอบการประเมินมีประสิทธิภาพสูงสุดเมื่อผสานรวมเข้ากับกระบวนการ CI/CD ของคุณ ตั้งค่าให้เรียกใช้โดยอัตโนมัติในคำขอดึงทุกครั้งที่มีการแก้ไขตรรกะการแบ่งส่วนข้อมูล การกำหนดค่าโมเดลเวกเตอร์ฝังตัว แม่แบบคำสั่ง หรือพารามิเตอร์การค้นคืน กระบวนการจะผ่านก็ต่อเมื่อตัวชี้วัดทั้งหมดผ่านเกณฑ์ขั้นต่ำและไม่มีตัวชี้วัดใดถดถอยจากค่าพื้นฐานของสาขาหลัก วิธีนี้ช่วยป้องกันไม่ให้คุณภาพลดลงโดยไม่ตั้งใจขณะนำระบบไปใช้งานจริง
# GitHub Actions workflow (eval.yml)
# on:
# pull_request:
# paths:
# - 'rag/**'
# - 'prompts/**'
# - 'config/**'
# jobs:
# evaluate:
# runs-on: ubuntu-latest
# steps:
# - uses: actions/checkout@v3
# - name: Install dependencies
# run: pip install -r requirements.txt
# - name: Run evaluation harness
# run: |
# python eval/run_harness.py \
# --test-set eval/golden_dataset.json \
# --config config/rag_config.yaml \
# --fail-on-regression
# env:
# OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}สร้างรายงานที่มนุษย์อ่านเข้าใจ
นอกเหนือจากไฟล์ตัวชี้วัดดิบแล้ว ให้สร้างรายงาน HTML หรือ Markdown ที่มนุษย์อ่านเข้าใจเพื่อให้ทีมตรวจสอบในความคิดเห็นของคำขอดึงได้ รายงานควรมีตารางสรุปตัวชี้วัดทั้งหมด รายการกรณีทดสอบที่ไม่ผ่านพร้อมคำถาม คำตอบที่คาดหวัง คำตอบที่สร้างขึ้น และส่วนข้อมูลที่ดึงมา รวมถึงแผนภูมิแนวโน้มที่แสดงตัวชี้วัดจากการเรียกใช้ 10 ครั้งล่าสุด รายงานแบบภาพช่วยให้ผู้มีส่วนได้ส่วนเสียที่ไม่ใช่สายเทคนิคเข้าใจว่าระบบกำลังพัฒนาขึ้นหรือไม่
def generate_markdown_report(metrics, failed_cases, run_id):
lines = [
f'# RAG Evaluation Report — {run_id}\n',
'## Summary Metrics',
'| Metric | Score | Target |',
'|--------|-------|--------|',
f'| Hit Rate@5 | {metrics["hit_rate_at_5"]:.1%} | > 80% |',
f'| MRR | {metrics["mrr"]:.3f} | > 0.70 |',
f'| Mean Latency | {metrics["mean_latency_ms"]:.0f}ms | < 500ms |',
'',
f'## Failed Cases ({len(failed_cases)} failures)'
]
for case in failed_cases[:10]: # show first 10
lines += [
f'**Q:** {case["question"]}',
f'**Expected:** {case["expected_answer"]}',
f'**Generated:** {case["generated_answer"]}\n'
]
return '\n'.join(lines)ติดตามค่าใช้จ่ายต่อการประเมินหนึ่งครั้ง
การเรียกใช้การประเมินมีค่าใช้จ่าย เพราะต้องเรียกใช้เอพีไอเวกเตอร์ฝังตัว เอพีไอ LLM และ LLM ผู้ประเมิน ให้ติดตามค่าใช้จ่ายของการประเมินแต่ละครั้งควบคู่กับตัวชี้วัดคุณภาพ การประเมินที่ครอบคลุม 100 กรณีทดสอบโดยทั่วไปมีค่าใช้จ่าย 0.50–2.00 ดอลลาร์สหรัฐ ขึ้นอยู่กับโมเดลที่ใช้ ใช้โมเดลราคาถูกกว่าสำหรับการเรียกผู้ประเมิน (GPT-4o-mini สำหรับให้คะแนนความยึดมั่นตามข้อมูล) และสงวนโมเดลราคาแพงไว้สำหรับการสร้างคำตอบ ระบุค่าใช้จ่ายโดยประมาณของการเรียกใช้ไว้ในรายงานที่บันทึก เพื่อให้จัดสรรงบประมาณการประเมินในรอบการพัฒนาได้
def estimate_run_cost(results, config):
# Embedding cost
embed_tokens = sum(len(r['question'].split()) * 1.3 for r in results)
embed_cost = (embed_tokens / 1_000_000) * 0.02 # $0.02/1M tokens
# Generation cost
total_gen_tokens = sum(r['tokens_used'] for r in results)
gen_cost = (total_gen_tokens / 1_000_000) * 5.0 # gpt-4o approx
# Judge cost (faithfulness evals)
judge_cost = len(results) * 0.001 # ~$0.001 per eval with gpt-4o-mini
total = embed_cost + gen_cost + judge_cost
print(f'Evaluation cost estimate: ${total:.2f}')
print(f' Embedding: ${embed_cost:.3f}')
print(f' Generation: ${gen_cost:.3f}')
print(f' Judgment: ${judge_cost:.3f}')
return totalกำหนดเวลาการประเมินเพื่อเฝ้าติดตามระบบใช้งานจริง
นอกเหนือจากการประเมินผ่าน CI/CD เมื่อมีการเปลี่ยนแปลงโค้ดแล้ว ให้เรียกใช้โครงทดสอบตามกำหนดเวลาในระบบใช้งานจริง เช่น รายวันหรือรายสัปดาห์ โดยทดสอบกับคำถามจริงของผู้ใช้ที่สุ่มจากบันทึกเหตุการณ์ วิธีนี้ตรวจจับการเปลี่ยนแปลงของข้อมูลได้ เพราะเมื่อคลังเอกสารและรูปแบบคำถามของผู้ใช้เปลี่ยนไป คุณภาพของระบบอาจลดลงได้แม้ไม่มีการเปลี่ยนแปลงโค้ด ตั้งค่าการประเมินรายสัปดาห์ให้สุ่มคำถามล่าสุดของผู้ใช้ 50 ข้อ ประเมินคำถามเหล่านั้น และส่งสรุปคุณภาพไปยังช่อง Slack ของทีมโดยอัตโนมัติ
# Example scheduled evaluation (cron job or scheduled cloud function)
import random
def sample_production_queries(query_log_file, n=50):
with open(query_log_file) as f:
all_queries = [json.loads(line) for line in f]
sample = random.sample(all_queries, min(n, len(all_queries)))
# Convert to golden dataset format (without expected answers — use LLM judge)
return [
{'question': q['user_question'], 'relevant_chunk_ids': []}
for q in sample
]
# Run weekly evaluation against production queries
if __name__ == '__main__':
prod_queries = sample_production_queries('/var/log/rag_queries.jsonl')
harness = RAGEvaluationHarness(retriever, llm_client, config)
metrics = harness.run(prod_queries)
send_slack_digest(metrics)แสดงแนวโน้มของตัวชี้วัดตามเวลา
ตัวเลขดิบในไฟล์ JSONL ตีความได้ยากเมื่อดูอย่างรวดเร็ว ให้สร้างภาพแสดงแนวโน้มอย่างง่ายที่แสดงตัวชี้วัดแต่ละรายการจากการประเมิน 20 ครั้งล่าสุดบนแผนภูมิเส้น ใช้เวลาที่เรียกใช้เป็นแกน x และคะแนนตัวชี้วัดเป็นแกน y วาดเส้นแนวนอนที่เกณฑ์ขั้นต่ำที่ยอมรับได้ เมื่อตัวชี้วัดลดลงต่ำกว่าเส้นเกณฑ์ ปัญหาจะมองเห็นได้ทันทีโดยไม่ต้องอ่านข้อมูลดิบ เครื่องมืออย่าง Matplotlib หรือแดชบอร์ดบนเว็บอย่างง่าย (Grafana, Streamlit) เหมาะสำหรับงานนี้
import json
import matplotlib.pyplot as plt
from pathlib import Path
def plot_metric_trends(history_file='eval_history.jsonl', metric='hit_rate_at_5'):
records = [
json.loads(line)
for line in Path(history_file).read_text().strip().split('\n')
]
timestamps = [r['timestamp'][:10] for r in records[-20:]]
scores = [r['metrics'].get(metric, 0) for r in records[-20:]]
plt.figure(figsize=(10, 4))
plt.plot(timestamps, scores, marker='o', label=metric)
plt.axhline(y=0.80, color='r', linestyle='--', label='Min threshold')
plt.title(f'{metric} over last 20 evaluations')
plt.xticks(rotation=45)
plt.tight_layout()
plt.savefig(f'eval_trend_{metric}.png')
print(f'Saved trend chart for {metric}')ตรวจสอบความเข้าใจอย่างรวดเร็ว
ทดสอบความเข้าใจแนวคิดวิศวกรรม AI จากบทเรียนนี้
สรุปบทเรียน
ในบทเรียนนี้ คุณได้เรียนรู้วิธีจัดโครงสร้างโครงทดสอบการประเมินที่สมบูรณ์ด้วยการจัดการข้อมูลการทดสอบ การเรียกใช้กระบวนการ การคำนวณตัวชี้วัด และการสร้างรายงาน วิธีเปรียบเทียบการเรียกใช้กับค่าพื้นฐานและทำให้ CI/CD ล้มเหลวเมื่อเกิดการถดถอย วิธีสร้างรายงานที่มนุษย์อ่านเข้าใจเพื่อให้ทีมตรวจสอบ และ วิธีเรียกใช้การเฝ้าติดตามระบบใช้งานจริงตามกำหนดเวลาเพื่อตรวจจับการเปลี่ยนแปลงของข้อมูลโดยไม่ต้องแก้ไขโค้ด ขณะนี้คุณมีพื้นฐานที่สมบูรณ์สำหรับสร้างและประเมินระบบ RAG ที่ใช้งานจริงแล้ว
คำถามที่พบบ่อย
บทเรียน “การสร้างชุดเครื่องมือประเมินอัตโนมัติ” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “การสร้างชุดเครื่องมือประเมินอัตโนมัติ” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส AI Engineering Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส AI Engineering Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “การสร้างชุดเครื่องมือประเมินอัตโนมัติ”
สร้างกระบวนการประเมินที่ทำซ้ำได้ โดยเรียกใช้ระบบ RAG ทั้งหมดกับชุดทดสอบ คำนวณตัวชี้วัดทั้งหมด และสร้างรายงานเพื่อให้ติดตามการปรับปรุงเมื่อเวลาผ่านไป คุณปฏิบัติ AI Engineering Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน AI Engineering Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน AI Engineering Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน
บทเรียน “การสร้างชุดเครื่องมือประเมินอัตโนมัติ” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน AI Engineering Academy นี้ได้ไหม
ได้ บทเรียน AI Engineering Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- เหตุใดการประเมินจึงสำคัญต่อ RAG
- ตัวชี้วัดการค้นคืน: อัตราการพบ MRR และ NDCG
- ตัวชี้วัดการสร้างคำตอบ: ความสอดคล้องกับแหล่งข้อมูลและความเกี่ยวข้องของคำตอบ
- การสร้างชุดเครื่องมือประเมินอัตโนมัติ