TT Lab
시작하기
배우기 러닝패스 코스

LLM 엔지니어링

RAG 파이프라인과 평가

TT Lab 에서 이어서 보기

목표

문서를 청크로 나눠 색인하고, 질의로 검색하고, 검색 품질을 지표로 측정하고, 근거 없는 답변과 답할 수 없는 질문을 걸러 내는 RAG 파이프라인 한 벌을 만듭니다.

왜 중요한가

RAG 에서 가장 흔한 실수는 검색 실패와 생성 실패를 구분하지 않는 것입니다. 답변이 이상할 때 프롬프트부터 고치는데, 정답 문서가 애초에 검색되지 않았다면 프롬프트를 아무리 다듬어도 소용이 없습니다.

그래서 이 실습은 검색 지표를 먼저 계산합니다. Recall@3 은 정답 문서가 상위 3개 안에 들어왔는지를, MRR 은 몇 위에 나왔는지를 봅니다. 이 숫자가 낮으면 손볼 곳은 검색기이지 생성기가 아닙니다.

다음으로 근거 판정과 거절 규칙을 만듭니다. 검색 점수가 낮을 때 답하지 않는 것은 기능 부족이 아니라 안전장치입니다. 관련 없는 문서를 근거로 그럴듯한 답을 지어내는 것보다 모른다고 말하는 편이 훨씬 낫습니다.

모델은 쓰지 않습니다. 검색과 평가는 전부 numpy 로 계산할 수 있고, 그 부분이 RAG 품질의 대부분을 결정하기 때문입니다.

단계

작업 디렉터리는 /root/llm 이고, 토큰화 규칙은 앞 실습과 같습니다(소문자로 바꾼 뒤 [가-힣a-z0-9]+).

  1. docs 의 각 body 를 마침표(.)로 나눠 앞뒤 공백을 지우고 빈 조각을 버린 청크를 /root/llm/chunks.tsv 에 저장합니다. 형식은 docs.id<탭>청크번호<탭>본문 이고 청크번호는 문서마다 0부터 시작합니다. 문서 순서대로 씁니다.
  2. 청크 단위 TF-IDF 행렬을 /root/llm/chunk_tfidf.npy 로 저장합니다. 모양은 (청크 수, 항 수)이고 항은 청크 전체에서 모은 어휘를 오름차순 정렬한 것입니다. idf 의 N 은 청크 수이며 공식과 정규화는 앞 실습과 같습니다.
  3. 아래 질의 8개에 대해 상위 3개 청크를 /root/llm/retrieved.tsv 에 질의번호<탭>순위<탭>docs.id<탭>청크번호<탭>점수 로 저장합니다. 총 24줄이고 점수는 소수점 여섯 자리, 동점이면 문서 id 가 작은 쪽, 그다음 청크 번호가 작은 쪽이 앞섭니다.
    1. 인덱스를 만들었는데 왜 순차 스캔인가
    2. 복합 인덱스는 컬럼 순서를 어떻게 정하나
    3. 격리 수준을 올려도 안 잡히는 이상 현상은 무엇인가
    4. 페이지 폴트가 잦으면 왜 느려지나
    5. 가상 주소를 물리 주소로 어떻게 바꾸나
    6. 연결 거부와 타임아웃은 무엇이 다른가
    7. 큰 요청만 멈추는 이유는 무엇인가
    8. GPU 에서 워프란 무엇인가
  4. 위 질의의 정답 문서는 순서대로 24, 25, 27, 12, 11, 19, 17, 6 입니다. Recall@3 과 MRR 을 계산해 /root/llm/metrics.tsv 에 두 줄로 저장합니다. 첫 칸은 recall_at_3 과 mrr, 둘째 칸은 소수점 세 자리 값입니다. Recall@3 은 정답 문서가 상위 3개 안에 있으면 1로 세어 질의 수로 나눈 값이고, MRR 은 정답이 처음 나온 순위의 역수를 평균한 값(없으면 0)입니다.
  5. 1번 질의의 상위 3개 청크 본문을 순위 순서대로 한 줄씩 /root/llm/context.txt 에 저장합니다.
  6. 아래 답변 후보 3개가 5번 컨텍스트에 근거하는지 판정해 /root/llm/grounded.tsv 에 번호<탭>겹침비율<탭>판정 으로 저장합니다. 겹침 비율은 답변 토큰을 중복 없이 모아 그중 컨텍스트 토큰 집합에 들어 있는 비율이고 소수점 세 자리입니다. 0.6 이상이면 grounded, 아니면 hallucinated 입니다.
    1. 인덱스는 값으로 정렬된 구조라 컬럼에 함수를 씌우면 그 정렬이 쓸모없어진다
    2. 옵티마이저가 인덱스를 쓰지 않는 것은 대개 옳은 판단이다
    3. 인덱스를 만들면 어떤 쿼리든 언제나 세 배 빨라진다
  7. 코퍼스에 없는 질의 3개에 대해 최고 점수와 판정을 /root/llm/refusal.tsv 에 번호<탭>최고점수<탭>판정 으로 저장합니다. 점수는 소수점 여섯 자리이고, 0.15 미만이면 refuse, 아니면 answer 입니다.
    1. 김치찌개 맛있게 끓이는 법
    2. 프리미어리그 이번 주 경기 일정
    3. 제주도 항공권 최저가 예약
  8. /root/llm/rag_report.tsv 에 세 줄로 요약을 남깁니다. chunks<탭>청크수, queries<탭>질의수, recall_at_3<탭>값 형식입니다.

참고

문서를 문장 단위 청크로 나누기

마침표로 나눈 뒤 앞뒤 공백을 지우고 빈 조각은 버립니다. 청크 번호는 문서마다 0부터 다시 시작합니다.

청크 단위로 색인 만들기

idf 를 계산할 때 N 이 문서 수가 아니라 청크 수라는 점에 주의하세요.

질의 8개로 상위 3개 청크 검색하기

질의도 같은 방식으로 벡터를 만듭니다. 동점 처리 규칙을 지키세요.

Recall@3 과 MRR 계산하기

정답 문서가 상위 3개 안에 있으면 1, 없으면 0 입니다. MRR 은 정답이 나온 순위의 역수를 평균합니다.

컨텍스트 조립하기

1번 질의의 검색 결과를 순위 순서대로 한 줄씩 이어 붙입니다.

답변이 컨텍스트에 근거하는지 판정하기

답변 토큰을 중복 없이 모아 컨텍스트에 있는 비율을 셉니다. 기준값을 넘는지로 판정합니다.

코퍼스 밖 질문 거절하기

최고 점수가 임계값 미만이면 답하지 않는다고 표시합니다. 점수 자체도 기록해야 합니다.

요약 보고서 만들기

청크 수, 질의 수, Recall@3 세 가지를 이름과 값의 쌍으로 남깁니다.