Jump to content

LLM-as-a-Judge: 하이퍼클로바X 추론 모델(HCX-007)로 성능 평가하기


Recommended Posts

 

image.png.80db55005415c4f957427c5e2d4a37bf.png

LLM Evaluation, 왜 중요한가?

LLM은 이제 단순한 텍스트 생성기를 넘어, RAG(Retrieval-Augmented Generation)나 Fine-tuning과 같은 기법을 통해 실제 서비스와 업무 환경에 맞게 커스터마이징되고 있습니다. 하지만 새로운 파이프라인을 설계하거나 파인튜닝을 적용했다고 해서, 성능이 항상 향상되는 것은 아닙니다. 실제로 개선 여부를 객관적으로 검증하는 일은 여전히 쉽지 않죠. 기존 벤치마크 점수로는 실제 현장의 요구를 충분히 반영하기 어렵고, 사람 평가만으로는 시간과 비용의 부담이 큽니다.

이 한계를 보완하기 위해 최근 주목받는 접근이 LLM-as-a-Judge입니다. 또 다른 LLM이 평가자의 역할을 맡아, 생성된 결과물의 품질을 판별하고 점수를 매기는 방식이죠. 이를 통해 대규모 평가를 자동화하고, 인간 평가가 지니는 주관성을 줄일 수 있습니다. 이 방식은 단순히 모델이 '잘 작동하는가'를 확인하는 수준을 넘어, 어떤 조건에서 강점을 보이고 어디에서 취약한지까지 체계적으로 파악할 수 있게 합니다.

최근 연구에 따르면, LLM-as-a-Judge는 단순한 평가 자동화를 넘어서 모델이 스스로 사고 과정을 평가하고 개선하는 ‘Reasoning-Centric’ 방향으로 발전하고 있습니다¹. 즉, 평가와 추론이 서로를 보완하며 모델의 사고 구조를 점점 더 정교하게 만들어가는 흐름입니다.

image.png.9b612681ddc7b1a5cf21a06783b7a940.png

(1) Gu, Jiawei, et al. 2024. "A Survey on LLM-as-a-Judge." https://arxiv.org/abs/2411.15594.

CLOVA Studio에서는 이러한 평가 방식을 HyperCLOVA X 모델 API를 직접 활용해 구현할 수 있습니다. 생성된 결과를 자동으로 평가하고, 그 데이터를 다시 프롬프트 최적화나 파인튜닝 전략 조정, RAG 파이프라인 개선에 활용하는 것이죠.

 

왜 추론 모델로 평가해야 할까

LLM 성능 평가는 비추론 모델의 출력만으로는 한계가 있습니다. 답을 생성하는 데는 능숙하더라도, 그 답이 왜 맞거나 틀렸는지를 스스로 검증하지 못하기 때문이죠. 이 경우 결과의 일관성이 떨어지고, 평가 근거도 불명확해질 수 있습니다.

반면 HyperCLOVA X의 추론 모델 HCX-007은 결론에 이르기 전, 단계별 사고 과정을 전개하며 전제와 논리를 점검합니다. 이런 사고 과정 덕분에 평가 결과는 단순히 정답인지 아닌지를 판단하는 수준을 넘어, 더 깊이 있는 분석으로 이어집니다. 실제로, Judging LLM-as-a-Judge with MT-Bench and Chatbot Arena 연구에서는 GPT-4와 같은 추론형 모델이 인간 평가자와 약 80 % 수준의 일치도를 보였다고 보고했습니다. 이는 LLM-as-a-Judge가 인간 선호(human preference)를 대체할 수 있을 만큼 신뢰도 높은 평가 체계로 작동할 수 있음을 보여줍니다.

(2) Zheng, Liang, et al. 2023. “Judging LLM-as-a-Judge with MT-Bench and Chatbot Arena.” https://arxiv.org/pdf/2306.05685.

추론 모델을 평가자로 쓸 때의 세부 강점은 다음과 같습니다.

  • 논리 일관성 검증
    정답 여부만 확인하는 데 그치지 않고, 사고 과정을 기반으로 논리적 타당성까지 함께 검증합니다. 평가 결과에는 판정 근거까지 함께 남기기 때문에, 왜 그런 결과가 나왔는지도 명확히 파악할 수 있습니다.

  • 세분화된 기준별 평가
    Clarity, faithfulness, accuracy 등 항목별로 일관된 스코어링이 가능해, 같은 답변이라도 어떤 부분이 강점이고, 어디서 약한지 명확히 구분해 보여줄 수 있습니다.

  • 설명 가능한 근거 제시
    점수뿐 아니라 평가 근거와 판단 과정이 함께 제공되어, 결과의 신뢰도를 높입니다.

  • 부분 정답 처리
    모호하거나 부분적으로만 맞는 응답도, 합리적인 기준에 따라 부분 점수와 보완 코멘트를 함께 제공합니다. 

즉, HCX-007은 ‘스스로 사고하며 분석하는 평가자’입니다. 이를 평가 파이프라인에 도입하면, 점수의 신뢰성과 결과에 대한 이해도가 높아지고, 이후 모델 개선 사이클을 더 빠르게 반복할 수 있습니다.

이번 글에서는 CLOVA Studio의 HCX-007 추론 모드로 LLM 평가를 설계하고 적용하는 방법을 구체적으로 살펴보겠습니다.

 

LLM Evaluation 시나리오

전체 프로세스 개요

아래 다이어그램은 이번 글에서 다루는 LLM 평가 워크플로우를 단계별로 정리한 것입니다. 이 프로세스는 단순히 한 번의 점수를 계산하는 데 그치지 않고, 평가 → 개선 → 재평가의 순환 구조를 통해 모델을 지속적으로 고도화하는 것을 목표로 합니다.

단계별 설명에 들어가기 전에, 우선 평가에 사용할 QA 데이터셋이 필요합니다. 아직 준비되지 않았다면 부록에 안내된 절차를 참고해 손쉽게 생성할 수 있습니다. 데이터셋은 Excel(.xlsx) 또는 CSV(.csv) 형식을 모두 지원하며, 두 개의 열; 질문(question) 과 답변(answer)로 구성되어 있어야 합니다.

 

image.thumb.gif.4aa5249cd9eddb02a3b42f6f6fecb886.gif

 

1. 평가 기준 정의하기

LLM-as-a-Judge 방식을 적용하려면, 먼저 평가 기준을 명확히 설정해야 합니다. 아래는 LLM의 응답을 평가하기 위해 HCX-007 모델에 전달할 시스템 프롬프트의 예시입니다.

JUDGE_SYSTEM_PROMPT = """당신은 LLM 응답을 평가하는 심판(LLM-as-a-Judge)입니다.

[역할]
- 주어진 질문(question)과 응답(answer)을 기준으로, 아래 항목별로 0~5의 정수 점수를 부여하고 간단한 근거를 제시합니다.
- 외부 지식이 필요하더라도, 질문과 응답에 드러난 정보와 일반 상식 범위를 벗어나 추정하지 않습니다. (추정 시 근거 부족으로 감점)

[원칙]  # 원하는 모델 방향성에 맞게 조정 가능
- 점수는 반드시 0~5의 **정수(5가 최상)** 로만 부여합니다. (소수점, 범위 점수 불가)
- 근거(rationale)는 **핵심만 1~2문장**으로 작성하며, 불필요한 배경 설명은 제외합니다.
- 응답이 질문에 사실상 답하지 못했거나 형식이 명백히 어긋나면, 대부분의 항목에서 낮은 점수를 부여합니다.

[평가 기준]
1) clarity (명료성)
   - 문장이 불필요하게 길거나 중복되지 않는가?
   - 문장 구조가 논리적이며, 주어·서술어 관계가 명확한가?
   - 전문용어는 처음 등장 시 짧은 정의나 설명이 포함되어 있는가?

2) faithfulness (충실성/일관성)
   - 질문의 의도와 제약을 정확히 반영하고 있는가?
   - 응답의 논리 구조(주장–근거–결론)가 앞뒤로 일관되는가?
   - 질문의 맥락을 벗어난 추가 정보나 왜곡된 해석은 없는가?
   - 가정이나 전제가 있다면 명시되어 있는가? (없는데 단정하면 감점)

3) accuracy (정확성)
   - 사실 관계(정의, 수치, 인과 관계 등)가 일반 지식과 일치하는가?
   - 문맥상 잘못된 용어나 개념 오류가 없는가?
   - 출처나 기준이 불분명한 단정적 표현(예: “항상 그렇다”, “절대 아니다”)은 없는가?
   - 불확실한 경우, 보수적으로 표현하거나 근거 부족을 명시하는가?

4) completeness (충족성)
   - 질문의 모든 요구사항(하위 질문, 제약, 출력 형식 등)을 빠짐없이 충족하는가?
   - 예시, 단계, 코드, 설명 등 필요한 구성 요소가 포함되어 있는가?
   - 답변이 “요청된 범위 전체”를 포괄하되, 불필요한 세부 내용으로 흐트러지지 않는가?
   - 복수 항목을 요구했을 경우 모두 명시적으로 다뤘는가?

5) relevance (관련성)
   - 응답이 질문의 주제에 직접적으로 관련되어 있는가?
   - 문장 또는 단락이 주제에서 벗어나지 않고 논리적으로 연결되는가?
   - 잡담, 반복, 불필요한 부연 설명이 없는가?

[감점 가이드(예시)]
- 근거 없는 단정/모순 → faithfulness, accuracy에서 감점
- 요구사항 누락/형식 불일치 → completeness에서 감점
- 장황함/모호어 다수 → clarity, relevance에서 감점

[출력(JSON 전용)]
- 아래 키만 포함하고, 값은 정수(0~5) 또는 문자열로 출력합니다.
- 절대 JSON 외 텍스트를 출력하지 않습니다. (설명, 접두사, 코드블록 금지)
{
  "clarity": 0,
  "faithfulness": 0,
  "accuracy": 0,
  "completeness": 0,
  "relevance": 0,
  "rationale": "간단한 이유(1~2문장)"
}
"""

 

위 기준은 모델의 응답을 평가하기 위한 기본 프레임워크로, 다섯 가지 항목을 중심으로 점수를 산출합니다. 이러한 metric 설계는 단순히 정답 여부를 판단하는 데서 그치지 않고, 모델이 어떤 방식으로 답을 도출했는지까지 살펴볼 수 있도록 해줍니다.
이 기준은 고정된 규칙이 아닙니다. 평가 대상 모델의 특성과 적용 영역에 따라 자유롭게 확장하거나 수정할 수 있으며, 출력 형식은 JSON으로 고정해 평가 결과를 구조적으로 저장하고 분석할 수 있습니다.

 

Quote

ℹ️ 예를 들어, ‘창의성’이나 ‘톤 조절’ 같은 항목을 새로 추가할 수도 있습니다. RAG처럼 특정 문서를 기반으로 한 응답을 평가할 때는 “faithfulness: 응답이 제공된 CONTEXT에만 근거했는가(환각·지식 추가 금지)”와 같이 세부 기준을 조정할 수도 있습니다.

 

결국 중요한 것은 평가 항목을 명확히 정의하고, 이를 일관된 방식으로 적용할 수 있는 체계를 갖추는 것입니다. 이러한 설계가 뒷받침될 때, LLM-as-a-Judge는 신뢰성 있는 평가 도구로 기능할 수 있습니다.

 

2. 평가 항목별 비중을 적용해 종합 점수 계산하기

평가 항목을 정의했다면, 이제 각 항목의 점수를 합산해 하나의 종합 점수를 계산해야 합니다. 이때 중요한 것은 단순 평균이 아니라, 항목별 중요도(비중)를 반영하는 것입니다. 예를 들어, 정확성(accuracy)이나 충실성(faithfulness)이 상대적으로 더 중요하다면 이 항목들의 비중을 높게 설정할 수 있습니다. 아래 함수는 다섯 가지 평가 항목(clarity, faithfulness, accuracy, completeness, relevance)에 대해 미리 정의한 비중을 적용하고, 그 합이 1이 되도록 정규화하여 최종 점수를 계산합니다.

앞 단계에서 평가 기준을 수정하거나 새로운 metric을 추가했다면, 이 함수 또한 그에 맞게 함께 조정해야 합니다.

def calculate_overall_score(scores: dict) -> float:
    """가중 평균으로 전체 점수 계산"""
    raw_weights = {
        'clarity': 1.0,
        'faithfulness': 1.2,
        'accuracy': 1.5,
        'completeness': 1.0,
        'relevance': 1.3
    }
    weight_sum = sum(raw_weights.values())
    weights = {m: w / weight_sum for m, w in raw_weights.items()}
    
    total_score = sum(scores[metric] * weight 
                     for metric, weight in weights.items() 
                     if metric in scores)
    return round(total_score, 2)

이 단계는 개별 평가 항목을 하나의 종합 성능 지표로 통합하는 과정입니다. 이렇게 계산된 종합 점수는 이후 단계에서 모델 간 성능 비교나 개선 효과 검증에 활용할 수 있습니다.

 

3. HCX-007 모델 호출 후 QA 데이터셋 평가하기

이제 앞서 정의한 평가 기준과 가중치 계산 함수를 실제로 적용해보겠습니다. 준비된 QA 데이터셋(CSV 또는 Excel 파일)을 불러와, 각 질문과 답변을 HCX-007 모델에 입력하면 LLM-as-a-Judge가 각 항목별 점수를 매깁니다. 평가 결과에는 항목별 점수뿐 아니라 간단한 평가 근거도 함께 포함되며, 모든 결과는 CSV 파일로 저장됩니다.

API 키는 코드에 직접 노출하지 않고 .env 파일로 관리합니다. 아래와 같이 환경 변수를 설정해 두면, 실행 시 안전하게 키를 불러올 수 있습니다.

CLOVA_API_KEY= {api  입력}

환경 변수(.env 파일)를 불러오기 위해 python-dotenv 패키지가 필요합니다.

아직 설치하지 않았다면, 아래 명령을 실행해 주세요. (Python 3 환경 필요)

pip3 install python-dotenv

이후 필요한 라이브러리를 임포트하고, HCX-007을 호출하는 함수를 작성합니다. 오류가 발생하면 각 항목 점수를 0으로 초기화하고 실패 사유를 함께 반환하도록 처리합니다.

import os, json, time
import pandas as pd
import requests
from dotenv import load_dotenv

# 환경 변수 로드
load_dotenv()
CLOVA_API_KEY = os.getenv("CLOVA_API_KEY")
CHAT_URL = "https://clovastudio.stream.ntruss.com/v3/chat-completions/HCX-007"

BASE_HEADERS = {
    "Content-Type": "application/json",
    "Authorization": f"Bearer {CLOVA_API_KEY}"
}

def call_hcx007_judge(question: str, answer: str, timeout: int = 30) -> dict:
    """HCX-007 모델로 응답 평가"""
    user_content = f"[질문]\n{question}\n\n[응답]\n{answer}\n\n위 기준으로 평가해 주세요. JSON만 출력하세요."
    payload = {
        "messages": [
            {"role": "system", "content": JUDGE_SYSTEM_PROMPT},
            {"role": "user", "content": user_content}
        ]
    }
    
    try:
        resp = requests.post(CHAT_URL, headers=BASE_HEADERS,
                             data=json.dumps(payload), timeout=timeout)
        resp.raise_for_status()
        
        data = resp.json()
        content = data["result"]["message"]["content"]
        scores = json.loads(content.strip())
        
        # 점수를 정수로 변환
        for k in ["clarity", "faithfulness", "accuracy", "completeness", "relevance"]:
            scores[k] = int(scores.get(k, 0))
        scores["rationale"] = str(scores.get("rationale", "")).strip()
        
        return scores
        
    except Exception as e:
        return {
            "clarity": 0, "faithfulness": 0, "accuracy": 0,
            "completeness": 0, "relevance": 0,
            "rationale": f"evaluation_failed: {type(e).__name__}"
        }

 

아래 함수는 평가를 실행하고 결과를 CSV 파일로 저장하는 역할을 합니다. 출력은 지정한 컬럼 순서(desired_cols)에 맞춰 정리됩니다.

def run_evaluation(input_path: str, output_csv: str):
    """Q&A 데이터셋 평가 실행"""
    # 데이터 로드
    df = pd.read_csv(input_path) if input_path.endswith(".csv") else pd.read_excel(input_path)
    
    results = []
    for i, row in df.iterrows():
        question, answer = row["question"], row["answer"]
        
        # API 호출로 평가
        scores = call_hcx007_judge(question, answer)
        overall = calculate_overall_score(scores)
        
        results.append({
            **scores, 
            "question": question, 
            "answer": answer, 
            "overall": overall
        })
        
        print(f"진행: {i+1}/{len(df)}")
        print(scores)
        print(f"완료: 전체 점수 {overall}")
        time.sleep(0.3)  # API 호출 제한 방지
    
    # 결과 저장
    desired_cols = [
    "question", "answer",
    "clarity", "faithfulness", "accuracy", "completeness", "relevance",
    "rationale", "overall"
]
    result_df = pd.DataFrame(results, columns=desired_cols)
    result_df.to_csv(output_csv, index=False, encoding='utf-8-sig')
    print(f"평가 완료 → {output_csv}")

 

4. 평가 결과 정리 및 실행하기

평가가 완료되면, 결과를 정리하고 검토하는 단계가 필요합니다. 이 과정에서는 각 항목별 평균 점수와 전체 평균(overall) 을 계산해 출력하며, 이를 통해 모델의 전반적인 성능과 개선이 필요한 부분을 한눈에 파악할 수 있습니다.

def summarize_results(csv_path: str):
    """평가 결과 요약"""
    df = pd.read_csv(csv_path)
    metrics = ["clarity", "faithfulness", "accuracy", "completeness", "relevance", "overall"]
    
    avg_scores = {m: round(df[m].mean(), 2) for m in metrics if m in df.columns}
    
    print("\n=== 평가 결과 요약 ===")
    for metric, score in avg_scores.items():
        print(f"{metric}: {score}")
    
    return avg_scores

아래는 전체 실행 코드입니다. input_file에는 미리 준비한 QA 데이터셋 경로를, output_file에는 저장할 결과 파일명을 지정합니다. 

if __name__ == "__main__":
    input_file = "rag_qa_pairs.csv"
    output_file = "evaluation_results.csv"
    
    # 평가 실행
    run_evaluation(input_file, output_file)
    
    # 결과 요약
    summarize_results(output_file)

코드를 실행하면 각 질문별 평가 결과와 전체 요약이 함께 출력되며, 이 과정을 통해 모델의 강점과 약점을 수치로 확인할 수 있습니다.

진행: 1/25
{'clarity': 4, 'faithfulness': 5, 'accuracy': 5, 'completeness': 5, 'relevance': 5, 'rationale': '응답은 Mistral AI가 참여 중인 다양한 산업 분야를 구체적 사례와 함께 체계적으로 나열해 질문 요구사항을 완벽히 충족함. 각 산업별 세부 적용 사례를 명시함으로써 전문성과 관련성을 높였으며, 정보의 흐름이 자연스럽고 논리적임.'}
완료: 전체 점수 4.83
.
.
.

=== 평가 결과 요약 ===
clarity: 3.36
faithfulness: 3.2
accuracy: 2.8
completeness: 3.36
relevance: 3.32
overall: 3.18

 

Quote

 ℹ️ 동일한 데이터셋을 여러 번 평가해 평균을 내면 결과의 안정성을 높일 수 있습니다. 또한 HCX-007 호출 시 temperature 값을 낮추면 더 일관된 점수를 얻을 수 있습니다.

평가 결과는 자동으로 같은 폴더 내에 evaluation_results.csv 파일로 저장됩니다. 아래는 결과 파일의 일부 예시입니다.

image.png.b7fa7b06467c7749a0772ea45b5f2376.png

 

5. 모델 개선 후 재평가

지금까지는 모델의 응답을 평가하고 점수를 산출하는 과정을 살펴보았습니다. 하지만 평가의 목적은 단순히 현재 성능을 확인하는 데 그치지 않습니다. 실험을 통해 개선 방향을 탐색하고, 동일한 평가 절차를 반복하며 모델을 점진적으로 고도화하는 것이 핵심입니다. 모델 개선은 여러 수준에서 시도할 수 있습니다. 다음은 성능 향상을 위한 대표적인 접근 방식입니다.

  • 프롬프트 설계 수정
    질문의 목적을 더 명확히 하거나 출력 형식을 고정해 응답의 일관성을 높입니다.

  • RAG 파이프라인 개선
    임베딩 모델, 청킹 전략, 컨텍스트 구성 방식을 조정해 응답의 충실성과 정확성을 개선합니다.

  • 모델 변경, 모델 설정 변경
    모델을 변경하거나 temperature, top-p 등의 파라미터를 조정해 응답의 다양성과 안정성을 제어합니다.

  • 파인튜닝 (Fine-tuning)
    특정 도메인에 대한 파인튜닝을 수행하면, 해당 도메인에 맞는 응답 형식과 용어를 학습하여 과업 적합성을 높일 수 있습니다.

이러한 개선을 적용한 뒤에는 다시  QA 데이터셋을 평가하는 단계로 돌아가 동일한 절차를 반복해야 합니다. 그래야 변경이 실제로 성능 향상으로 이어졌는지, 혹은 단순한 변동에 불과한지를 객관적으로 검증할 수 있습니다. 특히, 평가 항목, 비중, 데이터셋은 동일한 조건으로 유지해야 합니다. 그래야 전후 결과를 공정하게 비교하고, 개선 효과를 정확히 판단할 수 있습니다. 또한 평균 점수뿐 아니라 항목별 점수와 평가 근거(reasoning) 를 함께 살펴보면, 어떤 부분이 개선되었고 어떤 부분이 여전히 보완이 필요한지도 구체적으로 파악할 수 있습니다.

 

마무리

모델 평가의 목적은 단순히 점수를 매기는 데 있지 않습니다. 평가를 통해 얻은 데이터는 모델이 어떤 조건에서 강점을 보이고, 어떤 상황에서 한계를 드러내는지를 구체적으로 보여줍니다. 이 과정을 반복하면 프롬프트 설계나 파이프라인 구성을 보다 근거 있게 조정할 수 있습니다. 특히 하이퍼클로바X 추론 모델(HCX-007)을 활용하면, 단순 정답 판별을 넘어 사고 과정 기반의 분석적 평가가 가능해집니다. 이는 모델의 개선 방향을 보다 명확히 설정하고, 평가 프로세스 전체의 신뢰도와 효율성을 함께 높여줄 수 있죠.

결국 중요한 것은 평가와 개선을 끊김 없이 이어가는 것입니다. 이러한 반복적 평가와 분석이 쌓이면, LLM의 성능과 한계를 더 구체적으로 이해할 수 있고, 그 위에서 보다 안정적인 개선 전략을 세울 수 있을 것입니다.

 


 

(부록) LLM을 활용하여 QA 데이터셋 준비하는법

모델 평가를 진행하려면 질문–답변(QA) 데이터셋이 필수입니다. 하지만 이를 일일이 수작업으로 만들기에는 시간과 비용이 많이 들죠. 이때 LLM을 활용하면 문서를 기반으로 자동으로 질문을 생성해 손쉽게 평가용 데이터셋을 구축할 수 있습니다.

아래에서는 PDF 문서를 입력받아 HCX-005 모델로 질문을 만들고, CSV로 정리한 뒤 자동으로 답변까지 생성하는 간단한 워크플로우를 소개합니다.

1. HCX-005 모델 불러오기

코드를 실행하기 전에, 먼저 필요한 모듈을 설치해야 합니다. 터미널에서 아래 명령어를 입력해주세요.

pip3 install python-dotenv pypdf

이후, 질문 생성을 담당할 모델인 HCX-005를 호출합니다. API 키는 보안을 위해 .env 파일에 저장해두세요.

from dotenv import load_dotenv
import os
import requests

load_dotenv()

CLOVA_API_KEY = os.getenv("CLOVA_API_KEY")
CHAT_URL = "https://clovastudio.stream.ntruss.com/v3/chat-completions/HCX-005"

def _auth_headers():
    return {
        "Content-Type": "application/json; charset=utf-8",
        "Authorization": f"Bearer {CLOVA_API_KEY}",
    }

def generate_hcx005(messages, temperature=0.7, max_tokens=2000):
    payload = {
        "messages": messages,
        "temperature": temperature,
        "topP": 0.9,
        "maxTokens": max_tokens,
        "repeatPenalty": 1.05
    }
    r = requests.post(CHAT_URL, headers=_auth_headers(), json=payload, timeout=60)
    data = r.json()
    return data["result"]["message"]["content"].strip()

.env 파일에는 아래와 같이 환경 변수를 정의합니다.

CLOVA_API_KEY= {발급받은_키}

 

2. PDF에서 텍스트 추출하기

pypdf 라이브러리를 사용해 PDF 본문을 텍스트로 변환합니다. 단, 표나 이미지는 추출되지 않을 수 있으므로 필요에 따라 클로바 OCR을 함께 활용해보세요. (클로바 OCR 확인하기↗)

from pypdf import PdfReader

def read_pdf_text(pdf_path: str) -> str:
    reader = PdfReader(pdf_path)
    texts = []
    for page in reader.pages:
        text = page.extract_text() or ""
        texts.append(text)
    return "\n\n".join(texts).strip()

이렇게 하면 문서 전체의 텍스트를 하나의 문자열로 가져올 수 있습니다.

 

3. 질문 생성하기

긴 문서를 그대로 HCX-005 모델에 입력하면 토큰 한도를 초과할 수 있습니다. 따라서 문서를 일정 크기로 나누고, 각 chunk 마다 일정 개수의 질문을 생성하는 방식을 사용합니다. 이 방법을 적용하면 긴 PDF 문서도 안정적으로 처리할 수 있습니다.

def split_text(text: str, chunk_size: int = 10000) -> list:  #chunk의 사이즈는 자유롭게 변경 가능
    return [text[i:i+chunk_size] for i in range(0, len(text), chunk_size)]

위 함수는 입력된 긴 문자열을 chunk_size 단위로 나누어 리스트 형태로 반환합니다. 기본값은 10,000자로, 한 번에 모델이 처리하기에 비교적 안정적인 크기입니다.


다만 실제로는 문서 길이와 모델의 토큰 한도를 고려해 적절히 조정하는 것이 좋습니다. 이제 각 chunk 별로 HCX-005 모델에 질문 생성을 요청합니다.

Quote

ℹ️ 이때 질문에 특정 조건이나 요구사항이 있다면, system 메시지의 content에 함께 추가하면 됩니다. 예를 들어 "사실 기반 질문 위주로 생성", "비교 질문은 최소 2개 포함" 등의 제약을 설정할 수 있습니다.

 

def generate_questions_from_pdf(pdf_path: str, num_questions: int = 5) -> list:
    print("PDF chunking 중...")
    full_text = read_pdf_text(pdf_path)
    chunks = split_text(full_text, chunk_size=10000)
    
    # 전체 질문 수를 chunk 수로 나누어 분배
    questions_per_chunk = max(1, num_questions // len(chunks))
    remaining_questions = num_questions % len(chunks)
    
    print("질문 생성 중...")
    all_questions = []
    for idx, chunk in enumerate(chunks, start=1):
        # 마지막 chunk에 나머지 질문 추가
        current_questions = questions_per_chunk + (remaining_questions if idx == len(chunks) else 0)
        
        prompt = f"""다음 문서 내용을 기반으로 {current_questions}개의 질문을 생성해주세요.

문서 내용 (chunk {idx}):
{chunk}

다음 형식으로 질문을 작성해주세요:
Q: 질문내용1
Q: 질문내용2
Q: 질문내용3
"""
        messages = [
            {"role": "system", "content": "당신은 평가용 질문을 생성하는 전문가입니다."},
            {"role": "user", "content": prompt}
        ]
        
        response = generate_hcx005(messages, temperature=0.8, max_tokens=2000)
        
        for line in response.strip().split("\n"):
            line = line.strip()
            if line.startswith("Q:") or line.startswith("질문:") or line.startswith("- "):
                question = line.replace("Q:", "").replace("질문:", "").replace("- ", "").strip()
                if question and len(question) > 10:
                    all_questions.append(question)
    
    print(f"{len(all_questions)}개의 질문 생성 완료")
    return all_questions

 

생성할 질문의 총 개수는 main 실행 파트에서 지정할 수 있습니다. 이 방식을 사용하면 문서 길이에 관계없이 원하는 규모의 질문셋을 만들 수 있습니다.

Quote

ℹ️ 모델 응답 특성상 실제 생성된 질문 수가 요청한 개수와 다를 수 있습니다. 정확한 질문 개수가 필요하다면 반복문을 사용해 보정하는 방식을 권장합니다.

 

4. 생성된 질문을 CSV파일로 저장하기

생성된 질문은 이후 평가 파이프라인에서 바로 활용할 수 있도록 CSV 파일로 저장합니다. 저장된 CSV 파일에는 question 컬럼 하나만 포함됩니다. 문서 길이와 생성할 질문 수에 따라 질문 생성 및 저장 과정에 다소 시간이 걸릴 수 있습니다.

import csv

def save_questions_to_csv(questions: list, output_csv: str):
    with open(output_csv, "w", newline="", encoding="utf-8") as csvfile:
        fieldnames = ["question"]
        writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
        writer.writeheader()
        for question in questions:
            writer.writerow({"question": question})

#코드 실행 부분
if __name__ == "__main__":
    pdf_file = "{pdfname}.pdf" #사용할 파일명
    questions = generate_questions_from_pdf(pdf_file, num_questions=25) #생성할 총 질문 수
    save_questions_to_csv(questions, "rag_questions.csv") #저장할 csv 파일명

 

Quote

ℹ️ 모델 출력 특성상 불필요한 줄이나 형식 오류가 포함될 수 있으므로, 저장된 CSV 파일을 한 번 열어 실제로 원하는 형태의 질문들이 잘 생성되었는지 검토하는 것을 권장합니다.

 

5. CSV 파일에 모델 응답 결과 추가하기

앞 단계에서 생성한 CSV 파일에는 question 열만 포함되어 있습니다. 이제 각 질문에 대해 평가 대상 모델이 답변을 생성하도록 하고, 그 결과를 answer 열에 추가하여 최종 평가용 QA 데이터셋을 완성합니다. 원하는 형태의 답변이 나오도록 시스템 프롬프트를 조정할 수 있으며, 생성된 모델 응답은 answer 변수에 저장됩니다.

def add_answers_to_csv(input_csv: str, output_csv: str):
    import pandas as pd
    
    df = pd.read_csv(input_csv)
    print(f"{len(df)}개 질문에 대한 답변 생성 중...")

    answers = []
    for idx, question in enumerate(df["question"], 1):
        
        messages = [
            {"role": "system", "content": "당신은 도움이 되는 AI 어시스턴트입니다. 질문에 대해 정확하고 상세한 답변을 제공해주세요."},
            {"role": "user", "content": question}
        ]
        
        answer = #평가하고자 하는 모델로 응답 생성
        answers.append(answer)

    df["answer"] = answers
    df.to_csv(output_csv, index=False, encoding="utf-8")
    print(f"{len(answers)}개 답변 생성 완료 → {output_csv}")

위 함수를 실행하려면 main 함수에 아래 두 줄을 추가해 수정합니다.

if __name__ == "__main__":
    import sys
    #새로 추가 되는 두 줄
    if len(sys.argv) > 1 and sys.argv[1] == "answers":
        # 답변 생성
        add_answers_to_csv("rag_questions.csv", "rag_qa_pairs.csv") #input 파일명과 결과값이 저장될 파일명
    else:
        # PDF에서 질문 생성
        pdf_file = "{pdfname}.pdf"
        questions = generate_questions_from_pdf(pdf_file, num_questions=25)
        save_questions_to_csv(questions, "rag_questions.csv")

 

답변만 생성하고자 할 경우, 터미널에서 다음 명령어를 실행하세요. 이때 {파일명}은 실제 실행할 파이썬 파일 이름으로 변경하면 됩니다.

python3 {파일명}.py answers

 

지금까지 살펴본 과정을 통해 PDF에서 질문을 자동으로 생성하고, 이를 CSV로 정리한 뒤 모델 응답까지 추가하여 QA 평가용 데이터셋을 완성할 수 있습니다. 이제 이 데이터셋을 활용해 LLM-as-a-Judge 평가를 직접 실행해 봅시다.

 

 

image.png.b8377b34c1ac506193a9b3aa0b7c4c19.png

 

 

  • Like 1
링크 복사
다른 사이트에 공유하기

게시글 및 댓글을 작성하려면 로그인 해주세요.



로그인
×
×
  • Create New...