본문 바로가기

AI·LLM 엔지니어링

로컬 LLM 구축 1편: vLLM·GGUF·FastAPI로 사내 AI 서버 만들기

반응형

요약: vLLM, GGUF, FastAPI를 조합해 사내에서 직접 운영할 수 있는 로컬 LLM API 서버 구조를 정리합니다.

대상 독자: 로컬 LLM을 처음 서버 형태로 배포하려는 개발자와 사내 AI PoC 담당자

핵심 키워드: 로컬 LLM, vLLM, GGUF, FastAPI, 사내 AI 서버

반응형
로컬 LLM 구축 가이드

로컬 LLM 구축 가이드

vLLM + GGUF + FastAPI로 만드는 사내 AI 시스템

기업 내부 문서 검색용 LLM 실전 구축 튜토리얼

사내 문서 검색 시스템을 만들 때 가장 중요한 건 보안 + 속도 + 확장성입니다.
클라우드 기반 LLM을 적용하면 편하지만, 금융권·공공기관 등에서는 내부망 외부 반출이 불가능해 로컬 LLM이 필수입니다.

여기서는 제가 실제 프로젝트에서 사용한 구조 그대로
vLLM + GGUF + FastAPI 기반 사내 문서 검색 LLM 시스템 구축 과정을 정리합니다.


 1. 전체 아키텍처 구조

[ 사내 문서 저장소 ]  
      ↓ (크롤링 & 수집)
[ Extractor: PDF/Text/HTML 파서 ]
      ↓
[ Embedding Pipeline ]
      - 문서 chunking
      - embedding 생성 (bge-m3 또는 jina-embeddings)
      - 벡터 DB 저장 (Qdrant / Milvus)
      ↓
[ API 서버 FastAPI ]
      - 검색 → RAG → 프롬프트 구성
      - vLLM 서버로 질의
      ↓
[ vLLM (GGUF 모델 로드) ]
      - Llama 3.1 70B GGUF 또는 Qwen 32B GGUF
      ↓
[ 사용자 Web UI / 내부 포털 ]

이 구조를 쓰면

  • 보안 문제 없음(외부 전송 X)
  • vLLM 엔진으로 응답 속도 월등히 빠름
  • 벡터 DB + RAG로 문서 검색 정확도 확보
  • FastAPI 기반이라 쉽게 내부 시스템과 연동 가능

 2. vLLM 서버 구성 (GGUF 모델 로드)

2.1 vLLM 설치

pip install vllm

2.2 GGUF 모델 다운로드 예시

wget https://huggingface.co/QuantFactory/Llama-3.1-70B-GGUF/resolve/main/llama-3.1-70b.q4_k_m.gguf

2.3 vLLM 서버 실행

python3 -m vllm.entrypoints.openai.api_server \
  --model ./llama-3.1-70b.q4_k_m.gguf \
  --tensor-parallel-size 1 \
  --port 8000 \
  --max-model-len 16384

⚙ 추천 옵션

  • --gpu-memory-utilization 0.9 : GPU 메모리 최대 활용
  • --max-model-len 16384 : RAG에서 긴 문맥 처리용

 3. 문서 Embedding + Vector DB 구성

문서를 RAG로 연결하기 위해선
chunking → embedding → vector DB 저장
이 3단계를 반드시 거쳐야 한다.

3.1 chunking 예시

def chunk_text(text, size=512, overlap=50):
    chunks = []
    for i in range(0, len(text), size - overlap):
        chunks.append(text[i:i+size])
    return chunks

3.2 Embedding 예시 (bge-m3)

from sentence_transformers import SentenceTransformer
model = SentenceTransformer("BAAI/bge-m3")
embedding = model.encode(chunks)

3.3 Qdrant 저장

from qdrant_client import QdrantClient

client = QdrantClient(":memory:")

client.recreate_collection(
    collection_name="docs",
    vector_size=1024,
    distance="Cosine"
)

client.upsert(
    collection_name="docs",
    points=[
        {
            "id": idx,
            "vector": vec.tolist(),
            "payload": {"text": chunk}
        }
        for idx, vec in enumerate(embedding)
    ]
)

 4. FastAPI로 검색 API 만들기

4.1 RAG 검색 → Prompt → LLM 호출

from fastapi import FastAPI
from qdrant_client import QdrantClient
import requests

app = FastAPI()
client = QdrantClient(":memory:")

VLLM_ENDPOINT = "http://127.0.0.1:8000/v1/chat/completions"

@app.post("/ask")
def ask(query: str):
    # 벡터 검색
    embedding = embed_model.encode([query])[0]
    result = client.search(
        collection_name="docs",
        query_vector=embedding,
        limit=3
    )

    context = "\n".join([r.payload.get("text") for r in result])

    prompt = f"""
당신은 사내 문서 검색 AI입니다.
아래 문서를 참고해서 질문에 답하세요.

[문서]
{context}

[질문]
{query}

[답변]
"""

    # vLLM 호출
    res = requests.post(
        VLLM_ENDPOINT,
        json={
            "model": "local-model",
            "messages": [
                {"role": "user", "content": prompt}
            ],
            "max_tokens": 1024
        }
    )

    return res.json()

 5. 운영 중 실제 문제 & 해결 경험

✔ 문제 1: 문서 검색 결과가 정확하지 않았던 이유

원인: chunk 크기가 너무 작고 embedding 품질이 낮았음
해결: bge-m3 + chunk-size 512로 변경 → 정확도 개선


✔ 문제 2: vLLM 응답 속도가 불규칙

원인: CPU fallback 발생
해결:

  • CUDA Toolkit 버전 통일
  • --gpu-memory-utilization 0.9 설정
  • 부하 시 GPU 여러 개로 tensor parallel 설정

✔ 문제 3: FastAPI가 RAG 단계에서 병목

원인: embedding 모델 inference 속도 느림
해결:

  • embedding 서버를 별도로 띄워 비동기 처리
  • async + background task 적용
  • Qdrant 검색을 캐싱하여 반복 요청 최적화

 6. 실전 팁 3가지

💡 팁 1: 가능한 한 “vLLM + GGUF” 조합을 쓰라

GGUF는 메모리를 적게 쓰고, vLLM은 Serving 속도가 빨라
조합 자체가 가장 안정적이고 운영비가 거의 없음.


💡 팁 2: Embedding 서버는 반드시 별도 프로세스로 분리하라

RAG 시스템에서 가장 느린 부분은 embedding이다.
서버 분리만 해도 응답속도 30% 이상 빨라짐.


💡 팁 3: 프롬프트에 검색된 문서 3개 이상 넣지 마라

문맥이 길어질수록 오히려 답변 품질이 떨어진다.
3개 이하가 가장 안정적이고 명확하다.


 7. 마무리

위 구조만 정리해도
은행·공공기관·대기업 내부망에서 완전히 독립적으로 돌아가는
실전형 로컬 LLM 문서 검색 시스템을 구축할 수 있다.

 

반응형
좋아요공감
공유하기
URL 복사카카오톡 공유페이스북 공유엑스 공유
통계
게시글 관리

'AI·LLM 엔지니어링' 카테고리의 다른 글

〈LangChain 기반 RAG 시스템 구축〉 2편 : 임베딩 & 벡터DB 구축  (0)〈LangChain 기반 RAG 시스템 구축〉 1편: 데이터 준비 파이프라인 구축  (0)로컬 LLM 서버 구축 가이드: vLLM, GGUF, FastAPI로 사내 AI API 만들기  (0)3편 로컬 LLM 구축 가이드 – RAG 성능 최적화 + 평가 지표  (0)2편 로컬 LLM 구축 가이드 - 고성능 서버(GPU) 환경 구축 기반  (0)
2025.11.27
2025.11.27
2025.11.27
2025.11.27
2025.11.26

실무 적용 체크리스트

점검 항목운영 기준

모델 실행 GGUF 또는 오픈소스 LLM을 서버에서 안정적으로 로드
API 계층 FastAPI로 내부 서비스가 호출할 수 있는 엔드포인트 구성
검색 결합 문서 임베딩과 Vector DB를 연결해 RAG 확장 가능
운영 기준 GPU 메모리, 응답 시간, 장애 재시작 정책을 함께 설계

자주 묻는 질문

로컬 LLM 구축에 vLLM이 꼭 필요한가요?

동시 요청과 추론 처리량이 중요하다면 vLLM이 유리합니다. 단순 테스트는 llama.cpp나 Ollama로 시작해도 됩니다.

GGUF 모델은 어떤 경우에 적합한가요?

GPU 자원이 제한적이거나 양자화 모델로 비용을 줄여야 하는 환경에 적합합니다.

FastAPI를 붙이는 이유는 무엇인가요?

사내 시스템이 HTTP API로 LLM을 호출하게 만들면 권한, 로그, 모니터링, 장애 대응을 표준화하기 쉽습니다.

함께 읽으면 좋은 글

반응형