181 lines
5.8 KiB
Plaintext
181 lines
5.8 KiB
Plaintext
우분투(Ubuntu) 서버 환경에서 Mistral LLM을 구축하고 파이썬 API 서버(FastAPI)로 띄우는 전체 과정을 순서대로 정리해 드립니다.
|
|
|
|
하드웨어(GPU 유무, RAM 용량)에 구애받지 않고 가장 안정적으로 동작하는 **표준 라이브러리(`transformers`) 기준**으로 작성되었습니다.
|
|
|
|
---
|
|
|
|
## 1단계: 가상환경 및 필수 라이브러리 설치
|
|
|
|
시스템 파이썬을 보호하고 의존성 충돌을 막기 위해 가상환경(Conda)을 세팅합니다.
|
|
|
|
**1. Conda 가상환경 생성 및 활성화**
|
|
|
|
```bash
|
|
conda create -n mistral-env python=3.10 -y
|
|
conda activate mistral-env
|
|
|
|
```
|
|
|
|
**2. 필수 파이썬 패키지 설치**
|
|
AI 구동 커널, 웹 서버 라이브러리, 허깅페이스 통신 모듈을 한 번에 설치합니다.
|
|
|
|
```bash
|
|
pip install torch transformers accelerate fastapi uvicorn huggingface_hub
|
|
|
|
```
|
|
|
|
## 2단계: Hugging Face 인증 및 모델 다운로드
|
|
|
|
Mistral 7B 모델은 허깅페이스(Hugging Face)를 통해 배포되므로 토큰 인증이 필요합니다.
|
|
|
|
**1. 토큰 로그인**
|
|
|
|
```bash
|
|
python -m huggingface_hub.cli login
|
|
|
|
```
|
|
|
|
* `Token:` 프롬프트가 뜨면 허깅페이스 사이트(Settings -> Access Tokens)에서 발급받은 토큰을 붙여넣고 엔터를 칩니다. (보안상 화면에 글자가 보이지 않습니다.)
|
|
* `Add token as git credential? (y/n)` 질문에는 `n`을 입력합니다.
|
|
|
|
**2. 모델 다운로드 경로 준비**
|
|
|
|
```bash
|
|
mkdir -p ~/mistral_models/7B-Instruct-v0.3
|
|
|
|
```
|
|
|
|
**3. 모델 다운로드 실행 (약 15GB)**
|
|
|
|
```bash
|
|
python -m huggingface_hub.cli download mistralai/Mistral-7B-Instruct-v0.3 --local-dir ~/mistral_models/7B-Instruct-v0.3 --local-dir-use-symlinks False
|
|
|
|
```
|
|
|
|
## 3단계: 파이썬 웹 서버 코드 작성 (`serve_mistral.py`)
|
|
|
|
FastAPI를 사용하여 외부에서 API로 LLM에 질문을 던질 수 있도록 서버 코드를 작성합니다.
|
|
|
|
**1. 파이썬 파일 생성**
|
|
|
|
```bash
|
|
nano serve_mistral.py
|
|
|
|
```
|
|
|
|
**2. 서버 코드 붙여넣기**
|
|
메모리 부족(Killed)이나 GPU(CUDA) 에러를 방지하기 위해 용량을 절반으로 줄이는 `float16` 옵션과 자동 디스크 오프로딩이 적용된 코드입니다.
|
|
|
|
```python
|
|
import warnings
|
|
warnings.filterwarnings("ignore")
|
|
|
|
from fastapi import FastAPI
|
|
from fastapi.responses import JSONResponse
|
|
from pydantic import BaseModel
|
|
import uvicorn
|
|
import torch
|
|
import os
|
|
from transformers import AutoModelForCausalLM, AutoTokenizer
|
|
import time
|
|
|
|
# =========================================================
|
|
# [시스템] AI 모델 로드
|
|
# =========================================================
|
|
model_path = os.path.expanduser("~/mistral_models/7B-Instruct-v0.3")
|
|
print("=== AI 모델 로딩 중... ===")
|
|
|
|
try:
|
|
tokenizer = AutoTokenizer.from_pretrained(model_path)
|
|
|
|
# 메모리 최적화 및 장치 자동 할당
|
|
model = AutoModelForCausalLM.from_pretrained(
|
|
model_path,
|
|
device_map="auto", # GPU가 없으면 자동으로 CPU/RAM 사용
|
|
torch_dtype=torch.float16, # 메모리 사용량 절반 감소
|
|
low_cpu_mem_usage=True
|
|
)
|
|
print("=== AI 준비 완료 ===")
|
|
except Exception as e:
|
|
print(f"!!! 모델 로드 실패: {e}")
|
|
exit()
|
|
|
|
app = FastAPI()
|
|
|
|
class ChatRequest(BaseModel):
|
|
prompt: str
|
|
|
|
# =========================================================
|
|
# [API] 메인 엔드포인트
|
|
# =========================================================
|
|
@app.post("/chat")
|
|
async def chat_endpoint(request: ChatRequest):
|
|
try:
|
|
user_input = request.prompt
|
|
print(f"\n>> 질문: {user_input}")
|
|
|
|
# 메시지 템플릿 적용
|
|
messages = [{"role": "user", "content": user_input}]
|
|
prompt = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
|
|
|
|
# 모델 장치(CPU/GPU)에 맞게 입력값 전달
|
|
inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
|
|
|
|
start_time = time.time()
|
|
print(" (AI 연산 시작...)")
|
|
|
|
# 텍스트 생성
|
|
with torch.no_grad():
|
|
outputs = model.generate(
|
|
**inputs,
|
|
max_new_tokens=512,
|
|
temperature=0.1,
|
|
do_sample=True,
|
|
pad_token_id=tokenizer.eos_token_id
|
|
)
|
|
|
|
print(f" (연산 완료: {time.time() - start_time:.2f}초)")
|
|
|
|
# 결과 디코딩 (입력된 프롬프트 제외)
|
|
generated_text = tokenizer.decode(outputs[0][inputs.input_ids.shape[1]:], skip_special_tokens=True)
|
|
|
|
return JSONResponse(content={"response": generated_text.strip()})
|
|
|
|
except Exception as e:
|
|
print(f"Server Error: {e}")
|
|
return JSONResponse(content={"response": "시스템 오류가 발생했습니다."}, status_code=500)
|
|
|
|
if __name__ == "__main__":
|
|
uvicorn.run(app, host="0.0.0.0", port=8000)
|
|
|
|
```
|
|
|
|
* 저장 후 종료: `Ctrl + O` -> `Enter` -> `Ctrl + X`
|
|
|
|
## 4단계: 무중단 백그라운드 실행 (`tmux`)
|
|
|
|
SSH 터미널 접속을 끊어도 서버가 계속 켜져 있도록 가상 화면(`tmux`)을 활용합니다.
|
|
|
|
**1. 백그라운드 세션 생성**
|
|
|
|
```bash
|
|
tmux new -s aiserver
|
|
|
|
```
|
|
|
|
**2. 환경 활성화 및 서버 실행**
|
|
새로 열린 가상 화면에서 서버를 켭니다.
|
|
|
|
```bash
|
|
conda activate mistral-env
|
|
python serve_mistral.py
|
|
|
|
```
|
|
|
|
**3. 가상 화면 빠져나오기 (서버 유지)**
|
|
서버가 정상적으로 켜진 것을 확인한 뒤, 키보드에서 `Ctrl + B`를 누르고 손을 뗀 다음 `D`를 누릅니다.
|
|
이제 터미널 프로그램을 종료해도 백그라운드에서 AI 서버가 정상적으로 요청을 대기합니다.
|
|
|
|
---
|
|
|
|
> **운영 팁:** 프로세스가 램 용량을 초과해 강제 종료(Killed)되는 현상이 발생한다면, 우분투 하드디스크 공간을 램처럼 활용하는 **스왑 메모리(Swap Memory)**를 16GB 이상 할당해 주어야 모델이 죽지 않고 연산을 완료할 수 있습니다. |