# Part 6: AI 모델 서비스화 기초 (FastAPI) --- ### 💡 지난 시간 복습 [Part 5: AI 개발 핵심 라이브러리](part_5_ai_core_libraries.md)에서는 NumPy, Pandas, Scikit-learn 등을 사용하여 데이터를 처리하고, 붓꽃 품종 예측 모델을 학습시킨 후 `iris_model.pkl` 파일로 저장했습니다. 이제 우리는 예측 모델이라는 결과물을 손에 쥐게 되었습니다. --- 학습된 AI 모델은 그 자체로는 가치를 창출하기 어렵습니다. API(Application Programming Interface)를 통해 다른 서비스와 연동되고, 실제 사용자의 요청을 처리할 수 있을 때 비로소 가치를 갖게 됩니다. 이 섹션에서는 **Part 5에서 학습하고 저장한 Scikit-learn 모델(`iris_model.pkl`)**을 빠르고 안정적인 API로 만드는 방법을 소개합니다. 이를 위해 **FastAPI**라는 현대적인 고성능 웹 프레임워크를 사용합니다. FastAPI는 Python 3.7+의 타입 힌트(Type Hint)에 기반하여, 코드 작성과 동시에 데이터 유효성 검사, 자동 API 문서 생성을 지원하여 개발 생산성을 획기적으로 높여줍니다. --- ## 1. 왜 FastAPI를 사용하는가? - **고성능**: 비동기(Asynchronous) 웹 요청을 지원하는 `ASGI`(Asynchronous Server Gateway Interface) 기반으로 만들어져, Node.js나 Go에 버금가는 매우 빠른 성능을 보여줍니다. - **빠른 개발 속도**: 타입 힌트를 기반으로 코드를 작성하면, FastAPI가 입력 데이터의 유효성을 자동으로 검사해주므로 개발자가 직접 검증 코드를 작성하는 수고를 덜어줍니다. - **자동 대화형 문서**: 코드만 작성하면 OpenAPI(Swagger UI)와 ReDoc 형태의 대화형 API 문서를 자동으로 생성해줍니다. 이를 통해 프론트엔드 개발자나 API 사용자가 별도의 문서 없이도 API를 쉽게 테스트하고 이해할 수 있습니다. - **간편함과 표준 준수**: 배우기 쉽고 사용하기 간편하며, OpenAPI, JSON Schema 등 웹 표준을 철저히 준수합니다. --- ## 2. API 서버 구축 단계별 예제 > **사전 준비**: 아래 명령어를 터미널에 입력하여 필요한 라이브러리들을 설치해야 합니다. `uvicorn`은 FastAPI 애플리케이션을 실행시켜주는 경량 ASGI 서버입니다. > **`Part 5`에서 생성된 `iris_model.pkl` 파일이 지금 만들 `main.py` 파일과 같은 디렉토리에 있어야 합니다.** ```bash pip install fastapi "uvicorn[standard]" scikit-learn joblib numpy ``` ### 2.1. 기본 FastAPI 앱 만들기 (`main.py`) 아래 코드를 `main.py` 라는 이름의 파일로 저장하세요. ```python # main.py from fastapi import FastAPI, HTTPException, Request from pydantic import BaseModel from typing import List import joblib import numpy as np from contextlib import asynccontextmanager # ------------------------------------------------------------------- # 1. 모델 로딩 및 리소스 관리를 위한 Lifespan 이벤트 핸들러 정의 # ------------------------------------------------------------------- @asynccontextmanager async def lifespan(app: FastAPI): # 애플리케이션 시작 시 실행될 코드 print("--- 서버 시작: 모델을 로드합니다. ---") try: # 모델을 로드하여 app.state에 저장 app.state.model = joblib.load("iris_model.pkl") # 모델이 예측할 클래스(품종)의 실제 이름 정보도 함께 저장 app.state.iris_target_names = {0: 'setosa', 1: 'versicolor', 2: 'virginica'} print("--- 모델 로드 성공 ---") except FileNotFoundError: print("!!! 모델 파일(iris_model.pkl)을 찾을 수 없습니다. !!!") app.state.model = None yield # 여기에서 애플리케이션이 실행됨 # 애플리케이션 종료 시 실행될 코드 print("--- 서버 종료: 리소스를 정리합니다. ---") # 필요한 경우 리소스 정리 로직 추가 (예: DB 연결 해제 등) app.state.clear() # 2. FastAPI 애플리케이션 인스턴스 생성 및 Lifespan 연결 app = FastAPI( title="붓꽃 품종 예측 API", description="Scikit-learn 모델을 이용한 붓꽃 품종 예측 API입니다.", lifespan=lifespan ) # 3. 입력 데이터의 형식을 Pydantic 모델로 정의 class IrisFeatures(BaseModel): features: List[float] class Config: json_schema_extra = { "example": { "features": [5.1, 3.5, 1.4, 0.2] # setosa 품종의 실제 데이터 } } # 4. API 엔드포인트(Endpoint) 정의 @app.get("/") def read_root(): """API의 루트 경로로, 간단한 환영 메시지를 반환합니다.""" return {"message": "붓꽃 품종 예측 API에 오신 것을 환영합니다!"} @app.post("/predict") def predict_iris(request: Request, data: IrisFeatures): """ 붓꽃의 특징(features) 4개를 입력받아 품종을 예측하고 결과를 반환합니다. - **data**: `IrisFeatures` Pydantic 모델 형식의 요청 Body """ # Lifespan에서 로드한 모델 객체를 가져옴 model = request.app.state.model iris_target_names = request.app.state.iris_target_names if model is None: raise HTTPException(status_code=503, detail="모델이 로드되지 않았습니다. 서버 로그를 확인하세요.") if len(data.features) != 4: raise HTTPException(status_code=400, detail="입력 피처는 4개여야 합니다. (sepal length, sepal width, petal length, petal width)") try: model_input = np.array(data.features).reshape(1, -1) except Exception as e: raise HTTPException(status_code=400, detail=f"입력 데이터 변환 중 오류 발생: {e}") prediction_idx = model.predict(model_input)[0] prediction_proba = model.predict_proba(model_input)[0] class_name = iris_target_names.get(int(prediction_idx), "Unknown") confidence = prediction_proba[int(prediction_idx)] return { "input_features": data.features, "predicted_class_id": int(prediction_idx), "predicted_class_name": class_name, "confidence": float(confidence) } ``` ### 2.2. API 서버 실행 및 테스트 1. **서버 실행**: 터미널을 열고 `main.py` 파일이 있는 디렉토리에서 아래 명령어를 실행합니다. ```bash uvicorn main:app --reload ``` - `main`: `main.py` 파일을 의미합니다. - `app`: `main.py` 파일 안에서 `app = FastAPI()`로 생성한 FastAPI 인스턴스 객체를 의미합니다. - `--reload`: 코드가 변경될 때마다 서버를 자동으로 재시작해주는 개발용 옵션입니다. 2. **자동 생성된 API 문서 확인**: 서버가 성공적으로 실행되면 (`Application startup complete.`), 웹 브라우저를 열고 다음 두 주소 중 하나로 접속합니다. - **Swagger UI**: http://127.0.0.1:8000/docs - **ReDoc**: http://127.0.0.1:8000/redoc

FastAPI Swagger UI

3. **API 테스트**: - Swagger UI 화면에서 `/predict` 엔드포인트를 클릭하여 펼칩니다. - 오른쪽 위에 있는 `Try it out` 버튼을 클릭합니다. - `Request body`에 예시로 있는 JSON 데이터를 그대로 두거나 다른 값으로 수정합니다. ```json { "features": [6.7, 3.0, 5.2, 2.3] // virginica 품종의 데이터 } ``` - `Execute` 버튼을 누르면 API 서버로 요청이 전송되고, 그 아래 `Response body`에서 예측 결과를 확인할 수 있습니다. --- ### ✅ 정리 및 다음 단계 이번 파트에서는 **FastAPI**를 사용하여, Part 5에서 만든 `iris_model.pkl` 머신러닝 모델을 **실시간으로 예측 결과를 제공하는 API 서버**로 만드는 과정을 실습했습니다. - **FastAPI**: 높은 성능과 빠른 개발 속도, 자동 문서 생성 기능을 갖춘 현대적인 웹 프레임워크 - **`lifespan`**: 서버 시작/종료 시 모델 로딩과 같은 초기화/정리 작업을 수행 - **Pydantic**: API의 입출력 데이터 형식을 명확하게 정의하고 자동으로 유효성 검사 - **Uvicorn**: FastAPI 애플리케이션을 실행하는 ASGI 서버 이제 여러분은 학습된 모델을 실제 서비스로 만들 수 있는 첫걸음을 떼었습니다. 하지만 현재의 코드는 모든 로직이 `main.py` 단일 파일에 집중되어 있어, 기능이 복잡해질수록 유지보수가 어려워지는 한계가 있습니다. **➡️ 다음 시간: [Part 7: 실전형 AI API 서버 구축](part_7_production_ready_api.md)** 다음 시간에는 단일 파일 구조를 벗어나, 실제 프로덕션 환경에서도 통용되는 **체계적인 프로젝트 구조**로 API 서버를 리팩토링합니다. **라우터 분리, 데이터베이스 연동, 설정 관리** 등 더 견고하고 확장 가능한 서버를 만드는 방법을 배우게 될 것입니다.