21장. LLM 기능은 어떻게 테스트하는가
21장. LLM 기능은 어떻게 테스트하는가
LLM 기능을 처음 붙이면 많은 팀이 비슷한 착각을 한다. API가 잘 호출되고, 응답이 오고, 에러만 안 나면 "동작한다"고 생각하는 것이다. 하지만 실제 서비스에서는 그다음부터가 진짜 시작이다. 사용자는 단지 응답이 오는지를 보지 않는다. 쓸 만한 답인지, 믿을 수 있는지, 빠른지, 일관적인지, 그리고 업무에 도움이 되는지를 본다.
문제는 여기서 전통적인 테스트 방식이 바로 한계를 드러낸다는 점이다. 일반적인 웹 서비스는 같은 입력에 같은 출력이 나오는 경우가 많다. 그래서 기대값을 정확히 적어 두고, 그 값과 일치하는지만 검사해도 꽤 많은 문제를 잡을 수 있다. 반면 LLM은 같은 질문에도 표현이 달라질 수 있고, 정답이 하나로 고정되지 않는 작업도 많다. 요약, 재작성, 분류, 답변 생성 같은 기능은 특히 그렇다.
그래서 LLM 테스트의 핵심은 단순하다. "정확히 같은 답"을 찾는 대신, "우리 서비스가 받아들일 수 있는 좋은 답의 범위"를 정의하고, 그 범위를 지속적으로 검사해야 한다. 이 장에서는 바로 그 방법을 다룬다. 테스트셋을 어떻게 만들고, 자동 평가를 어디까지 믿고, 휴먼 리뷰는 어떻게 설계해야 하는지 실무 관점에서 정리해 보자.

전통적인 단위 테스트만으로는 부족한 이유
LLM 기능에도 단위 테스트는 필요하다. 다만 테스트 대상이 달라질 뿐이다. 예를 들어 프롬프트 템플릿에 변수가 빠지지 않았는지, 응답 JSON 파싱이 실패했을 때 재시도가 동작하는지, 권한이 없는 사용자가 특정 기능을 호출하지 못하는지 같은 부분은 여전히 일반적인 테스트로 검증할 수 있다.
하지만 모델 응답의 "품질"은 이런 방식만으로 보장되지 않는다. 이유는 크게 세 가지다.
출력이 확률적이다. 같은 요청이라도 표현, 길이, 강조점이 조금씩 달라질 수 있다.
정답이 하나가 아니다. 좋은 요약은 여러 형태로 가능하고, 좋은 답변도 상황에 따라 달라진다.
실패 형태가 다양하다. 문법 오류처럼 눈에 띄는 실패도 있지만, 사실과 다른 내용, 중요한 누락, 지나친 확신처럼 더 위험한 실패도 있다.
결국 LLM 테스트는 "코드가 실행되느냐"보다 "결과가 제품 요구사항을 만족하느냐"를 검증하는 일에 가깝다. 즉, 테스트의 중심이 함수 단위에서 사용자 가치 단위로 이동한다.
먼저 테스트할 대상을 다시 나누자
LLM 기능을 테스트할 때는 하나의 큰 덩어리로 보지 말고, 계층을 나눠 보는 편이 좋다. 그래야 무엇을 자동화하고 무엇을 사람에게 맡길지 선명해진다.
코드 레벨 테스트
이 층은 가장 익숙하다. 프롬프트 조립 함수, 입력 검증, 응답 스키마 검사, 후처리 로직, 캐시 키 생성, 재시도 정책, 폴백 분기 같은 부분이 여기에 들어간다. 이 영역은 가능한 한 결정적이어야 하므로 기존 테스트 기법을 적극적으로 쓴다.
모델 출력 테스트
여기서는 "이 답이 우리 기준에서 괜찮은가"를 본다. 예를 들어 요약이 핵심을 놓치지 않았는지, 분류 결과가 정책에 맞는지, 추천 문구가 과장되지 않았는지 같은 문제다. 이 층부터는 exact match, 즉 문자열 완전 일치가 거의 쓸모없어진다.
기능 수준 테스트
사용자가 실제로 기능을 썼을 때 원하는 결과를 얻는지 본다. 예를 들어 고객센터 자동답변 기능이라면, 답변 문장이 자연스러운지뿐 아니라 문의 해결에 도움이 되는지, 상담원 이관이 필요한 경우를 놓치지 않는지가 중요하다.
비즈니스 수준 테스트
마지막은 서비스 관점이다. 응답이 좀 그럴듯한 수준을 넘어 실제 지표를 개선하는지 봐야 한다. 클릭률, 해결률, 전환율, 재문의율, CS 처리 시간, 편집 후 채택률 같은 운영 지표가 여기에 해당한다.
LLM 테스트는 보통 위 네 층을 함께 봐야 한다. 아래층만 통과했다고 위층 품질이 자동으로 좋아지지는 않는다.
좋은 평가의 출발점은 품질 기준을 문장으로 쓰는 것이다
테스트셋을 만들기 전에 먼저 해야 할 일이 있다. 바로 "좋은 응답이 무엇인지"를 말로 정의하는 것이다. 이 단계 없이 데이터를 모으면 나중에 팀마다 기준이 달라져서 평가가 흔들린다.
예를 들어 요약 기능이라면 단지 "짧게 줄인다"가 기준이 아니다. 다음 같은 기준이 더 실무적이다.
핵심 사실을 빠뜨리지 않는다.
원문에 없는 내용을 지어내지 않는다.
지정한 길이 제한을 지킨다.
읽는 사람이 바로 쓸 수 있게 구조가 분명하다.
민감 정보가 있다면 적절히 제거하거나 마스킹한다.
분류 기능도 마찬가지다. "정확하다"만으로는 부족하다. 어떤 오분류가 특히 치명적인지까지 정해야 한다. 스팸을 정상 메일로 놓치는 것이 더 위험한지, 정상 메일을 스팸으로 잘못 보내는 것이 더 위험한지에 따라 테스트 기준이 달라진다.
즉, LLM 품질 평가는 모델의 똑똑함을 재는 시험이 아니라 제품 요구사항을 채점하는 작업이다.
테스트셋은 작게 시작하되, 대표성 있게 만들어야 한다
많은 팀이 처음부터 수천 건짜리 데이터셋을 만들려다 지친다. 처음에는 작아도 괜찮다. 대신 대표성이 있어야 한다. 테스트셋은 모델을 감탄시키기 위한 문제가 아니라, 서비스의 약점을 빨리 드러내는 문제 모음이어야 한다.
가장 실용적인 시작점은 실제 사용자 요청을 바탕으로 케이스를 모으는 것이다. 물론 개인정보와 민감 정보는 제거하거나 익명화해야 한다. 그 위에 제품 팀이 중요하게 보는 시나리오를 추가하면 된다.
테스트셋에는 최소한 다음 성격의 케이스가 섞여야 한다.
자주 들어오는 일반 케이스
매출이나 신뢰와 직접 연결되는 핵심 케이스
모델이 자주 틀리는 경계 케이스
길이가 매우 길거나 형식이 지저분한 입력
애매하거나 모호한 표현이 포함된 입력
안전성 문제가 생길 수 있는 위험 케이스
이 구성이 중요한 이유는 평균 점수의 함정 때문이다. 일반 케이스에서 잘하는 모델이 핵심 케이스에서 자주 실패하면 서비스 전체로는 나쁜 모델일 수 있다. 테스트셋은 평균을 예쁘게 만드는 도구가 아니라, 위험을 먼저 발견하는 도구여야 한다.
테스트셋을 만드는 실전 절차
테스트셋을 만드는 가장 현실적인 순서는 다음과 같다.
먼저 기능의 대표 입력 30개에서 50개 정도를 모은다. 이때 실제 운영 로그, 베타 사용자 피드백, 기획 문서의 예시 입력을 함께 활용하면 좋다. 그다음 각 케이스에 대해 기대 결과를 한 줄 정답으로 쓰려 하지 말고, 평가 기준을 붙인다. 예를 들어 "반드시 포함해야 할 사실", "언급하면 안 되는 내용", "허용 길이", "출력 형식" 같은 조건이다.
그 후에 케이스를 묶는다. 예를 들어 요약 기능이라면 회의록 요약, 이메일 요약, 정책 문서 요약, 잡음이 많은 메모 요약처럼 유형을 나눌 수 있다. 분류 기능이라면 쉬운 케이스와 헷갈리는 케이스를 분리해 두는 편이 좋다.
마지막으로 케이스마다 중요도를 표시한다. 모든 실패가 같은 무게를 갖는 것은 아니다. 한 건의 치명적 실패가 열 건의 사소한 성공보다 더 중요할 수 있다.
이렇게 만들어진 테스트셋은 시간이 지나며 계속 자라난다. 운영 중 발생한 실패 사례를 회수해 테스트셋에 넣는 순간, 품질 시스템이 비로소 학습하기 시작한다.
정답이 하나 없는 작업은 어떻게 자동 평가할까
여기서 가장 많이 나오는 질문이 있다. "요약이나 답변 생성은 정답이 여러 개인데, 자동 평가가 가능한가?" 가능하다. 다만 한 가지 점수로 모든 것을 해결하려고 하면 안 된다.
자동 평가는 보통 세 가지 축을 조합해서 설계한다.
규칙 기반 평가
가장 먼저 챙길 것은 기계적으로 검사할 수 있는 규칙이다. 출력 형식이 JSON인지, 필수 필드가 있는지, 글자 수 제한을 넘지 않았는지, 금지어가 포함되지 않았는지, 특정 섹션 제목이 있는지 같은 조건이다. 이런 검사는 화려하지 않지만 매우 강력하다. 서비스 사고의 상당수는 의외로 이런 기본 규칙에서 발생한다.
과업별 정답 비교
분류처럼 정답 라벨이 비교적 명확한 작업은 정확도, 정밀도, 재현율 같은 전통적인 지표를 그대로 쓸 수 있다. 추출 작업도 비슷하다. 예를 들어 문서에서 날짜, 금액, 회사명을 뽑는 기능은 정답셋을 만들어 비교하기 좋다.
다만 생성형 작업은 여기서 조금 더 영리해져야 한다. 완전히 같은 문장인지가 아니라, 필요한 의미를 담고 있는지를 봐야 한다. 그래서 "반드시 포함해야 할 핵심 항목 체크" 같은 방식이 효과적이다. 요약이라면 핵심 사건 세 가지가 들어갔는지, 액션 아이템이 빠지지 않았는지처럼 평가 기준을 쪼개는 편이 낫다.
LLM을 심사위원으로 쓰는 평가
이른바 모델 기반 평가다. 다른 LLM에게 응답의 관련성, 충실성, 명확성, 안전성을 채점하게 하는 방식이다. 빠르고 확장성이 좋아서 유용하지만, 맹신하면 안 된다. 심사위원 모델도 편향될 수 있고, 말만 번지르르한 답에 높은 점수를 줄 수 있다.
따라서 모델 기반 평가는 단독으로 쓰기보다 규칙 기반 평가와 휴먼 리뷰 사이의 중간 계층으로 쓰는 편이 좋다. 즉, 1차 대량 스크리닝에는 좋지만 최종 판정의 전부가 되어서는 안 된다.
평가 항목은 하나의 총점보다 여러 개의 축으로 보는 편이 낫다
LLM 기능을 숫자 하나로 요약하려는 유혹은 강하다. 하지만 총점 하나는 빠르게 편해지는 대신 빠르게 위험해진다. 예를 들어 응답이 자연스럽고 친절해서 총점은 높은데, 사실 오류가 잦다면 서비스 입장에서는 나쁜 결과다.
그래서 실무에서는 축을 나눠 점검하는 것이 좋다. 자주 쓰는 축은 다음과 같다.
정확성: 사실과 맞는가, 원문과 모순되지 않는가
충실성: 핵심을 빠뜨리지 않았는가
관련성: 질문과 상관없는 말이 섞이지 않았는가
형식 준수: 지정한 구조와 길이를 지켰는가
안전성: 위험하거나 부적절한 내용이 없는가
실용성: 사용자가 바로 활용할 수 있는가
이렇게 축을 나눠 보면 모델 교체나 프롬프트 수정의 영향도 더 잘 보인다. 예를 들어 새 프롬프트가 형식 준수는 크게 개선했지만 충실성을 떨어뜨렸다면, 총점 하나로는 놓칠 수 있는 중요한 정보를 잡을 수 있다.
자동 평가는 회귀 테스트의 중심이 된다
LLM 기능에서 자동 평가가 가장 빛나는 순간은 변경 비교다. 프롬프트를 바꾸거나, 모델 버전을 올리거나, 후처리 로직을 수정했을 때 예전보다 나아졌는지 나빠졌는지를 빠르게 확인할 수 있기 때문이다.
이때 중요한 것은 절대 점수보다 상대 비교다. 기존 버전과 새 버전을 같은 테스트셋에 돌리고, 각 케이스에서 어떤 차이가 났는지 본다. 특히 중요도 높은 케이스에서 악화가 생기면 전체 평균이 조금 올라가도 릴리스를 보류하는 판단이 필요하다.
실무에서는 보통 이런 흐름이 잘 맞는다. 코드가 바뀌면 먼저 결정적인 코드 테스트를 돌린다. 그다음 회귀용 평가셋에 대해 자동 평가를 실행한다. 마지막으로 점수가 애매하게 갈리거나 중요 케이스에서 차이가 난 부분만 사람에게 넘긴다. 이렇게 하면 비용을 통제하면서도 품질을 놓치지 않을 수 있다.
휴먼 리뷰는 비싸지만, 끝까지 필요하다
아무리 자동 평가가 좋아져도 사람의 판단은 사라지지 않는다. 특히 브랜드 톤, 업무 적합성, 미묘한 오해 가능성, 사용자 신뢰에 미치는 인상 같은 요소는 결국 사람이 더 잘 본다.
다만 휴먼 리뷰도 감에 의존하면 금방 흔들린다. 리뷰어마다 기준이 달라지기 때문이다. 그래서 휴먼 리뷰는 반드시 루브릭, 즉 채점 기준표를 가져야 한다.
예를 들어 고객 문의 답변 기능을 리뷰한다면 다음처럼 기준을 나눌 수 있다.
질문 의도를 정확히 이해했는가
정책상 허용되지 않는 안내를 하지 않았는가
필요한 정보가 빠지지 않았는가
말투가 서비스 톤과 맞는가
상담원 이관이 필요한 상황을 잘 감지했는가
각 항목을 1점부터 5점까지 매기거나, 통과·보류·실패처럼 단순화할 수도 있다. 중요한 것은 리뷰어가 "좋아 보인다"가 아니라 같은 기준으로 판단하게 만드는 것이다.
휴먼 리뷰는 전수검사보다 표본검사가 현실적이다
운영 중인 서비스에서 모든 응답을 사람이 볼 수는 없다. 그래서 표본 추출 전략이 필요하다. 여기서 무작위 샘플만 보면 반쪽짜리다. 문제는 보통 드문 케이스에서 크게 터지기 때문이다.
실무에서는 세 갈래 샘플링이 유용하다.
무작위 샘플: 전체 평균 품질을 본다.
위험 샘플: 긴 입력, 낮은 신뢰 점수, 재시도 발생 건, 폴백 발생 건처럼 이상 신호가 있는 응답을 본다.
중요 샘플: 매출, 법적 리스크, 핵심 고객과 연결된 요청을 우선 본다.
이렇게 보면 "전체적으로는 괜찮은데, 위험 구간에서 무너진다"는 사실을 더 빨리 알 수 있다.
사람과 자동 평가가 엇갈릴 때는 무엇을 믿을까
실무에서 정말 자주 벌어지는 일이다. 자동 평가는 점수가 올랐는데, 사람이 보기엔 오히려 나빠진 것 같을 수 있다. 또는 반대일 수도 있다.
이럴 때는 누가 맞는지를 먼저 따지기보다, 평가 기준이 어긋난 이유를 찾아야 한다. 보통 원인은 세 가지 중 하나다.
첫째, 자동 평가가 너무 얕다. 형식은 잘 지켰지만 내용이 빈약한 응답을 높은 점수로 볼 수 있다. 둘째, 사람의 기준이 문서화되지 않았다. 리뷰어마다 기대치가 달라 점수가 흔들린다. 셋째, 실제 제품 목표와 평가 목표가 다르다. 예를 들어 모델은 친절해졌지만 사용자는 더 빠른 정답을 원할 수 있다.
이럴 때는 리뷰 회의를 길게 하기보다, 문제 사례를 모아 루브릭과 자동 평가 기준을 다시 다듬는 편이 낫다. 좋은 평가 시스템은 한 번에 완성되지 않는다. 실제 실패를 먹고 자란다.
온라인 테스트는 오프라인 평가를 대체하지 않는다
A/B 테스트를 하면 다 해결될 것처럼 느껴질 때가 있다. 물론 온라인 실험은 중요하다. 실제 사용자 행동에서 답을 얻을 수 있기 때문이다. 하지만 온라인 테스트만 믿는 것은 위험하다.
이유는 간단하다. LLM의 품질 문제는 클릭률 같은 지표에 바로 드러나지 않을 수 있다. 사용자는 잘못된 답을 보고도 그냥 떠나 버릴 수 있다. 또는 소수 사용자에게만 심각한 피해가 나는 문제는 평균 지표에 잘 보이지 않는다.
그래서 좋은 운영팀은 오프라인 평가와 온라인 지표를 함께 본다. 오프라인에서는 회귀와 안전성을 막고, 온라인에서는 실제 효용을 검증한다. 둘은 경쟁 관계가 아니라 역할 분담 관계다.
기능별로 테스트 방식은 달라져야 한다
모든 LLM 기능을 같은 평가 프레임으로 재면 무리가 생긴다. 기능 성격에 따라 테스트 방식도 달라져야 한다.
요약 기능은 핵심 누락과 사실 왜곡을 잘 봐야 한다. 재작성 기능은 의미 보존과 톤 변경의 성공 여부가 중요하다. 분류 기능은 라벨 정확도와 혼동 구간 분석이 핵심이다. RAG 기반 답변은 답변 품질만이 아니라 검색된 문서의 적절성, 근거 연결성, 출처 제시 여부까지 함께 봐야 한다. 툴 호출 기능은 자연어 문장보다 호출 파라미터 정확성과 실패 처리 로직이 더 중요할 수 있다.
즉, "LLM 평가"라는 하나의 상자가 있는 것이 아니다. 실제로는 기능별 평가 설계의 묶음에 가깝다.
실패를 발견했을 때는 원인을 분리해서 봐야 한다
테스트 결과가 나쁘다고 해서 항상 모델이 문제인 것은 아니다. LLM 서비스에서는 실패 원인이 여러 층에 숨어 있다.
입력 전처리가 잘못되어 문맥이 누락되었을 수도 있다. 프롬프트가 장황해서 핵심 지시가 묻혔을 수도 있다. 검색 결과가 엉뚱했을 수도 있고, 후처리 규칙이 정상 응답을 망가뜨렸을 수도 있다. 모델 자체보다 시스템 주변부가 문제인 경우가 생각보다 많다.
그래서 테스트 결과는 가능하면 다음 단위로 쪼개어 기록하는 편이 좋다.
입력은 적절했는가
검색이나 컨텍스트 주입은 적절했는가
모델 원응답은 괜찮았는가
후처리와 정책 적용이 결과를 망치지 않았는가
최종 사용자 경험은 만족스러웠는가
이렇게 층을 나눠 보면 "모델을 바꿔야 하나"라는 큰 결론으로 성급하게 가지 않고, 실제 병목을 찾기 쉬워진다.
테스트셋은 살아 있는 자산이어야 한다
LLM 기능은 시간이 지나면서 변한다. 모델 버전이 바뀌고, 사용자 질문이 바뀌고, 제품 포지션도 바뀐다. 그런데 테스트셋이 처음 만든 그대로 멈춰 있으면 품질 관리도 멈춘다.
좋은 팀은 테스트셋을 운영 자산처럼 관리한다. 새로 발생한 실패 사례를 넣고, 중요도가 바뀐 시나리오를 반영하고, 더 이상 의미 없는 케이스는 정리한다. 특히 릴리스 후 장애나 고객 불만으로 이어진 사례는 반드시 평가셋에 편입해야 한다. 그래야 같은 실수를 반복하지 않는다.
쉽게 말해 테스트셋은 교과서가 아니라 사고 사례집에 가깝다. 과거의 실패가 다음 배포를 지켜 주는 셈이다.
실무에서 권장하는 최소 테스트 루틴
복잡한 평가 체계를 한 번에 만들 필요는 없다. 처음에는 작게 시작해도 된다. 다만 최소한의 루틴은 있어야 한다.
첫째, 코드 레벨의 결정적 테스트를 준비한다. 프롬프트 변수 누락, 응답 파싱, 재시도, 권한, 폴백은 자동화한다. 둘째, 기능별 회귀 평가셋을 만든다. 처음에는 30건 정도여도 괜찮다. 셋째, 형식 준수와 금지 규칙 같은 기계적 검사를 자동화한다. 넷째, 중요 케이스에 대해서는 사람 리뷰를 붙인다. 다섯째, 운영 중 실패 사례를 회수해 평가셋에 추가한다.
이 다섯 가지만 돌아가도 "왠지 좋아 보인다" 수준에서 "어느 부분이 좋아졌고 어느 부분이 나빠졌는지 안다" 수준으로 올라갈 수 있다. 실무에서 필요한 것은 완벽한 평가보다 반복 가능한 평가다.
한 가지 예로 보는 평가 설계
회의록 요약 기능을 만든다고 해 보자. 사용자는 긴 회의 내용을 넣고, 핵심 논의와 액션 아이템을 빠르게 보고 싶어 한다.
이 기능의 테스트는 단지 요약문이 자연스러운지만 보면 부족하다. 먼저 테스트셋에는 짧은 회의, 긴 회의, 잡담이 많은 회의, 결정 사항이 없는 회의, 여러 사람이 비슷한 의견을 반복하는 회의가 포함되어야 한다. 그다음 평가 기준은 "핵심 안건 포함 여부", "결정 사항 누락 여부", "액션 아이템의 담당자와 기한 보존 여부", "원문에 없는 결정 사항 생성 금지", "출력 형식 준수"처럼 나뉘어야 한다.
자동 평가는 액션 아이템 섹션 존재 여부, 길이 제한, 금지된 표현 사용 여부를 검사할 수 있다. 더 나아가 핵심 안건 키워드가 포함됐는지 규칙으로 볼 수도 있다. 사람 리뷰는 요약이 실제 업무에 도움이 되는지, 누락이 치명적인지, 말투와 구조가 읽기 편한지를 판정한다.
이렇게 설계하면 같은 요약 기능이라도 "문장이 부드럽다"와 "업무에 쓸 수 있다"를 구분해서 관리할 수 있다.
결국 테스트의 목적은 배포를 자신 있게 만드는 것이다
LLM 기능 테스트의 목적은 모델을 시험하는 데 있지 않다. 팀이 더 자주, 더 안전하게 배포하도록 돕는 데 있다. 프롬프트를 바꿔도, 모델을 교체해도, 비용 절감을 위해 경량 모델로 일부 트래픽을 넘겨도, 어떤 품질 변화가 생길지 예측 가능해야 한다.
그러려면 세 가지가 필요하다. 대표성 있는 테스트셋, 반복 가능한 자동 평가, 그리고 기준이 분명한 휴먼 리뷰다. 이 셋이 함께 있어야 LLM 기능은 감각의 영역에서 관리의 영역으로 넘어온다.
LLM 서비스는 원래부터 완벽하게 맞는 답을 내는 기계가 아니다. 대신 잘 설계된 테스트 체계가 있으면, 불완전한 시스템을 충분히 신뢰 가능한 제품으로 바꿀 수 있다. 바로 그 전환점이 운영 품질의 시작이다.
이 노트는 보도·비평·교육·연구 목적으로 작성되었습니다. 저작권 문의가 있으시면 에서 알려주세요.