자동화된 평가 도구 구축
전체 RAG 시스템을 테스트 세트에 대해 실행하고 모든 지표를 계산하며 보고서를 생성하는 반복 가능한 평가 파이프라인을 만들어 시간에 따른 개선을 추적합니다.
자동화된 평가 도구 구축은(는) CoddyKit의 무료 AI Engineering Academy 강의입니다. 이것은 4개 중 4번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 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 처리 흐름을 실행하고 모든 중간 출력을 수집하십시오. 여기에는 검색된 청크 ID와 점수, 형식이 지정된 문맥, 생성된 답변, 토큰 수가 포함됩니다. 이러한 중간 값을 저장하는 것은 실패를 디버깅하는 데 필수적입니다. 질문의 점수가 낮을 때 비용이 큰 처리 흐름을 다시 실행하지 않고도 정확히 어떤 청크가 검색되었고 답변이 왜 틀렸는지 확인할 수 있기 때문입니다.
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)
}한 번의 처리로 모든 지표 계산하기
모든 시험 사례의 출력을 수집한 후 결과를 한 번만 순회하여 전체 지표를 계산하십시오. 청크 ID에서 계산하는 검색 지표와 평가자 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버전 정보와 함께 결과 저장하기
구성에 따른 결과를 비교할 수 있도록 모든 평가 실행을 버전 메타데이터와 함께 저장해야 합니다. 코드의 git 커밋 해시, 구성 매개변수(임베딩 모델, 청크 크기, K, 임계값, LLM 모델), 타임스탬프, 사람이 읽을 수 있는 실행 설명을 포함하십시오. 결과는 JSON Lines 파일이나 데이터베이스 테이블에 저장합니다. 이렇게 하면 시스템이 어떻게 발전해 왔는지 영구적인 이력이 남습니다.
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%포인트)보다 많이 하락하는 경우입니다. 지표 변경 사항을 보여 주는 차이 표를 출력합니다. 어떤 지표든 크게 하락하면 평가 실행이 0이 아닌 종료 코드로 실패해야 하며, 그러면 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) == 0CI/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)평가 실행당 비용 추적하기
평가 실행에는 비용이 듭니다. 임베딩 API, LLM API, 평가자 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 시스템을 구축하고 평가하는 데 필요한 기반을 모두 갖추었습니다.
자주 묻는 질문
“자동화된 평가 도구 구축” 강의는 무료인가요?
네 — “자동화된 평가 도구 구축” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 AI Engineering Academy 강의 전체를 잠금 해제할 수 있습니다. AI Engineering Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
“자동화된 평가 도구 구축”에서 뭘 배우나요?
전체 RAG 시스템을 테스트 세트에 대해 실행하고 모든 지표를 계산하며 보고서를 생성하는 반복 가능한 평가 파이프라인을 만들어 시간에 따른 개선을 추적합니다. 브라우저에서 직접 실행하는 실습 코드로 AI Engineering Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.
AI Engineering Academy을(를) 시작하는 데 경험이 필요한가요?
사전 경험은 필요하지 않습니다. CoddyKit의 AI Engineering Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 4번째 강의입니다.
“자동화된 평가 도구 구축” 강의는 얼마나 걸리나요?
대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.
이 AI Engineering Academy 강의에서 코드를 작성하고 실행할 수 있나요?
네. 모든 AI Engineering Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.