AI‐8단계‐최종 통합 설계 및 회고 - 100-hours-a-week/KTB4-5th-wiki GitHub Wiki

단계 8: 최종 통합 설계 및 회고

1. 통합 설계의 범위

이 문서는 단계 1~7에서 확정한 설계를 하나의 서비스 아키텍처로 연결한 최종 통합본입니다. 이미지 분석, 레시피 검색·동기화, 외부 API, 데이터 소유권, 배포와 관측 기준을 같은 흐름에서 설명합니다.

문서의 다이어그램과 구성요소는 서비스 아키텍처의 기준입니다. 성능·품질 평가는 측정된 수치만 사용하고 측정하지 않은 성과는 임의로 제시하지 않습니다.

2. 최종 서비스 아키텍처

flowchart LR
    U[PWA 사용자<br/>촬영·확인·수정] -->|업로드 URL 요청| B[서비스 백엔드]
    U -->|이미지 직접 업로드| S3[(S3)]
    B -->|POST /ai/v1/analyses<br/>objectKey| API[단일 FastAPI AI 서버]

    subgraph ANALYSIS[이미지 분석 런타임]
        API --> Q[bounded asyncio.Queue]
        Q --> W[소비자 코루틴 2개]
        W -->|S3 서명 URL·SHA-256| IT[원격 GPU Worker<br/>MobileNetV3-Small 입력 유형]
        IT -->|이미지 내려받기| S3
        IT -->|영수증| OCR[PP-OCRv5]
        IT -->|식품 실물| PROD[YOLO-World 영역 분리·Gemma 비전]
        IT -->|기타·판독 불가| DIRECT[재촬영·직접 입력 결과]
        OCR --> AUX[EC2 규칙·PostgreSQL 상품 카탈로그·별칭]
        AUX -->|미확정 상품행만| GEMMA[Worker Ollama<br/>gemma4:e2b]
        AUX --> VALID[정규화·날짜·상태 검증]
        GEMMA --> VALID
        PROD --> VALID
        DIRECT --> RESULT[인메모리 상태·결과]
        VALID --> RESULT
    end

    RESULT -->|POST /api/v1/internal/image-analyses/callback<br/>완료 콜백| B
    B -. 콜백 누락 확인 시에만<br/>분석 결과 GET .-> API
    B -->|처리 중·결과| U
    U -->|사용자 확정| B
    B --> INV[(백엔드 MySQL<br/>사용자·냉장고·재료 원본)]

    INV -->|권한 확인된 확정 재고 스냅샷| REC[레시피 추천 오케스트레이터]
    REC --> NORM[원본 구성 보존<br/>재료명 정규화·검색어·fingerprint]
    NORM --> CACHE{인메모리 추천 캐시}
    CACHE -->|hit| B
    CACHE -->|miss| PGQ{AI PostgreSQL에<br/>사용 가능한 레시피가 있는가}
    PGQ -->|있음| RANK[제외 재료 필터<br/>임박도·활용률 순위]
    PGQ -->|없음| F[식품안전나라]
    F -->|후보 없음| M[TheMealDB]
    M -->|후보 없음| T[Tavily 최종 검색]
    F -->|후보 있음| RV[출처·필수값·이용 조건 검증]
    M -->|후보 있음| RV
    T -->|허용된 후보 있음| RV
    T -->|후보 없음·저장 불가| EMPTY[빈 추천 결과]
    RV --> PG[(AI PostgreSQL<br/>승인된 레시피 원본)]
    PG --> RANK
    RANK --> CACHESET[추천 결과 캐시 저장]
    CACHESET --> B
    EMPTY --> B

    PG -->|커서 기반 변경 API| SYNC[백엔드 주기 동기화 작업]
    SYNC --> COPY[(백엔드 MySQL<br/>레시피 사본)]

    API -. trace·metric .-> OTEL[OpenTelemetry<br/>OpenInference]
    REC -. trace·metric .-> OTEL
    OTEL --> PHX[Phoenix OSS]
    API -. 집계 지표 .-> PROM[Prometheus]
    REC -. 집계 지표 .-> PROM
    PROM --> GRAF[Grafana OSS]
Loading

2.1 요청과 데이터의 흐름

이미지 분석 요청은 백엔드가 인증과 권한을 확인한 뒤 AI 서버로 전달합니다. AI 서버는 작업을 최대 100개의 대기 작업을 보관하는 인메모리 큐에 넣고, 설정된 소비자 코루틴이 전체 분석 파이프라인을 실행합니다. 모델 추론은 원격 GPU Worker에 맡기고 FastAPI는 큐·상태·결과·재시도를 관리합니다. 큐가 가득 차면 작업을 무한 대기시키지 않고 429 AI_QUEUE_FULL과 작업량이 많다는 안내를 반환합니다.

완료되면 AI 서버가 백엔드의 고정된 내부 콜백 API로 결과를 보냅니다. 백엔드는 analysisId를 기준으로 중복 콜백을 멱등 처리합니다. 분석 결과 GET은 일정 간격으로 반복 호출하는 정상 경로가 아니라 콜백 누락을 확인하는 보조 경로입니다. 큐·작업 상태·콜백 재시도 기록은 프로세스 메모리에만 있으므로 재시작 이후 복구를 보장하지 않습니다.

AI 결과는 재고 확정값이 아니라 후보입니다. 사용자가 확인·수정한 뒤에만 백엔드가 MySQL 재료 원본을 변경합니다. AI 서버는 MySQL에 직접 쓰지 않습니다.

레시피 추천에서는 백엔드가 권한을 확인한 확정 재고 스냅샷을 전달합니다. AI는 원본 재료 구성을 보존하고 정규화된 이름·소비기한으로 inventory_fingerprint를 만들며, 정규화·중복 제거·정렬한 제외 재료로 exclusion_fingerprint를 만듭니다. 두 fingerprint와 추천 모드로 캐시 키를 구성합니다. 검색 순서는 추천 결과 캐시 → AI PostgreSQL → 식품안전나라 → TheMealDB → Tavily이며, Tavily는 앞선 구조화 원천에서 사용할 후보가 없을 때만 호출합니다.

외부 응답은 공통 형식으로 정규화하고 출처, 필수 필드와 이용 조건을 통과한 경우에만 AI PostgreSQL에 저장합니다. AI PostgreSQL은 레시피 원본을 소유하고 백엔드는 커서 기반 변경 API를 주기적으로 읽어 자기 MySQL의 레시피 사본을 트랜잭션으로 갱신합니다. AI가 백엔드 데이터베이스에 직접 접근하지 않습니다.

2.2 구성요소별 도입 이유와 효과

구성요소 도입 이유 기대 효과와 명시적 한계
FastAPI 내부 API 백엔드 계약과 모델 구현을 분리 모델 교체 시 앱·백엔드 변경 범위를 줄임. 초기에는 단일 인스턴스만 지원
bounded asyncio.Queue 긴 CPU 분석을 HTTP 접수와 분리하고 메모리 폭증 방지 빠른 접수와 backpressure 제공. 재시작 복구·수평 확장은 제공하지 않음
완료 콜백 + GET 보조 조회 지속 폴링 없이 결과 전달 정상 요청량을 줄이고 누락 확인 경로 유지. 콜백 기록도 재시작 시 유실 가능
MobileNetV3 + PP-OCRv5 + 제한된 Gemma 모든 입력을 무거운 모델에 보내지 않고 역할별 처리 빠른 경로와 어려운 상품행 보완을 분리. 현재 긴 영수증 재현율은 목표 미달
규칙·정규화·상태 정책 모듈 모델 추정과 이미지 근거, 수량과 중량 계약을 강제 잘못된 자동 저장 방지, NEEDS_REVIEW와 직접 입력으로 안전하게 전환
논리 모듈과 포트·어댑터 OCR, DB, 외부 공급자 변경을 도메인 규칙에서 격리 계약 테스트와 독립 수정이 쉬우며 FastAPI와 GPU Worker를 독립 배포 가능
AI PostgreSQL 원본 / MySQL 사본 레시피 수집 책임과 사용자 서비스 조회 책임 분리 AI가 원천을 개선하면서 백엔드는 안정적인 사본 사용. 동기화 지연·충돌 관리 필요
추천 결과 인메모리 캐시 동일 재고 구성의 반복 검색과 외부 호출 감소 비용·지연 감소. TTL·최대 건수는 실측 후 결정하며 재시작 시 사라짐
REST 공급자 어댑터 공급자가 고정된 초기 범위에서 단순한 통합 유지 MCP 없이 인증·재시도·속도 제한·오류 변환을 공급자별 격리
식품안전나라·TheMealDB·Tavily 국내 구조화 원천, 해외 보조, 최종 웹 탐색의 역할 분리 무료 원천을 우선하고 Tavily 크레딧 사용 최소화. 저장·표시는 공급자별 약관 확인 필요
OpenTelemetry·Phoenix·Prometheus·Grafana 요청별 trace와 전체 운영 지표를 함께 관측 토큰·지연·큐·오류·비용 추적. 저장공간·보관기간·배치 위치는 검증 필요

3. 단계별 설계 적용 결과

단계 주요 결정과 변경 확보한 효과
1. 모델 API /ai/v1 분석·피드백·추천·동기화 계약, ERD enum과 측정값 규칙, 내부 인증 경계 모델과 서비스 계약 분리, 사용자 확인 전 재고 저장 차단
2. 추론 최적화 MobileNetV3, PP-OCRv5, PostgreSQL 보조 자료, 미확정 행만 Gemma, 원격 GPU Worker 전체 입력을 언어 모델에 보내지 않고 병목과 오류 유형을 분리
3. 모듈화 도메인·애플리케이션·포트·어댑터 분리, 데이터 수정 권한 명시 OCR·모델·DB 변경의 영향 범위를 해당 어댑터와 모듈로 제한
4. 파이프라인 bounded 인메모리 큐, 소비자 2개, 원격 GPU Worker 호출, LangGraph 재시도 1회, 완료 콜백, 레시피 단방향 동기화 이벤트 루프 차단과 무제한 적재를 방지하는 실행 계약 확보
5. 데이터·컨텍스트 원본 재료와 정규화 값을 분리하고 승인된 자료만 조회, 규칙 기반 추천 근거 없는 날짜·상품명 생성과 재고 원본 오염 방지
6. 외부 통합 MCP 미도입, RecipeSourcePort, 식품안전나라 → TheMealDB → Tavily fallback 공급자 종속성·비용·장애를 어댑터로 격리하고 최종 검색 호출 최소화
7. 인프라·관측 EC2(FastAPI·PostgreSQL)와 RunPod GPU Worker 분리, Uvicorn worker 1개, Ollama 토큰/TPS, Phoenix·Prometheus·Grafana 품질·지연·토큰·큐·외부 비용을 같은 버전 기준으로 비교 가능

4. 현재 성능과 품질 평가

4.1 실제로 관측한 값

평가 범위 관측값 판단
개발에 사용한 영수증 20장 상품행 정밀도 96.7%, 재현율 90.6%, 종합점수 93.5% 목표를 넘었지만 같은 자료로 규칙을 조정했으므로 출시 성능이 아님
사용자 제공 영수증 21장 최초 실행 정밀도 95.6%, 재현율 81.1%, 종합점수 87.8% 정밀도 목표만 충족. 재현율·종합점수 미달
같은 21장, 고정 설정 3회 반복 정밀도 95.1%, 재현율 73.6%, 종합점수 83.0% 재현된 운영 기준값. 상품행 누락 개선 필요
21장 최초 전체 경로 중앙값 7.07초, 95% 완료시간 18.44초 실제 EC2 수치가 아니며 긴 영수증 목표 12초를 초과
반복 후처리 구간 중앙값 약 2.43.4초, 95% 완료시간 약 11.915.7초 기존 OCR 결과를 재사용했으므로 전체 경로 시간과 직접 비교 불가
개발 환경 빠른 경로 OCR 중앙값 약 4.22초 1차 승인 기준 중앙값 5초 이내지만 최종 목표 3초에는 미달
(GPU 전환 후) 정답 영수증 8장·상품 28개 정밀도 91.3%, 재현율 75.0%, F1 82.3%, 수량 100%, 카테고리 81.0% 앞 3장은 규칙 보완에 사용. 재현율·F1 미달
(GPU 전환 후) KORIE 한국 영수증 100장 성공 100/100, Worker 평균 5.18초·p95 9.46초, API 평균 16.18초·p95 23.82초 동시 3건이라 API에 큐 대기 포함. 상품 단위 정확도 미산출
(GPU 전환 후) 입력 유형 분류 MobileNetV3 v1 독립 test macro F1 97.38% 공개 데이터 기준. 한국 실사용 표본은 작음
(GPU 전환 후) 실물 사진 단일 포장 워밍 3~6초, 다중 포장 11개 중 11개 분리 다중 포장 상품명 정확도와 10초 목표 미달

위쪽 6개 행은 단계 2의 CPU 단독 실험, "GPU 전환 후" 행은 원격 GPU Worker(Colab T4) 전체 경로 측정값입니다(단계 2의 12.11절). 특히 20장과 21장은 개선 방향 결정에 사용됐으므로 최종 승인에는 별도의 직접 촬영 평가 자료가 필요합니다.

4.2 아직 측정하지 않은 값

다음 항목은 현재 수치가 없으므로 성과로 주장하지 않습니다.

  • 실제 EC2에서의 시간당 처리량, 동시 요청별 큐 대기시간과 최대 메모리
  • 입력 유형 분류, 실물 식재료명·용량·소비기한의 독립 정확도
  • 완료 콜백 성공률, 평균 재시도 횟수와 누락 복구율
  • 레시피 공급자별 후보 적합률, 중복률, 응답시간과 저장 가능 비율
  • 추천 클릭률, 저장률, 조리 완료율, 사용자 만족도와 재료 폐기 감소율
  • 추천 캐시 hit율, 외부 API 호출 절감률, Tavily 실제 크레딧 사용량
  • AI PostgreSQL과 백엔드 MySQL 사이의 동기화 지연·충돌·누락률
  • 월 EC2 실제 비용과 요청당 추정 계산비용

4.3 출시 판단 기준

이미지 분석은 단일 정확도만으로 승인하지 않습니다. 영수증 상품행 종합점수 0.90 이상, 식품·비식품 분류 종합점수 0.95 이상, 입력 유형 분류 종합점수 0.95 이상과 정상 응답 형식 비율을 함께 확인합니다. 빠른 분석 경로는 1차 중앙값 5초·95% 완료시간 8초 이하, 긴 영수증은 95% 완료시간 12초 이하를 목표로 유지합니다.

GPU 전환 후 Worker 처리시간은 대부분 10초 안으로 들어왔지만, 영수증 재현율·F1은 여전히 목표 0.90에 미달합니다. 따라서 RECOGNIZED 범위를 확대하거나 사용자 확인 단계를 제거할 근거가 없습니다.

5. 프로젝트 회고

5.1 배운 점

영수증 OCR과 상품 판별은 같은 문제가 아니었습니다. 문자를 잘 읽어도 상품행 경계, 가격·수량 관계, 비식품 제거가 틀리면 재고 후보 품질은 낮습니다. 이후 평가는 OCR 성공률 하나가 아니라 상품행 정밀도·재현율, 표준명, 측정값과 날짜 출처를 분리해 보게 됐습니다.

입력을 줄이거나 모델을 크게 만드는 것이 항상 개선으로 이어지지 않았습니다. 상품 영역만 먼저 넣거나 고정 길이로 나눈 방식은 전체 문맥을 잃어 품질이 낮아졌고, 실험에서는 전체 OCR 문맥을 유지한 gemma4:e2b 경로가 더 나았습니다. 모델 크기보다 입력 구조와 출력 검증이 먼저라는 결론을 얻었습니다.

비동기 처리라고 해서 반드시 외부 메시지 큐나 지속 폴링이 필요한 것은 아니었습니다. MVP 요구사항에서는 bounded 인메모리 큐와 완료 콜백이 더 단순합니다. 대신 재시작 유실과 단일 인스턴스라는 한계를 숨기지 않고 확장 조건으로 분리했습니다.

재료와 레시피의 소유권을 나누면서 시스템 경계가 명확해졌습니다. 백엔드는 확정 재고를 소유하고, AI는 레시피 원본과 검색을 담당하며, MySQL 레시피는 서비스용 사본으로 유지합니다. 이 구조는 양쪽 데이터베이스에 누가 쓸 수 있는지에 대한 추측을 줄였습니다.

외부 검색 결과는 발견했다고 바로 저장할 수 있는 데이터가 아닙니다. API 응답의 구조뿐 아니라 원문·이미지의 저장, 가공, 표시와 재배포 조건을 공급자별로 확인해야 합니다. 확인되지 않은 후보를 저장하지 않는 정책을 아키텍처에 포함했습니다.

5.2 어려웠던 점과 대응

어려움 대응 남은 한계
같은 평가 자료에서도 생성 설정에 따라 결과가 달라짐 고정 설정으로 3회 반복하고 최초값과 재현값을 분리 기록 독립된 신규 평가 세트 필요
긴 영수증에서 상품행 누락 집중 전체 OCR 문맥 유지, 좌표·가격·수량 관계 개선을 우선순위로 지정 반복 재현율 73.6%로 목표 미달
ERD에 없는 분석 작업·보조 자료·레시피 원본의 위치 작업은 메모리, 보조 자료·레시피 원본은 AI PostgreSQL, 재료는 MySQL로 소유권 분리 저장소별 소유권과 동기화 방향 유지 필요
비동기 완료 전달 방식 AI → 백엔드 콜백과 멱등 처리, GET 보조 확인 설계 프로세스 재시작 후 콜백 전달 보장 없음
공급자별 스키마·약관 차이 포트·어댑터, 공통 후보 계약과 이용 조건 검증 단계 도입 운영 키로 품질·한도·저장 허가 확인 필요
관측값 없이 임계값을 정할 위험 토큰·TPS·큐·동기화 지표를 먼저 정의하고 숫자는 부하 시험 후 결정 운영 데이터에 따라 경고 임계값 조정 필요

6. 현재 아키텍처의 강점과 약점

강점

  • 백엔드 MySQL, AI PostgreSQL과 인메모리 작업의 소유권이 명확하여 임의 교차 쓰기를 막습니다.
  • 모델 출력은 항상 검증과 사용자 확인을 거치므로 소비기한·수량 오류가 곧바로 재고가 되지 않습니다.
  • OCR, Gemma, 공급자 API와 데이터베이스가 어댑터 뒤에 있어 교체 시 핵심 규칙의 변경 범위를 줄입니다.
  • 캐시와 기존 레시피를 외부 API보다 먼저 사용하고 Tavily를 최후로 제한해 지연과 사용량을 줄이는 방향입니다.
  • trace, 지표와 비용을 모델·프롬프트·파서 버전에 연결해 품질과 속도를 함께 비교할 수 있습니다.
  • MVP 범위에서 불필요한 분산 구성과 MCP를 넣지 않아 운영 대상을 줄였습니다.

약점과 위험

  • 작업과 결과가 메모리에만 있어 배포·장애·인스턴스 종료 시 복구되지 않습니다.
  • Uvicorn worker 1개와 소비자 2개, Worker 안 OCR·Gemma 직렬 실행이므로 수평 확장과 높은 지속 유입을 감당할 수 없습니다.
  • OpenTelemetry·Phoenix·Prometheus·Grafana로 trace·토큰·지연·큐·오류 지표를 수집합니다.
  • 바코드 인식은 보류 상태라 바코드만 보이는 포장은 OCR·비전 판별에 의존합니다.
  • 영수증 재현율과 95% 완료시간은 목표 달성 여부를 지속 측정하고 실물 이미지 품질은 독립 평가 세트로 검증합니다.
  • 레시피 원본과 MySQL 사본 사이의 동기화 지연을 측정하고 변경 이력은 최대 동기화 지연보다 오래 보관합니다.
  • 외부 공급자 이용 조건과 운영 한도를 확정하기 전에는 모든 후보를 영구 저장할 수 없습니다.
  • 개인정보 동의·보관·철회 정책과 관측 데이터 보관기간을 데이터 거버넌스 정책으로 관리합니다. 보조 자료 저장소는 AI PostgreSQL receipt_ai를 사용합니다.
  • 백엔드는 analysisId와 사용자 요청의 임시 매핑, TTL, 콜백 누락 제한시간과 GET 확인 횟수를 운영 설정으로 관리합니다.

7. 향후 개선 계획

우선순위 개선 항목 실행 내용 완료 판단 기준
1 평가 기준선 확정 모델·프롬프트·사전·파서 버전을 고정하고 신규 직접 촬영 자료로 재평가 목표 지표와 오류 목록을 재현 가능한 보고서로 생성
2 긴 영수증 품질 개선 종이 영역 보정과 전체 문맥을 보존한 좌표·상품명·가격·수량 관계 개선 독립 세트 상품행 종합점수 0.90 이상
3 RunPod 운영 배포·검증 고정 RunPod Worker 배포, 관측 도구 연결, 동시 1·3·5·10건·큐 포화·정상 종료·강제 종료 시험 처리시간·GPU 메모리·큐 상한·월 비용 근거 확보, 토큰·지연 대시보드 확인
4 레시피 저장·검색 구현 AI PostgreSQL 스키마, 안정 식별자·revision·인덱스와 중복 제거 구현 동일 원천 재수집 시 중복 0건, 필수 필드 검증 통과
5 공급자 운영 검증 식품안전나라, TheMealDB, Tavily 순서로 샘플 품질·지연·한도·약관 확인 공급자별 저장·표시 정책과 호출 상한 승인
6 동기화 신뢰성 최초 전체 동기화, 커서 증분, 멱등 재처리와 INACTIVE 전파 시험 부분 반영 없이 재실행 가능하고 지연·누락 지표 수집
7 관측 도구 적용 3번 RunPod 배포 때 OpenTelemetry/OpenInference, Phoenix, Prometheus, Grafana 연결 토큰·TPS·큐·콜백·공급자·동기화 대시보드 확인
8 사용자 효과 평가 수정률, 직접 입력 전환, 추천 클릭·저장·조리 완료를 개인정보 정책 안에서 집계 사전 정의한 기간과 표본으로 개선 전후 비교
9 콜백 누락 정책 확정 백엔드 임시 매핑, 완료 제한시간과 제한된 GET 확인 횟수를 부하 결과로 결정 연속 폴링 없이 정상·지연·중복·누락·재시작 시나리오 통과

영속 복구, 무중단 배포, 다중 AI 인스턴스 또는 단일 인스턴스 처리량을 넘는 지속 유입이 실제 요구가 되면 작업 저장과 분산 실행 구조를 다시 설계합니다. 제품은 요구사항과 실측 전에 정하지 않습니다.

벡터 검색, 학습 랭커와 추가 모델은 초기 필수 구성으로 넣지 않습니다. 규칙 기반 추천의 후보 부족이나 순위 품질 한계가 사용자 지표로 확인됐을 때 평가 세트와 비용 기준을 만든 뒤 도입합니다. 사용자 수정값은 동의·보관·철회 정책과 검수를 통과한 경우에만 평가 또는 학습 자료로 사용합니다.

8. 최종 결론

현 시점의 설계는 가벼운 EC2 API 서버와 별도 GPU 추론 Worker, 사용자 확인이 필요한 재고 데이터, 여러 출처에서 확보해야 하는 레시피라는 서비스 조건에 맞습니다. 이미지 분석은 MobileNetV3·PP-OCRv5·YOLO-World와 필요한 상품행만 처리하는 Worker의 Gemma를 조합하고, 실패를 추정값으로 숨기지 않습니다. 레시피 원본은 AI PostgreSQL이 소유하고 백엔드 MySQL에는 사본을 단방향 동기화합니다.

또한 캐시와 기존 레시피를 먼저 사용하고 구조화 API 두 곳 이후에만 Tavily를 호출하므로 외부 의존성과 비용을 제한합니다. 포트·어댑터와 표준 관측 계층은 향후 모델·공급자를 교체할 때 서비스 계약을 유지할 수 있게 합니다. 초기에는 단일 프로세스 인메모리 구조를 선택하되 복구·확장이 필요해지는 조건을 명시해 단순성과 한계를 함께 관리합니다.

따라서 이 아키텍처는 현재 서비스 규모에 적합한 기준선입니다. 독립 품질 평가, 실제 EC2 부하 시험, 레시피 이용 조건 확인, PostgreSQL 동기화 검증과 사용자 효과 측정을 통해 운영 기준을 지속적으로 조정합니다.

⚠️ **GitHub.com Fallback** ⚠️