Guider/AI/AiDevGuide0007
AI#07· 48분 읽기

AiDevGuide0007

실전 프로젝트 완전 정복

list목차(47)
AI DEV GUIDE SERIES — FINAL

실전 프로젝트 완전 정복 A-Z

HuggingFace · FastAPI · Docker · CI/CD · 포트폴리오 · 취업 전략

AI 개발자 취업의 모든 것 — 포트폴리오 완성부터 이직까지 한 번에 끝내기!

대상: 생성형 AI 기초 완료자기간: 4~6주난이도: ★★★★★Guide 7/7 (최종)

AI Dev Guide 시리즈 완주 현황

단계 가이드 핵심 주제 상태
01 AiDevGuide0001 AI 개념 완전 정복 완료
02 AiDevGuide0002 Python 기초 완전 정복 완료
03 AiDevGuide0003 데이터 다루기 (NumPy·Pandas·Matplotlib) 완료
04 AiDevGuide0004 머신러닝 완전 정복 (Scikit-learn) 완료
05 AiDevGuide0005 딥러닝 완전 정복 (TensorFlow·PyTorch) 완료
06 AiDevGuide0006 생성형 AI (OpenAI API·LangChain·RAG) 완료
07 AiDevGuide0007 (현재 · 최종) 실전 프로젝트 (HuggingFace·FastAPI·Docker) 학습중

전체 학습 목차 (10 Chapters)

Ch. 챕터명 핵심 내용 난이도
01 HuggingFace 완전 정복 Hub, Transformers, Datasets, Spaces ★★★☆☆
02 FastAPI로 AI 서비스 개발 REST API, 비동기, WebSocket, 미들웨어 ★★★☆☆
03 Docker & 컨테이너화 Dockerfile, Docker Compose, 멀티스테이지 ★★★★☆
04 클라우드 배포 (AWS · GCP · Azure) EC2, ECS, Lambda, Cloud Run, 로드밸런서 ★★★★☆
05 CI/CD 파이프라인 구축 GitHub Actions, 자동 테스트, 자동 배포 ★★★★☆
06 MLOps & 모델 관리 MLflow, DVC, 모델 레지스트리, 드리프트 감지 ★★★★★
07 포트폴리오 프로젝트 — AI 챗봇 서비스 풀스택 AI 서비스 E2E 구현 ★★★★★
08 포트폴리오 구성 전략 GitHub, 블로그, README, 데모 사이트 ★★★★☆
09 AI 개발자 취업 전략 이력서, 코딩 테스트, 기술 면접 완전 정복 ★★★★★
10 현업 면접 Q&A TOP 10 시스템 설계, MLOps, 배포 관련 핵심 질문 ★★★★★

Ch 01. HuggingFace 완전 정복

AI 개발의 GitHub — 수십만 개 모델과 데이터셋을 손끝에서 활용하기

1-1. HuggingFace 생태계

서비스 설명 주요 활용
Hub 모델/데이터셋/Space 저장소 모델 다운로드, 공유
Transformers BERT, GPT, Llama 등 통합 라이브러리 파인튜닝, 추론
Datasets 수만 개 공개 데이터셋 학습 데이터 로드
Spaces Gradio/Streamlit 앱 무료 호스팅 데모 배포
Inference API 모델 API 즉시 사용 빠른 프로토타이핑

1-2. Pipeline — 5줄로 AI 완성

pip install transformers torch accelerate
    
    from transformers import pipeline
    
    # 텍스트 분류
    classifier = pipeline("text-classification", model="snunlp/KR-FinBert-SC")
    result = classifier("이 영화 정말 재미있어요!")
    print(result)  # [{"label": "positive", "score": 0.998}]
    
    # 번역
    translator = pipeline("translation_ko_to_en", model="Helsinki-NLP/opus-mt-ko-en")
    result = translator("안녕하세요! 반갑습니다.")
    print(result[0]["translation_text"])
    
    # 요약
    summarizer = pipeline("summarization", model="facebook/bart-large-cnn")
    result = summarizer("Long text to summarize...", max_length=130, min_length=30)
    print(result[0]["summary_text"])
    
    # 이미지 분류
    img_classifier = pipeline("image-classification", model="google/vit-base-patch16-224")
    result = img_classifier("cat.jpg")
    print(result[0])  # {"label": "tabby cat", "score": 0.956}
    
    # 텍스트 생성 (LLM)
    generator = pipeline("text-generation", model="meta-llama/Llama-3.2-1B-Instruct",
                           device_map="auto", torch_dtype="auto")
    result = generator("파이썬 학습 방법:", max_new_tokens=200)
    print(result[0]["generated_text"])

1-3. HuggingFace Hub — 모델 업로드 & 관리

from huggingface_hub import HfApi, login
    
    # 로그인
    login(token="hf_...")  # HuggingFace 토큰
    
    api = HfApi()
    
    # 모델 업로드
    api.upload_folder(
        folder_path="./my_model",
        repo_id="username/my-awesome-model",
        repo_type="model"
    )
    
    # 모델 카드 작성
    model_card = """
    ---
    language: ko
    license: mit
    tags:
      - text-classification
      - korean
    datasets:
      - nsmc
    metrics:
      - accuracy
    ---
    # 한국어 감성 분석 모델
    NSMC 데이터셋으로 파인튜닝된 BERT 기반 한국어 감성 분석 모델입니다.
    ## 사용 방법
    ```python
    from transformers import pipeline
    clf = pipeline("text-classification", model="username/my-awesome-model")
    ```
    """
    api.upload_file(
        path_or_fileobj=model_card.encode(),
        path_in_repo="README.md",
        repo_id="username/my-awesome-model"
    )

1-4. Gradio로 데모 앱 & Spaces 배포

pip install gradio
    
    import gradio as gr
    from transformers import pipeline
    
    sentiment_pipeline = pipeline("text-classification", model="snunlp/KR-FinBert-SC")
    
    def analyze_sentiment(text):
        result = sentiment_pipeline(text)[0]
        label = "긍정" if result["label"] == "positive" else "부정"
        return f"{label} (신뢰도: {result['score']:.1%})"
    
    # Gradio 인터페이스
    demo = gr.Interface(
        fn=analyze_sentiment,
        inputs=gr.Textbox(label="텍스트 입력", placeholder="감성 분석할 텍스트를 입력하세요..."),
        outputs=gr.Textbox(label="분석 결과"),
        title="한국어 감성 분석 데모",
        description="BERT 기반 한국어 감성 분석 모델입니다.",
        examples=[
            ["이 제품 정말 최고예요! 강추합니다!"],
            ["배송이 너무 느려서 실망했어요."]
        ],
        theme=gr.themes.Soft()
    )
    
    # HuggingFace Spaces에 배포
    # 1. huggingface.co에서 새 Space 생성
    # 2. app.py로 저장 후 push
    demo.launch(share=True)  # 로컬 + 공개 링크 생성

Ch 02. FastAPI로 AI 서비스 개발

현업 표준 Python 웹 프레임워크 — 고성능 AI API 서버 완전 구축

2-1. FastAPI 기본 설정 & 프로젝트 구조

pip install fastapi uvicorn[standard] pydantic python-multipart
    
    # 프로젝트 구조
    ai-service/
    ├── app/
    │   ├── __init__.py
    │   ├── main.py          # FastAPI 앱 진입점
    │   ├── api/
    │   │   ├── routes/
    │   │   │   ├── predict.py   # AI 예측 엔드포인트
    │   │   │   ├── chat.py      # 챗봇 엔드포인트
    │   │   │   └── health.py    # 헬스체크
    │   ├── core/
    │   │   ├── config.py    # 환경 설정
    │   │   └── security.py  # 인증/인가
    │   ├── models/
    │   │   └── schemas.py   # Pydantic 스키마
    │   └── services/
    │       └── ai_service.py  # AI 비즈니스 로직
    ├── Dockerfile
    ├── docker-compose.yml
    ├── requirements.txt
    └── .env

2-2. 완전한 AI API 서버 구현

# app/main.py
    from fastapi import FastAPI, HTTPException, Depends, Security
    from fastapi.middleware.cors import CORSMiddleware
    from fastapi.middleware.trustedhost import TrustedHostMiddleware
    from contextlib import asynccontextmanager
    from app.core.config import settings
    import logging
    
    logger = logging.getLogger(__name__)
    
    # 앱 시작 시 모델 로드
    @asynccontextmanager
    async def lifespan(app: FastAPI):
        logger.info("AI 모델 로딩 중...")
        app.state.model = load_ai_model()  # 무거운 모델 1회만 로드
        logger.info("모델 로드 완료!")
        yield
        logger.info("서버 종료")
    
    app = FastAPI(
        title="AI Service API",
        version="1.0.0",
        description="AI 기반 텍스트 분석 서비스",
        lifespan=lifespan
    )
    
    # CORS 설정
    app.add_middleware(
        CORSMiddleware,
        allow_origins=["https://yourdomain.com"],
        allow_credentials=True,
        allow_methods=["GET", "POST"],
        allow_headers=["*"],
    )
    
    # 라우터 등록
    from app.api.routes import predict, chat, health
    app.include_router(predict.router, prefix="/api/v1/predict", tags=["Predict"])
    app.include_router(chat.router,    prefix="/api/v1/chat",    tags=["Chat"])
    app.include_router(health.router,  prefix="/health",         tags=["Health"])

2-3. 엔드포인트 구현 — 감성 분석 API

# app/models/schemas.py
    from pydantic import BaseModel, Field
    from typing import List, Optional
    
    class SentimentRequest(BaseModel):
        text: str = Field(..., min_length=1, max_length=1000, description="분석할 텍스트")
        language: str = Field(default="ko", description="언어 코드")
    
    class SentimentResponse(BaseModel):
        text: str
        sentiment: str          # positive/negative/neutral
        confidence: float       # 0.0 ~ 1.0
        processing_time_ms: float
    
    class BatchSentimentRequest(BaseModel):
        texts: List[str] = Field(..., max_items=100)
    
    # app/api/routes/predict.py
    from fastapi import APIRouter, Request, HTTPException, Depends
    from app.models.schemas import SentimentRequest, SentimentResponse
    from app.core.security import verify_api_key
    import time
    
    router = APIRouter()
    
    @router.post("/sentiment", response_model=SentimentResponse)
    async def analyze_sentiment(
        request_body: SentimentRequest,
        http_request: Request,
        api_key: str = Depends(verify_api_key)  # API 키 인증
    ):
        start = time.time()
        model = http_request.app.state.model
    
        try:
            result = model(request_body.text)[0]
            elapsed = (time.time() - start) * 1000
            return SentimentResponse(
                text=request_body.text,
                sentiment=result["label"],
                confidence=round(result["score"], 4),
                processing_time_ms=round(elapsed, 2)
            )
        except Exception as e:
            raise HTTPException(status_code=500, detail=str(e))
    
    @router.post("/sentiment/batch")
    async def batch_sentiment(
        request_body: BatchSentimentRequest,
        http_request: Request
    ):
        model = http_request.app.state.model
        results = model(request_body.texts)
        return {"results": results, "count": len(results)}

2-4. 스트리밍 WebSocket 챗봇 API

# app/api/routes/chat.py
    from fastapi import APIRouter, WebSocket, WebSocketDisconnect
    from fastapi.responses import StreamingResponse
    from openai import AsyncOpenAI
    import json, asyncio
    
    router = APIRouter()
    async_client = AsyncOpenAI()
    
    # HTTP 스트리밍 (SSE)
    @router.post("/stream")
    async def stream_chat(message: dict):
        async def generate():
            stream = await async_client.chat.completions.create(
                model="gpt-4o-mini",
                messages=[{"role": "user", "content": message["content"]}],
                stream=True
            )
            async for chunk in stream:
                if chunk.choices[0].delta.content:
                    data = json.dumps({"token": chunk.choices[0].delta.content})
                    yield f"data: {data}
    
    "
            yield "data: [DONE]
    
    "
    
        return StreamingResponse(generate(), media_type="text/event-stream")
    
    # WebSocket (양방향 실시간)
    @router.websocket("/ws/{session_id}")
    async def websocket_chat(websocket: WebSocket, session_id: str):
        await websocket.accept()
        conversation = []  # 세션별 대화 이력
    
        try:
            while True:
                msg = await websocket.receive_text()
                conversation.append({"role": "user", "content": msg})
    
                full_response = ""
                stream = await async_client.chat.completions.create(
                    model="gpt-4o-mini",
                    messages=conversation,
                    stream=True
                )
                async for chunk in stream:
                    token = chunk.choices[0].delta.content or ""
                    if token:
                        await websocket.send_json({"token": token})
                        full_response += token
    
                conversation.append({"role": "assistant", "content": full_response})
                await websocket.send_json({"done": True})
        except WebSocketDisconnect:
            print(f"Session {session_id} disconnected")

Ch 03. Docker & 컨테이너화

"내 컴퓨터에서는 됐는데" 문제 완전 해결 — AI 서비스 이식성 100%

3-1. AI 서비스용 Dockerfile

# Dockerfile (멀티스테이지 빌드)
    # Stage 1: 의존성 설치
    FROM python:3.11-slim AS builder
    
    WORKDIR /app
    COPY requirements.txt .
    RUN pip install --no-cache-dir --user -r requirements.txt
    
    # Stage 2: 실행 이미지 (최소화)
    FROM python:3.11-slim AS runtime
    
    WORKDIR /app
    
    # 비루트 사용자 생성 (보안)
    RUN useradd -m -u 1000 appuser
    
    # 의존성 복사
    COPY --from=builder /root/.local /home/appuser/.local
    COPY --chown=appuser:appuser . .
    
    USER appuser
    ENV PATH=/home/appuser/.local/bin:$PATH
    
    # 환경 변수
    ENV PYTHONUNBUFFERED=1 \
        PYTHONDONTWRITEBYTECODE=1 \
        PORT=8000
    
    EXPOSE 8000
    
    # 헬스체크
    HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
        CMD curl -f http://localhost:8000/health || exit 1
    
    # GPU 지원 (필요시)
    # FROM nvidia/cuda:12.1-cudnn8-runtime-ubuntu22.04
    
    CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000", \
         "--workers", "4", "--access-log", "--log-level", "info"]

3-2. Docker Compose — 전체 스택 구성

# docker-compose.yml
    version: "3.9"
    
    services:
      # FastAPI 앱
      api:
        build:
          context: .
          dockerfile: Dockerfile
          target: runtime
        ports:
          - "8000:8000"
        environment:
          - DATABASE_URL=postgresql://user:pass@db:5432/aidb
          - REDIS_URL=redis://redis:6379
          - OPENAI_API_KEY=${OPENAI_API_KEY}
        env_file:
          - .env
        depends_on:
          db:
            condition: service_healthy
          redis:
            condition: service_started
        volumes:
          - ./models:/app/models  # 모델 파일 마운트
        restart: unless-stopped
        networks:
          - ai-network
    
      # Nginx 리버스 프록시
      nginx:
        image: nginx:alpine
        ports:
          - "80:80"
          - "443:443"
        volumes:
          - ./nginx.conf:/etc/nginx/nginx.conf
          - ./ssl:/etc/nginx/ssl
        depends_on: [api]
        networks:
          - ai-network
    
      # PostgreSQL DB
      db:
        image: postgres:16-alpine
        environment:
          POSTGRES_DB: aidb
          POSTGRES_USER: user
          POSTGRES_PASSWORD: pass
        volumes:
          - postgres_data:/var/lib/postgresql/data
        healthcheck:
          test: ["CMD-SHELL", "pg_isready -U user"]
          interval: 10s
        networks:
          - ai-network
    
      # Redis 캐시
      redis:
        image: redis:7-alpine
        command: redis-server --maxmemory 256mb
        networks:
          - ai-network
    
    volumes:
      postgres_data:
    
    networks:
      ai-network:
        driver: bridge

3-3. 핵심 Docker 명령어 정리

# 빌드
    docker build -t ai-service:v1.0 .
    docker build --no-cache -t ai-service:latest .
    
    # 실행
    docker run -d -p 8000:8000 --name ai-api ai-service:latest
    docker run -e OPENAI_API_KEY=sk-... ai-service:latest
    
    # Docker Compose
    docker compose up -d          # 백그라운드 실행
    docker compose down           # 중단
    docker compose logs -f api    # 로그 확인
    docker compose ps             # 상태 확인
    docker compose exec api bash  # 컨테이너 접속
    
    # 이미지 관리
    docker images                 # 이미지 목록
    docker rmi ai-service:v1.0    # 이미지 삭제
    docker system prune -a        # 미사용 전체 정리
    
    # ECR 배포 (AWS)
    aws ecr get-login-password --region ap-northeast-2 | docker login --username AWS --password-stdin 123456789.dkr.ecr.ap-northeast-2.amazonaws.com
    docker tag ai-service:latest 123456789.dkr.ecr.ap-northeast-2.amazonaws.com/ai-service:latest
    docker push 123456789.dkr.ecr.ap-northeast-2.amazonaws.com/ai-service:latest

Ch 04. 클라우드 배포 (AWS · GCP · Azure)

실제 서비스 운영 — 글로벌 접근 가능한 AI 서비스 배포

4-1. 클라우드 서비스 비교

서비스 AWS GCP Azure
컨테이너 ECS / EKS Cloud Run / GKE ACI / AKS
서버리스 Lambda Cloud Functions Azure Functions
ML 플랫폼 SageMaker Vertex AI Azure ML
무료 티어 12개월 프리티어 $300 크레딧 $200 크레딧
한국 리전 ap-northeast-2 (서울) asia-northeast3 (서울) Korea Central

4-2. AWS EC2 + ECS 배포 실전

# AWS CLI 설치 및 설정
    pip install awscli
    aws configure  # Access Key, Secret Key, Region 입력
    
    # ECR 레포지토리 생성
    aws ecr create-repository --repository-name ai-service --region ap-northeast-2
    
    # ECS 태스크 정의 (task-definition.json)
    {
      "family": "ai-service",
      "networkMode": "awsvpc",
      "requiresCompatibilities": ["FARGATE"],
      "cpu": "1024",
      "memory": "2048",
      "containerDefinitions": [{
        "name": "ai-api",
        "image": "123456789.dkr.ecr.ap-northeast-2.amazonaws.com/ai-service:latest",
        "portMappings": [{"containerPort": 8000, "protocol": "tcp"}],
        "environment": [
          {"name": "ENV", "value": "production"}
        ],
        "secrets": [
          {"name": "OPENAI_API_KEY", "valueFrom": "arn:aws:ssm:ap-northeast-2:123456789:parameter/openai-key"}
        ],
        "logConfiguration": {
          "logDriver": "awslogs",
          "options": {"awslogs-group": "/ecs/ai-service", "awslogs-region": "ap-northeast-2"}
        },
        "healthCheck": {
          "command": ["CMD-SHELL", "curl -f http://localhost:8000/health || exit 1"],
          "interval": 30, "timeout": 5, "retries": 3
        }
      }]
    }
    
    # ECS 서비스 배포
    aws ecs register-task-definition --cli-input-json file://task-definition.json
    aws ecs create-service \
      --cluster ai-cluster \
      --service-name ai-service \
      --task-definition ai-service:1 \
      --desired-count 2 \
      --launch-type FARGATE \
      --load-balancers targetGroupArn=arn:aws:...

4-3. GCP Cloud Run — 가장 간편한 배포

# Google Cloud SDK 설치
    gcloud auth login
    gcloud config set project my-ai-project
    
    # Cloud Build로 이미지 빌드 + 배포 (한 번에!)
    gcloud run deploy ai-service \
      --source . \
      --region asia-northeast3 \
      --platform managed \
      --allow-unauthenticated \
      --memory 2Gi \
      --cpu 2 \
      --concurrency 80 \
      --max-instances 10 \
      --set-env-vars OPENAI_API_KEY=sk-... \
      --set-secrets OPENAI_API_KEY=openai-key:latest
    
    # Cloud Run 특징
    # - 요청이 없으면 0으로 스케일 다운 (비용 절약)
    # - 요청 급증 시 자동 스케일 업
    # - HTTPS 자동 제공
    # - 첫 2백만 요청/월 무료

Ch 05. CI/CD 파이프라인 구축

코드 Push → 자동 테스트 → 자동 배포 — 개발 생산성 10배 향상

5-1. GitHub Actions 완전한 CI/CD 파이프라인

# .github/workflows/deploy.yml
    name: AI Service CI/CD
    
    on:
      push:
        branches: [main]
      pull_request:
        branches: [main]
    
    env:
      REGISTRY: ghcr.io
      IMAGE_NAME: ${{ github.repository }}
    
    jobs:
      # 1. 테스트
      test:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v4
          - uses: actions/setup-python@v5
            with:
              python-version: "3.11"
              cache: "pip"
          - run: pip install -r requirements.txt -r requirements-dev.txt
          - name: 린트 (코드 스타일 검사)
            run: |
              ruff check .
              black --check .
          - name: 타입 체크
            run: mypy app/
          - name: 단위 테스트
            run: pytest tests/ -v --cov=app --cov-report=xml
            env:
              OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY_TEST }}
          - name: 커버리지 업로드
            uses: codecov/codecov-action@v4
    
      # 2. Docker 빌드 & 푸시
      build:
        needs: test
        runs-on: ubuntu-latest
        if: github.ref == "refs/heads/main"
        outputs:
          image-tag: ${{ steps.meta.outputs.tags }}
        steps:
          - uses: actions/checkout@v4
          - name: Docker 메타데이터
            id: meta
            uses: docker/metadata-action@v5
            with:
              images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
              tags: |
                type=sha,prefix=sha-
                type=raw,value=latest
          - name: GitHub Container Registry 로그인
            uses: docker/login-action@v3
            with:
              registry: ${{ env.REGISTRY }}
              username: ${{ github.actor }}
              password: ${{ secrets.GITHUB_TOKEN }}
          - name: Docker Buildx 설정
            uses: docker/setup-buildx-action@v3
          - name: 빌드 & 푸시
            uses: docker/build-push-action@v5
            with:
              context: .
              push: true
              tags: ${{ steps.meta.outputs.tags }}
              cache-from: type=gha
              cache-to: type=gha,mode=max
    
      # 3. 프로덕션 배포
      deploy:
        needs: build
        runs-on: ubuntu-latest
        environment: production  # 수동 승인 필요
        steps:
          - name: GCP 인증
            uses: google-github-actions/auth@v2
            with:
              credentials_json: ${{ secrets.GCP_SA_KEY }}
          - name: Cloud Run 배포
            uses: google-github-actions/deploy-cloudrun@v2
            with:
              service: ai-service
              region: asia-northeast3
              image: ${{ needs.build.outputs.image-tag }}
          - name: 배포 알림 (Slack)
            uses: slackapi/slack-github-action@v1
            with:
              payload: '{"text": "배포 완료! ${{ github.sha }}"}'
            env:
              SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}

5-2. pytest로 AI 서비스 테스트

# tests/test_api.py
    import pytest
    from fastapi.testclient import TestClient
    from unittest.mock import patch, MagicMock
    from app.main import app
    
    client = TestClient(app)
    
    class TestSentimentAPI:
        def test_sentiment_positive(self):
            """긍정 텍스트 분류 테스트"""
            with patch("app.api.routes.predict.model") as mock_model:
                mock_model.return_value = [{"label": "positive", "score": 0.99}]
                response = client.post("/api/v1/predict/sentiment",
                    json={"text": "이 제품 정말 좋아요!"},
                    headers={"X-API-Key": "test-key"})
            assert response.status_code == 200
            data = response.json()
            assert data["sentiment"] == "positive"
            assert data["confidence"] > 0.9
    
        def test_empty_text_returns_422(self):
            """빈 텍스트 검증 테스트"""
            response = client.post("/api/v1/predict/sentiment",
                json={"text": ""},
                headers={"X-API-Key": "test-key"})
            assert response.status_code == 422
    
        def test_health_check(self):
            """헬스체크 테스트"""
            response = client.get("/health")
            assert response.status_code == 200
            assert response.json()["status"] == "ok"

Ch 06. MLOps & 모델 관리

프로덕션에서 AI 모델을 안정적으로 운영하기 — 실험 추적부터 드리프트 감지까지

6-1. MLflow — 실험 추적 & 모델 레지스트리

pip install mlflow
    
    import mlflow
    import mlflow.sklearn
    from sklearn.ensemble import RandomForestClassifier
    from sklearn.metrics import accuracy_score
    
    # MLflow 서버 실행 (로컬)
    # mlflow server --host 0.0.0.0 --port 5000
    
    mlflow.set_tracking_uri("http://localhost:5000")
    mlflow.set_experiment("sentiment-classifier-v2")
    
    with mlflow.start_run(run_name="rf-baseline"):
        # 하이퍼파라미터 기록
        params = {"n_estimators": 100, "max_depth": 10, "random_state": 42}
        mlflow.log_params(params)
    
        # 모델 학습
        model = RandomForestClassifier(**params)
        model.fit(X_train, y_train)
    
        # 지표 기록
        accuracy = accuracy_score(y_test, model.predict(X_test))
        mlflow.log_metric("accuracy", accuracy)
        mlflow.log_metric("f1_score", f1_score(y_test, model.predict(X_test)))
    
        # 모델 저장
        mlflow.sklearn.log_model(model, "model",
            registered_model_name="sentiment-classifier")
    
        # 아티팩트 저장
        mlflow.log_artifact("confusion_matrix.png")
        mlflow.log_artifact("feature_importance.csv")
    
    # 최고 모델 로드
    best_model = mlflow.sklearn.load_model("models:/sentiment-classifier/Production")
    predictions = best_model.predict(X_new)

6-2. 모델 모니터링 & 드리프트 감지

pip install evidently
    
    from evidently import ColumnMapping
    from evidently.report import Report
    from evidently.metric_preset import DataDriftPreset, ModelPerformancePreset
    
    # 데이터 드리프트 감지
    report = Report(metrics=[DataDriftPreset(), ModelPerformancePreset()])
    report.run(
        reference_data=train_df,  # 학습 때 데이터
        current_data=production_df,  # 현재 프로덕션 데이터
        column_mapping=ColumnMapping(target="label", prediction="prediction")
    )
    report.save_html("drift_report.html")
    
    # 드리프트 감지 시 알림
    result = report.as_dict()
    drift_detected = result["metrics"][0]["result"]["dataset_drift"]
    if drift_detected:
        send_slack_alert("경고: 데이터 드리프트 감지! 모델 재학습 필요")
        trigger_retraining_pipeline()

6-3. MLOps 성숙도 모델

레벨 특징 도구
Level 0 수동 프로세스, 스크립트 실행 Jupyter Notebook
Level 1 ML 파이프라인 자동화 MLflow + DVC
Level 2 CI/CD + 자동 재학습 GitHub Actions + MLflow
Level 3 완전 자동화 + 모니터링 Kubeflow + Evidently

Ch 07. 포트폴리오 프로젝트 — 풀스택 AI 챗봇 서비스

취업에 필요한 모든 기술을 담은 완성형 AI 프로젝트 — 기획부터 배포까지

7-1. 프로젝트 개요 — AI 문서 분석 서비스

항목 내용
서비스명 DocAI — 기업 문서 AI 분석 플랫폼
핵심 기능 PDF 업로드 → RAG 기반 Q&A → 요약 → 번역
기술 스택 FastAPI + LangChain + Chroma + OpenAI + PostgreSQL + Redis + Docker
프론트엔드 Next.js + Tailwind CSS + WebSocket
배포 GCP Cloud Run + GitHub Actions CI/CD

7-2. 백엔드 전체 구현

# app/services/doc_ai_service.py
    from langchain_openai import ChatOpenAI, OpenAIEmbeddings
    from langchain_chroma import Chroma
    from langchain.text_splitter import RecursiveCharacterTextSplitter
    from langchain_community.document_loaders import PyPDFLoader
    from langchain_core.prompts import ChatPromptTemplate
    from langchain_core.runnables import RunnablePassthrough
    from langchain_core.output_parsers import StrOutputParser
    import hashlib, os, redis, json
    
    redis_client = redis.from_url(os.getenv("REDIS_URL"))
    
    class DocAIService:
        def __init__(self):
            self.embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
            self.llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
            self.splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=50)
    
        async def process_document(self, file_path: str, doc_id: str) -> dict:
            """문서 처리 및 벡터 DB 저장"""
            loader = PyPDFLoader(file_path)
            docs = loader.load()
            chunks = self.splitter.split_documents(docs)
            for c in chunks:
                c.metadata["doc_id"] = doc_id
    
            vectordb = Chroma.from_documents(
                chunks, self.embeddings,
                persist_directory=f"./chroma/{doc_id}"
            )
            return {"doc_id": doc_id, "chunks": len(chunks), "pages": len(docs)}
    
        async def ask_question(self, doc_id: str, question: str) -> str:
            """RAG 기반 질문 답변 (캐싱 포함)"""
            cache_key = f"qa:{doc_id}:{hashlib.md5(question.encode()).hexdigest()}"
            cached = redis_client.get(cache_key)
            if cached:
                return json.loads(cached)["answer"]
    
            vectordb = Chroma(
                persist_directory=f"./chroma/{doc_id}",
                embedding_function=self.embeddings
            )
            retriever = vectordb.as_retriever(
                search_type="mmr", search_kwargs={"k": 5, "fetch_k": 20}
            )
    
            prompt = ChatPromptTemplate.from_template("""
    주어진 문서 내용만을 기반으로 질문에 답변하세요.
    문서에 없는 내용은 "해당 문서에서 찾을 수 없습니다"라고 답하세요.
    
    문서 내용:
    {context}
    
    질문: {question}
    답변:""")
    
            chain = (
                {"context": retriever | (lambda d: "
    
    ".join(x.page_content for x in d)),
                 "question": RunnablePassthrough()}
                | prompt | self.llm | StrOutputParser()
            )
            answer = await chain.ainvoke(question)
    
            # 캐시 저장 (24시간)
            redis_client.setex(cache_key, 86400, json.dumps({"answer": answer}))
            return answer
    
        async def summarize(self, doc_id: str) -> str:
            """문서 요약"""
            vectordb = Chroma(persist_directory=f"./chroma/{doc_id}",
                               embedding_function=self.embeddings)
            all_docs = vectordb.get()
            full_text = " ".join(all_docs["documents"][:20])  # 상위 20청크
    
            response = await self.llm.ainvoke(
                f"다음 문서를 3~5줄로 요약하세요:
    
    {full_text[:3000]}"
            )
            return response.content

7-3. REST API 엔드포인트

# app/api/routes/documents.py
    from fastapi import APIRouter, UploadFile, File, HTTPException, BackgroundTasks
    import uuid, aiofiles, os
    
    router = APIRouter()
    service = DocAIService()
    
    @router.post("/upload")
    async def upload_document(
        file: UploadFile = File(...),
        background_tasks: BackgroundTasks = None
    ):
        if not file.filename.endswith(".pdf"):
            raise HTTPException(status_code=400, detail="PDF만 지원합니다")
        if file.size > 50 * 1024 * 1024:  # 50MB 제한
            raise HTTPException(status_code=400, detail="파일 크기 초과")
    
        doc_id = str(uuid.uuid4())
        file_path = f"/tmp/{doc_id}.pdf"
        async with aiofiles.open(file_path, "wb") as f:
            await f.write(await file.read())
    
        background_tasks.add_task(service.process_document, file_path, doc_id)
        return {"doc_id": doc_id, "status": "processing", "filename": file.filename}
    
    @router.post("/{doc_id}/ask")
    async def ask_question(doc_id: str, body: dict):
        answer = await service.ask_question(doc_id, body["question"])
        return {"doc_id": doc_id, "question": body["question"], "answer": answer}
    
    @router.get("/{doc_id}/summary")
    async def get_summary(doc_id: str):
        summary = await service.summarize(doc_id)
        return {"doc_id": doc_id, "summary": summary}

Ch 08. 포트폴리오 구성 전략

합격하는 AI 개발자 포트폴리오 만들기 — GitHub부터 데모까지

8-1. 포트폴리오 체크리스트

항목 중요도 구체적 내용
GitHub 프로필 필수 잔디 일관성, 핀된 레포 6개, 프로필 README
프로젝트 README 필수 데모 GIF, 기술스택 배지, 아키텍처 다이어그램
라이브 데모 권장 HuggingFace Spaces, Streamlit Cloud, Vercel
기술 블로그 권장 프로젝트 회고, 기술 선택 이유, 트러블슈팅
논문/대회 가산점 Kaggle 입상, arXiv 논문, AI 해커톤

8-2. 완벽한 GitHub README 템플릿

# 🤖 DocAI — AI 문서 분석 플랫폼
    
    [![Python](https://img.shields.io/badge/Python-3.11-blue)]()
    [![FastAPI](https://img.shields.io/badge/FastAPI-0.115-green)]()
    [![Docker](https://img.shields.io/badge/Docker-24.0-blue)]()
    [![License](https://img.shields.io/badge/License-MIT-yellow)]()
    [![Demo](https://img.shields.io/badge/Demo-Live-brightgreen)](https://docai-demo.com)
    
    > PDF 문서를 업로드하면 AI가 즉시 분석하고 질문에 답변합니다.
    
    ## 데모
    ![데모 GIF](docs/demo.gif)
    
    ## 주요 기능
    - 📄 PDF 업로드 및 자동 텍스트 추출
    - 🔍 RAG 기반 정확한 Q&A (환각 방지)
    - 📝 3~5줄 자동 요약
    - 🌐 한/영 번역 지원
    - ⚡ 실시간 스트리밍 응답
    
    ## 아키텍처
    ```
    Client → Nginx → FastAPI → OpenAI API
                            → LangChain → Chroma VectorDB
                            → PostgreSQL (메타데이터)
                            → Redis (캐싱)
    ```
    
    ## 기술 스택
    | 분류 | 기술 | 선택 이유 |
    |------|------|----------|
    | Backend | FastAPI | 비동기, 자동 문서화 |
    | AI | LangChain + OpenAI | RAG 파이프라인 |
    | VectorDB | Chroma | 개발 편의성 |
    | Cache | Redis | API 비용 50% 절감 |
    | Deploy | GCP Cloud Run | 서버리스, 비용 최적화 |
    
    ## 성능 지표
    - 평균 응답 시간: 1.2초
    - 답변 정확도: 94.3% (100개 Q&A 수동 평가)
    - 캐시 히트율: 43% (API 비용 절감)
    
    ## 로컬 실행
    ```bash
    git clone https://github.com/username/docai
    cd docai
    cp .env.example .env  # API 키 설정
    docker compose up -d
    # http://localhost:8000/docs 접속
    ```

8-3. GitHub 프로필 README

# 안녕하세요! AI 개발자 홍길동입니다 👋
    
    > 생성형 AI와 백엔드 개발로 가치 있는 서비스를 만드는 것을 즐깁니다.
    
    ## 기술 스택
    **AI/ML**: Python · PyTorch · TensorFlow · HuggingFace · LangChain · OpenAI API
    **Backend**: FastAPI · PostgreSQL · Redis · Docker
    **Cloud**: GCP · AWS · GitHub Actions
    
    ## 주요 프로젝트
    | 프로젝트 | 설명 | 기술 | 링크 |
    |---------|------|------|------|
    | DocAI | AI 문서 분석 플랫폼 | FastAPI, RAG, LangChain | [Demo](https://docai.com) |
    | SentimentBot | 한국어 감성 분석 API | BERT, HuggingFace | [GitHub](https://github.com/...) |
    
    ## 최근 활동
    ![GitHub Stats](https://github-readme-stats.vercel.app/api?username=YOUR_ID&show_icons=true&theme=dark)
    ![Top Languages](https://github-readme-stats.vercel.app/api/top-langs/?username=YOUR_ID&theme=dark)

Ch 09. AI 개발자 취업 전략

면접 합격을 위한 모든 것 — 이력서, 코딩테스트, 기술면접 완전 정복

9-1. AI 개발자 취업 로드맵

직군 필수 기술 연봉 (2025) 주요 기업
ML Engineer Python, PyTorch, Docker, CI/CD 5천~1억5천 카카오, 네이버, 쿠팡
AI 백엔드 FastAPI, LangChain, RAG, AWS 4천~1억2천 스타트업, 핀테크
MLOps Engineer Kubernetes, MLflow, Airflow 6천~1억8천 빅테크, AI 스타트업
AI 연구원 논문 독해/구현, PyTorch, 수학 6천~억+ 삼성리서치, LG AI

9-2. 합격하는 AI 이력서 작성법

# 이력서 프로젝트 작성 공식: STAR 방법
    # S(Situation): 상황/문제
    # T(Task): 맡은 역할
    # A(Action): 실제 한 일
    # R(Result): 수치화된 결과
    
    # 나쁜 예:
    "RAG 기반 챗봇 개발"
    
    # 좋은 예:
    "사내 문서 검색 효율 개선 필요로 RAG 기반 챗봇을 설계·구현하여
     평균 문서 검색 시간을 15분 → 30초로 97% 단축.
     (FastAPI + LangChain + Chroma + GPT-4o-mini, Redis 캐싱으로 API 비용 43% 절감)"
    
    # 기술 스택 분류 예시
    기술 스택:
      AI/ML: Python, PyTorch, TensorFlow, HuggingFace, LangChain, OpenAI API
      Backend: FastAPI, PostgreSQL, Redis, SQLAlchemy
      DevOps: Docker, GitHub Actions, GCP Cloud Run, AWS EC2
      Tools: Git, MLflow, Jupyter, VS Code

9-3. 기술 면접 필수 준비 항목

분야 준비 항목 참고 자료
코딩 테스트 자료구조, 알고리즘, DP, 그래프 프로그래머스, 백준 200+
ML 이론 손실함수, 역전파, 정규화, 평가지표 cs229, 면접 질문집
시스템 설계 AI 서비스 아키텍처, 스케일링, 캐싱 System Design Interview
프로젝트 회고 기술 선택 이유, 트러블슈팅, 성과 본인 프로젝트 철저히 준비

9-4. 추천 학습 커뮤니티 & 자료

분야 추천 자료
논문 읽기 Papers With Code, arXiv, Semantic Scholar
실습 Kaggle, DrivenData, HuggingFace 대회
커뮤니티 모두의연구소, 가짜연구소, AI 코리아
영상 Andrej Karpathy, Yannic Kilcher, 이수안 컴퓨터 연구소
채용 정보 원티드, 링크드인, 로켓펀치, 잡플래닛

Ch 10. 현업 면접 Q&A TOP 10

AI 개발자 최종 면접 — 시스템 설계, MLOps, 배포 핵심 질문 완벽 답변

Q1. AI 서비스의 시스템 아키텍처를 설계해보세요.

① Load Balancer → ② FastAPI 서버 (다중 인스턴스) → ③ Redis 캐시 → ④ AI 모델 서버 (GPU) → ⑤ Vector DB → ⑥ PostgreSQL. 스케일링 전략: 수평 확장(ECS) + 오토스케일링 + CDN. 모델은 별도 서버 분리로 확장성 확보.

Q2. API 응답 속도를 개선하는 방법은?

① Redis 캐싱 (동일 쿼리 재처리 방지) ② 비동기 처리 (FastAPI async/await) ③ 배치 처리 (여러 요청 묶어서 처리) ④ 모델 경량화 (Quantization, ONNX) ⑤ CDN 활용 ⑥ DB 인덱싱 최적화 ⑦ Connection Pool 관리

Q3. Docker와 가상머신(VM)의 차이는?

VM: 하이퍼바이저 위에 전체 OS를 가상화(GB 단위). Docker: 호스트 OS 커널을 공유하는 컨테이너 (MB 단위, 5-10배 빠른 시작). AI 서비스에서 Docker 선호 이유: 재현성, 배포 일관성, 마이크로서비스 구성 용이.

Q4. CI/CD에서 Blue-Green 배포란?

현재 서비스(Blue)를 유지하면서 새 버전(Green)을 별도 환경에 배포. 테스트 완료 후 트래픽을 Green으로 전환. 문제 발생 시 즉시 Blue로 롤백 가능. 다운타임 제로 배포의 핵심 전략. Canary 배포는 일부 트래픽만 새 버전으로 보내는 점진적 방식.

Q5. RAG 시스템의 품질을 어떻게 평가하나요?

RAGAS 프레임워크 사용: ① Faithfulness (컨텍스트 충실도) ② Answer Relevance (답변 관련성) ③ Context Precision (검색 정밀도) ④ Context Recall (검색 재현율). 실제로는 100~300개 Q&A 골든셋 구성 후 정기 평가. 인간 평가와 자동 평가 병행.

Q6. 모델 배포 시 A/B 테스트 설계는?

① 트래픽 분할 (80/20으로 시작) ② 측정 지표 사전 정의 (CTR, 전환율, 응답만족도) ③ 통계적 유의성 검증 (p-value < 0.05) ④ 충분한 샘플 수 확보 후 결론. 온라인 평가와 오프라인 평가를 함께 사용.

Q7. LLM 서비스의 Rate Limiting 설계는?

Redis + Sliding Window 방식: 사용자별 분당/시간당 요청 수 제한. 토큰 버킷 알고리즘으로 burst 허용. 429 Too Many Requests 반환 시 Retry-After 헤더 포함. 플랜별 차등 제한 (Free: 10req/min, Pro: 100req/min).

Q8. MLflow와 DVC의 차이는?

MLflow: 실험 추적 (파라미터, 지표, 모델 아티팩트), 모델 레지스트리, 서빙. DVC: 데이터 버전 관리 (Git과 유사), 대용량 파일 Git 외부 저장, 재현 가능한 ML 파이프라인. 둘은 상호보완적으로 함께 사용하면 완전한 MLOps 구성 가능.

Q9. 대규모 데이터 처리 시 성능 최적화는?

① 배치 임베딩 (단건보다 10배 빠름) ② 비동기 I/O (aiofiles, httpx) ③ 멀티프로세싱 (CPU 병렬화) ④ 스트리밍 처리 (메모리 절약) ⑤ 데이터 파이프라인 (Apache Kafka, Airflow) ⑥ GPU 병렬 추론 (DataParallel)

Q10. 프로덕션 AI 서비스 장애 대응 방법은?

① Fallback 전략: OpenAI 오류 시 로컬 LLM으로 전환 ② Circuit Breaker 패턴 ③ 알림: Slack + PagerDuty ④ 로깅: 구조화 로그 (JSON) + ELK Stack ⑤ 사후 분석 (Post-mortem): 원인 분석 → 재발 방지 → 문서화 ⑥ SLO/SLA 정의 (가용성 99.9%)

학습 완료 체크리스트 — AI 개발자 취업 준비

Ch01~Ch03 인프라 기초

☐ HuggingFace Hub 모델 업로드
☐ Gradio Space 데모 배포
☐ FastAPI AI 서버 구현
☐ Docker로 컨테이너화

Ch04~Ch06 배포&운영

☐ GCP Cloud Run 배포 완료
☐ GitHub Actions CI/CD 파이프라인
☐ MLflow 실험 추적 설정
☐ 모델 모니터링 시스템 구축

Ch07~Ch08 포트폴리오

☐ 풀스택 AI 서비스 E2E 구현
☐ GitHub README 완성
☐ 라이브 데모 배포
☐ 기술 블로그 포스팅 3개+

Ch09~Ch10 취업 준비

☐ STAR 방식 이력서 작성
☐ 코딩 테스트 프로그래머스 Lv.3
☐ 면접 Q&A 10개 완벽 답변
☐ 5개 회사 이상 지원!

🎉

AI Dev Guide 시리즈 완주!

Guide 01 → 07 — 7개 가이드 완전 정복

AI 개념부터 실전 배포까지 — 당신은 이제 AI 개발자입니다!

✅ Guide 01 — AI 개념 완전 정복
✅ Guide 02 — Python 기초 완전 정복
✅ Guide 03 — 데이터 다루기 (NumPy·Pandas·Matplotlib)
✅ Guide 04 — 머신러닝 완전 정복 (Scikit-learn)
✅ Guide 05 — 딥러닝 완전 정복 (TensorFlow·PyTorch)
✅ Guide 06 — 생성형 AI (OpenAI API·LangChain·RAG)
🏆 Guide 07 — 실전 프로젝트 (HuggingFace·FastAPI·Docker·취업)

다음 목표

AI 개발자 취업 성공!

계속 성장하기

Kaggle · 논문 구현 · 오픈소스