질의응답 시스템(Question Answering Systems)

세 가지 시스템이 현대 질의응답(Question Answering; QA)을 만들었습니다. 추출형(Extractive)은 답이 되는 구간(span)을 찾고, 검색 증강형(Retrieval-Augmented)은 문서(document)에 근거(grounding)해 답하며, 생성형(Generative)은 답(answer)을 직접 만들어 냅니다. 오늘날의 AI 어시스턴트는 모두 이 세 가지의 혼합입니다.

유형: Build 언어: Python 선수 강의: Phase 5 · 11 (Machine Translation), Phase 5 · 10 (Attention Mechanism) 예상 시간: 약 75분

학습 목표

  • 추출형(Extractive) QA, 오픈 도메인(open-domain) QA, 생성형(Generative) QA의 차이를 설명합니다.
  • 검색 증강(Retrieval-Augmented) QA와 RAG의 검색기(retriever)-읽기 모델(reader) 구조를 이해합니다.
  • 정확 일치(Exact Match; EM), 토큰 단위 F1(token-level F1), 인용 정확도(citation accuracy), 거절 보정(refusal calibration)을 구분합니다.
  • RAGAS의 신뢰성(faithfulness), 답변 적합성(answer relevance), 문맥 정밀도/재현율(context precision/recall)을 이해합니다.

문제

사용자가 "When did the first iPhone launch?"라고 물으면 사용자는 "June 29, 2007."이라는 답을 기대합니다. "Apple's history is long and varied." 같은 두루뭉술한 답이 아니고, 아무 문장도 없이 "2007"만 덩그러니 놓인 답도 아닙니다. 직접적이고, 근거가 있으며, 정확한 답을 기대하는 것입니다.

지난 10년 동안 세 가지 아키텍처(architecture)가 QA 분야를 지배해 왔습니다.

  • 추출형 QA(Extractive QA). 질문(question)과 답을 포함하고 있다고 알려진 단락(passage)이 주어졌을 때, 그 단락 안에서 답이 되는 구간(answer span)의 시작 인덱스와 끝 인덱스를 찾아냅니다. SQuAD가 대표적인 벤치마크(canonical benchmark)입니다.
  • 오픈 도메인 QA(Open-domain QA). 단락이 주어지지 않습니다. 먼저 관련 있는 단락을 검색(retrieve)한 뒤, 거기서 답을 추출하거나 생성합니다. 오늘날 모든 RAG 파이프라인의 기반입니다.
  • 생성형/닫힌 책 QA(Generative / Closed-book QA). 대형 언어 모델(Large Language Model; LLM)이 자신의 파라미터에 저장된 기억(parametric memory)에서 직접 답합니다. 검색 단계가 없으므로 추론(inference)은 가장 빠르지만, 사실 신뢰도는 가장 낮습니다.

2026년의 추세는 혼합형(hybrid)입니다. 가장 적절한 단락 몇 개를 먼저 검색하고, 생성 모델이 그 단락에 근거(grounded)해서 답하도록 프롬프트(prompt)를 줍니다. 이것이 RAG이며, 14강에서 검색 쪽을 깊이 다룹니다. 이번 강의에서는 QA 쪽을 만듭니다.

사전 테스트

2문제 · 이 강의를 시작하기 전에 얼마나 알고 있는지 확인해보세요

1.규제 준수(compliance) 팀이 감사(auditor) 질문에 답할 때 규제 문서의 정확한 문장을 인용해야 합니다. 어떤 QA 아키텍처가 가장 적합하고, 그 이유는 무엇인가요?

2.검색 증강(Retrieval-Augmented) QA 시스템이 검색기(retriever)와 읽기 모델(reader)을 분리하는 이유는 무엇인가요?

0/2 답변 완료

개념

Extractive QA find answer span in given passage question: "When was iPhone released?" context: [long passage] BERT / RoBERTa + span head predict (start_idx, end_idx) "June 29, 2007" verbatim span, never invents SQuAD-style. never hallucinates. needs passage + question together. fails on unanswerable questions unless SQuAD 2.0-trained. RAG retrieve passages, then answer question only retriever BM25 + dense + rerank top-k passages (grounding context) reader (LLM or extractive) grounded answer + citations Generative (closed-book) answer from model weights question decoder-only LLM (GPT, Claude, Llama) parametric memory only free-form answer (may hallucinate) good on common knowledge. bad on rare / recent facts. needs RAG for reliability.

추출형(Extractive). 질문과 단락을 함께 트랜스포머(Transformer; BERT 계열)에 입력하고, 답의 시작 토큰(start token) 인덱스와 끝 토큰(end token) 인덱스를 예측하는 두 개의 헤드(head)를 학습시킵니다. 손실 함수는 유효한 위치 전반에 대한 교차 엔트로피(cross-entropy)입니다. 출력은 단락 안에서 잘라낸 구간(span)이며, 구조상 환각(hallucination)을 일으키지 않습니다. 다만 단락이 답을 담고 있지 않으면 답을 할 수 없다는 한계도 구조적으로 가지고 있습니다.

검색 증강(Retrieval-Augmented; RAG). 두 단계로 이루어집니다. 먼저 검색기(retriever)가 말뭉치(corpus)에서 상위 top-k개의 단락을 찾고, 그다음 읽기 모델(reader; 추출형 또는 생성형)이 그 단락들을 사용해 답을 만듭니다. 검색기와 읽기 모델을 분리한 덕분에 각각을 독립적으로 학습하고 평가할 수 있습니다. 현대적인 RAG는 그 사이에 재순위 모델(reranker)을 추가하는 경우가 많습니다.

생성형(Generative). 디코더 전용 LLM(GPT, Claude, Llama)이 학습된 가중치(learned weights)만 가지고 답합니다. 검색 단계가 없습니다. 흔한 일반 지식에는 매우 강하지만, 드물거나 최근에 일어난 사실(rare/recent facts)에서는 치명적으로 약합니다. 환각이 발생하는 빈도는 해당 사실이 사전 학습 데이터(pretraining data)에 등장한 빈도와 반비례 관계를 보입니다.

직접 만들기

Step 1: 사전 학습된 모델로 추출형 QA 구현

from transformers import pipeline

qa = pipeline("question-answering", model="deepset/roberta-base-squad2")

passage = (
    "Apple Inc. released the first iPhone on June 29, 2007. "
    "The device was announced by Steve Jobs at Macworld in January 2007."
)
question = "When was the first iPhone released?"

answer = qa(question=question, context=passage)
print(answer)
{'score': 0.98, 'start': 57, 'end': 70, 'answer': 'June 29, 2007'}

deepset/roberta-base-squad2는 답할 수 없는 질문(unanswerable question)까지 포함하는 SQuAD 2.0으로 학습된 모델입니다. 기본 설정에서는 question-answering 파이프라인이 모델의 널 점수(null score)가 이기더라도 가장 점수가 높은 구간을 그대로 반환합니다. 즉, 자동으로 빈 답을 돌려주지는 않습니다. 명시적으로 "답할 수 없음"을 표현하게 하려면 파이프라인 호출 시 handle_impossible_answer=True를 전달해야 합니다. 이때 파이프라인은 널 점수가 모든 구간 점수보다 클 때만 빈 답을 반환합니다. 어떤 경우든 score 필드는 항상 함께 확인해야 합니다.

Step 2: 검색 증강 파이프라인(스케치)

from sentence_transformers import SentenceTransformer
import numpy as np

encoder = SentenceTransformer("sentence-transformers/all-MiniLM-L6-v2")

corpus = [
    "Apple Inc. released the first iPhone on June 29, 2007.",
    "Macworld 2007 featured the iPhone announcement by Steve Jobs.",
    "Android launched in 2008 as Google's mobile operating system.",
    "The first iPod was released in 2001.",
]
corpus_embeddings = encoder.encode(corpus, normalize_embeddings=True)


def retrieve(question, top_k=2):
    q_emb = encoder.encode([question], normalize_embeddings=True)
    sims = (corpus_embeddings @ q_emb.T).squeeze()
    order = np.argsort(-sims)[:top_k]
    return [corpus[i] for i in order]


def answer(question):
    passages = retrieve(question, top_k=2)
    combined = " ".join(passages)
    return qa(question=question, context=combined)


print(answer("When was the first iPhone released?"))

두 단계 파이프라인입니다. 밀집 검색기(dense retriever; Sentence-BERT)가 의미적 유사도(semantic similarity)로 관련 단락을 찾아 주고, 추출형 읽기 모델(extractive reader; RoBERTa-SQuAD)이 그렇게 합쳐진 상위 단락에서 답이 되는 구간을 뽑습니다. 작은 말뭉치에는 이대로도 잘 동작하지만, 백만 문서 규모의 말뭉치에서는 FAISS나 벡터 데이터베이스(vector database)를 사용해야 합니다.

Step 3: RAG로 생성형 QA 구현

def rag_generate(question, llm):
    passages = retrieve(question, top_k=3)
    prompt = f"""Context:
{chr(10).join('- ' + p for p in passages)}

Question: {question}

Answer using only the context above. If the context does not contain the answer, say "I don't know."
"""
    return llm(prompt)

프롬프트 패턴(prompt pattern)이 중요합니다. 문맥에 근거해서 답하라고 명시적으로 지시하고, 문맥에 답이 없으면 "I don't know"라고 답하도록 시키는 것만으로도, 단순한(naive) 프롬프팅 대비 환각률(hallucination rate)이 40~60% 줄어듭니다. 더 정교한 패턴은 여기에 인용(citation), 신뢰도 점수(confidence score), 구조화된 추출(structured extraction)을 덧붙입니다.

Step 4: 실제 상황을 반영하는 평가

SQuAD는 정확 일치(Exact Match; EM)토큰 단위 F1(token-level F1)을 사용합니다. EM은 정규화(소문자화, 구두점 제거, 관사 제거) 이후의 엄격한 일치 여부이며, 예측이 정확히 일치하지 않으면 0점입니다. F1은 예측과 정답 사이의 토큰 겹침(token overlap)으로 계산하여 부분 점수를 줍니다. 두 지표 모두 다른 표현(paraphrase)에 박합니다. 예를 들어 "June 29, 2007"과 "June 29th, 2007"은 보통 EM이 0이지만(서수 표현이 정규화를 깨뜨립니다), 겹치는 토큰 덕분에 F1은 꽤 높게 나옵니다.

운영 환경(production)의 QA에서는 다음을 함께 봅니다.

  • 답변 정확도(Answer accuracy). 지표가 의미적 동등성(semantic equivalence)을 충분히 포착하지 못하므로, LLM이 판정(LLM-judged)하거나 사람이 판정(human-judged)합니다.
  • 인용 정확도(Citation accuracy). 인용된 단락이 실제로 답을 뒷받침하는지 봅니다. 생성된 인용과 검색된 단락 사이의 문자열 일치(string match)로 자동 확인하기 쉽습니다.
  • 거절 보정(Refusal calibration). 검색된 단락 안에 답이 없을 때, 시스템이 정확히 "I don't know"라고 말하는지 봅니다. 잘못된 확신율(false confidence rate)을 측정합니다.
  • 검색 재현율(Retrieval recall). 읽기 모델을 평가하기 전에, 검색기가 정답 단락을 상위 top-k에 끌어올렸는지 먼저 측정합니다. 빠진 단락을 읽기 모델이 메워 줄 수는 없습니다.

RAGAS: 2026년의 운영 평가 프레임워크

RAGAS는 RAG 시스템 전용으로 설계된 평가 프레임워크이며, 2026년 기준 사실상의 기본 선택지입니다. 골드 참조(gold reference) 없이도 다음 네 가지 차원을 점수로 매깁니다.

  • 신뢰성(Faithfulness). 답변 안의 각 주장(claim)이 검색된 문맥(retrieved context)에서 나온 것인지 봅니다. 자연어 추론(Natural Language Inference; NLI) 기반의 함의(entailment)로 측정하며, 가장 핵심적인 환각 지표(primary hallucination metric)입니다.
  • 답변 적합성(Answer relevance). 답변이 질문에 실제로 응답하는지 봅니다. 답변으로부터 가상의 질문(hypothetical question)을 생성한 뒤, 그것이 원래 질문과 얼마나 가까운지를 비교합니다.
  • 문맥 정밀도(Context precision). 검색된 청크(chunk) 중 실제로 관련 있는 것의 비율입니다. 낮으면 프롬프트에 잡음(noise)이 많이 섞여 있다는 뜻입니다.
  • 문맥 재현율(Context recall). 답하는 데 필요한 정보가 검색 결과 집합에 모두 들어 있는지 봅니다. 낮으면 읽기 모델이 잘 답할 수 없습니다.

참조 없이도 점수를 매길 수 있다는 점 덕분에, 정답이 정리되어 있지 않은 실제 운영 트래픽(live production traffic)에서도 평가가 가능합니다. 정확 일치 지표가 무의미한 개방형 질문에는 LLM을 판정자로 사용하는 LLM-as-judge 방식을 위에 얹어 보강합니다.

pip install ragas로 설치하고 자신의 검색기와 읽기 모델을 연결하면, 질의(query)마다 네 개의 스칼라(scalar) 점수가 나오고 회귀(regression) 발생 시 알림(alert)을 걸 수 있습니다.

사용하기

2026년의 표준 스택입니다.

활용 사례권장 구성
단락이 주어졌을 때 답 구간 찾기deepset/roberta-base-squad2
고정된 말뭉치에서 닫힌 책 방식은 허용 불가RAG: 밀집 검색기(dense retriever) + LLM 읽기 모델
문서 저장소(document store) 위의 실시간 QA혼합 검색(BM25 + 밀집) + 재순위 모델 기반 RAG (14강)
후속 질문이 있는 대화형 QA대화 이력(conversation history)을 가진 LLM + 매 턴 RAG
사실성이 매우 중요한 규제 영역권위 있는 말뭉치 기반의 추출형 QA. 생성형 단독 사용은 금지

추출형 QA는 RAG와 LLM이 더 많은 경우를 처리하게 되면서 2026년에는 한물간 느낌이 있습니다. 그러나 법률 리서치, 규제 준수(regulatory compliance), 감사 도구(audit tool)처럼 본문을 문자 그대로 인용해야 하는 맥락에서는 여전히 실서비스에 사용됩니다.

산출물 만들기

outputs/skill-qa-architect.md로 저장합니다.

---
name: qa-architect
description: Choose QA architecture, retrieval strategy, and evaluation plan.
version: 1.0.0
phase: 5
lesson: 13
tags: [nlp, qa, rag]
---

Given requirements (corpus size, question type, factuality constraint, latency budget), output:

Guide the student in Korean.

1. Architecture. Extractive, RAG with extractive reader, RAG with generative reader, or closed-book LLM. One-sentence reason.
2. Retriever. None, BM25, dense (name the encoder), or hybrid.
3. Reader. SQuAD-tuned model, LLM by name, or "domain-fine-tuned DistilBERT."
4. Evaluation. EM + F1 for extractive benchmarks; answer accuracy + citation accuracy + refusal calibration for production. Name what you are measuring and how you are measuring it.

Refuse closed-book LLM answers for regulatory or compliance-sensitive questions. Refuse any QA system without a retrieval-recall baseline (you cannot evaluate the reader without knowing the retriever surfaced the right passage). Flag questions that require multi-hop reasoning as needing specialized multi-hop retrievers like HotpotQA-trained systems.

연습문제

  1. 쉬움. 위에 나온 SQuAD 추출형 파이프라인을 위키피디아(Wikipedia) 단락 10개에 적용합니다. 손으로 질문 10개를 만들어 정답률을 측정합니다. 단락과 질문이 깔끔하다면 10개 중 7~9개는 맞아야 합니다.
  2. 중간. 거절 분류기(refusal classifier)를 추가합니다. 검색기의 최상위 점수가 임곗값(예: 코사인 0.3) 아래로 내려가면 읽기 모델을 호출하지 않고 "I don't know"를 반환하게 합니다. 임곗값은 별도 검증 셋(held-out set)에서 튜닝합니다.
  3. 어려움. 원하는 주제로 1만 문서(10,000-document) 규모의 말뭉치를 만들고 그 위에 RAG 파이프라인을 구축합니다. BM25와 밀집 검색을 결합한 혼합 검색에 RRF(Reciprocal Rank Fusion) 결합을 적용합니다(14강 참고). 혼합 검색 단계가 있을 때와 없을 때의 답변 정확도를 비교하고, 어떤 질문 유형이 가장 큰 이득을 얻는지 정리합니다.

핵심 용어

용어흔한 설명실제 의미
추출형 QA(Extractive QA)답 구간 찾기주어진 단락 안에서 답의 시작·끝 인덱스를 예측합니다.
오픈 도메인 QA(Open-domain QA)말뭉치 위에서 하는 QA단락이 주어지지 않으므로 검색 후 답해야 합니다.
RAG검색 후 생성검색 증강 생성. 검색기 + 읽기 모델 파이프라인입니다.
SQuAD대표 벤치마크Stanford Question Answering Dataset. EM과 F1을 사용합니다.
환각(Hallucination)지어낸 답검색된 문맥이 뒷받침하지 않는 읽기 모델의 출력입니다.
거절 보정(Refusal calibration)모를 때 입 닫기답할 수 없을 때 시스템이 정확히 "I don't know"라고 말하는 능력입니다.

더 읽을거리

실습 코드

이 강의의 실습 코드 1개

main
Code

산출물

이 강의에서 생성된 프롬프트, 스킬, 코드 산출물 1개

qa-architect

Choose QA architecture, retrieval strategy, and evaluation plan.

Skill

확인 문제

3문제 · 모두 맞추면 완료 표시가 가능합니다

1.QA 시스템이 'June 29, 2007'을 예측했는데 정답은 'June 29th, 2007'입니다. 정확 일치(Exact Match; EM) 점수가 0입니다. 이 결과가 EM 지표에 대해 드러내는 점은 무엇인가요?

2.RAGAS 평가에서 신뢰성(faithfulness) 점수는 답변의 각 주장(claim)이 검색된 문맥(context)에서 함의(entailment)되는지를 측정합니다. 이것이 핵심 환각(hallucination) 지표로 간주되는 이유는 무엇인가요?

3.RAG 시스템의 답변 정확도는 높은데 거절 보정(refusal calibration)이 낮습니다. 실질적인 위험은 무엇인가요?

0/3 답변 완료

추가 문제 풀기

AI가 강의 내용을 바탕으로 새로운 문제를 생성합니다