코드 평가

코드 평가 (Code-Evals)

G-Eval이 자연어 기준으로 평가를 정의한다면, Code-Eval은 Confident AI 플랫폼에서 직접 Python 코드를 작성해 커스텀 메트릭을 만들고 실행하게 해줘요. JSON 구조 검증, 결정적 채점, 복잡한 계산처럼 자연어로 표현하기 어려운 평가 로직이 필요할 때 특히 유용해요. 이 글에서는 Code-Eval의 동작 방식과 작성 예시를 살펴볼게요.

출처: 문서

본문

개요

Code-Eval은 Confident AI 플랫폼에서 직접 Python 코드를 작성해 커스텀 메트릭을 만들고 실행하게 해줘요. 자연어 기준을 쓰는 G-Eval과 달리, deepeval 프레임워크를 사용해 평가 로직을 완전히 프로그램적으로 제어할 수 있어요.

Code-Eval도 Confident AI에서 실행돼요.

왜 Code-Eval인가요?

자연어로 표현할 수 없는 평가 로직이 필요할 때 Code-Eval이 안성맞춤이에요.

  • 정확한 포맷 검증 — JSON 구조, 정규 표현식 패턴, 특정 출력 포맷을 검증해요.
  • 결정적 채점 — LLM 변동성 없이 일관된 규칙 기반 로직을 적용해요.
  • 복잡한 계산 — 다단계 연산, 통계 분석, 집계를 수행해요.
  • 커스텀 비즈니스 규칙 — 내 사용 사례에 고유한 도메인별 검증 로직을 구현해요.

톤, 도움됨, 미묘한 품질 검사 같은 주관적 평가가 필요하다면 G-Eval을 쓰세요 — LLM-as-a-judge 추론을 처리하고 코드 없이도 만들기 쉬워요.

동작 방식

Code-Eval은 deepeval에서 커스텀 메트릭 만들기와 똑같이 동작해요. BaseMetric을 상속하는 Python 클래스를 작성하고 평가 로직을 구현하면 돼요.

다만 Confident AI에서는 다음 메서드만 편집할 수 있어요.

  • a_measure() — 평가 로직이 실행되는 async 메서드
  • is_successful() — 테스트 케이스 통과 여부를 결정

메트릭의 다른 모든 부분(초기화, 프로퍼티 등)은 플랫폼이 처리해요.

사용 가능한 패키지

내 코드는 안전한 환경에서 실행되며 다음에 접근할 수 있어요.

  • deepeval 라이브러리 — 항상 GitHub의 최신 버전. BaseMetric, 테스트 케이스 타입 등 모든 유틸리티를 포함해요.
  • 표준 Python 라이브러리 — json, re, math, collections, datetime 등
  • 외부 네트워크 호출 없음 — 보안을 위해 외부 API 호출은 (현재는) 지원되지 않아요.

UI로 Code-Eval 만들기

Code-Eval 메트릭은 Project > Metrics > Library 아래에서 만들 수 있어요.

메트릭 세부 정보 입력

메트릭 이름, 그리고 선택적으로 설명을 입력해요. single-turn 또는 multi-turn 메트릭 중 무엇을 만들지도 토글할 수 있어요.

Video

일반 메트릭 정보 (General Metric Info)

메트릭 이름은 프로젝트 내에서 고유해야 하며, 어떤 기본 메트릭 이름과도 충돌하면 안 돼요.

평가 코드 작성

G-Eval에서 criteria, evaluation steps, rubric을 정의하는 대신, 평가 **점수(score)**를 직접 계산하는 Python 코드를 작성해요.

내 코드는 적절한 base class를 상속하고 다음을 구현해야 해요.

  • a_measure(test_case) — self.score, self.reason, self.success를 설정하는 async 평가 로직
  • is_successful() — threshold에 따라 메트릭 통과 여부를 반환(미리 채워져 있음, 변경 권장하지 않음)

a_measure() 메서드가 self.score를 반환할 필요는 없지만, 반환하길 권장해요.

Single-turn

single-turn 메트릭은 BaseMetric을 상속하고 LLMTestCase를 받아요.

from deepeval.metrics import BaseMetric
from deepeval.test_case import LLMTestCase

class CodeMetric(BaseMetric):
    async def a_measure(self, test_case: LLMTestCase) -> float:
        # Your evaluation logic here
        if len(test_case.actual_output) > 5:
            self.score = 1
        else:
            self.score = 0

        self.success = self.score >= self.threshold
        return self.score

    def is_successful(self) -> bool:
        if self.error is not None:
            self.success = False
        else:
            try:
                self.success = self.score >= self.threshold
            except TypeError:
                self.success = False
        return self.success

LLMTestCase 객체는 input, actual_output, expected_output 등의 파라미터에 접근할 수 있게 해줘요.

Multi-turn

multi-turn 메트릭은 BaseConversationalMetric을 상속하고 ConversationalTestCase를 받아요.

from deepeval.metrics import BaseConversationalMetric
from deepeval.test_case import ConversationalTestCase

class CodeMetric(BaseConversationalMetric):
    async def a_measure(self, test_case: ConversationalTestCase) -> float:
        # Your evaluation logic here
        if len(test_case.turns) > 5:
            self.score = 1
        else:
            self.score = 0

        self.success = self.score >= self.threshold
        return self.score

    def is_successful(self) -> bool:
        if self.error is not None:
            self.success = False
        else:
            try:
                self.success = self.score >= self.threshold
            except TypeError:
                self.success = False
        return self.success

ConversationalTestCase는 turns 목록에 접근할 수 있게 해주며, 각 turn은 role, content 등 다른 파라미터를 담고 있어요.

테스트 케이스 파라미터에 대한 자세한 내용은 Test Cases, Goldens, and Datasets 문서를 참고하세요.

검토 후 저장

코드를 작성했으면 최종 검토 페이지에서 모든 게 올바른지 확인하고 Save를 클릭해요.

이제 Code-Eval 메트릭을 metric collection에 추가해 원격 eval을 시작할 수 있어요.

고급 사용법 (Advanced Usage)

상세 로그 설정 (Set verbose logs)

self.verbose_logs로 평가 로직의 중간 단계와 결정 경로를 로그로 남길 수 있어요. 복잡한 메트릭을 디버깅하거나 점수가 어떻게 계산되는지 이해할 때 유용해요.

from deepeval.metrics import BaseMetric
from deepeval.test_case import LLMTestCase

class CodeMetric(BaseMetric):
    async def a_measure(self, test_case: LLMTestCase) -> float:
        # Log anything for debugging purposes
        self.verbose_logs = "Wow I can't believe I can do this on Confident AI"

        return self.score

    def is_successful(self) -> bool:
        if self.error is not None:
            self.success = False
        return self.success

상세 로그는 메트릭 결과와 함께 Confident AI 대시보드에 표시되어, 평가 결정 과정을 쉽게 추적할 수 있어요.

reasoning 기록 (Log reasoning)

self.reason로 점수에 대한 사람이 읽을 수 있는 설명을 남겨요. 특정 점수가 왜 부여됐는지 이해하는 데 도움이 되며 평가 결과에 표시돼요.

from deepeval.metrics import BaseMetric
from deepeval.test_case import LLMTestCase

class CodeMetric(BaseMetric):
    async def a_measure(self, test_case: LLMTestCase) -> float:
        # Set any reason you wish
        self.reason = "Wow I can't believe I can do this on Confident AI"

        return self.score

    def is_successful(self) -> bool:
        if self.error is not None:
            self.success = False
        return self.success

명확한 self.reason는 평가 결과를 이해하기 훨씬 쉽게 만들어요. 특히 실패한 테스트 케이스를 검토하거나 예상 밖의 점수를 디버깅할 때 그렇지요.

예외 발생 (Raise exceptions)

Python에서 평소처럼 에러를 던지고 self.error에 기록할 수도 있어요.

from deepeval.metrics import BaseMetric
from deepeval.test_case import LLMTestCase

class CodeMetric(BaseMetric):
    async def a_measure(self, test_case: LLMTestCase) -> float:
        try:
            raise ValueError("Raising an error because I feel like it")
        except Exception as e:
            # Surface the error before re-raising
            self.error = str(e)
            raise

        return self.score

    def is_successful(self) -> bool:
        if self.error is not None:
            self.success = False
        return self.success

더 알아보기