대부분의 팀에서 LLM 애플리케이션 평가는 파편화된 난장판에 가깝다. 인간 어노테이터의 평가는 구글 스프레드시트에 흩어져 있고, LLM 판사(LLM-as-a-Judge) 채점 결과는 어딘가의 스크립트 출력 로그에 묻힌다. 사용자 피드백은 아무도 보지 않는 별도 대시보드로 흘러가고, CI 파이프라인에서 도는 코드 검증 결과는 다른 신호들과 전혀 상관관계를 맺지 못한다.
랭퓨즈(Langfuse)의 평가 시스템은 이 복잡함을 단칼에 정리하는 한 가지 설계 결정을 내렸다: 모든 품질 판단을 ’스코어(Score)’라는 단일 객체로 일원화하는 것이다. 인간의 평가, LLM 판사의 판단, 정규식 검사 결과, 사용자의 ‘싫어요’ 클릭까지 — 모두가 완전히 동일한 데이터 구조를 갖는다. 동일한 구조이기에 동일한 분석 엔진과 대시보드를 공유한다.
단순해 보이는 이 결정이 다운스트림 전체의 개발 경험을 근본적으로 바꿔놓는다.
스코어(Score)의 본질
랭퓨즈의 모든 스코어는 네 가지 속성으로 구성된다: 이름(예: “correctness”), 값(value), 데이터 타입, 그리고 선택적 코멘트(comment).
지원하는 데이터 타입은 숫자(numeric, 예: 0.9), 범주형(categorical, 예: “정답” / “부분 정답”), 불리언(boolean, 합격/불합격), 텍스트(text, 자유 형식 메모)다. 연속적인 판단에는 숫자를, 이산형 레이블에는 범주형을, 이진 검증에는 불리언을 쓰고, 나중에 정형화할 정성적 피드백은 텍스트로 남긴다.
스코어는 트레이스(Trace), 옵저베이션(Observation), 세션(Session), 데이터셋 실행 결과(Dataset run)에 부착된다. 가장 흔한 형태는 트레이스에 붙여 엔드투엔드 단일 인터랙션 전체의 점수를 매기는 것이다.
여기서 결정적인 특징이 있다. 스코어는 언제든지 사후에 추가될 수 있다는 점이다. 트레이싱 시점에 무엇이 일어났는지를 설명하며 이후 변경되지 않는 태그(tags)와 달리, 스코어는 ’얼마나 좋은가’를 측정하기 때문에 몇 시간, 며칠, 혹은 몇 주 뒤에도 추가할 수 있다. 지난주 프로덕션 트래픽 기록에 새로운 LLM 판사 평가기를 소급 적용하여 이전 트레이스들 위에 새로운 점수를 매기는 작업이 가능하다.
스코어를 생성하는 5가지 경로
LLM 판사 (LLM-as-a-Judge): LLM이 정해진 루브릭(기준표)에 따라 출력을 평가한다. 기준을 정의하고 트레이스에서 변수(입력, 출력, JSONPath 기반 메타데이터)를 매핑하면, 판사가 추론 근거와 함께 구조화된 스코어를 산출한다. GPT-4o, Claude Sonnet, Gemini Pro 등 구조화된 출력을 지원하는 모델이면 무엇이든 활용할 수 있다. 연구 결과에 따르면 인간 평가자와의 일치도가 80~90%에 달해, 인간 작업자 간 일치도와 맞먹는 수준이다.
코드 평가기 (Code evaluators): 랭퓨즈 내부에서 실행되는 결정론적 파이썬 또는 타입스크립트 코드다. LLM 호출 없이 완전 일치, 정규식, JSON 유효성, 스키마 검사, 비즈니스 규칙 등을 검증한다. 런타임은 격리되어 표준 라이브러리만 사용 가능하고 네트워크는 차단되며 2초 타임아웃이 걸린다. 제약이 커 보이지만, 프로덕션에서 필수적인 핵심 규칙 검증에는 충분하다.
UI 기반 직접 평가: 사람이 트레이스를 보며 클릭으로 스코어를 부여한다. 사전에 정의된 스코어 설정이 필요하며, 실험 비교 화면에서 실험 결과를 직접 어노테이션할 때도 활용된다.
어노테이션 큐 (Annotation queues): 구조화된 전문가 검토 워크플로우다. 스코어 설정이 포함된 큐를 생성하고 트레이스를 할당하면, 검토자들이 단축키를 이용해 빠르게 처리한다. 그라운드 트루스(ground truth) 데이터셋을 구축하는 도메인 전문가들을 위해 설계되었다.
API/SDK를 통한 수집: 프로그래밍 방식의 수집이다. 애플리케이션 코드, CI 파이프라인, 혹은 독자적인 평가 서비스에서 점수를 계산한 뒤 랭퓨즈로 전송한다. 사용자 피드백(좋아요/싫어요), 가드레일 판정 결과, 커스텀 평가 파이프라인의 연동 통로가 된다.
옵저베이션(Observation) 단위로의 진화
랭퓨즈가 다른 평가 플랫폼들과 가장 크게 차별화되는 지점은 트레이스 레벨에서 옵저베이션 레벨(observation-level) 평가로 패러다임을 전환하고 있다는 점이다.
트레이스가 전체 인터랙션이라면, 옵저베이션은 그 안의 세부 작업 단위 — 한 번의 LLM 호출, 한 번의 검색, 한 번의 도구 실행 — 를 의미한다. 이 차이는 매우 크다.
예를 들어 에이전트가 문서 검색 → 답변 생성 → 도구 호출 → 응답 포맷팅 과정을 거친다고 해보자. 트레이스 레벨에서는 전체 파이프라인에 통으로 점수를 매길 수밖에 없다. 반면 옵저베이션 레벨에서는 검색 단계에만 관련성(relevance) 평가기를 붙이고, LLM 생성 단계에만 유해성(toxicity) 검사를 수행하며, 도구 호출 단계에만 포맷 유효성 검증기를 따로 붙일 수 있다. 하나의 트레이스 안에서 각 작업 특성에 맞는 평가기를 독립적으로 가동하는 것이다.
이는 실행 속도의 획기적인 향상으로 이어진다. 옵저베이션 단위 평가는 비동기 병렬로 처리된다. 특정 작업 유형만 타깃팅할 수 있고(예: 내부 LLM 호출은 제외하고 고객 노출용 LLM 호출만 평가), 메타데이터 필터링과 트레이스 필터를 조합할 수도 있다. “프리미엄 고객이 남긴 ‘고객지원’ 태그 대화의 모든 LLM 생성 단계만 평가” 같은 복잡한 조건도 별도 파이프라인 구축 없이 단순 필터 조합으로 해결된다.
기존의 트레이스 레벨 평가기는 점진적으로 폐기될 예정(deprecated)이며, v4 버전에서 완전히 전환된다.
실험(Experiments): 오프라인 평가 경로
실험은 배포 전 안전성을 검증하는 방법이다. 데이터셋(입력값과 정답 출력값 모음)을 만들고, 애플리케이션 로직을 담은 태스크 함수를 작성한 뒤, 모든 데이터 항목에 대해 실행하고 점수를 매긴다.
데이터셋 기능에서 주목할 점들:
- 버전 관리: 추가, 수정, 삭제, 아카이빙할 때마다 새 버전이 생성된다. 특정 타임스탬프 시점의 데이터셋 상태를 불러와 과거와 동일한 조건으로 실험을 재현할 수 있다.
- 스키마 강제: 입력과 정답 출력에 JSON Schema 검증을 선택 적용할 수 있어 잘못된 데이터 주입을 사전에 차단한다.
- 멀티미디어 지원: 데이터셋 항목에 이미지, 오디오, 비디오를 포함할 수 있다.
- 프로덕션 데이터 파이프라인: 실제 운영 중 실패한 트레이스를 골라 데이터셋에 추가하고, 전문가가 모범 답안을 달아 회귀 테스트 데이터셋으로 발전시킬 수 있다.
SDK를 통한 실험 실행은 세밀한 제어를 제공한다:
result = langfuse.run_experiment(
name="고객 지원 에이전트 테스트",
data=test_data,
task=my_agent,
evaluators=[accuracy_eval, tone_eval],
run_evaluators=[avg_accuracy],
max_concurrency=10,
)
print(result.format())
UI를 통한 프롬프트 실험도 지원한다. 프롬프트 관리 화면에서 버전을 선택하고 데이터셋과 모델을 지정하면 코드 한 줄 없이 바로 성능을 비교해 볼 수 있다.
스코어 분석: 설정 없이 즉시 얻는 검증 지표
스코어가 쌓이기 시작하면 별도 설정 없이 바로 스코어 분석(Score Analytics) 대시보드가 활성화된다.
단일 스코어를 선택하면 분포 차트, 시간별 추세, 통계값(개수, 평균, 표준편차)이 나타난다. 동일한 타입의 두 스코어를 동시에 선택하면 상관관계 지표, 혼동 행렬(confusion matrix), 일치도 통계가 즉시 계산된다.
이 2개 스코어 비교 기능이 매우 유용하다. 동일한 트레이스에 대해 GPT-4o와 Gemini를 평가자로 실행하여 두 모델의 점수를 비교해 보자. 피어슨 상관계수가 0.984라면 평가 체계의 신뢰도가 높다는 뜻이다. 인간 평가자의 어노테이션과 LLM 판사의 판정 간 코헨의 카파(Cohen’s Kappa) 계수가 0.85라면, 해당 평가는 충분히 자동화해도 안전하다는 신호다.
매칭 데이터와 전체 데이터의 비율을 통해 커버리지 공백도 한눈에 파악할 수 있다. 총 1,143개의 스코어 중 매칭된 쌍이 567개뿐이라면, 절반의 트레이스는 단 하나의 평가 방식만 거쳤다는 뜻이므로 보강이 필요하다.
CI/CD 파이프라인 통합
랭퓨즈는 깃허브 액션(langfuse/experiment-action)을 공식 지원하여 배포 파이프라인에서 점수 기준치를 통과하지 못하면 PR을 차단(gating)할 수 있다.
experiment(context) 함수를 작성하고 평가기를 정의한 뒤, 점수가 임계치에 미치지 못하면 RegressionError를 던진다. 깃허브 액션은 통과 여부, 상세 점수, 랭퓨즈 비교 뷰 링크, 항목별 출력 결과를 PR 코멘트로 깔끔하게 요약해 등록한다.
def experiment(context: RunnerContext):
result = context.run_experiment(
name="PR gate",
task=my_task,
evaluators=[exact_match],
run_evaluators=[avg_accuracy],
)
accuracy = next(
e.value for e in result.run_evaluations if e.name == "avg_accuracy"
)
if accuracy < 0.95:
raise RegressionError(
result=result, metric="avg_accuracy",
value=accuracy, threshold=0.95,
)
return result
Pytest나 Vitest 같은 표준 테스트 프레임워크와 결합해서 사용하는 것도 자연스럽다.
맺으며
랭퓨즈의 평가 아키텍처는 확고한 베팅을 걸었다. 각 평가 방식마다 개별적인 전용 도구를 만드는 것보다, 모든 품질 신호를 ’스코어’라는 단일 원자(primitive)로 통합하고 이를 세밀한 옵저베이션 단위로 다루는 것이 훨씬 더 강력하다는 점이다. 직관적인 스코어 분석, CI/CD 자동 차단, 데이터셋 버전 관리 등 랭퓨즈의 장점들은 모두 이 탄탄한 기본기 위에서 나온다.
현재 LLM 애플리케이션의 평가 신호들이 스프레드시트, 일회성 스크립트, 개별 대시보드로 흩어져 있다면, ‘스코어 기반 단일화’ 패러다임을 진지하게 검토해 보길 권한다. 참신해서가 아니라, 품질 평가를 사후 대응이 아닌 체계적인 소프트웨어 엔지니어링의 핵심 축으로 세워주기 때문이다.