본문으로 건너뛰기
페이지 목차
이 페이지에서 검색

로컬 LLM

이 페이지에 묻기

로컬 LLM · 현재 차시와 목차 본문에서만 찾아 답합니다. 답을 지어내지 않고 해당하는 대목을 그대로 보여 주며, 여기에 없으면 없다고 알려 드립니다.

생성형 AI가 아니라 이 페이지 본문을 찾아 그대로 보여 주는 방식입니다. 외부로 나가는 요청이 없습니다.

LOCAL · LLM

로컬 LLM

생성 수정

로컬 모델 실행과 GPU·메모리 이해부터 서빙·RAG·도구 호출·업무형 앱 구현까지 차례로 살펴봅니다.

42개 문서 · 3일차 · 18 / 42

17차시 · LLM Serving 아키텍처

지도 위치 : 3일차 · ③추론 엔진 ↔ ④API 층의 경계 · 3일차 출발점 | 이전: 16차시 하드웨어별 최적 모델 선정 | 다음: 18차시 vLLM 환경 구축 키워드 : LLM Inference와 Serving, Model Server, API Server, 클라이언트-서버 구조

이 차시를 다 읽으면

  1. Inference와 Serving 을 유와 종차로 정의하고, "서빙"이라는 번역어의 함정을 말할 수 있다.
  2. 클라이언트 → API 서버 → 모델 서버 → GPU 네 칸 구조도를 그리고, 칸마다 맡는 일과 맡지 않는 일을 말할 수 있다.
  3. 앱 프로세스 안에서 모델을 직접 돌리면 생기는 세 가지 문제 를 축 ⑤(하나 ↔ 여럿)로 설명할 수 있다.
  4. 서빙 층이 해결해야 할 다섯 가지 (동시성 · 큐 · 인증 · 모니터링 · 모델 관리)를 댈 수 있다.
  5. "느리다 / 동시 요청에서 죽는다"라는 뭉뚱그린 증상을 쪼개어, 각각이 3일차의 어느 차시 로 이어지는지 말할 수 있다.

0. 이 차시의 판별 축

#축왼쪽 (0)오른쪽 (1)이 축으로 갈리는 것큰 축 (README 5장)
1한 번 계산인가, 계속 제공하는가Inference (한 번 실행)Serving (여럿에게 지속 제공)실행 ↔ 운영한 번 계산 ↔ 여럿에게 제공 (파생 축, 부모 ⑤)
2모델을 어디에 두는가앱 프로세스 안에 모델모델 서버로 분리장애 · VRAM · 확장⑤ 하나 ↔ 여럿 (모놀리식 ↔ MSA, 3.2)
3몇 명이 쓰는가1인 (요청 하나씩)다수 (동시 요청)처리 방식 · 측정 지표⑤ 하나 ↔ 여럿

1~2일차는 사실상 혼자 쓰는 쪽 (축 3의 왼쪽)에서 모델 하나, 요청 하나를 들여다봤습니다. 3일차는 같은 모델을 상담원 10명이 동시에 쓰게 만듭니다. 이 전환은 소프트웨어가 자라면서 흔히 거치는 "스크립트에서 서버로" 의 한 사례입니다.

용어정의
스크립트[프로그램의 실행 방식]인데, [ 내가 실행하면 할 일을 한 번 하고 끝난다 ]는 점에서 서버와 구별된다. 예: python summarize.py
서버[프로그램의 실행 방식]인데, [ 계속 떠 있으면서 네트워크로 들어오는 요청을 기다렸다가 처리한다 ]는 점에서 스크립트와 구별된다. 요청을 보내는 쪽은 클라이언트 라고 부릅니다

5차시의 Ollama가 이미 작은 서버였습니다(ollama run도 사실은 서버에 요청을 보내는 클라이언트). 이번 차시는 같은 전환을 여러 사람 · GPU 한 장 이라는 조건에서 제대로 설계합니다.


1. Inference와 Serving — 같은 모델, 다른 층

1.1 정의

추론 (Inference) — 앞에서 정의한 대로(2차시 1절) [모델 사용 단계]인데, [ 가중치를 바꾸지 않고 입력에 대한 출력만 계산한다 ]는 점에서 학습과 구별된다.

서빙 (Serving) — [모델 운영 방식]인데, [ 학습된 모델을 네트워크 너머 여러 클라이언트에게 지속적으로 · 동시에 제공한다 ]는 점에서 한 번 실행해 결과를 얻는 추론(Inference)과 구별된다.

InferenceServing
묻는 것이 입력에 대한 출력은?누가 언제 물어도 답할 수 있는가?
단위요청 하나요청의 흐름 (동시 · 연속)
수명계산이 끝나면 끝서버가 떠 있는 동안 계속
성공 기준출력이 나왔다여럿이 동시에 써도 정해진 시간 안에, 죽지 않고 나온다
실패 모습에러, 틀린 답대기열 폭증, 메모리 부족으로 다운, 한 사람 때문에 모두 느려짐
이 과정에서1~2일차 (model.generate, ollama run)3일차 (vllm serve)

⭐ Serving은 Inference를 포함합니다. 서빙 서버 안에서도 결국 요청마다 추론이 일어납니다. 서빙은 그 위에 "여럿 · 계속" 을 얹은 층입니다.

1.2 ⚠️ 번역어 함정 — "서빙"

"서빙"을 "모델을 실행한다" 정도로 읽으면 3일차 전체가 흐려집니다. 원 뜻은 식당의 serve , 즉 손님에게 계속 내어 주는 일 입니다(README 6장).

대상서빙인가왜
Jupyter에서 model.generate() 한 번❌한 번 계산하고 끝. Inference
밤새 문의 메일 1,000통을 스크립트로 요약❌많이 처리하지만 기다리는 클라이언트가 없음 . 오프라인 배치 추론(18차시의 LLM 클래스가 이 자리)
vllm serve로 서버만 띄워 둠⚠️ 반쪽제공은 하지만 인증 · 모니터링 · 용량 계획이 없으면 운영이 아님 (4절)
상담원 10명이 쓰는 문의봇 뒤의 모델 서버⭕여럿에게, 계속, 동시에

💡 비유는 마지막에, 기억 보조로만 씁니다. 식당으로 그리면 요리 한 접시를 만드는 것 이 Inference, 식당을 열어 손님을 계속 받는 것 이 Serving입니다.


2. ⭐ 구조도 — 네 칸

[클라이언트]   상담원 브라우저 × 10, 사내 시스템
     │  HTTP (JSON)                      ← 7차시에 Ollama에 보낸 것과 같은 종류의 요청
     ▼
[API 서버]     FastAPI — 앱 로직 · 인증 · 프롬프트 조립 · 입력 검증 · 로그
     │  HTTP (OpenAI 호환 API)            ← 20차시: 이 화살표가 "포트"
     ▼
[모델 서버]    vLLM 또는 Ollama — 토큰화 · 배칭 · KV 캐시 관리 · 생성
     │  CUDA
     ▼
[GPU]         가중치 + KV 캐시 (VRAM)      ← 9차시의 예산식

2.1 칸마다 정의

모델 서버 (Model Server) — [서버 프로세스]인데, [ 모델을 VRAM에 상주시켜 두고 추론 요청만 받아 처리한다 ]는 점에서 업무 규칙을 다루는 API 서버와 구별된다. 이 과정의 vLLM · Ollama · llama-server가 여기에 속합니다.

API 서버 (API Server) — [서버 프로세스]인데, [ 업무 규칙 · 인증 · 입출력 검증을 맡고 추론은 모델 서버에 위임한다 ]는 점에서 모델 서버와 구별된다. 이 과정에서는 FastAPI (Python으로 HTTP API 서버를 만드는 웹 프레임워크)로 만드는 문의봇 백엔드가 이 자리입니다(25차시).

클라이언트-서버 구조 — [프로그램 배치 방식]인데, [ 요청하는 쪽(클라이언트)과 응답하는 쪽(서버)을 나누고, 둘이 네트워크 규약으로만 대화한다 ]는 점에서 한 프로그램 안에서 함수를 직접 부르는 방식과 구별된다. 그 규약이 HTTP 입니다. 클라이언트가 주소 · 메서드(GET · POST 등) · 본문(JSON) 으로 요청하면, 서버가 상태 코드(200 성공, 401 인증 실패 등) · 본문 으로 답합니다(7차시에서 Ollama에 curl로 보낸 것이 이것). 3일차에 달라지는 것은 서버가 두 겹 이 되었다는 점 하나입니다. API 서버는 브라우저에게는 서버이고, 모델 서버에게는 클라이언트 입니다.

2.2 칸마다 책임

칸맡는 일맡지 않는 일문의봇에서
클라이언트화면, 입력, 스트리밍 표시프롬프트 내용, 인증 판단상담원이 문의를 붙여 넣고 "요약" 클릭
API 서버상담원 로그인 확인, 시스템 프롬프트 조립, 개인정보 마스킹, 결과 검증(29차시), 로그행렬 계산, 배칭"이 상담원이 이 문의를 볼 권한이 있는가" → 프롬프트 조립 → 모델 서버 호출
모델 서버토큰화, 여러 요청 묶어 계산(배칭), KV 캐시, 생성누가 요청했는지, 업무 규칙들어온 messages로 다음 토큰을 계속 생성
GPU실제 계산, 가중치 · KV 캐시 보관전부RTX 4090 24GB 한 장

2.3 반례 — "API 서버 없이 모델 서버를 바로 열면 안 되나?"

웹 서비스의 오래된 원칙 하나가 답입니다. 사용자는 데이터베이스(DB)에 직접 붙지 않고, 반드시 백엔드 서버를 거친다. 백엔드가 권한 확인 · 잘못된 요청 차단 · 데이터 보호 · 선행 처리를 맡기 때문입니다. 모델 서버도 같은 이유로 안 됩니다. DB 자리에 모델 서버를 넣기만 하면 됩니다.

상담원 → API 서버 → 모델 서버     ⭕
상담원 → 모델 서버                ❌
백엔드를 거치는 이유모델 서버를 직접 열면
권한 확인vLLM의 --api-key는 키 하나 뿐입니다(19차시). "상담원 A는 자기 담당 문의만" 같은 사용자별 인가가 없습니다
잘못된 요청 차단클라이언트가 시스템 프롬프트를 바꾸거나 max_tokens를 마음대로 키울 수 있습니다
데이터 보호개인정보 마스킹 · 로그 정책을 걸 곳이 없습니다
선행 처리프롬프트 조립 · 결과 검증을 브라우저가 하게 됩니다

첫 줄의 두 단어를 갈라 둡니다. 인증 (Authentication)은 "누구인가" 를 확인하는 것(로그인, API 키)이고, 인가 (Authorization)는 "그 사람이 이것을 해도 되는가" 를 판단하는 것입니다. 키 하나로는 "누군가 키를 가졌다"까지만 알 수 있고, 상담원마다 다른 권한은 가를 수 없습니다.

2.4 모델 서버는 허브다

모델 서버 하나를 문의봇, 사내 검색, 요약 배치가 함께 쓰기 시작하면 모양이 스타 토폴로지 가 됩니다. 가운데 하나( 허브 )에 여럿( 스포크 )이 매달린 연결 모양입니다. 모델 서버가 허브, 앱들이 스포크입니다.

⚠️ 이 모양의 약점은 분명합니다. 허브가 죽으면 전부 죽습니다. 이런 지점을 단일 장애점 (SPOF, Single Point of Failure)이라고 합니다. 3일차에서는 대책 두 가지를 지킵니다. 헬스 체크 (서버가 살아 있는지 주기적으로 묻는 짧은 요청)는 19차시의 /health로, 허브를 얇게 유지하기 (허브에 기능을 몰아넣지 않아 고장 날 거리를 줄이기)는 "모델 서버에는 업무 로직을 넣지 않는다"(2.2 표)로 지킵니다.


3. ⭐ 왜 앱 프로세스 안에서 모델을 직접 돌리면 안 되나

3.1 흔히 처음 만드는 모양

AI에게 "요약 API 만들어 줘"라고 하면 이런 코드가 자주 나옵니다.

from fastapi import FastAPI
from transformers import AutoModelForCausalLM, AutoTokenizer

app = FastAPI()
tok = AutoTokenizer.from_pretrained("Qwen/Qwen3-8B")
model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen3-8B", torch_dtype="auto", device_map="auto")

@app.post("/summarize")
def summarize(body: dict):
    inputs = tok(body["text"], return_tensors="pt").to(model.device)
    out = model.generate(**inputs, max_new_tokens=300)
    return {"summary": tok.decode(out[0], skip_special_tokens=True)}

🔍 읽는 포인트

  • from_pretrained(...)가 앱 파일 맨 위 에 있습니다 → 앱 프로세스가 곧 모델입니다.
  • model.generate(...) 한 줄이 요청 하나를 GPU에서 끝까지 처리합니다. 다른 요청과 묶는 장치가 없습니다.

혼자 쓸 때는 잘 돕니다. 상담원 10명이 쓰기 시작하면 세 가지가 터집니다.

#문제무슨 일이 생기나배경 개념
1요청마다 블로킹한 요청의 생성이 끝나야 다음 요청이 GPU를 씁니다. 10번째 상담원은 앞의 9명이 끝나기를 기다립니다. async def로 바꿔도 해결되지 않습니다. 기다림이 아니라 GPU 계산 그 자체 이기 때문입니다CPU-bound ↔ I/O-bound (아래) · 2차시 4절
2프로세스마다 VRAM 중복처리량을 늘리려고 uvicorn --workers 4(같은 앱 프로세스를 4개 띄우는 옵션)를 쓰면 모델이 4번 로드 됩니다. 8B FP16 ≈ 16GB × 4 = 64GB → 24GB GPU에 들어가지 않습니다운영체제는 프로세스마다 메모리 공간을 따로 줍니다. 그래서 모델도 따로 올라갑니다
3확장 · 배포 불가앱 코드 한 줄을 고쳐 재시작할 때마다 모델도 다시 로딩 (수십 초 이상). 앱 버그로 죽으면 모델도 같이 죽음. 앱만 / 모델만 따로 늘릴 수 없음모놀리식 ↔ MSA (3.2)

🔍 1번 행의 단어들 — 블로킹 은 한 일이 끝날 때까지 다음 일이 멈춰 서는 것입니다. async def 는 Python에서 함수를 비동기 (기다리는 동안 다른 일을 하는 방식, README 축 ⑥)로 만드는 표시입니다. 비동기는 I/O-bound 일, 즉 네트워크 응답이나 디스크를 기다리느라 느린 일에는 효과가 큽니다. 기다리는 동안 다른 요청을 처리하면 되니까요. 하지만 CPU-bound 일, 즉 계산 장치가 쉬지 않고 계산하느라 느린 일에는 효과가 없습니다. 놀고 있는 시간이 없기 때문입니다. 앱 프로세스 안의 model.generate는 뒤쪽입니다(자세히 22차시 3.3).

3.2 축 ⑤로 다시 읽기 — 모놀리식 ↔ MSA

3.1의 3번 문제는 시스템을 한 덩어리로 둘 것인가, 나눌 것인가 의 문제입니다. 이 선택에는 이름이 있습니다.

용어정의
모놀리식 (Monolithic)[시스템 배치 방식]인데, [ 모든 기능을 한 프로그램(한 프로세스)에 넣어 함께 배포하고 함께 실행한다 ]는 점에서 MSA와 구별된다
MSA (Microservice Architecture)[시스템 배치 방식]인데, [ 기능별로 작은 서버를 따로 띄우고 서로 네트워크(HTTP 등)로 부른다 ]는 점에서 모놀리식과 구별된다

앱 안에 모델을 넣는 것이 모놀리식이고, 모델 서버를 떼어 내는 것이 MSA 쪽으로 한 걸음 가는 것입니다. 둘의 거래는 README 5.1의 축 ⑤ 한 줄, "뭉치면 단순하고 빠르지만 같이 멈추고, 나누면 안전하고 따로 늘릴 수 있지만 통신 비용을 낸다" 가 그대로 적용됩니다.

앱 안에 모델 (뭉침, 0)모델 서버 분리 (쪼갬, 1)
통신 비용없음 (메모리 호출)HTTP 왕복 한 번. 생성 시간(초 단위)에 비하면 작음
같이 죽는가앱이 죽으면 모델도 죽음앱 재배포해도 모델은 그대로 떠 있음
VRAM워커 수만큼 중복모델은 한 번만 올라감, 여러 앱이 공유
동시 요청직접 만들어야 함엔진이 배칭으로 처리 (21차시)
엔진 교체앱 코드를 고쳐야 함주소만 바꿈 (20차시)

⚠️ 반례 — 뭉치는 게 맞는 경우도 있습니다. 혼자 쓰는 실험 노트북, 한 번 돌리고 끝나는 배치 처리(18차시의 오프라인 추론)는 서버를 세우는 비용이 더 큽니다. README 5.1의 경고처럼 어느 쪽도 발전된 형태가 아닙니다. 규모와 실패 비용이 답을 정합니다.

3.3 "스크립트에서 서버로"의 반복

0절에서 본 전환이 이번에는 모델을 들고 한 번 더 일어납니다. 실행의 주체 란 "누가 언제 내 코드를 부르는가"입니다. 스크립트는 내가 실행할 때 돌고, 서버에서는 프레임워크가 요청이 올 때마다 내 코드를 부릅니다.

일반 웹 서비스로컬 LLM 3일차
전환 전python summarize.py — 내가 진입점, 혼자 실행model.generate() — 내 스크립트 안에서 모델 실행
전환 후FastAPI + uvicorn이 요청을 받아 내 함수를 호출모델 서버 (vLLM)가 요청을 받아 엔진 호출
바뀐 것실행의 주체가 스크립트 → 프레임워크실행의 주체가 앱 → 모델 서버
요약 문장"실행의 주체를 스크립트에서 웹 프레임워크로 옮긴다""실행의 주체를 앱에서 모델 서버로 옮기고, 앱은 HTTP로 부른다 "

4. 서빙이 해결해야 할 다섯 가지

4.1 목록

해결할 것없으면 생기는 일주로 맡는 칸다루는 차시
동시성요청이 하나씩 줄 서서 처리됨모델 서버 (배칭)21
큐 (대기열)몰릴 때 무한정 쌓이거나 서버가 죽음모델 서버 (대기열) + API 서버 (타임아웃 · 재시도)21, 22
인증사내망 누구나 GPU를 씀, 개인정보 노출API 서버 (사용자별) + 모델 서버 (--api-key, 서비스 간)19
모니터링"느려요"라는 말 말고는 아무것도 모름둘 다 (/metrics, 로그)22
모델 관리지금 무슨 모델 · 어떤 설정으로 떠 있는지 아무도 모름모델 서버 + 설정 기록19, 23

4.2 "느리다 / 죽는다"를 증상별로 쪼개기

LLM 서비스가 느리거나 동시 요청에서 죽으면, 흔히 원인을 "서빙 설정 문제" 한 줄로 뭉뚱그립니다. 그래서는 어디를 손볼지 알 수 없습니다. 3일차는 이 한 줄을 증상별로 쪼갭니다.

증상어디서 생기나3일차에서
혼자 쓸 때도 첫 글자가 늦다Prefill, 긴 시스템 프롬프트21 (프리픽스 캐싱), 22 (TTFT 측정)
혼자일 땐 빠른데 10명이면 느리다동시성 · 배칭 · 대기열21, 22, 23
서버가 아예 안 뜬다 / 동시 요청에서 죽는다VRAM 예산 (KV 캐시 자리 부족)19, 23
긴 메일에서만 에러가 난다컨텍스트 길이 설정19, 23
이 정도면 Ollama로도 되지 않나?엔진 선택24

앞으로 다시 만납니다 — 3일차 순서: 18 설치 → 19 서버 띄우기 → 20 포트(OpenAI 호환 API) → 21 엔진 내부 → 22 측정 → 23 최적화 → 24 Ollama와 비교. 5일차 35차시에서 이 구조를 프로젝트로 다시 세웁니다.


5. 실습 — 맡기고 검수하기

이 차시는 설계 입니다. 코드를 받기 전에 구조와 책임을 먼저 받습니다.

지시

문의봇의 서빙 구조를 설계해줘.
조건: 상담원 10명 동시 사용, 문의에 고객 개인정보 포함(외부 전송 금지),
     RTX 4090 24GB 1대, 모델 Qwen3-8B, 앱은 FastAPI.

1. [클라이언트 → API 서버 → 모델 서버 → GPU] 구조도를 텍스트 그림으로.
2. [칸 | 맡는 일 | 맡지 않는 일 | 이 칸이 죽으면 생기는 일] 표.
3. [동시성 | 큐 | 인증 | 모니터링 | 모델 관리] 각각을 어느 칸이 맡는지 표.
4. 첨부한 내 8차시 앱 코드가 모델을 앱 프로세스 안에서 돌리는지,
   모델 서버에 HTTP로 요청하는지 판정하고, 근거가 된 코드 줄을 그대로 인용해줘.
vLLM · Ollama의 기능은 공식 문서에 근거가 있는 것만 쓰고, 확인 못 한 것은 "확인 필요"라고 써.

받을 증거

  • 구조도와 표 세 개
  • 4번 판정의 근거 코드 줄 원문 (판정만 있고 줄이 없으면 다시 요청)

내가 직접 볼 것

볼 것이걸로 아는 것 / 왜 내가 보는가
상담원 → 모델 서버 직행 화살표가 있는가있으면 2.3의 ❌ 구조. 인증 · 마스킹이 빠진 것
근거 줄에 from_pretrained · generate가 있는가, http://localhost:11434 같은 주소가 있는가앞쪽이면 앱 안에 모델(3.1), 뒤쪽이면 서버 분리. 코드를 다 읽지 않고도 판정 가능
모델 서버가 한 대뿐일 때 헬스 체크 대책이 적혀 있는가허브 = 단일 장애점 (2.4)
인증이 API 서버에도 있는가모델 서버의 키 하나로는 사용자별 인가가 안 됨

부록 A. 스스로 확인하기

#질문답이 있는 곳
1Serving을 유와 종차로 정의하면? Inference와 무엇으로 갈리는가?1.1
2밤새 메일 1,000통을 요약하는 스크립트는 서빙인가?1.2
3네 칸 구조도와 각 칸이 맡지 않는 일은?2, 2.2
4모델 서버를 브라우저에 직접 열면 안 되는 이유를 "사용자는 DB에 직접 붙지 않는다"는 원칙으로 설명하면? 인증과 인가는 어떻게 다른가?2.3
5모델 서버가 허브라면 어떤 위험과 대책이 따라오는가?2.4
6앱 안에서 모델을 돌릴 때 생기는 세 문제는?3.1
7async def로 바꾸면 블로킹이 풀리지 않는 이유는? (CPU-bound ↔ I/O-bound)3.1
8모놀리식과 MSA를 유와 종차로 정의하면? 앱 안에 모델을 두는 것은 어느 쪽인가?3.2
9서빙이 해결해야 할 다섯 가지와 각각 맡는 칸은?4.1

부록 B. 자주 하는 실수

실수바로잡기
"서빙 = 모델을 실행하는 것"❌ 서빙은 여럿에게 계속 제공 하는 층. 한 번 실행은 Inference
"워커를 늘리면 동시 처리가 된다"❌ 앱 안에 모델이 있으면 모델이 워커 수만큼 복제 됨
"async를 붙이면 동시에 생성된다"❌ 생성은 GPU 계산. 동시 처리는 엔진의 배칭 이 함 (21차시)
"모델 서버에 API 키가 있으니 인증은 끝"⚠️ 키 하나는 서비스 간 인증 . 사용자별 인가는 API 서버에서
"서버를 분리하면 무조건 좋다"⚠️ 혼자 쓰는 실험 · 배치에는 뭉친 쪽이 단순. 규모가 답을 정함

부록 C. NotebookLM 복습 프롬프트

이 17차시 노트만 근거로 5문제를 내줘. 비전공자 기준으로.
"Inference와 Serving의 차이", "앱 안에서 모델을 돌리면 생기는 세 문제", "모델 서버를 직접 노출하면 안 되는 이유"는 반드시 포함해줘.
답은 내가 답한 다음에 채점하고, 틀린 이유를 노트의 절 번호를 근거로 설명해줘.