페이지 목차
이 페이지에서 검색
로컬 LLM
이 페이지에 묻기
로컬 LLM · 현재 차시와 목차 본문에서만 찾아 답합니다. 답을 지어내지 않고 해당하는 대목을 그대로 보여 주며, 여기에 없으면 없다고 알려 드립니다.
생성형 AI가 아니라 이 페이지 본문을 찾아 그대로 보여 주는 방식입니다. 외부로 나가는 요청이 없습니다.
LOCAL · LLM
로컬 LLM
생성 수정
로컬 모델 실행과 GPU·메모리 이해부터 서빙·RAG·도구 호출·업무형 앱 구현까지 차례로 살펴봅니다.
42개 문서 · 1일차 · 3 / 42
2차시 · LLM 구조와 추론 원리
지도 위치 : 1일차 · ②모델 층의 내부 | 이전: 1차시 로컬 LLM 이해 | 다음: 3차시 개발환경 구축 키워드 : Transformer, Tokenizer, Embedding, Attention, Decoder, 파라미터, Context Length, LLM 추론 과정
이 차시를 다 읽으면
- 글 한 줄이 들어가 다음 토큰이 나오기까지의 다섯 단계 를 순서대로 말할 수 있다.
- "추론"과 "토큰"과 "파라미터"가 이 과정에서 각각 무엇을 뜻하는지 번역어 함정 과 함께 말할 수 있다.
- 어텐션의 Q · K · V 를 한 문장씩으로 말하고, K와 V가 왜 저장되는지(KV 캐시) 설명할 수 있다.
- Prefill과 Decode 를 순차 ↔ 병렬 축에 꽂고, 체감상 어떤 시간에 해당하는지 말할 수 있다.
- 컨텍스트 길이 안에 무엇무엇이 함께 들어가야 하는지 말할 수 있다.
0. 이 차시의 판별 축
| # | 축 | 왼쪽 (0) | 오른쪽 (1) | 이 축으로 갈리는 것 | 큰 축 (README 5장) |
|---|---|---|---|---|---|
| 1 | 형식인가 뜻인가 | 토크나이저 (글을 자름) | 어텐션 (문맥을 입힘) | 토큰 ↔ 문맥이 반영된 벡터 | ⑧ 구문론 ↔ 의미론 |
| 2 | 한꺼번에인가 하나씩인가 | Prefill (입력 전체를 병렬로) | Decode (한 토큰씩 순차로) | 첫 글자까지의 시간 ↔ 글자가 흘러나오는 속도 | 순차 ↔ 병렬 (파생 축) |
| 3 | 누가 값을 정하는가 | 학습이 정함 | 사람이 실행 전에 정함 | 모델 파라미터(가중치) ↔ 추론 파라미터(Temperature 등) | 파생 축 |
이 차시의 질문은 두 가지입니다. 뜻이 어떻게 만들어지는가 (축 1), 그리고 그 계산이 몇 번 반복되고 무엇이 메모리에 쌓이는가 (축 2). 두 번째 질문이 2~3일차 전체의 출발점입니다.
1. ⚠️ 먼저 단어 세 개를 갈라놓기
이 과정의 나머지 39차시가 이 세 단어 위에 섭니다. 셋 다 같은 한국어가 다른 영어를 가리키는 함정이 있습니다.
| 단어 | 이 과정에서의 뜻 | 헷갈리는 형제 | 갈리는 축 |
|---|---|---|---|
| 추론 | Inference — 학습이 끝난 모델을 실행해서 출력을 얻는 것 | Reasoning — 단계적으로 생각하는 능력 | 실행 ↔ 능력 |
| 토큰 | LLM이 글을 다루는 조각 단위 | 웹 로그인에 쓰는 인증 토큰 (JWT · 액세스 토큰) | 같은 철자, 다른 범주 |
| 파라미터 | 모델 파라미터 = 가중치. "8B" = 80억 개 | 추론 파라미터(Temperature 등, 6 · 13차시), 함수 매개변수 | 누가 값을 정하는가 (축 3) |
추론 (Inference) — [모델 사용 단계]인데, [ 가중치를 바꾸지 않고 입력에 대한 출력만 계산한다 ]는 점에서 가중치를 바꾸는 학습(Training) · 파인튜닝과 구별된다.
💡 그래서 "추론 서버", "추론 성능"은 "생각을 잘하는가"가 아니라 "실행이 빠르고 가벼운가" 의 이야기입니다.
2. 전체 흐름 — 다섯 단계 ⭐
"배송이 늦어요"
│ ① Tokenizer: 글 → 토큰 번호 (형식)
▼
[1234, 567, 8910]
│ ② Embedding: 번호 → 숫자 벡터
▼
[[0.12, -0.5, ...], [...], [...]]
│ ③ Transformer 블록 × N층 (Attention + 계산) (의미)
▼
│ ④ 출력: 다음 토큰 후보마다 확률
▼
"죄송" 30%, "확인" 25%, "고객" 10%, ...
│ ⑤ Sampling: 하나 고름 (6차시의 Temperature, Top-P)
▼
"죄송" → 입력 끝에 붙여서 ③부터 다시 → "합니다" → ... → 끝 토큰이 나오면 멈춤
①은 0절 축 1의 왼쪽(형식), ③은 오른쪽(의미)입니다. ⑤의 "다시 ③부터" 가 이 차시에서 가장 중요한 화살표입니다. 이 반복 때문에 4절의 Prefill / Decode가 생깁니다.
2.1 구성 요소를 유와 종차로
| 요소 | 정의 (유 + 종차) | 알아 둘 점 |
|---|---|---|
| Tokenizer | [전처리기]인데, [ 글을 모델 고유의 어휘 번호로 자른다 ]는 점에서 띄어쓰기 기준의 단순 분리와 구별된다 | 모델마다 다릅니다. 한국어는 영어보다 토큰이 더 많이 드는 경우가 많음 → 같은 글도 더 비싸고 느림 |
| Embedding | [변환층]인데, [ 토큰 번호를 뜻이 비슷할수록 가까이 놓이는 벡터로 바꾼다 ]는 점에서 단순히 글자를 숫자로 바꾸는 인코딩과 구별된다 | "강아지"와 "개"의 벡터는 가깝고, "강아지"와 "자동차"는 멂 |
| Attention | [계산 메커니즘]인데, [ 각 토큰이 앞 토큰들 중 무엇을 참고할지 Q · K · V로 계산한다 ]는 점에서 모든 토큰을 똑같이 섞는 계산과 구별된다 | 2.2절 |
| Transformer 블록 | [신경망 단위]인데, [ Attention과 계산층을 한 묶음으로 여러 층 쌓는다 ]는 점에서 글을 한 글자씩 순서대로 처리하던 이전 구조(RNN)와 구별된다 | 80억 파라미터급 모델은 이 블록이 30~40층 |
| Decoder-only | [Transformer 구조]인데, [ 앞의 토큰만 보고 다음을 생성한다 ]는 점에서 입력 전체를 앞뒤로 보는 Encoder와 구별된다 | 오늘날 대부분의 생성형 LLM |
2.2 ⭐ 어텐션의 Q · K · V, 그리고 KV 캐시
어텐션은 세 가지 역할로 이루어집니다. 각 토큰이 세 개의 벡터를 만들고, 각각 한 문장의 질문 · 답 으로 기억하면 됩니다.
| 기호 | 이름 | 이 토큰이 하는 말 |
|---|---|---|
| Q | Query (질의) | "나를 설명해 주는 게 앞에 있는가?" |
| K | Key (열쇠) | "내가 그 단서다." |
| V | Value (값) | "그렇다면 내가 이런 의미를 더해 주겠다." |
예를 들어 "파란 상자가 늦게 도착했다"에서 "상자"의 Q는 앞의 토큰들에게 묻고, "파란"의 K가 "내가 너를 꾸민다"고 답하면, "파란"의 V가 "상자"의 의미에 "파랗다"를 더합니다. Q와 K가 얼마나 잘 맞는지가 얼마나 주목할지(가중치) 가 되고, 그 가중치만큼 V를 더합니다.
이번에 비용의 눈으로 볼 것은 생성 중에 무슨 일이 반복되는가 입니다.
- 새 토큰을 하나 만들 때마다, 그 토큰의 Q 는 앞의 모든 토큰의 K와 V 에 질문을 던져야 합니다.
- 앞 토큰들의 K와 V는 이미 한 번 계산한 값 입니다. 매번 다시 계산하면 낭비입니다.
- 그래서 한 번 계산한 K와 V를 메모리에 쌓아 둡니다. 이것이 KV 캐시 입니다.
KV 캐시 (KV Cache) — [메모리 영역]인데, [ 이미 처리한 토큰들의 Key · Value 계산 결과를 저장해 재계산을 피한다 ]는 점에서 응답 자체를 저장하는 웹 캐시와 구별된다.
⚠️ 대가가 있습니다. 대화가 길어질수록(토큰이 많을수록) KV 캐시가 계속 커집니다. 모델 크기만으로 필요한 GPU 메모리를 계산하면 모자라는 이유가 바로 이것입니다.
앞으로 다시 만납니다 — 9차시에서 KV 캐시 크기를 직접 계산 하고, 21차시에서 vLLM이 이 캐시를 어떻게 관리해 동시 처리량을 늘리는지(PagedAttention) 봅니다.
3. Context Length — 한 번에 볼 수 있는 상한
컨텍스트 길이 (Context Length) — [모델의 제약]인데, [ 입력과 출력을 합친 토큰 수의 상한 ]이라는 점에서 출력만 제한하는 최대 생성 길이(max tokens)와 구별된다.
컨텍스트 길이 ≥ 시스템 프롬프트 + 대화 기록 + 이번 질문 + 이번에 생성할 답
| 구분 | 뜻 |
|---|---|
| 모델이 지원하는 최대치 | 모델 카드에 적힌 값 (예: 32K, 128K) |
| 실제로 설정해서 쓰는 값 | 실행 엔진에서 지정 (Ollama num_ctx, vLLM --max-model-len) |
둘은 다릅니다. 길게 설정할수록 KV 캐시 자리를 미리 많이 잡아 메모리를 씁니다(13, 19차시).
⚠️ 넘치면 앞부분이 잘리거나 에러가 납니다. 조용히 잘리는 경우 가 가장 위험합니다. 긴 문의 메일의 앞부분(고객 이름 · 주문번호)이 잘려 나가도 모델은 그럴듯한 답을 만듭니다(6차시).
4. ⭐ 추론의 두 단계 — Prefill과 Decode
2절 흐름도의 "다시 ③부터" 화살표가 추론을 두 단계로 가릅니다.
| Prefill | Decode | |
|---|---|---|
| 정의 | 입력 전체를 한 번에 읽어 KV 캐시를 채우는 단계 | 토큰을 하나씩 생성하는 단계 |
| 0절 축 2 | 병렬 — 입력 토큰들을 GPU가 동시에 계산 | 순차 — 앞 토큰이 나와야 다음 토큰을 계산 |
| 무엇이 병목인가 | 계산량 (입력이 길수록 오래) | 메모리 읽기 (토큰 하나마다 가중치 전체를 메모리에서 읽어야 함) |
| 체감 | 첫 글자가 나올 때까지의 시간 = TTFT | 글자가 흘러나오는 속도 = TPS |
⚠️ README 5.3의 경고 그대로, 순차 ↔ 병렬은 동기 ↔ 비동기와 다른 축 입니다. Decode가 느린 것은 "기다려서"가 아니라 구조상 하나씩밖에 못 만들어서 입니다. 그래서 코드를 비동기로 바꾼다고 Decode가 빨라지지 않습니다.
⭐ 이 구분이 실무에서 중요한 이유는 해결 방법이 다르기 때문 입니다.
| 증상 | 어느 단계 | 손볼 곳 |
|---|---|---|
| 긴 문서를 넣으면 첫 응답이 늦다 | Prefill | 입력 줄이기, 앞부분 재사용(프리픽스 캐시, 21차시) |
| 답이 느릿느릿 나온다 | Decode | 가중치를 가볍게 (양자화 10~12차시), 메모리 속도가 빠른 GPU (15차시) |
앞으로 다시 만납니다 — 14차시에서 TTFT와 TPS를 실제로 재고, 15차시에서 "왜 양자화하면 Decode가 빨라지는가"를 이 표로 설명합니다.
💡 비유는 마지막에 — Prefill은 시험지를 한 번에 훑어 읽는 시간 , Decode는 답안을 한 글자씩 써 내려가는 시간 입니다.
5. 실습 — 맡기고 검수하기
이 차시의 개념은 직접 눈으로 보면 훨씬 빨리 잡힙니다. 코드는 AI에게 맡기고 결과표만 봅니다.
지시
Qwen/Qwen3-8B 토크나이저로 아래 문장들을 토큰으로 나눠 보여줘.
[문장 | 글자 수 | 토큰 수 | 토큰 조각 목록] 표로. 실행한 코드와 출력 원문도 붙여줘.
1. "배송이 너무 늦어요. 주문번호는 20261128-001입니다."
2. "My delivery is very late. Order number is 20261128-001."
3. (고객 문의 메일 예시 한 통 전체)
받을 증거
- 실제 실행 출력 원문 (토크나이저마다 결과가 다르므로 추정치는 의미가 없습니다 )
내가 직접 볼 것
| 볼 것 | 이걸로 아는 것 |
|---|---|
| 같은 뜻의 한국어 · 영어 토큰 수 차이 | 한국어 서비스의 비용 · 속도 · 컨텍스트 소모 |
| 주문번호가 몇 조각으로 쪼개지는지 | 잘게 쪼개질수록 모델이 숫자를 정확히 다루기 어려움 → 29차시에서 추출 검증이 필요한 이유 |
| 메일 한 통이 몇 토큰인지 | 13차시에서 컨텍스트 길이를 정하는 근거 |
부록 A. 스스로 확인하기
| # | 질문 | 답이 있는 곳 |
|---|---|---|
| 1 | 이 과정의 "추론"은 영어로 무엇이고, Reasoning과 무엇이 다른가? | 1 |
| 2 | LLM 토큰과 로그인 토큰은 같은 범주인가? | 1 |
| 3 | 글이 들어가 다음 토큰이 나오기까지 다섯 단계는? | 2 |
| 4 | 토크나이저와 어텐션은 구문 ↔ 의미 축의 어디에 놓이는가? | 0, 2 |
| 5 | Q · K · V를 각각 한 문장으로 말하면? | 2.2 |
| 6 | KV 캐시는 무엇을, 왜 저장하는가? | 2.2 |
| 7 | 컨텍스트 길이 안에 함께 들어가야 하는 네 가지는? | 3 |
| 8 | Prefill과 Decode는 각각 순차 ↔ 병렬의 어느 쪽이고, 체감상 어떤 시간인가? | 4 |
| 9 | Decode가 느린데 비동기 코드로 해결되지 않는 이유는? | 4 |
부록 B. 자주 하는 실수
| 실수 | 바로잡기 |
|---|---|
| "추론 성능 = 모델이 얼마나 똑똑한가" | ❌ 이 과정의 추론은 Inference(실행) . 빠르고 가벼운가의 문제 |
| "8B의 파라미터와 Temperature는 같은 파라미터" | ❌ 하나는 학습이 정한 가중치 , 하나는 사람이 정하는 실행 설정 |
| "KV 캐시 = 응답을 저장해 두는 캐시" | ❌ 앞 토큰의 Key · Value 계산 결과 를 저장 |
| "임베딩 = 글자를 숫자로 바꾸는 것" | ⚠️ 그건 인코딩입니다. 임베딩은 거리에 뜻이 있습니다 |
| "컨텍스트 길이 = 모델 카드의 최대치" | ⚠️ 실제로는 엔진에서 설정한 값 이 적용됨 |
| "첫 응답이 늦은 것과 생성이 느린 것은 같은 문제" | ❌ Prefill ↔ Decode, 해결책이 다름 |
| "글자 수로 비용과 용량을 계산" | ❌ 기준은 토큰 수 |
부록 C. NotebookLM 복습 프롬프트
이 2차시 노트만 근거로 6문제를 내줘. 비전공자 기준으로.
"추론·토큰·파라미터의 번역어 함정", "Q·K·V와 KV 캐시", "Prefill과 Decode"는 반드시 포함해줘.
답은 내가 답한 다음에 채점하고, 틀린 이유를 노트의 절 번호를 근거로 설명해줘.
LangTailor