Geonwoo Lee
← Projects

최종 5인 팀 프로젝트

Mealplanning

식비 예산과 행동 데이터를 연결한 식생활 추천 서비스

LLM 비교 평가·모델 선정, Guardrail 로직 개선, 추천 노출·행동 이벤트 데이터 흐름 분석, AWS 서버리스 AI 기능 구성·검증을 맡았습니다. 아래에는 제가 직접 판단하고 확인한 과정을 근거와 함께 정리했습니다.

밀플래닝 서비스 대표 이미지
밀플래닝
01

프로젝트 개요

기간2026.06.29 — 08.26
참여 인원5명
담당 역할LLM 비교 평가·모델 선정 · Guardrail 로직 개선 · 추천 노출·행동 이벤트 데이터 흐름 분석 · AWS 서버리스 AI 기능 구성·검증
15LLM 후보

누적 1,750건 평가 기록 · 품질·비용·응답 지연·Guardrail 4축

166 → 247Guardrail 통과 건수

같은 275건으로 재측정 · 추가 LLM 호출 없음

session_id데이터 흐름 문제

조회한 44건이 전부 NULL · 전달 경로 추적

팀 환경과 개인 기여를 구분했습니다. EKS, Argo CD, Prometheus/Grafana 등은 팀 실행 환경이며 개인이 구축·운영한 범위가 아닙니다.

02

주요 실측 및 문제 해결 과정

프로젝트에서 담당한 작업과 주요 판단 과정을 실제 측정 결과와 함께 정리했습니다. 각 항목에서 문제를 확인한 과정, 선택 기준, 결과와 한계를 확인할 수 있습니다.

일부 스크립트·코드 작성과 반복 실행에는 AI 도구를 활용했으며, 비교 기준 설정·실험 조건 결정·결과 해석·채택과 되돌림 판단은 직접 수행했습니다.

A 구성과 아키텍처서비스가 어떤 문제를 다루는지와, 제가 맡은 기능을 어디까지 서버리스로 옮겼는지 3개 항목
A-1이 서비스는 어떤 문제를 해결하려 했나팀이 함께 만든 서비스 흐름과 그 안에서 제 기여 범위

문제 상황

식비를 관리하려면 «무엇을 먹을지»와 «얼마를 쓸지»를 따로 계산해야 했습니다. 레시피를 고르는 화면과 장을 보는 화면, 지출을 적는 화면이 분리돼 있으면 사용자가 같은 정보를 두 번 입력하게 됩니다.

서비스가 동작하는 방식

월 식비 예산을 먼저 설정하면 그 값이 레시피 추천·장바구니 예상 결제액·월별 잔액 계산의 공통 기준으로 쓰이도록 구성됐습니다. 영수증을 찍으면 품목과 금액이 추출돼 냉장고 재고와 지출 내역에 함께 반영되고, 보유 재료는 다시 추천과 장바구니 자동 제외 조건으로 이어집니다.

팀 공동 기능과 제 기여

  • 팀 공동 구현 — 온보딩·예산 설정, 냉장고 재고, 레시피 검색·레시피북, 개인 레시피 작성. 서비스 흐름으로 설명하며 제 단독 구현으로 적지 않습니다.
  • 제 기여가 뚜렷한 부분 — 영수증 OCR과 YouTube 영상 레시피 추출의 서비스 코드, 그리고 챗봇 응답 경로.
  • 팀 실행 환경 — Kubernetes 기반 온프렘·AWS 환경, 데이터 저장소, Cache, CI/CD, Observability. 개발은 이 환경 위에서 했지만 구축·운영은 제 범위가 아닙니다.
기여 범위 — 서비스 기획·전체 구현: 팀 공동 · AI 기능(챗·OCR·영상 추출) 서비스 코드: 본인 주담당 · 인프라 구축/운영:
A-2서버리스로 무엇을 옮기고 무엇을 남겼나검토 기준을 먼저 정하고, 기준에 걸린 기능은 옮기지 않았습니다

문제 상황

AI 기능이 상시 떠 있는 워크로드로 돌면 쓰지 않는 시간에도 자원을 붙잡습니다. 호출이 몰리지 않는 기능부터 이벤트 기반으로 옮길 수 있는지 검토했습니다.

확인 및 분석

«옮길 수 있는가»를 감으로 정하지 않으려고 검토 기준 5개를 먼저 정하고, 하나라도 걸리면 후보에서 빼는 방식으로 12종을 전부 확인했습니다.

가설 및 선택지

  • 전부 옮긴다 — 관리 지점은 줄지만 걸리는 기능에서 되돌리기 비용이 커집니다.
  • 기준을 세워 통과한 것만 옮긴다.
  • 옮기지 않는다 — 상시 자원 점유가 계속됩니다.

수행 및 결정

두 번째를 택했습니다. 12종 중 10종을 채택하고 2종은 제외했습니다. Terraform(AWS)으로 Lambda·SQS·SNS·S3·EventBridge Scheduler 구성을 작성하고, 함수가 무엇에 깨어나고 실패하면 어디로 가는지를 트리거와 실패 경로로 먼저 정리했습니다.

결과

이벤트 기반으로 옮긴 기능은 호출이 있을 때만 실행되도록 구성됐고, 제외한 2종은 근거를 남긴 채 기존 방식으로 유지했습니다.

한계 및 고려사항 — 옮기면 잃는 것이 있습니다. 상시 프로세스에서 유지하던 상태와 연결을 매 호출마다 다시 만들어야 하고, 콜드 스타트가 지연에 더해집니다. 그래서 «무엇을 잃는가»를 판정표에 먼저 적고 시작했습니다.

여기서 얻은 작은 교훈 — 테스트가 있다는 것과 실행된다는 것은 다릅니다

서버리스 테스트 파일이 저장소에 있는데도 CI 설정에는 해당 실행 경로가 들어 있지 않아 한 번도 돌지 않고 있었습니다. 파일 존재가 아니라 «파이프라인이 실제로 무슨 명령을 실행하는지»를 봐야 한다는 것을 확인하고 실행 경로에 편입했습니다. 같은 변경에서 제 스모크 테스트 자체의 오류도 발견해 고쳤습니다 — 잘못된 필드명을 보냈는데 200이 돌아와 통과처럼 보이던 경우였습니다.
CI/CD를 구축하거나 운영한 것이 아니라, 기존 검증 과정의 누락을 찾아 보완한 범위입니다.

기여 범위 — 검토 기준 정의·채택/제외 결정·Terraform 작성: 본인 · 상위 인프라 결정과 클러스터 운영:
서버리스 검토 기준 5개와 옮기지 않은 것정제한 실측 원본2026-08-18
이전 후보 12종을 다섯 개 축으로 판정한 표와, 옮기면서 잃는 것을 먼저 적어 둔 절입니다. 지표 · 이전 후보 12종 → 채택 10 / 제외 2 실측 문서 보기 → 기록 전문 보기 →
A-3레시피 후기는 어떻게 모으고 붙였나후기 141,298건을 수집·분류하고 전 레시피에 요약을 연결한 과정

문제 상황

레시피마다 후기가 쌓여 있어도 사용자가 전부 읽지는 않습니다. 후기를 감정으로 분류하고 요약해 붙이려 했는데, 자유 요약은 근거를 다시 쓰는 작업과 성격이 달라 어떤 모델이 맞는지 미리 정할 수 없었습니다.

확인 및 분석

후보 5종을 같은 케이스로 재봤습니다. 판정을 가른 것은 문장 품질이 아니라 존댓말 지시를 지키는지였습니다. 지시를 무시하는 모델은 요약이 그럴듯해도 서비스 말투와 어긋났습니다.

스키마를 실제 DB에 적용하기 전에는 설계 전제가 실 DB와 어긋나지 않는지 먼저 점검했습니다. 그 과정에서 가격 이상탐지의 기준선이 아직 짧고, 두 소매 가격을 합치면 편차가 부풀어 탐지가 죽는다는 것을 확인했습니다.

수행 및 결정

부정 후기가 있는 레시피만 LLM으로 요약하고 나머지는 템플릿으로 처리했습니다. 가격 기준선은 소매별로 나누고, 이력이 짧은 구간의 급락은 기록만 하고 알리지 않도록 게이트를 뒀습니다.

결과

후기 141,298건을 수집하고, 이 중 141,282건을 감정 분류한 뒤 레시피 6,873개 전부에 요약 결과를 연결했습니다.

초기 비용 추정 36,291원을 기준으로 LLM 적용 대상과 입력량을 조정했고, 예상 비용을 약 2.1~2.2만원 수준으로 낮출 수 있는 구조를 확인했습니다.

한계 및 고려사항 — 가격 기준선은 이력이 더 쌓이기 전까지 미성숙 상태로 둡니다. 문서에도 해결하지 못한 항목을 그대로 적어 뒀습니다.
기여 범위 — 후기 수집·감정 분류·요약 처리, 요약 모델 선정·비용 구조 설계·스키마 적용 검증: 본인
리뷰 감정분석·요약 완료 리포트정제한 실측 원본2026-07-29
모델을 무엇으로 골랐고 비용을 어떻게 낮췄는지, 해결하지 못한 항목까지 당시 그대로 적은 기록입니다. 지표 · 후기 141,298건 · 분류 99.99% · 요약 커버리지 6,873/6,873 기록 전문 보기 →
추가 자료 · 스키마 적용과 가격 이상탐지 판정정제한 실측 원본2026-07-29
설계 전제를 실 DB에서 점검하고 적용한 결과, 그리고 두 소매를 합친 기준선을 실측으로 기각한 대목입니다. 지표 · 사전 점검 실패 0 · 소매 합산 시 편차 중앙값 2.08배 기록 전문 보기 →
B 결정어떤 기준으로 기술과 모델을 선택했는지 2개 항목
B-1어떤 기준으로 모델을 골랐나후보 15종 · 누적 1,750건 평가 기록 · 판단을 5번 바꿨습니다

문제 상황

관리형 모델로 옮길 수 있게 되면서 «코드 구조상 옮길 수 있는가»만 보고 이관 가능으로 적었습니다. 그런데 구조상 가능한 것과 품질이 유지되는 것은 다른 문제였습니다.

확인 및 분석

구조상 가능 여부만으로 판단하지 않고 동일 조건에서 실제 응답을 비교했습니다. 처음에는 응답 품질만 봤지만, 서비스에 올리려면 비용·응답 지연·Guardrail 통과 여부를 같이 봐야 한다는 것이 드러났습니다. 응답이 좋아도 검증 단계에서 막히는 모델이 있었기 때문입니다.

가설 및 선택지

  • 값이 싼 모델로 교체한다.
  • 기존 모델을 유지한다.
  • 기능별로 나눠 배치한다.

수행 및 결정

저비용 모델이 기존 모델과 만점 동률로 나왔을 때, 모델이 좋아진 게 아니라 테스트가 쉬웠을 수 있다고 보고 더 어려운 케이스 세트를 새로 만들어 다시 쟀습니다. 그러자 갈렸습니다 — 환각 안전성은 모든 모델이 같았고 차이는 정보 완전성이었습니다. 저비용 모델은 답변에서 금액을 통째로 빠뜨렸습니다.
비용 43%·속도 2배 이점보다 식비 앱에서 금액이 안 보이는 손실이 더 크다고 판단해 즉시 교체를 보류했습니다. 이후 실패 원인을 프롬프트로 제거한 뒤, 실제 서비스에서 다듬는 경로에서 동률을 확인하고 조건이 충족된 기능만 옮겼습니다.

결과

후보 15종을 같은 기준으로 재측정해 누적 1,750건의 평가 기록을 남겼고, 새 측정이 나올 때마다 권고를 5번 바꿨습니다. 최종 결과만 남기지 않고 그때그때의 비교표와 판단 변경 시점을 함께 보존했습니다.

한계 및 고려사항 — 어려운 케이스에서 저비용 모델이 끝까지 남긴 실패는 영양·가격처럼 숫자가 몰린 답변이었습니다. 이 답변은 서비스에서 LLM을 거치지 않고 템플릿 그대로 나가고, LLM이 다듬는 것은 레시피 추천뿐이라 교체해도 사용자가 보는 답에는 영향이 없다고 판단했습니다. 다만 이건 지금 설정에 기댄 판단이라, 숫자가 몰린 답변까지 LLM이 다듬도록 바뀌면 판정을 다시 해야 합니다.
또한 입력 케이스풀이 이후 소실돼 완전히 동일한 재현은 불가능합니다. 채점 스크립트와 결과 문서는 남아 있습니다.

배운 점 / 다음 판단

평가 결과가 포화될 때는 모델 차이보다 평가 케이스의 난이도를 먼저 점검해야 한다는 점을 배웠습니다.

기여 범위 — 비교 기준 정의·재측정 요구·최종 선정: 본인 판단
후보 15종 전수 실측정제한 실측 원본2026-07-28
모델별 품질·안전·단가·월비용·품질손실을 한 표에 놓고 비교한 실제 리포트 구간입니다. 월비용 산정식도 함께 있습니다. 지표 · 품질(HARD) n/25 · 안전(환각) n/25 · 원/콜 · 월비용 · 품질손실% 실측 문서 보기 → 기록 전문 보기 →
추가 실측 자료 · 측정 방법과 뒤집힌 1차 판단정제한 실측 원본2026-07-28
코드 구조상 이관 가능하다는 초기 판단을 실제 측정으로 다시 검토한 기록입니다. 무엇을 어떻게 쟀는지와, 같은 모델을 리전만 바꿔 비교한 결과가 함께 있습니다. 지표 · 11모델 × 50케이스 = 550건 · 에러 0 추가 자료 보기 → 기록 전문 보기 →
B-2영수증 OCR은 어떤 기준으로 골랐나실물 13장 · 5개 방식 · 성공 기준을 먼저 정의했습니다

문제 상황

영수증을 찍어 품목과 금액을 자동으로 넣으려면 감열지 인쇄와 구겨진 종이에서도 구조화된 결과가 나와야 했습니다.

확인 및 분석

실물 영수증 13장을 같은 조건에서 5개 방식에 통과시켰습니다. 다운스케일, 재시도, 타임아웃을 모두 고정했습니다.

가설 및 선택지

  • 로컬 OCR 엔진 — 외부 API 호출 비용 없음, 오프라인 가능.
  • 비전 모델 — 구조화 출력을 바로 받을 수 있음.
  • 추론 강화 옵션을 켠 상위 모델 — 정확할 것이다.

수행 및 결정

성공을 무엇으로 셀지부터 정했습니다. 합계 정합 — 추출한 품목 금액의 합이 영수증 총액과 맞으면 성공입니다. 그리고 이 지표의 한계를 같이 적었습니다. 품목이 한두 개인 영수증은 쉽게 통과하고, 총액을 못 읽으면 품목이 맞아도 실패로 처리됩니다. 즉 절대 수치는 무르고 상대 순위만 견고합니다.
경량 비전 모델은 13장 중 12장에서 합계 정합을 확인했고, 실행 오류는 없었습니다. 상위 모델은 추론 옵션을 켜도 더 낫지 않으면서 비용이 수십 배였고, 로컬 엔진은 구조화 출력 자체가 나오지 않았습니다.

결과

경량 비전 모델을 채택했습니다. 사용자가 결과를 확인·수정하는 단계를 앞에 둬서 인식 오류를 사람이 보정할 수 있게 했습니다.

한계 및 고려사항 — 13장은 작은 표본이고, 품목명과 가격의 개별 정오는 따로 검증하지 않았습니다. 그래서 «인식 정확도»라고 쓰지 않고 합계 정합 기준이라고 적습니다. 외부 API 의존이 생기는 것도 감수한 부분입니다.

배운 점 / 다음 판단

지표를 먼저 정의하고 그 한계까지 적어 두면, 나중에 숫자를 과장해서 읽지 않게 됩니다.

기여 범위 — 비교 착수·성공 기준 정의·한계 명시·채택: 본인 판단
영수증 OCR 5개 방식 비교근거 기반 정리2026-07-21
원본이 Markdown 문서라 동일한 수치로 표를 다시 구성했습니다. 측정값은 원본과 같습니다. 영수증 원본 이미지는 개인정보라 싣지 않았습니다. 지표 · 합계 정합 성공률 · 방식별 비용/오류 실측 문서 보기 →
C 검증과 개선바꾼 것이 정말 나아졌는지 같은 기준으로 다시 쟀습니다 4개 항목
C-1정상 응답이 왜 막혔고, 어떻게 줄였나같은 275건에서 통과 166건 → 247건 · 추가 호출 없음

문제 상황

응답 내용은 문제가 없는데 검증 단계에서 막히는 경우가 반복됐습니다. 막히면 템플릿 답변으로 대체되므로, 유료 호출을 하고 결과를 버리는 셈이었습니다.

확인 및 분석

실패한 케이스를 모아 다시 봤더니 상당수가 환각이 아니었습니다. 사용자가 질문에 쓴 재료와 금액을 그대로 되풀이한 것을 검증 로직이 «근거 없는 내용»으로 오판하고 있었습니다.

가설 및 선택지

  • 모델을 바꾼다 — 비용과 재검증이 따라옵니다.
  • 검증 기준을 느슨하게 한다 — 진짜 환각까지 통과합니다.
  • 근거로 인정하는 범위를 고친다 — 사용자 질문도 근거에 포함합니다.

수행 및 결정

세 번째를 택했습니다. 근거 문자열에 사용자 질문 원문한글 수사를 숫자로 편 정규화 결과를 함께 넣도록 처리 방식을 바꿨습니다. 「8천원」 같은 표현이 8000과 이어지도록 한 것입니다.

결과

같은 275건 평가 세트를 다시 돌려 통과가 166건에서 247건으로 늘었습니다(약 60% → 90%). 문자열 구성만 바꾼 변경이라 LLM 호출은 한 건도 늘지 않았습니다.

한계 및 고려사항 — 근거로 인정하는 범위를 넓힌 만큼, 사용자가 잘못된 전제를 질문에 담으면 그것이 근거로 통과할 여지가 생깁니다. 수정 후에도 남은 실패는 모르는 것을 지어내는 유형에 몰려 있었고, 그것이 다음 개선의 표적이 됐습니다.

배운 점 / 다음 판단

«모델이 나쁘다»로 결론 내기 전에 판정 로직부터 확인하게 됐습니다. 이 건은 모델을 교체하거나 LLM 호출을 추가하지 않고 판정 로직 수정으로 통과 건수를 개선했습니다.

기여 범위 — 오탐 의심 제기·재측정 요구·채택: 본인 판단
가드레일 수정 효과 — 같은 275건 재측정정제한 실측 원본2026-07-28
모델 11종 각각에서 몇 건이 회수됐는지 막대로 보여주는 실제 리포트 구간입니다. 합계와 «추가 LLM 호출 없음» 조건이 같은 화면에 있습니다. 지표 · 통과 건수 / 275 (pass count · 정확도가 아닙니다) 실측 문서 보기 → 기록 전문 보기 →
C-2한 번 좋아진 결과를 왜 되돌렸나9회차 반복 검증 · 회차당 30건 · 총 270 호출

문제 상황

챗봇이 주제에서 벗어난 질문에 답해 버리거나, 반대로 답해야 할 질문을 거절하는 경우가 있었습니다. 판정 규칙을 고쳐 가며 반복해서 쟀습니다.

확인 및 분석

30건 스위트로 회차를 돌렸습니다. 초반 개선으로 점수가 올랐지만, 특정 회차에서 넣은 경계 매칭 규칙이 복합 요리명을 놓치게 만든다는 것을 확인했습니다. 「갈비찜」이 「매콤돼지갈비찜」 안에 들어 있는 경우를 못 잡는 식이었습니다.

가설 및 선택지

  • 점수가 올랐으니 그대로 둔다.
  • 되돌린다 — 오매칭이 다시 생길 수 있습니다.
  • 예외 목록을 덧붙인다 — 규칙이 계속 늘어납니다.

수행 및 결정

되돌렸습니다. 복합 요리명을 놓치는 손실이 오매칭을 막는 이득보다 컸고, 원래 막으려던 주제 이탈은 앞단의 다른 장치가 이미 걸러 주고 있었기 때문입니다.
그리고 좋은 점수가 나온 뒤 바로 다음 단계로 가지 않고, 학습에 쓰지 않은 seed 3개로 같은 코드를 다시 돌려 특정 케이스에만 맞춘 개선이 아닌지 확인했습니다.

결과

되돌린 뒤에도 점수가 유지됐고, 서로 다른 seed에서도 비슷한 수준이 나왔습니다. 이후 생성 백엔드를 붙일 때는 «판정 결과가 같아야 한다»를 가설로 먼저 적고 확인했습니다.

한계 및 고려사항 — 30건은 작은 스위트입니다. «검증 체계를 구축했다»고 할 규모가 아니라 반복 확인의 습관에 가깝습니다. 회차 간 비교는 같은 스위트 안에서만 유효합니다.

배운 점 / 다음 판단

점수가 오른 변경도 조건이 한정되면 손해일 수 있다는 것, 그리고 좋은 결과일수록 다른 조건에서 먼저 확인해야 한다는 것을 기준으로 삼게 됐습니다.

기여 범위 — 되돌림 판단·seed 일반화 확인 단계 삽입·회귀 가설 설정: 본인 판단
9회차 반복 검증과 되돌린 판단근거 기반 정리2026-07-14 ~ 07-15
보존된 원본 실행 기록에서 회차·seed·케이스 수를 그대로 읽어 표로 옮겼습니다. 이 실험은 270 호출이며, 아래 C-3의 2,276 호출과는 다른 실험입니다. 지표 · 30건 스위트 정답 수 · seed별 일반화 확인 실측 문서 보기 →
C-32,276회 비교에서 무엇을 확인했나1,138건 × 2라운드 · 나빠진 항목도 함께 남겼습니다

문제 상황

소규모 스위트로는 잡히지 않는 문제가 있었습니다. 특히 재료가 많은 답변에서 품목이 잘리거나 금액이 빠지는 경우였습니다.

확인 및 분석

말투·난이도·품목 수를 조합해 1,138건을 만들고, 튜닝 전후로 두 번 돌려 2,276회를 비교했습니다. 생성은 seed를 고정해 결정적으로 맞췄습니다. 1차 계측에서 다품목 이름 잘림, 질문 문장을 요리 이름처럼 인용하는 동작, 그리고 채점기 자체의 오탐까지 드러났습니다.

가설 및 선택지

  • 모델을 바꾼다.
  • 프롬프트에서 실패 원인을 직접 금지한다.
  • 후처리로 걸러 낸다.

수행 및 결정

프롬프트에서 실패 원인을 직접 막았습니다. 여러 줄 근거가 오면 모든 줄의 재료와 금액을 답변에 포함하도록 하고, 질문 문장을 요리 이름처럼 인용하는 것을 금지했습니다. 그리고 전체 평균이 아니라 실제 서비스에서 다듬는 경로를 기준으로 판단했습니다.

결과

실제 서비스 경로의 치명 결함이 88건에서 21건으로 줄었습니다(720건 기준 12.2% → 2.9%). 전체 1,138건 기준으로는 9.9% → 4.6%입니다.

한계 및 고려사항 — 나빠진 것도 있습니다. 같은 변경에서 금액 손실은 26건에서 31건으로 늘었고, 재료비 카테고리 통과율은 72.2%에서 66.7%로 떨어졌습니다. 좋아진 숫자만 남기지 않고 그대로 기록했습니다. 이 실험의 입력 케이스풀도 이후 소실돼 완전한 재현은 불가능합니다.

배운 점 / 다음 판단

전체 평균은 실제 사용자가 겪는 것과 다를 수 있습니다. 그래서 어느 경로가 실제로 그 코드를 지나가는지 먼저 나눠서 보게 됐습니다.

기여 범위 — 실험 규모·조건 지정·판단 기준(실제 서비스 경로) 설정: 본인 판단
튜닝 전후 2,276회 비교정제한 실측 원본2026-07-29
결과 요약과 카테고리별 통과율을 함께 담은 실제 리포트 구간입니다. 악화된 항목이 그대로 보입니다. 지표 · 치명 결함률 = (금액 손실 + 이름 누락) / 케이스 수 실측 문서 보기 → 기록 전문 보기 →
C-4CRF 경량화는 어떻게 검증했나예측이 한 건도 달라지지 않는 것을 먼저 확인했습니다

문제 상황

재료 인식 모델을 서빙할 때 학습용 라이브러리가 통째로 따라왔습니다. 추론에는 쓰이지 않는데도 배포 패키지 대부분을 차지했습니다.

확인 및 분석

패키지 크기를 뜯어 보니 수치 연산·머신러닝 라이브러리 세 개가 대부분이었습니다. 모델을 학습 객체가 아니라 네이티브 형식으로 저장하면 추론 전용 경량 라이브러리만으로 열 수 있었습니다.

가설 및 선택지

  • 그대로 둔다 — 배포 방식에 제약이 남습니다.
  • 포맷을 바꾼다 — 결과가 달라질 위험이 있습니다.

수행 및 결정

경량화 이후에도 동일 모델로 볼 수 있는지를 확인하기 위해, 채택 기준을 크기 감소가 아니라 예측 결과의 완전 일치로 정했습니다.
사람이 검수한 정답 50건으로 두 경로의 예측을 전수 비교했고, 라벨과 추출 결과가 50건 모두 일치하는 것을 확인한 뒤에 반영했습니다. 학습은 기존 스택을 그대로 두고 서빙만 네이티브 포맷으로 바꿨습니다.

결과

배포 패키지가 크게 줄면서 성능 지표는 유지됐습니다. 부수적으로 알게 된 것도 있습니다 — 학습 객체를 그대로 불러오는 방식은 파일 내용에 따라 코드가 실행되는 경로라, 모델을 외부 저장소에서 받아 오는 구조에서는 그 자체가 위험 지점이 됩니다. 네이티브 포맷은 순수 데이터라 그 경로가 없습니다.

한계 및 고려사항 — 네이티브 포맷에는 학습 이력과 라벨 집합 같은 메타데이터가 담기지 않아 따로 기록해야 합니다. 경량화 아이디어의 최초 제안보다, 기존 출력과의 등가성 검증 기준을 세우고 결과를 확인해 채택 여부를 판단하는 역할을 맡았습니다.

배운 점 / 다음 판단

«좋아 보이는 변경»일수록 채택 조건을 먼저 숫자로 못 박아 두면, 나중에 논쟁이 생기지 않습니다.

기여 범위 — 등가성 증명 요구·검증 기준 정의·최종 채택: 본인 판단
CRF 서빙 포맷 등가성 — 실제 재실행실제 재실행2026-08-31 재실행
보존된 학습 산출물과 검수 정답 50건이 남아 있어 지금 다시 돌린 실제 출력입니다. 만들어 낸 화면이 아닙니다. 지표 · span P/R/F1 (검수 정답 50건) · 두 경로 예측 일치 건수 실행 결과 보기 →
D 트러블슈팅과 신뢰성값을 직접 조회해 어느 구간에서 끊겼는지 확인한 기록 3개 항목
D-1학습 label이 안 만들어진 이유조회한 44건이 전부 비어 있었습니다

문제 상황

추천이 화면에 노출된 기록은 쌓이는데, 학습에 필요한 긍정 label이 한 건도 만들어지지 않았습니다.

확인 및 분석

모델을 다시 학습시키는 대신 학습 SQL의 조인 조건과 실제 저장된 이벤트를 대조했습니다. 노출과 행동을 잇는 키 값을 조회한 44건이 전부 비어 있었습니다.

가설 및 선택지

  • 모델 문제 — 학습을 다시 돌린다.
  • SQL 조인 조건 문제.
  • 값이 애초에 전달되지 않는다.

수행 및 결정

세 번째로 좁히고 값을 따라 올라갔습니다. Frontend의 세션 생성 → API 요청 본문 → 이벤트 저장 → 학습 데이터 순서로 각 구간에서 값이 실려 있는지 확인했고, 요청에 필드가 실리지 않는 지점을 찾아 전달 경로를 고쳤습니다.

결과

끊겨 있던 노출과 행동의 연결이 복구돼, 이후 쌓이는 데이터부터는 label이 만들어질 수 있는 상태가 됐습니다.

한계 및 고려사항 — 이미 지나간 기간의 label은 복구할 수 없어, 이후 데이터가 다시 쌓이는지 확인해야 했습니다.
규모를 주장하는 사례가 아닙니다. 조회한 44건이 전부 비어 있었다는 사실과 그 원인 경로만을 근거로 씁니다.

배운 점 / 다음 판단

«어느 기술이 고장났나»보다 «신호가 어느 구간에서 끊겼나»를 먼저 보게 됐습니다. AI 기능의 이상도 모델 내부 문제로 단정하면 원인을 놓칩니다.

기여 범위 — 발견·원인 분석·수정: 본인
학습 label이 생성되지 않은 경로근거 기반 정리2026-08 초
내부 테이블명과 코드 경로는 공개하지 않고, 구간별로 무엇을 확인해 어떤 결과가 나왔는지만 정리했습니다. 지표 · 조인 키 NULL 비율 — 조회 44건 전부 NULL 근거 보기 →
추가 판단 근거 · 데이터 규모를 과장하지 않기로 한 판단근거 기반 정리2026-08-18
추천 노출 이벤트 320건을 확인하고, 학습 데이터 규모를 실제보다 크게 표현하지 않기로 판단했습니다. 지표 · 추천 노출 이벤트 320건 (2026-08-18 실측) 추가 자료 보기 →
D-2외부 모델 버전이 바뀌면 왜 문제가 생기나고칠 범위를 6개 컴포넌트로 넓힌 판단

문제 상황

모델을 «최신» 별칭으로 부르고 있었는데, 그 별칭이 상위 세대를 가리키게 되면서 기존에 쓰던 파라미터가 거부됐습니다. 해당 기능이 전량 실패했습니다.

확인 및 분석

실패한 기능은 하나였지만, 코드베이스를 훑어 보니 같은 방식으로 별칭을 쓰는 곳이 여러 군데였습니다. 즉 지금 조용한 곳도 다음 별칭 변경에서 같은 방식으로 깨질 수 있었습니다.

가설 및 선택지

  • 실패한 기능만 고친다 — 가장 빠릅니다.
  • 별칭을 쓰는 곳을 전부 찾아 고정한다.
  • 예외 처리를 넣어 실패를 흡수한다 — 원인이 남습니다.

수행 및 결정

두 번째를 택했습니다. 실측으로 고른 모델과 런타임이 실제로 부르는 모델이 어긋날 수 있는 지점 전부를 범위로 잡고 6개 컴포넌트를 특정 버전으로 고정했습니다. 벤치마크로 고른 모델이 아닌 것이 돌면 그 벤치마크 결과 자체가 무효가 되기 때문입니다.

결과

운영 문서까지 포함해 12개 파일이 정렬됐고, 별칭 변경으로 계약이 바뀌는 경로가 제거됐습니다.

한계 및 고려사항 — 버전을 고정하면 개선된 상위 모델이 나와도 자동으로 따라가지 않아, 올릴 때마다 다시 측정해야 합니다. 그 비용은 감수했습니다.
최초 장애 인지보다, 동일한 위험이 있는 호출 지점을 함께 확인하고 수정 범위를 정하는 작업을 맡았습니다.

배운 점 / 다음 판단

장애가 발생한 지점만 수정하지 않고, 동일한 실패 조건이 있는 경로까지 함께 확인하는 방식으로 범위를 넓혔습니다.

기여 범위 — 수정 범위 결정: 본인 판단
모델 별칭 드리프트와 버전 고정근거 기반 정리2026-07-22
팀 저장소 커밋에 남아 있는 변경 범위와 사유입니다. 어떤 컴포넌트가 함께 정렬됐는지 보입니다. 지표 · 변경 파일 12 · 정렬한 컴포넌트 6 커밋 근거 보기 →
D-3Running인데 새 배포는 안 되던 이유프로젝트가 끝난 뒤 실행 환경을 점검하며 확인한 사례
프로젝트 종료 후 점검 — 프로젝트가 끝난 뒤 실행 환경을 점검하며 확인한 사례입니다. 프로젝트 기간 중 대응한 장애가 아닙니다.

문제 상황

워크로드는 정상으로 보이는데 새 배포만 실패했습니다. 겉으로는 아무 문제가 없어 보였습니다.

확인 및 분석

기존 Pod는 노드에 남아 있던 이미지로 계속 실행되고 있었습니다. 재시작 횟수도 0이었습니다. 반면 레지스트리 접근이 필요한 순간 — 즉 새 배포나 재스케줄링 — 에만 실패가 드러났습니다.

결과 / 배운 점

Pod가 Running 상태인 것과 새 배포가 가능한 상태는 다르다는 점을 확인했습니다. 현재 상태가 정상인 것과 다음 변경을 수행할 수 있는 것은 별개이고, 둘 다 운영 상태의 일부입니다. 주기적 점검이 실패 신호를 만들고 있었지만 그 실패 자체에는 알림이 걸려 있지 않아 아무도 모르고 있었습니다.

기여 범위 — 종료 후 개인 점검: 본인 · 클러스터 구축·운영: