RAG2026-5일36차시 · 평가 실습7 / 18← 이전목차다음 →MetaContents

36차시. 평가 실습

4. 실습 ② — 답변 평가

출처: 원본 PDF 36차시_평가실습.pdf 8쪽 · 쪽 그림 8쪽

LLM 심판을 씁니다. 26차시 Verifier와 비슷하지만 평가 전용 프롬프트를 만듭니다.

📝 eval/prompts.py

Python
from langchain_core.prompts import ChatPromptTemplate

# ── Faithfulness: 근거 충실성 ──
FAITH_PROMPT = ChatPromptTemplate.from_template(
    "당신은 평가자입니다. 답변의 각 주장이 근거 자료에 "
    "있는지 확인하고 JSON만 출력하십시오.\n\n"
    "[근거]\n{context}\n\n"
    "[답변]\n{answer}\n\n"
    "평가 방법\n"
    "1. 답변을 사실 주장 단위로 나눕니다\n"
    "2. 각 주장이 근거에 있으면 지지, 없으면 미지지로 셉니다\n"
    "3. 문장을 잇는 표현이나 일반 안내는 세지 않습니다\n\n"
    '{{"supported": 3, "unsupported": 1, "note": "수수료 언급이 근거에 없음"}}'
)

# ── Correctness: 정답 일치 ──
CORRECT_PROMPT = ChatPromptTemplate.from_template(
    "당신은 채점자입니다. 시스템 답변이 모범 답안과 "
    "같은 내용인지 판정하고 JSON만 출력하십시오.\n\n"
    "[질문] {question}\n"
    "[모범 답안] {gold}\n"
    "[시스템 답변] {answer}\n\n"
    "채점 기준\n"
    "- 표현이 달라도 핵심 사실이 같으면 correct: true\n"
    "- 숫자·기간·조건이 다르면 false\n"
    "- 모범 답안이 '확인할 수 없습니다'인데 시스템이 "
    "구체적으로 답했다면 false (환각)\n"
    "- 길이나 문체는 평가하지 않습니다\n\n"
    '{{"correct": true, "reason": "7일 이내로 일치"}}'
)

📝 eval/generation.py

Python
import json, re
import config
from eval.prompts import FAITH_PROMPT, CORRECT_PROMPT
from nodes.generator import build_context
from langchain_openai import ChatOpenAI
from langchain_core.output_parsers import StrOutputParser
# ★ 생성과 다른 모델로 자기 편향을 줄인다
_judge_llm = ChatOpenAI(model=config.EVAL_MODEL, temperature=0)
_faith   = FAITH_PROMPT   | _judge_llm | StrOutputParser()
_correct = CORRECT_PROMPT | _judge_llm | StrOutputParser()

def _parse(raw, default):
    m = re.search(r"\{.*\}", raw, re.S)
    if not m:
        return default
    try:
        return json.loads(m.group())
    except json.JSONDecodeError:
        return default

def eval_faithfulness(answer, docs):
    if not docs:
        return None                     # 근거가 없으면 평가 불가
    v = _parse(_faith.invoke({"context": build_context(docs),
                              "answer": answer}),
               {"supported": 0, "unsupported": 1})
    s, u = v.get("supported", 0), v.get("unsupported", 0)
    return s / (s + u) if (s + u) else 1.0

def eval_correctness(question, gold, answer):
    v = _parse(_correct.invoke({"question": question, "gold": gold,
                                "answer": answer}),
               {"correct": False, "reason": "판정 실패"})
    return bool(v.get("correct")), v.get("reason", "")
← 이전 절36차시 · 3. 검색 평가 결과 읽기다음 절 →36차시 · 5. 실습 ③ — 통합 평가 실행