Claude를 쓰는 기능도 만들고 끝이 아니라 배포하고 운영하고 고쳐 나가야 합니다. 이 수업에서는 모델이 끼어 있는 시스템에서 생애주기가 일반 소프트웨어와 어떻게 달라지는지를 다룹니다.
달라지는 지점
개발·배포·운영·유지보수라는 큰 틀은 같습니다. 다만 모델이 끼면 세 가지가 달라집니다.
같은 코드가 다른 결과를 냅니다. 배포하지 않아도 출력이 달라질 수 있습니다. 그래서 "코드가 안 바뀌었으니 동작도 같다"는 가정이 성립하지 않습니다.
의존 대상이 우리 손 밖에서 바뀝니다. 모델은 갱신되고, 그때 응답 경향이 달라질 수 있습니다. 라이브러리 버전과 달리 우리가 올리는 것이 아니라 고정하지 않으면 따라갑니다.
품질이 이분법이 아닙니다. 일반 기능은 되거나 안 되거나이지만, 요약 품질은 조금씩 나빠질 수 있습니다. 그래서 배포 판정에 통과·실패 테스트만으로는 부족하고 평가 세트 점수가 필요합니다.
이 세 가지 때문에 생애주기에 없던 활동이 붙습니다. 평가 세트를 만들고 유지하는 일, 모델 버전을 고정하고 옮기는 일, 프롬프트를 코드처럼 버전 관리하는 일입니다.
배포 전에 무엇을 통과시킬 것인가
일반 기능이라면 단위 테스트와 통합 테스트가 통과하면 나갑니다. 모델이 끼면 여기에 하나가 더 붙습니다.
# 배포 게이트 예시
def gate() -> bool:
unit_ok = run_pytest() # 코드가 도는가
contract_ok = run_schema_checks() # 출력 형식이 맞는가
quality = run_eval_set() # 품질이 기준 이상인가
return unit_ok and contract_ok and quality.pass_rate >= 0.90
평가 세트는 대표 사례, 어려운 경계 사례, 과거에 터진 사례 세 갈래로 만듭니다. 특히 세 번째가 중요합니다. 한 번 고친 문제가 다시 나오는 것을 막는 회귀 방지선입니다.
평가 세트를 만들 때 흔한 실수는 프롬프트를 고칠 때마다 같은 세트를 보며 고치는 것입니다. 그러면 그 세트에만 맞는 프롬프트가 됩니다. 개선용과 판정용을 나눠 두고, 판정용은 자주 보지 않는 편이 낫습니다.
운영 중에 지켜볼 것
배포한 뒤에는 코드가 그대로여도 상황이 변합니다. 최소한 이 셋은 봐야 합니다.
입력 분포 — 사용자가 넣는 내용이 처음 설계할 때와 달라졌는지. 새로운 유형이 늘면 프롬프트가 못 따라갑니다.
출력 이상 신호 — 길이가 갑자기 짧아지거나, 형식 검증 실패가 늘거나, 특정 문구가 반복되는지.
비용과 지연 — 토큰 사용량이 조용히 늘어나는 일이 흔합니다. 이력이 길어지거나 도구 결과가 커지면 그렇습니다.
여기서 중요한 것은 정상 응답에도 실패가 숨어 있다는 점입니다. HTTP 200이고 예외도 없는데 내용이 나빠지는 경우가 있습니다. 그래서 상태 코드만 보는 모니터링으로는 부족하고, 출력 자체의 특성을 봐야 합니다.
log.info("completion", extra={
"request_id": rid,
"model": resp.model, # 어느 버전이 답했는가
"input_tokens": resp.usage.input_tokens,
"output_tokens": resp.usage.output_tokens,
"stop_reason": resp.stop_reason, # max_tokens면 잘린 것이다
"schema_valid": is_valid,
})
고칠 때의 순서
품질이 떨어졌다는 신고를 받으면 순서가 있습니다. 아무 데나 손대면 무엇이 효과였는지 알 수 없습니다.
- 재현한다. 문제가 된 입력을 확보해 같은 결과가 나오는지 봅니다. 재현되지 않으면 입력 자체가 다른 것입니다.
- 무엇이 바뀌었는지 확인한다. 모델 버전, 프롬프트, 입력 분포, 도구 응답 중 무엇이 달라졌는지 좁힙니다.
- 한 번에 하나만 바꾼다. 프롬프트와 모델을 동시에 바꾸면 원인을 가릴 수 없습니다.
- 평가 세트로 확인한다. 그 한 건이 고쳐졌는지가 아니라 전체 점수가 올랐는지를 봅니다.
- 회귀 사례로 추가한다. 고친 사례를 평가 세트에 넣습니다.
4번이 특히 중요합니다. 신고된 한 건만 보고 프롬프트를 고치면 그 건은 고쳐지고 다른 열 건이 나빠지는 일이 흔합니다. 개별 사례가 아니라 집합으로 판정하는 습관이 이 영역의 핵심입니다.
시험 함정
- 코드가 바뀌지 않았으니 동작도 같다는 가정 — 모델이 끼면 성립하지 않습니다.
- 모델 버전을 고정하지 않아도 우리가 올릴 때만 바뀐다는 서술 — 고정하지 않으면 갱신을 따라갑니다.
- 통과·실패 테스트만으로 배포를 판정하는 선택지 — 품질은 이분법이 아니라 평가 세트 점수가 필요합니다.
- 개선용과 판정용 평가 세트를 같은 것으로 쓰는 접근 — 그 세트에만 맞는 프롬프트가 됩니다.
- 상태 코드와 예외만 보는 모니터링 — 정상 응답 안에 품질 저하가 숨습니다.
- 신고된 한 건이 고쳐졌는지로 수정을 판정하는 선택지 — 집합 점수로 확인해야 다른 사례의 악화를 잡습니다.
실습 시나리오
실제 시험과 같은 형식의 시나리오 문제입니다.
두 달째 잘 돌던 분류 기능의 정확도가 최근 떨어졌다는 신고가 들어왔습니다. 코드와 프롬프트는 배포 이후 바뀌지 않았습니다. 가장 먼저 확인할 것은 무엇입니까?
빌드 연습 · 배포 게이트와 회귀 세트 만들기
약 35분1.평가 세트 3갈래
대표 사례 10건, 경계 사례 5건, 과거 실패 사례 5건을 모읍니다.
기대 결과 · 각 사례에 기대 결과가 적혀 있습니다.
2.판정용 분리
개선용과 판정용을 나누고 판정용은 따로 보관합니다.
기대 결과 · 두 세트가 파일로 분리되어 있습니다.
3.게이트 스크립트
단위 테스트·형식 검증·평가 점수를 모두 확인하는 스크립트를 만듭니다.
기대 결과 · 기준 미달 시 0이 아닌 종료 코드로 끝납니다.
4.관측 항목 추가
모델 버전, 토큰, stop_reason, 형식 검증 결과를 로그에 남깁니다.
기대 결과 · 로그 한 줄로 어느 버전이 어떤 결과를 냈는지 알 수 있습니다.
5.회귀 추가 연습
일부러 실패 사례를 하나 만들어 고친 뒤 평가 세트에 넣습니다.
기대 결과 · 다시 돌렸을 때 그 사례가 통과로 바뀌고 세트에 남습니다.