LLM 엔지니어링 · RAG 구조 · 실습
RAG 파이프라인과 평가
목표
문서를 청크로 나눠 색인하고, 질의로 검색하고, 검색 품질을 지표로 측정하고, 근거 없는 답변과 답할 수 없는 질문을 걸러 내는 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<탭>값 형식입니다.
참고
- 청크 색인은 문서 색인보다 항 수가 비슷해도 행 수가 훨씬 많아집니다. 모양을 먼저 확인하세요.
- 점수는 정규화된 벡터의 내적, 즉 코사인 유사도입니다.
- 흔한 실수 1: idf 를 문서 수 기준으로 계산하면 값이 전부 어긋납니다. 청크 수를 쓰세요.
- 흔한 실수 2: 겹침 비율의 분모는 답변 토큰의 중복 없는 개수입니다.
단계 8개
- 문서를 문장 단위 청크로 나누기
- 청크 단위로 색인 만들기
- 질의 8개로 상위 3개 청크 검색하기
- Recall@3 과 MRR 계산하기
- 컨텍스트 조립하기
- 답변이 컨텍스트에 근거하는지 판정하기
- 코퍼스 밖 질문 거절하기
- 요약 보고서 만들기