14차시. 성능 비교 실습
실습 1 — 성능 비교 실습 실습 따라 하기
관련 수업 자료: 14차시 「3. 실습 ① — 자동 측정 도구 만들기」(7쪽) · 실습 코드 07/prepare.py, 11/retriever.py, 13/prompts.py
이 실습은 교안 해설(14_성능비교실습.md)의 실습 순서를 옮긴 것입니다. OpenAI 임베딩이나 채팅 모델을 부르는 파일은 .env 에 API 키가 있어야 돌아갑니다. 키가 없으면 실행 결과 샘플로 출력 모양을 확인합니다.
수업 자료와 이어지는 곳
| 실습 코드 | 원본 PDF | 이어지는 내용 |
|---|---|---|
07/prepare.py | 7쪽 | 14차시 「3. 실습 ① — 자동 측정 도구 만들기」 아래에 실었습니다 |
11/retriever.py | 7쪽 | 14차시 「3. 실습 ① — 자동 측정 도구 만들기」 아래에 실었습니다 |
13/prompts.py | - | 원본 PDF 에 짝이 되는 쪽이 없어 이 페이지 아래에 실었습니다 |
실행 흐름
기준선 → chunk만
chunk만 → k만
k만 → 프롬프트만
프롬프트만 → 정답률 토큰 시간실습 순서
12차시에서 모은 질문 20개(정상, 표현 변경, 없는 내용, 복합)를 고정합니다. 설정 한 칸만 바꾼 뒤 맞은 개수와 평균 응답 시간을 표에 적습니다. 왜 TOP_K가 그 값인지 한 줄을 같이 적습니다.
스스로 확인
- 한 번에 두 값을 바꾸면 왜 결론이 안 나는가?
- 같은 질문 세트를 유지해야 하는 이유를 아는가?
- 정답률이 같아도 토큰이 다르면 어느 쪽을 고르는가?
이어지는 실습 코드
실습 코드 · 13/prompts.py
실습 코드: 실습/src/13/prompts.py · 원본 PDF 에 같은 이름의 쪽이 없어 여기에 실었습니다.
이 파일은 13차시 「4. 실습 ① — 프롬프트 파일 분리」에 주석과 함께 전체가 실려 있습니다. 여기서는 이 차시에서 보는 부분의 해설과 실행 결과만 옮깁니다.
코드 해설
답변 규칙을 조금씩 바꾼 prompt 틀을 모아 둠. 실행해도 출력은 없습니다. 입력은 없음 (다른 파일이 이 틀을 import)이고, 출력은 없음입니다.
주석에 적힌 흐름입니다.
문자열 틀 -> ChatPromptTemplate -> PROMPTS 딕셔너리코드 앞에서 고정해 두는 말입니다.
- 25차시 이후 틀은 같은 파일에 정의만 되어 있고 PROMPTS에는 넣지 않습니다. generator2.py는 RETRY_PROMPT를 직접 가져옵니다.
- prompt: 모델에게 주는 지시문 틀. {context}는 검색된 자료, {question}은 질문입니다.
- citation: 문장 끝에 붙이는 [1] 같은 근거 번호. V2·V3 규칙 4번이 이것을 요구합니다.
함수로 나누지 않고 위에서 아래로 실행됩니다.
RAG_PROMPT_V1 = ChatPromptTemplate.from_template(— ── V1: 최소 버전 (비교 대조군) ── 자료와 질문만 넣고, 추측 금지·근거 번호 규칙은 없습니다.RAG_PROMPT_V2 = ChatPromptTemplate.from_template(— ── V2: 규칙 강화 버전 (권장) ── 자료 밖이면 전부 '자료에서 확인할 수 없습니다'라고 하게 합니다.RAG_PROMPT_V3 = ChatPromptTemplate.from_template(— ── V3: 부분 답변 허용 버전 (과잉 거부 방지) ── 질문의 일부만 자료에 있으면 그 부분만 답하게 합니다.PROMPTS = {"v1": RAG_PROMPT_V1,— 이름표로 세 틀을 고릅니다. compare_prompt.py가 이 딕셔너리를 순회합니다.RETRY_PROMPT = ChatPromptTemplate.from_template(— 25차시에 추가. 직전 답이 반려된 이유를 넣고 다시 쓰게 하는 틀입니다. generator2.py가 이 변수를 직접 가져오고, 등록 줄은 주석인 채로 둡니다.JUDGE_PROMPT = ChatPromptTemplate.from_template(— 26차시에 추가. 답을 새로 만들지 않고, 근거에 있는지·질문에 맞는지 판정만 하게 합니다. 중괄호를 두 번 쓴 부분은 format 빈칸이 아니라 출력에 남을 JSON 예시입니다.CLASSIFY_PROMPT = ChatPromptTemplate.from_template(— 29차시 추가 인사, 계산, 문서와 무관한 질문, 문서 질문을 한 단어로만 고르게 합니다.REWRITE_PROMPT = ChatPromptTemplate.from_template(— 30차시 추가 검색이 실패했을 때 같은 뜻의 짧은 검색어로 질문을 다시 쓰게 합니다.
파일 맨 아래 실행 결과 샘플 주석은 실행되지 않습니다. 화면 출력은 다음 절에 다시 적어 두었습니다.
코드 설명
make_store의_cache딕셔너리는(chunk_size, overlap)묶음을 키로 인덱스를 보관합니다. k나 프롬프트만 바꾸는 실험에서는 인덱스를 다시 만들지 않으므로 임베딩 비용이 들지 않습니다.tokens += len(ctx) // 2는 한글 두 글자를 1토큰으로 어림한 값입니다. 정확한 토큰 수가 아니고 자료(context) 길이만 셉니다. 설정끼리 견주는 용도로만 쓰십시오.run()은 이름, 정답률, 평균 토큰, 실패한 질문을 딕셔너리로 돌려줍니다. 8절의final["fails"]처럼 반환값을 받아 두어야 남은 실패를 다시 분석할 수 있습니다.f"{rate:>3.0f}%"의>3은 세 칸 오른쪽 정렬,.0f는 소수점 없이라는 뜻입니다. 줄마다 칸을 맞춰야 실험 결과를 한눈에 견줄 수 있습니다.- 이 차시는 전용 실습 파일이 없습니다. benchmark.py가 부르는
PROMPTS[version]은 13차시 prompts.py의 딕셔너리이고, v1·v2·v3 세 키만 있습니다.