1. 임베딩과의 관계
임베딩은 숫자로 끝나고, LLM은 다음 단어를 계속 만들어낸다.
- 임베딩은 "텍스트→벡터" 변환만 하고 끝남
- LLM은 같은 트랜스포머 계열 구조를 쓰지만 벡터에서 다시 텍스트를 생성한다.
- 둘 다 "문맥을 이해한다"는 점은 같은데, 출력 형태가 다른 것.
[ML] 벡터 임베딩(Vector Embedding) - 의미를 벡터로
cf) TF-IDF [ML] TF-IDF(Term Frequency-Inverse Document Frequency)1. TF-IDF?정의단어의 빈도(TF)와 역문서빈도(IDF)를 곱해서, 문서 내 각 단어의 "중요도"를 가중치로 매기는 방법단순히 "몇 번 나왔는가"만 세는 빈
blog.chaenii.me
2. 트랜스포머
트랜스포머의 핵심은 어텐션(attention) 메커니즘이다.
깊은 구조까지 알 필요는 없고, 풀고자 한 문제만 이해하면 충분하다.
이전 모델의 한계
- 문장을 한 단어씩 순서대로 읽으면서 "기억"을 누적하는 방식
- 문장이 길어지면 앞부분의 정보가 점점 희석되는 문제가 있었다
트랜스포머의 해법 - 전체를 한 번에
문장 전체를 동시에 보면서, 각 단어가 다른 모든 단어와 얼마나 "관련 있는지"를 직접 계산한다 (어텐션 스코어)
e.g) "그것은 책상 위에 있었다. 강아지가 그것을 물어뜯었다"에서 "그것"이 무엇을 가리키는지, 문장 전체를 동시에 보면서 가중치를 매겨 판단한다
어텐션 수식 (구조만 보면 충분)
각 단어는 세 가지 벡터로 변환된다:
| 벡터 | 역할 | 비유 |
| Query ($Q$) | "나는 무엇과 관련 있는가?" 를 묻는다 | 검색 키워드 |
| Key ($K$) | "나는 어떤 내용을 담고 있는가?" 를 알린다 | 책의 목차·태그 |
| Value ($V$) | 실제로 전달할 정보 | 책의 본문 |
계산 순서:
- 한 단어의 $Q$와 다른 모든 단어의 $K$를 내적 → 관련도 점수
- 소프트맥스로 정규화 → 가중치 (전체 합 = 1)
- 그 가중치로 $V$들을 가중평균 → 최종 출력
$$
\text{Attention}(Q,K,V) = \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right)V
$$
- $\sqrt{d_k}$로 나누는 건 벡터 차원이 커질수록 내적 값이 커져서 소프트맥스가 한쪽으로 쏠리는 걸 막기 위한 스케일 조정이다.
- 흥미로운 점: $QK^T$가 벡터 유사도에서 본 내적과 본질적으로 같은 연산이다.
- "이 단어와 저 단어가 얼마나 관련 있는가"를 코사인 유사도와 같은 방식(내적)으로 계산
- $\sqrt{d_k}$로 나누는 건 벡터 차원이 커질수록 내적 값이 커져서 softmax 출력이 한쪽으로 쏠리는 걸 막기 위한 스케일 조정이다.

- 문맥이 길어도 정보가 희석되지 않음
- 병렬 계산 가능: 순서대로 읽지 않아도 됨
- 학습 속도 증가
3. LLM 텍스트 생성 원리: 다음 토큰 예측
- LLM이 텍스트를 생성하는 원리 - 지금까지 나온 단어들을 보고, 다음에 올 단어(정확히는 토큰)가 무엇일지 확률로 예측하는 것:
$$
P(w_t \mid w_1, w_2, \ldots, w_{t-1})
$$
- 전체 어휘(e.g. 5만 개 토큰)에 대해 "다음 토큰이 이것일 확률" 전부 계산 → 확률분포 생성
- 그중 하나를 골라 출력
- 그 단어를 다시 입력에 추가 → 그다음 단어를 또 예측
- 반복 → 문장 완성
확률분포는 어떻게 만들어지는가: 소프트맥스(softmax):
- 신경망의 마지막 층은 어휘의 각 토큰마다 "점수"(logit)라는 임의의 실수를 출력한다.
- 소프트맥스가 이 점수들을 합이 1인 확률처럼 바꿔준다.
$$
P(w_i) = \frac{e^{z_i}}{\sum_j e^{z_j}}
$$
$z_i$는 토큰 $i$의 점수(logit).
지수함수를 쓰는 이유
- 항상 양수를 보장해서 확률처럼 다룰 수 있게 함
- 점수 차이를 "증폭"시켜서 점수가 높은 토큰일수록 확률이 비례 이상으로 더 커지게 함
- 점수가 약간만 높아도 확률은 훨씬 더 높아지는 식

4. Temperature: 확률분포에서 어떻게 뽑을 것인가
확률분포가 만들어진 다음, 실제로 어떤 토큰을 뽑을지를 결정하는 파라미터가 temperature다.
- temperature = 0: 항상 확률이 가장 높은 토큰을 그대로 선택(그리디 디코딩). 같은 입력엔 거의 항상 같은 출력
- temperature 높음(예: 1.0 이상): 확률이 낮은 토큰도 가끔 선택될 수 있게 함 — 같은 질문에도 매번 표현이나 결론이 조금씩 달라질 수 있음
temperature는 소프트맥스에 들어가기 전에 점수(logit) $z_i$를 $T$로 나누는 방식으로 구현된다:
$$
P(w_i) = \frac{e^{z_i/T}}{\sum_j e^{z_j/T}}
$$
- $T$가 작을수록(0에 가까울수록): 점수 차이가 나누기를 통해 더 크게 벌어져서 소프트맥스가 1등 토큰에 거의 모든 확률을 몰아줌(분포가 뾰족해짐)
- $T$가 클수록: 점수 차이가 줄어들어 여러 토큰에 확률이 고르게 퍼짐(분포가 평평해짐)
- $T=0$: 수학적으로는 나눗셈이 정의 안 되지만, 실제 구현에서는 "그냥 1등을 그대로 선택"하는 것으로 처리함

temperature=0이라고 해서 "신경망을 안 쓰고 룰베이스로 작동하는 것"이 아니다.
temperature=0이어도 모델은 여전히 입력 전체를 신경망으로 통과시켜 문맥을 이해하고 확률분포를 계산하는 무거운 연산을 그대로 한다.
temperature가 바꾸는 건 그 확률분포에서 마지막에 토큰 하나를 뽑는 방식뿐.
룰베이스는 신경망 연산이 전혀 없는 if-then 코드라서, temperature와 상관없이 LLM과는 완전히 다른 메커니즘이다.
법률·의료처럼 일관성이 중요한 도메인에서는 같은 질문에 항상 같은 답이 나오게 하기 위해 temperature를 0 또는 0에 가깝게(e.g. 0.1) 낮게 설정하는 게 일반적이다.
5. JSON 스키마: 출력 형식을 강제하기
LLM의 출력은 기본적으로 자유로운 텍스트다.
그런데 시스템에서 LLM의 답을 코드로 처리하려면 형식이 고정돼 있어야 한다.
그래서 프롬프트에 "이 JSON 스키마 형태로만 답하라"고 명시적으로 지시하고, 모델이 그 형식을 따르도록 유도한다.
모델이 형식을 어기고 설명을 덧붙이거나 마크다운 코드블록으로 감싸서 답하는 경우도 흔해서,
실전에서는 응답을 받은 뒤 그런 잡음을 제거하고 JSON 부분만 추출하는 파싱 로직을 따로 둔다.
파싱이 실패하면(JSON이 아니거나 필드가 빠졌으면) 이를 "신뢰할 수 없는 응답"으로 간주하고 별도 처리(재시도, 에스컬레이션, 폴백)를 하는 게 일반적이다.
6. 배치(batch)와 동시성(concurrency)
LLM API 호출은 비용과 시간이 든다.
항목 하나하나마다 호출하면 비효율적이라, 여러 항목을 한 번의 프롬프트에 묶어서(배치) 한 번의 호출로 처리하는 방식을 쓴다.
다만 배치가 너무 크면 모델의 응답 시간이 길어지고, 일부 추론(reasoning) 특화 모델은 처리시간이 오래 걸려 네트워크 타임아웃에 걸릴 수 있다.
그래서 배치 크기는 모델의 응답속도·타임아웃 제약을 보고 실전적으로 조정한다.
여러 배치를 처리해야 한다면, 순차적으로 하나씩 호출하는 대신 동시에 여러 개를 병렬로 호출(concurrency)해서 전체 처리시간을 줄인다.
다만 동시에 너무 많이 호출하면 API의 속도제한(rate limit)에 걸리므로, 동시 호출 개수에 상한을 두는 게 일반적이다.
7. 정리
- 트랜스포머는 어텐션으로 문장 전체를 한 번에 보며 단어 간 관련도를 계산 — RNN의 정보 희석 문제를 해결
- LLM은 "다음 토큰 확률분포"를 소프트맥스로 만들고, temperature로 그 분포에서 어떻게 뽑을지를 조절
- temperature=0이어도 신경망 연산(문맥 이해, 확률분포 계산)은 그대로 수행됨 — 룰베이스와는 본질적으로 다른 메커니즘
- 출력 형식을 강제(JSON 스키마)하고, 배치·동시성으로 비용·지연을 조절하는 게 실전 운영의 핵심
LLM은 학습된 지식(모델 학습 시점까지의 데이터)만 갖고 있다. 회사 내부 문서나 최신 정책처럼 모델이 모르는 정보를 답변에 반영하려면, 검색을 LLM 호출 앞에 끼워넣어야 한다. 그 설계 패턴이 RAG다.
GitHub 댓글