프롬프트 조금만 바꿔도 출력 품질이 들쭉날쭉합니다. 평가를 어떻게 자동화하나요?
혼자 LLM 기능을 만드는 1인 개발자입니다. 지금까지는 프롬프트 고치고 직접 몇 개 돌려보면서 "오 이게 더 낫네" 하고 감으로 머지해왔는데요. 기능이 늘어나니까 한 군데 프롬프트를 고치면 다른 케이스가 망가지는 회귀가 자꾸 생깁니다.
LLM은 출력이 매번 조금씩 달라서 단위테스트처럼 assert ==로 못 잡잖아요. 다들 LLM 기능 평가를 어떻게 자동화하시는지, 작게 시작하는 방법이 궁금합니다. 거창한 MLOps 도입할 여력은 없습니다.
답변 3개
- 채택된 답변에디터 검증
거창하게 갈 거 없습니다. "평가셋 + 채점 함수" 딱 이 두 개면 시작돼요. 저도 1인으로 굴리는데 파이썬 스크립트 하나로 버팁니다.
먼저 골든 셋부터. 실제로 들어왔거나 들어올 법한 입력 20~50개를 케이스로 고정하세요. 특히 "한 번 망가졌던" 케이스는 반드시 넣으세요 — 어차피 목적이 회귀 방지니까. 버그 터질 때마다 그 입력을 케이스로 박아두는 식으로 누적시키면 됩니다.
채점기는 출력 종류에 맞춰서:
- 분류/추출처럼 정답이 정해진 건 그냥 정확히 비교(
==, set 일치). LLM이라도 이런 태스크는 결정적 채점 됩니다. - 자유 서술처럼 정답이 하나가 아닌 건 "필수 키워드 포함 / 금지어 미포함 / 형식·길이 규칙" 같은 규칙 기반 어서션을 먼저 까세요. 의외로 회귀의 절반 이상이 이 단계에서 잡혀요. JSON 깨졌다든가 안 나와야 할 면책문구가 나왔다든가.
- 그래도 안 잡히는 품질 판단(말투, 사실성)은 그때 LLM-as-judge. 별도 호출에 "이 답이 기준 충족하는지 yes/no + 이유" 물어서 통과율 봅니다.
==로 못 잡는다는 비결정성은, 평가할 땐 temperature를 0으로 깔고 채점은 정확일치가 아니라 위의 규칙/판정 기반으로 하면 됩니다. 그리고 같은 케이스를 한 번이 아니라 5번 돌려서 통과율(5회 중 몇 회)을 보면 들쭉날쭉한 정도가 수치로 드러나요. 5/5면 안정, 3/5면 운임.이거 그냥 스크립트로 "프롬프트 바꾸기 전후 통과율"만 비교해도 감으로 머지하던 때랑은 차원이 다릅니다. Langfuse니 promptfoo니 도구는 나중에 필요해지면 붙이세요. 처음부터 MLOps 안 깔아도 됩니다.
- 분류/추출처럼 정답이 정해진 건 그냥 정확히 비교(
- 에디터 검증
LLM-as-judge 쓸 거면 함정 하나만 미리 경고할게요.
judge 프롬프트를 대충 만들면 얘가 거의 다 통과시켜버려서 "평가 통과함"이라는 가짜 안정감만 줍니다. 이게 진짜 무서운 게, 평가가 다 green인데 실제 품질은 새고 있는 거라 발견이 늦어요.
그래서 judge한테는 반드시 구체적인 rubric을 주고, 가능하면 "통과 예시 / 실패 예시"를 같이 넣으세요. 그리고 judge 자체도 사람이 라벨링한 케이스 10개쯤으로 한번 돌려서 사람 판단이랑 얼마나 일치하는지 확인하고 쓰세요. judge가 사람이랑 70%밖에 안 맞으면 그 judge는 못 믿는 거죠.
하나 더. 점수를 1~10점으로 받으면 judge가 대부분 7~8에 몰려서 변별이 안 됩니다. 차라리 yes/no 이진 판정 여러 개로 쪼개세요 — "사실관계 맞나? Y/N", "말투 적절한가? Y/N" 식으로. 이게 1~10점 한 방보다 훨씬 신뢰 갑니다.
작게 시작하는 거면 CI 붙이기 전에 그냥 로컬
pytest로 평가셋 돌리는 것부터 하세요. 케이스를@pytest.mark.parametrize로 깔고 각 케이스가 규칙 어서션 통과하는지 보면 됩니다. 통과율이 임계치(예: 90%) 밑이면 fail 처리하고요.비용 때문에 매 커밋마다 전체 LLM 평가 돌리는 건 부담이니까, 저는 프롬프트나 관련 코드 바뀐 PR에서만 돌게 path 필터 걸어둡니다. 1인 개발이면 이 정도 타협이 딱 현실적이에요.