LLM 평가, 왜 이렇게 느리고 불안정할까?

LLM 기반 시스템을 운영하다 보면 모델 학습보다 **평가(evaluation)**가 더 어렵다는 걸 깨닫게 됩니다. 모델은 비결정적(non-deterministic)이라서, 같은 입력에 대해 다른 출력을 내놓고, 평가자(judge)도 같은 데이터로 재실행하면 점수가 달라집니다. 참조 답변도 매번 다른 문자열로 재생성되고요.

이런 상황에서 스코어가 2% 움직였다면, 모델이 개선된 건지, 평가자가 흔들린 건지, 참조 데이터가 바뀐 건지 알 수 없습니다. 결국 평가 인프라의 문제이지, 모델 품질의 문제가 아닌 경우가 많습니다.

에어비앤비 엔지니어링 팀은 이 문제를 해결하기 위해 4가지 레이어를 구축했습니다. 각각의 레이어는 독립적으로 동작하지만, 서로 의존적입니다. 하나가 없으면 나머지도 무너집니다.

레이어 1: 노이즈의 이름을 붙여라

평가 노이즈에는 두 가지 원천이 있습니다.

  • 데이터 불확실성: 참조 답변이 매번 다르게 생성됨
  • 판정 불확실성: LLM 평가자가 같은 입력에도 다른 점수를 줌

에어비앤비 측정 결과, LLM 생성 참조 답변의 약 75%가 동일 입력에 대해 라벨링 실행마다 달랐고, 평가자도 같은 데이터셋에서 약 1%의 드리프트를 보였습니다. 실제 신호가 1~3% 수준이라면, 관측된 변화의 상당 부분은 노이즈입니다.

이를 해결하기 위해 이중 불확실성(dual indeterminacy) 프레임을 도입했습니다. 인식적 불확실성(epistemic uncertainty, 모델/평가자의 한계)과 우연적 불확실성(aleatoric uncertainty, 작업 자체의 모호성)을 구분하고, 각각 다른 진단과 해결책을 적용해야 합니다. 이 둘을 혼동하면 잘못된 결론에 도달할 수 있습니다.

실무에서는 이 두 가지가 함께 나타나기 쉽습니다. 예를 들어, 생성된 답변이 사용자의 선호도 정보를 놓친 경우(우연적)와 평가자가 도메인 지식이 없어 검증하지 못하는 경우(인식적)가 동시에 발생할 수 있습니다.

레이어 2: 결정론적 평가 기반

노이즈 평가자에 대한 직관적인 대응은 확률적 방법(샘플링, 다수결, 베이지안 모델링)입니다. 하지만 다수결은 정확도가 아니라 평가자의 중앙 경향으로 수렴하고, 베이지안 방법은 중앙 집중식 저장소가 필요해 복잡합니다.

더 간단한 방법은 평가자의 입력을 안정화하는 것입니다. 에어비앤비는 워크로드를 분석한 결과, 후보 모델의 출력 중 절반 이상이 동일한 문자열임을 발견했습니다. 즉, 대부분의 실험 변경은 일부 입력에만 영향을 주고, 같은 베이스 모델을 공유하는 후보들은 논쟁이 되는 예제에서만 갈라집니다.

그래서 샘플별 캐시를 구축했습니다.

  • 참조 답변: 샘플 ID와 생성 설정을 키로 캐싱
  • 평가자 점수: 샘플, 모델 출력, 평가자 설정, 메트릭을 키로 캐싱

이렇게 하면 동일한 입력에는 항상 동일한 결과가 반환됩니다. 평가는 결정론적(deterministic)이 되고, 효율적이며, 실행 간 비교가 가능해집니다.

# 예시: 참조 답변 캐시 (의사 코드)
from functools import lru_cache

@lru_cache(maxsize=None)
def get_reference(sample_id: str, config: tuple) -> str:
    # 실제로는 DB나 Redis에 캐싱
    return generate_reference(sample_id, config)

# 평가자 점수 캐시
@lru_cache(maxsize=None)
def get_judge_score(sample_id: str, model_output: str, judge_config: tuple, metric: str) -> float:
    return judge(model_output, judge_config, metric)

캐시 덕분에 부분 진행도 저장되어, 8,000번째 예제에서 실패해도 중단된 지점부터 재개할 수 있습니다. 이는 다음 레이어의 전제 조건입니다.

레이어 3: 범위가 제한된 모델 변형

평가가 결정론적이고 빨라지면, 병목은 '변경을 빠르게 만들 수 있는가'로 이동합니다. 전체 어댑터 재학습은 느리고 안전하지 않습니다. 대신 에어비앤비는 **마이크로 어댑터(micro adapter)**를 사용합니다.

마이크로 어댑터는 랭크가 50 미만인 작은 LoRA 패치로, 기존 공유 어댑터 위에 얹어 사용합니다. 특정 버그에 대한 최소한의 수정만 학습하며, 1시간 이내에 GPU 하나로 학습됩니다. 소프트웨어 핫픽스처럼 배포됩니다.

연구에 따르면, LoRA 어댑터는 수백 개 예제까지는 안정적으로 수정을 흡수하지만, 그 이상이 되면 추론 성능이 저하되고 과신하게 됩니다. 따라서 마이크로 어댑터는 이 한계 내에서만 사용해야 합니다.

스택 관리 규칙:

  • 동시 트리거 패치 융합: 겹치는 입력에 발화하는 패치는 서로 간섭할 수 있으므로, 학습 가능한 융합으로 해결
  • 누적 시 재학습: 특정 카테고리에 패치가 임계치에 도달하면 깨끗한 재학습으로 접기
  • 미사용 패치 언로드: 일정 기간 트리거되지 않은 패치는 자동으로 언로드

이 레이어는 레이어 2가 있어야만 동작합니다. 결정론적 평가 없이는 같은 날 수정이 불가능합니다.

레이어 4: 이음새에서의 종단 간 검증

마지막 레이어는 가장 쉽게 간과되는 부분입니다. 개별 컴포넌트(언어 감지, 전처리, 모델링, 서빙)는 모두 검증했는데, 결합된 프로덕션 동작은 여전히 예상치 못한 문제를 일으킵니다.

ML 컴포넌트는 전통적인 소프트웨어처럼 구성적 추론이 불가능합니다. 명세가 없기 때문에 이음새에서의 상호작용은 경험적으로만 관찰할 수 있습니다. 이를 해결하려면 대표 입력 세트를 전체 프로덕션 경로로 실행하고, 품질과 지연 시간을 측정해야 합니다.

에어비앤비는 다음을 포함하는 대표 세트를 구성합니다.

  • 트래픽 가중 샘플링
  • 꼬리(저빈도 로케일, 입력 모달리티, 과거 사고 패턴)의 과대 대표
  • 과거 인시던트의 회귀 케이스 시드

이 세트는 모든 릴리스 후보에 대해 효율적으로 실행될 수 있을 만큼 작고, 이음새에서 발생하는 버그를 배포 전에 표면화합니다.

주의사항 및 한계

이 접근법은 강력하지만, 몇 가지 주의할 점이 있습니다.

  • 캐시 무효화: 캐시 키에 포함된 설정이 바뀌면 기존 캐시가 무효화됩니다. 설정 변경 시 주의가 필요합니다.
  • LoRA 한계: 마이크로 어댑터는 수백 개 예제까지 유효합니다. 그 이상은 재학습이 필요합니다.
  • 대표 세트의 한계: 완벽한 대표성을 보장할 수 없습니다. 지속적인 업데이트가 필요합니다.

결론: 지루하지만 확실한 시스템 엔지니어링

LLM 파이프라인은 10년 전 ML 파이프라인과 근본적으로 다르지 않습니다. 가운데 비결정적 컴포넌트가 있을 뿐입니다. 이음새에서의 부채가 쌓이기 때문에, 컴포넌트가 아니라 이음새를 테스트하는 것이 중요합니다.

에어비앤비의 사례는 LLM 평가의 혁신이 화려한 모델 개선이 아니라, 지루하지만 확실한 시스템 엔지니어링 패턴에서 나온다는 것을 보여줍니다. 평가 인프라를 결정론적으로 만들고, 빠른 반복을 가능하게 하면, 같은 날 수정도 가능해집니다.

이 글의 근거 자료는 에어비앤비 엔지니어링 블로그에서 확인할 수 있습니다.

함께 보면 좋은 글

다음 단계 학습 방향

  1. 결정론적 캐싱을 자신의 평가 파이프라인에 도입해보세요.
  2. 마이크로 어댑터를 실험하여 특정 버그 수정에 적용해보세요.
  3. CACE 원칙을 팀과 공유하고, 이음새 테스트 문화를 만드세요.

LLM evaluation pipeline with deterministic caching and judge scoring Developer Related Image

본 콘텐츠는 신뢰할 수 있는 출처를 바탕으로 AI 도구를 활용하여 초안이 작성되었으며, 편집자의 검토를 거쳐 발행되었습니다. 전문가의 조언을 대체하지 않습니다.