Home LLM Judge — 외부 LLM으로 AI 분석 결과를 자동 검증하기
Post
Cancel

LLM Judge — 외부 LLM으로 AI 분석 결과를 자동 검증하기

에이전트가 에러를 분석하고 코드 수정을 제안할 때, 그 결과가 실제로 올바른지 어떻게 보장할 수 있을까?

self-reflection(자기 검증)을 이미 구현했지만 이건 같은 모델이 자기 출력을 검토하는 구조다. 생성한 사람과 검토하는 사람이 같으니 자기 편향(self-evaluation bias)이 생길 수 있다. 이 문제를 외부 LLM을 Judge로 활용하는 방식으로 해결했다.


아이디어: 생성과 검토를 분리한다

1
2
3
4
5
[분석 에이전트] (Ollama — gemma4:12b)
에러 로그 → 수정 제안 생성

[Judge] (Gemini — 외부 LLM)
에러 로그 + 수정 제안 → 품질 평가 (1~5점)

같은 모델을 쓰더라도 역할을 분리하면 의미가 있지만, 아예 다른 모델이 검토하면 더 독립적인 평가가 가능하다. 여기서는 Gemini API를 무료로 활용해 비용 없이 외부 검증을 추가했다.


평가 프롬프트 설계

Judge에게 줄 정보는 세 가지다.

  1. 원본 에러 로그 (무엇이 문제인가)
  2. 분석 에이전트의 결론 (원인, 병목, 수정 설명)
  3. 실제 코드 변경 (Before / After)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
def _build_prompt(error_log: str, suggestion: dict) -> str:
    fp = suggestion.get("file_patch", {})
    return f"""당신은 시니어 백엔드 엔지니어입니다. 아래 에러와 수정 제안을 검토해주세요.

## 에러 로그
{error_log[:1500]}

## 분석 결과
- 에러 원인: {suggestion.get("error_cause", "")}
- 수정 설명: {suggestion.get("suggested_fix", "")}

## 코드 수정
- Before: {fp.get("before", "")}
- After:  {fp.get("after", "")}

## 평가 기준
1. 수정이 에러 원인을 실제로 해결하는가?
2. After 코드가 논리적으로 올바른가?
3. 부작용이나 새로운 버그를 유발할 가능성이 있는가?

JSON만 응답하세요:
score"""

응답을 JSON으로 강제하고 temperature=0.1로 낮게 설정해 일관된 평가를 받도록 했다.


구현

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
async def judge_fix(error_log: str, llm_suggestion: str) -> dict | None:
    if not settings.gemini_api_key:
        return None  # API 키 없으면 조용히 건너뜀

    suggestion = json.loads(llm_suggestion)

    genai.configure(api_key=settings.gemini_api_key)
    model = genai.GenerativeModel("gemini-2.5-flash-lite")

    response = model.generate_content(
        prompt,
        generation_config=genai.GenerationConfig(
            temperature=0.1,
            max_output_tokens=256,
        ),
    )

    result = json.loads(response.text.strip())
    return {
        "score":      int(result["score"]),       # 1~5
        "confidence": result["confidence"],        # high / medium / low
        "reason":     result["reason"],            # 한 문장 평가
    }

실패해도 None을 반환할 뿐 파이프라인은 정상 진행된다. Judge는 보조 기능이지 핵심 흐름을 막아선 안 된다.


파이프라인 통합

분석 완료 직후, DB 저장 전에 Judge를 호출한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
# 분석 완료
suggestion = await ollama_service.analyze_log(server.id, raw_log, stack_trace)

# Judge 호출
judge_result = await judge_service.judge_fix(raw_log, suggestion)

# DB 저장 (judge 결과 포함)
record = AnalysisRecord(
    llm_suggestion=suggestion,
    judge_score=judge_result["score"] if judge_result else None,
    judge_confidence=judge_result["confidence"] if judge_result else None,
    judge_reason=judge_result["reason"] if judge_result else None,
)

Slack 메시지에 표시

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def _build_judge_block(record: AnalysisRecord) -> dict:
    score = record.judge_score or 0
    filled = "" * score + "" * (5 - score)
    confidence_emoji = {"high": "🟢", "medium": "🟡", "low": "🔴"}.get(record.judge_confidence, "")
    return {
        "type": "section",
        "text": {
            "type": "mrkdwn",
            "text": (
                f"*🤖 Gemini Judge*\n"
                f"{filled} ({score}/5)  {confidence_emoji} {record.judge_confidence}\n"
                f"_{record.judge_reason}_"
            ),
        },
    }

Slack에서 보면 이렇게 나온다.

1
2
3
4
5
🤖 Gemini Judge
⭐⭐⭐⭐⭐ (5/5)  🟢 high
제시된 수정안은 NullPointerException의 근본 원인을 정확히 파악하고,
null 값에 대한 방어 로직을 추가하여 에러를 효과적으로 해결하며,
새로운 부작용이나 버그를 유발할 가능성이 낮습니다.

실제 동작 로그

1
2
3
4
[judge] score=5 confidence=high reason=제시된 수정안은 NullPointerException의
근본 원인을 정확히 파악하고, null 값에 대한 방어 로직을 추가하여 에러를
효과적으로 해결하며, 새로운 부작용이나 버그를 유발할 가능성이 낮습니다.
[pipeline] judge score=5 confidence=high

설계 포인트

왜 같은 모델을 안 쓰나? 같은 모델이 생성한 결과를 같은 모델이 검토하면 자기 편향이 생긴다. 자신이 만든 답을 좋게 평가하는 경향이 있기 때문이다. 다른 모델(여기서는 Gemini)이 독립적으로 검토하면 더 신뢰할 수 있는 평가가 된다.

왜 실패해도 파이프라인을 멈추지 않나? Judge는 보조 지표다. API 장애나 할당량 초과로 Judge가 실패해도 에러 분석과 Slack 알림은 정상적으로 동작해야 한다. try/except로 감싸고 실패 시 None을 반환해 파이프라인에 영향을 주지 않는다.

비용은? Gemini API 무료 티어(하루 1,500회)를 사용한다. 에러 분석 1건당 Judge 호출이 1회이므로 하루 1,500건의 에러까지 무료로 검증할 수 있다.

This post is licensed under CC BY 4.0 by the author.

Error Memory — 과거 에러 분석 사례를 RAG로 재활용하기

-