로컬 LLM(llama-cpp-python)을 이용한 텍스트 분류 서비스. HTTP(FastAPI)와 gRPC 인터페이스를 동시에 제공합니다.
- REST API —
POST /classify,POST /classify/batch - gRPC —
Classify,ClassifyBatch,Health(Server Reflection 지원) - 카테고리 —
configs/categories.yaml기본값 + 요청별 오버라이드 - CUDA 지원 — GTX 1650(4GB VRAM) 기준 GPU 오프로드 가능
- Swagger UI —
/docs(REST), grpcurl (gRPC)
- Python 3.12+
- uv 패키지 매니저
- GGUF 형식 모델 파일
- (선택) CUDA 12.4 드라이버 (GPU 추론 시)
# 1. 의존성 설치
make install # CPU
make install-cuda # GPU (CUDA 12.4)
# 2. gRPC 스텁 생성
make proto
# 3. 환경 변수 설정
cp .env.example .env
# .env 에서 MODEL_PATH 를 실제 .gguf 파일 경로로 수정
# 4. 서버 실행
make run서버가 기동되면:
| 인터페이스 | 주소 |
|---|---|
| HTTP REST | http://localhost:8000 |
| Swagger UI | http://localhost:8000/docs |
| gRPC | localhost:50051 |
.env.example 파일을 복사해 .env로 사용합니다.
| 변수 | 기본값 | 설명 |
|---|---|---|
MODEL_PATH |
(필수) | GGUF 모델 파일 절대 경로 |
MODEL_N_CTX |
4096 |
컨텍스트 윈도우 크기 (토큰) |
MODEL_N_GPU_LAYERS |
0 |
GPU 오프로드 레이어 수 (-1 = 전체) |
API_HOST |
0.0.0.0 |
HTTP 바인드 주소 |
API_PORT |
8000 |
HTTP 포트 |
GRPC_HOST |
0.0.0.0 |
gRPC 바인드 주소 |
GRPC_PORT |
50051 |
gRPC 포트 |
LLM_MAX_TOKENS |
256 |
최대 생성 토큰 수 |
LLM_TEMPERATURE |
0.1 |
생성 온도 (낮을수록 결정적) |
CATEGORIES_CONFIG_PATH |
configs/categories.yaml |
기본 카테고리 파일 경로 |
| 모델 크기 | 권장 MODEL_N_GPU_LAYERS |
|---|---|
| 1.5B Q4_K_M | -1 (전체 GPU) |
| 3B Q4_K_M | -1 (전체 GPU) |
| 7B Q4_K_M | 20 (부분 오프로드) |
단건 분류 (기본 카테고리)
curl -s -X POST http://localhost:8000/classify \
-H "Content-Type: application/json" \
-d '{"text": "삼성전자가 신형 갤럭시 S25를 공개했다."}'단건 분류 (커스텀 카테고리)
curl -s -X POST http://localhost:8000/classify \
-H "Content-Type: application/json" \
-d '{
"text": "한국은행이 기준금리를 동결했다.",
"categories": [
{"name": "finance", "description": "Banking, markets, and monetary policy"},
{"name": "other", "description": "Anything else"}
]
}'배치 분류
curl -s -X POST http://localhost:8000/classify/batch \
-H "Content-Type: application/json" \
-d '{
"texts": [
"손흥민이 결승골을 넣었다.",
"새로운 AI 칩이 출시됐다."
]
}'헬스 체크
curl -s http://localhost:8000/healthgrpcurl 기준:
# 서비스 목록 (Server Reflection)
grpcurl -plaintext localhost:50051 list
# 단건 분류
grpcurl -plaintext \
-d '{"text": "삼성전자가 신형 갤럭시 S25를 공개했다."}' \
localhost:50051 classifier.ClassifierService/Classify
# 배치 분류
grpcurl -plaintext \
-d '{"texts": ["손흥민이 결승골을 넣었다.", "새로운 AI 칩이 출시됐다."]}' \
localhost:50051 classifier.ClassifierService/ClassifyBatch
# 헬스 체크
grpcurl -plaintext \
-d '{}' localhost:50051 classifier.ClassifierService/HealthClassifier/
├── main.py # FastAPI app + lifespan (HTTP + gRPC 동시 기동)
├── config.py # pydantic-settings 환경 변수
├── configs/
│ └── categories.yaml # 기본 카테고리 정의
├── api/
│ └── routes/
│ ├── health.py # GET /health
│ └── classify/
│ ├── classify.py # POST /classify, /classify/batch
│ └── dto.py # Pydantic 요청/응답 스키마
├── processor/
│ ├── llm.py # LLMEngine 싱글턴 (ThreadPoolExecutor)
│ ├── classifier.py # classify_text(), JSON 파싱
│ └── prompt.py # 프롬프트 빌더
├── grpc_server/
│ └── servicer.py # gRPC ClassifierService 구현체
└── proto/
├── classifier.proto # 서비스 정의
├── classifier_pb2.py # 생성된 메시지 스텁 (make proto)
└── classifier_pb2_grpc.py # 생성된 서비스 스텁 (make proto)
make help # 커맨드 목록
make install # 의존성 설치 (CPU)
make install-cuda # 의존성 설치 (CUDA 12.4 GPU)
make proto # proto → Python 스텁 생성
make run # 서버 실행
make fmt # black 포매터 실행
make fmt-check # 포맷 확인
make test # 테스트 실행
make clean # 빌드 아티팩트 제거huggingface-hub를 사용합니다.
# 예시: Qwen2.5 1.5B Instruct Q4_K_M
uv run huggingface-cli download \
Qwen/Qwen2.5-1.5B-Instruct-GGUF \
qwen2.5-1.5b-instruct-q4_k_m.gguf \
--local-dir ./models