← 전체 프로젝트

AI · DATA · WEB진행 중

공장 에너지 AI 플랫폼

ai-elite-bems-next

5개 공장의 에너지·생산 데이터를 통합하고 예측, 이상 진단, 보고까지 하나의 업무 흐름으로 연결했습니다. Streamlit으로 만든 v1을 사내 운영하며 만난 한계를 React·FastAPI 구조로 다시 설계했습니다.

기간2026 — 현재
기술 스택Python · MySQL · FastAPI · Next.js · LangChain
상태진행 중
저장소공개
PythonMySQLFastAPINext.jsLangChainLightGBM
통합 대시보드 — 최근 7일 원단위와 점검 필요 신호, 그리고 실측·AI 예측·P05~P95 구간을 겹쳐 본 추이
통합 대시보드 — 최근 7일 원단위와 점검 필요 신호, 그리고 실측·AI 예측·P05~P95 구간을 겹쳐 본 추이

개요

전력·연료·용수·폐수와 생산실적을 5개 공장(남양주1·남양주2·김해·광주·논산) 단위로 통합해, 조회 → 예측 → 이상 진단 → 보고로 이어지는 업무 흐름을 하나의 사내 웹 서비스로 만들었습니다. 사내 AI 전문가 육성과정(AI ELITE)에서 시작해 실제 운영까지 이어진 프로젝트입니다.

경영진은 매일 아침 한 화면에서 이상 여부와 전년비 성과를 확인하고, 실무자는 같은 데이터로 원단위 개선 과제를 찾습니다.

만든 기능

  • 대시보드 — AI 이상감지 배너(예측 대비 오차율 임계 초과 시 자동 감지), 7일 생산량·원단위 추이, 전년 동월 대비 비교
  • 에너지 모니터링 — 전력을 냉동·공압기·기타로 분해한 사용량 분석, 기간별 추이, 공장별 용수 대비 폐수 비율
  • 원단위 관리사용량 ÷ 생산량 효율 지표. 누계는 단순 평균이 아닌 가중 평균(Σ사용량 ÷ Σ생산량)으로 계산
  • AI 예측 — LightGBM·XGBoost·CatBoost 앙상블로 에너지 사용량 예측
  • AI 보고서 — LLM이 월간 실적 보고서를 생성하고, 이상 감지 시 원인 가설과 점검 우선순위를 제시
  • 관리자 기능 — 엑셀 업로드·검증, 절감 목표·이벤트 관리, 감사 로그, 예측 이력

예측 모델을 설계한 방식

  • 표 형태 데이터에 강한 부스팅 계열 3종(LightGBM·XGBoost·CatBoost)을 앙상블하고, scipy.optimize SLSQP로 가중치 합이 1이 되는 조건에서 손실을 최소화
  • v5.1은 MAPE 최소화, v5.2부터 Pinball Loss로 전환해 점 추정이 아닌 구간 예측으로 변경
  • 이상 판정 지표를 MAPE 대신 PICP(실측이 P05~P95 구간에 들어온 비율)로 바꿔, "얼마나 빗나갔나"가 아니라 "모델이 예상한 범위를 벗어났나"로 판단
  • 학습에 쓰지 않은 최근 3개월로 최종 성능을 채점

성능 (v5.3)

v5.2부터 모델은 하나의 값이 아니라 구간(P05~P95)을 출력합니다. 아래 수치는 구간의 상·하한이 아니라 중앙 추정(P50)과 실측의 오차입니다.

전사 기준 MAPE 약 7% — 전력·연료·용수 전체 기준. 공장·에너지원 단위로는 5% 이내에서 10%대 초반까지 편차가 있습니다.

다만 MAPE는 참고 지표입니다. 이상 여부 판정은 "얼마나 빗나갔나"가 아니라 "모델이 예상한 범위를 벗어났나"로 보는 것이 맞다고 판단해, 운영에서는 PICP(실측이 P05~P95 구간에 들어온 비율)를 주 지표로 씁니다.

이 편차를 평균으로 덮지 않고 원인을 하나씩 추적한 것이 이 프로젝트에서 가장 오래 매달린 부분입니다. 어려운 공장은 대개 데이터가 부족해서가 아니라, 에너지를 쓰는 설비가 생산량 지표에 잡히지 않아서 어려웠습니다.

편차의 원인을 찾은 과정

생산량(mix_prod_kg)만으로는 설명되지 않는 에너지 변동을 잡기 위해 재공품(WIP) 품목별 생산량을 피처 후보로 검토했습니다. 외부 AI가 상관분석으로 추천한 약 80개 후보가 출발점이었는데, 그대로 쓰지 않고 다시 걸렀습니다.

왜 그대로 쓰면 안 되는가

  • 통제변수 누락 — 김해 바나나맛우유믹스는 전력과 raw 상관 0.773이지만, 생산량을 통제한 잔차 상관은 0.19. "그 품목을 만드는 날 = 전체 생산량이 많은 날"일 뿐이라 모델이 이미 아는 정보
  • 큰 표본의 p-value 함정 — 1,228일 표본이면 r=0.07도 p<0.05. 유의성으로 거르면 거의 전부 통과
  • Selection bias — 외부 추천은 train·val·test 전 기간을 보고 계산된 것이라, 그대로 학습에 넣으면 테스트 성능이 낙관 편향됨
  • 카디널리티 폭발 — 5공장 × 3타겟 × 6개면 약 80개 피처. 일 800행 데이터에서 약한 신호 다수는 노이즈

3단계로 걸러냄

  1. 잔차 상관 (train 구간만) — 생산량·요일·월을 통제한 잔차끼리의 상관으로 재점수. 99개 후보 중 23개 통과
  2. Plant-target 단위 ablation — 후보를 넣은 모델과 뺀 모델을 직접 학습해 검증 MAPE 차이로 판정. 잔차를 통과해도 실제 학습에 도움이 안 되는 경우가 많았습니다(김해는 통과한 3개 모두 기각)
  3. 도메인 지식 보정 — 통계로는 영원히 못 찾을 것들이 여기서 나왔습니다

통계가 못 찾고 현장 지식이 찾은 것

현장에서 알게 된 사실 결과
공병은 mix_prod_kg에 포함되지 않는데 별도 전력 부하가 있다 잔차 상관 0.19로 통계에서는 탈락한 피처. 광주 전력 테스트 MAPE -2.48%p
남양주1 시트의 재공품 데이터가 사실 남양주2 생산품이었다 데이터 검증으로는 안 보이는 라벨링 오류. 정정 후 각 공장의 실 생산품으로 재구성
농축유는 살균·농축 공정에서 연료·용수 부하가 크다 남양주2 용수 -1.01%p, 연료 -0.61%p

단독 통계 분석이었다면 일주일이 걸렸을 발견이, 현장의 한 문장으로 한 시간 만에 해결된 경우가 여러 번 있었습니다.

신설 라인 — 모델이 학습할 수 없는 신호

김해에 2026-03-25부터 신설 라인이 가동되며 해당 구간의 예측이 눈에 띄게 나빠졌습니다. 원인은 트리 모델의 본질적 한계였습니다. 학습 데이터에서 분산이 0인 피처는 information gain이 0이라 모델이 아예 무시합니다. 재학습해도 없던 신호는 생기지 않습니다.

그래서 학습이 아닌 운영 단계의 사후 보정으로 풀었습니다.

1. baseline 모델로 예측
2. residual = 실측 − 예측
3. 절편을 0으로 강제한 OLS로 단위 부하 α 추정:  residual = α × 신설라인_생산량
4. 운영 예측 = model.predict(X) + α × 신설라인_생산량
에너지원 보정 전 보정 후 개선
연료 15.49% 9.85% -5.63%p
전력 7.56% 5.84% -1.72%p
용수 8.80% 8.80% 효과 없음

용수는 효과가 없었고, 그대로 기록에 남겼습니다. 이 보정 로직은 운영 서비스 코드에 상수와 함수로 반영되어 있습니다.

정리하면 — 상관계수는 가설을 만들고, 잔차와 ablation은 가설을 거르고, 도메인 지식은 새 가설을 만들고, 사후 보정은 학습하지 못한 신호의 마지막 방어선입니다. 넷 다 필요했고, 하나만으로는 안 됐습니다.

v1의 한계와 재설계 (진행 중)

Streamlit으로 만든 v1을 사내에서 운영하며, 화면을 조작할 때마다 전체 스크립트가 다시 실행되어 DB 조회와 모델 실행이 반복 트리거되는 구조적 한계를 만났습니다.

v2에서는 브라우저 렌더링과 Python 계산을 분리했습니다.

사내 사용자 브라우저
  ├─ :3000  React 19 / Next.js 15 운영 UI
  └─ :8000  FastAPI 브리지 ── 로컬 MySQL
                           ├─ v5.3 예측모델
                           ├─ AI 보고서 서비스
                           └─ Excel 업로드·검증

검증된 자산(MySQL 스키마, 예측 모델, LangChain 보고서, 엑셀 업로드 로직)은 버리지 않고 FastAPI 브리지로 연결해, 화면만 교체하고 계산 코어는 그대로 재사용했습니다.

  • 사내망 전용 설계 — DB 계정·OpenAI 키·기상청 키는 서버 프로세스 환경에서만 읽고 브라우저에 전달하지 않음
  • 조회 전용 DB 계정 분리, 쓰기 작업은 관리자 IP 검사 후 기존 서비스에 위임
  • 외부 클라우드로 데이터를 복제하지 않음
  • 검증 완료: 타입 체크, 프로덕션 빌드, HTTP 200 기동 smoke, 백엔드 단위 테스트 20건
  • 남은 작업: 재학습·기상 동기화·What-if·이상 진단 UI, 실제 사내 DB 기준 수치 동등성 검증

화면에 대한 안내

아래 화면들은 API를 연결하지 않은 예시 데이터 모드입니다. 사내 운영 데이터를 외부에 공개할 수 없어 이 상태로 캡처했고, 화면 상단 배너가 그 사실을 표시합니다.

이 모드는 캡처용으로 만든 것이 아니라 원래 구현해 둔 동작입니다. API가 응답하지 않을 때 화면이 깨지는 대신 구조를 유지한 채 예시 값을 보여주고, 지금 보는 수치를 운영 판단에 쓸 수 없다는 것을 사용자에게 명확히 알립니다. 조용히 잘못된 값을 보여주는 것보다 안전하다고 판단했습니다.

저장소