LLM 내부 동작 원리 — 백엔드 개발자를 위한 6단계 해설
"ChatGPT가 왜 이런 답을 냈지?"라는 질문을 한 번쯤 해봤을 거다. 프롬프트 엔지니어링 팁을 외우기 전에, LLM이 내부에서 어떻게 동작하는지 알면 그 이유가 보인다.
카카오페이 백엔드 개발자가 정리한 LLM 동작 원리 6단계를 함께 따라가본다. 신경망 지식이 없어도 이해할 수 있게 비유 위주로 풀어본다.
왜 알아야 하나
LLM을 "그냥 API 호출하는 블랙박스"로 쓰는 것과 내부를 이해하고 쓰는 건 결과가 다르다. Temperature를 왜 낮춰야 일관된 답이 나오는지, 왜 컨텍스트가 길면 앞 내용을 잊는 느낌인지, 왜 프롬프트에 예시를 넣으면 답이 달라지는지 — 이 모든 게 6단계 구조에서 설명된다.
1단계: Tokenization — 문장을 조각으로
가장 먼저 하는 일은 입력 텍스트를 토큰으로 쪼개는 것이다. 토큰은 단어일 수도, 단어 조각일 수도, 심지어 문자 하나일 수도 있다.
"인공지능"이라는 단어를 모르는 토크나이저는 "인공"과 "지능"으로 나눈다. 각 토큰은 정수 ID에 매핑된다.
입력: "Claude는 정말 똑똑하다"
토큰: ["Cl", "aud", "e", "는", "정말", "똑똑", "하다"]
ID: [3820, 1294, 68, 42891, 34291, 98472, 23841]BPE(Byte-Pair Encoding) 알고리즘이 가장 많이 쓰인다. "자주 함께 등장하는 문자 쌍을 하나로 합친다"는 단순한 원리인데, 학습 데이터 전체를 통계적으로 분석해서 최적의 어휘 사전을 만든다.
[💡 잠깐! 이 용어는?] BPE(Byte-Pair Encoding): 텍스트를 압축하는 알고리즘을 LLM 토크나이징에 적용한 것. 자주 등장하는 문자 쌍을 하나의 심볼로 합쳐나가면서 어휘 사전을 구성한다.
토크나이징은 학습 때 한 번 설계되고, 추론 때는 그 사전을 메모리에 로드해서 즉시 쓴다. "왜 영어보다 한국어가 더 많은 토큰을 쓰는가"가 여기서 결정된다 — 한국어는 학습 데이터에서 비율이 낮으니 토큰당 커버하는 문자 수가 적다.
2단계: Embedding — 숫자에 의미를 싣기
정수 ID는 컴퓨터가 계산하기 좋은 형태지만 의미가 없다. "자동차"가 ID 5000이고 "자전거"가 ID 5001이라고 해서 둘이 비슷하다는 뜻이 아니다.
임베딩은 각 토큰을 고차원 벡터로 변환한다. 실제로 768차원, 1024차원, 4096차원짜리 숫자 배열이다. 이 벡터 공간에서 비슷한 의미를 가진 단어들은 가까운 위치에 배치된다.
비유하면 서울 지도에서 "강남역"과 "선릉역"이 물리적으로 가깝듯이, 임베딩 공간에서 "자동차"와 "자전거"는 가까이 있고 "사랑"과는 멀리 있다.
"자동차" → [0.8, 0.2] (탈것, 엔진)
"자전거" → [0.7, 0.1] (탈것, 비엔진) ← 가까움
"행복" → [-0.3, 0.9] (감정) ← 멀리 있음실제 임베딩 값은 학습 과정에서 자동으로 결정된다. 개발자가 의미를 직접 넣는 게 아니라, 수십억 개의 텍스트를 학습하면서 모델이 스스로 의미 공간을 만든다.
3단계: Positional Encoding — 순서를 기억하기
임베딩만 있으면 "고양이가 강아지를 물었다"와 "강아지가 고양이를 물었다"가 같아 보인다. 같은 토큰들이 순서만 다른데, 어텐션 메커니즘은 기본적으로 순서를 모른다.
위치 인코딩이 각 위치에 고유한 벡터를 더해준다. sin/cos 함수를 이용해서 위치마다 다른 패턴을 만든다.
"고양이가 소파 위에서 잠을 잡니다"
"고양이" 의미벡터 + 0번_위치벡터 = 최종_입력벡터_0
"소파" 의미벡터 + 2번_위치벡터 = 최종_입력벡터_2
"잠을" 의미벡터 + 4번_위치벡터 = 최종_입력벡터_4이렇게 하면 같은 단어라도 위치에 따라 다른 벡터가 되어, 모델이 문장 구조를 파악할 수 있다.
4단계: Transformer & Attention — 관계를 계산하기
LLM의 핵심 엔진이다. 트랜스포머는 문장 속 단어들 사이의 관계를 계산한다.
"나는 사과를 먹었다"에서 "먹었다"는 "나는"(주어)과 "사과를"(목적어)에 강하게 연결된다. 어텐션(Attention)은 이 연결 강도를 수치로 계산하는 메커니즘이다.
"먹었다"가 다른 단어에 주는 가중치:
"나는" → 0.6 (주어 관계)
"사과를" → 0.7 (목적어 관계)
"그" → 0.1 (약한 관계)Multi-Head Self-Attention이라는 표현이 자주 나오는데, 쉽게 말하면 여러 "관점"에서 동시에 관계를 분석하는 것이다. 어떤 헤드는 문법적 관계를, 다른 헤드는 의미적 관계를 본다.
[💡 잠깐! 이 용어는?] Self-Attention: 입력 시퀀스 내에서 각 위치가 다른 위치들에 얼마나 "집중"해야 하는지를 계산하는 메커니즘. 멀리 떨어진 단어 간 관계도 거리에 관계없이 직접 연결된다.
트랜스포머 레이어는 수십 개에서 수백 개가 쌓인다. GPT-4는 레이어 수가 공개되지 않았지만, 레이어가 깊을수록 추상적인 의미를 포착할 수 있다고 알려져 있다.
5단계: Prediction — 다음 토큰 고르기
트랜스포머를 거치면 각 위치의 벡터가 변환된다. 이걸 선형 레이어에 통과시키면 어휘 사전의 모든 토큰에 대한 **점수(Logit)**가 나온다. Softmax를 적용하면 확률 분포가 된다.
"나는 커피를 ___"까지 왔을 때:
- "마셨다" → 0.42
- "좋아한다" → 0.31
- "마신다" → 0.18
- "먹었다" → 0.05
- 나머지 → ...
여기서 어떤 토큰을 고르느냐가 Temperature, Top-K, Top-P 설정으로 조절된다.
Greedy: 항상 가장 높은 확률 선택 → 반복적, 지루함
Top-K: 상위 K개 중 확률로 선택 → K=50이면 50개 후보
Top-P: 누적 확률 P까지 선택 → P=0.9면 합이 90%가 될 때까지
Temperature: 분포의 뾰족함 조절 → 높을수록 창의적, 낮을수록 보수적Temperature를 낮추면(0.10.3) 항상 비슷한 답이 나오고, 높이면(1.02.0) 예상 밖의 창의적인 답이 나온다. 코드 생성에는 낮은 Temperature, 창작에는 높은 Temperature가 적합한 이유다.
6단계: Loop & Decoding — 반복 생성
LLM은 한 번에 전체 답변을 내놓지 않는다. 한 토큰씩 반복해서 생성한다.
입력: "파이썬으로 Hello World를 출력하는 코드는?"
1턴: → "print" 생성, 입력에 추가
2턴: → "(" 생성
3턴: → "'Hello" 생성
4턴: → " World" 생성
5턴: → "')" 생성
6턴: → [EOS] 생성 → 종료EOS(End of Sentence) 토큰이 나오거나 최대 길이에 도달하면 멈춘다. 최종 정수 ID 배열을 디코딩해서 사람이 읽을 수 있는 텍스트로 변환하는 게 마지막 단계다.
이 반복 구조 때문에 스트리밍이 가능하다. 토큰이 생성될 때마다 바로 출력하면 ChatGPT처럼 글자가 흘러나오는 효과가 된다.
원리를 알면 프롬프트가 달라진다
6단계를 이해하면 효과적인 프롬프트 작성법이 보인다.
구체적인 컨텍스트 — 어텐션이 관련 정보에 더 집중할 수 있다.
❌ "에러가 나"
✅ "Spring Boot 3.1.5에서 JPA Repository save() 호출 시
NullPointerException이 발생. 스택 트레이스: [로그]"예시 제시(Few-shot) — Prediction 단계에서 원하는 패턴을 강하게 유도한다.
입력: "오류: 404"
출력: { "error": "NOT_FOUND", "message": "리소스를 찾을 수 없음" }
입력: "오류: 401"
출력:역할 부여 — "당신은 10년 차 백엔드 개발자다"는 어떤 단어 범위에서 다음 토큰을 고를지 좁혀준다. 전문적인 어휘가 더 높은 확률을 갖게 된다.
단계적 분해 — 큰 작업을 여러 프롬프트로 나누면 각 루프에서 더 정확한 토큰을 고른다. 컨텍스트 윈도우 제한도 피할 수 있다.
마무리
LLM은 텍스트를 토큰 → 벡터 → 위치 → 관계 → 확률 → 반복 순서로 처리한다. 이 파이프라인을 이해하면 LLM이 왜 이런 답을 냈는지, 어떻게 하면 더 나은 답을 유도할 수 있는지 직관이 생긴다.
- 긴 입력이 품질에 영향을 준다 → 어텐션의 컨텍스트 윈도우 한계 때문
- 같은 질문에 매번 다른 답이 나온다 → Temperature + 샘플링 때문
- 예시를 넣으면 답이 달라진다 → Few-shot이 확률 분포를 조정하기 때문
LLM은 "마법 같은 AI"가 아니라 수학적으로 설명 가능한 프로그래밍 가능한 언어 인터페이스다.
참고:
- 카카오페이 기술 블로그: https://tech.kakaopay.com/post/how-llm-works/
관심 있을 만한 포스트
AI 에이전트 프롬프트 캐싱 — 응답 속도를 높이는 공짜 최적화
AI 에이전트에서 시스템 프롬프트와 도구 정의를 캐싱해 응답 속도를 높이는 프롬프트 캐싱의 동작 원리와 설정 방법을 정리한다.
카카오페이 MCP Agent Toolkit — AI 에이전트로 결제 API 연동하기
카카오페이 개발팀이 MCP 표준으로 결제 Open API를 AI 에이전트에 연결한 방법과 실제 코드 구조를 살펴본다.
Nuxt MCP Server — AI가 내 앱 문서를 직접 읽게 만들기
Nuxt가 공개한 MCP 서버 구축 방법과 @nuxtjs/mcp-toolkit으로 Resource, Tool, Prompt를 정의하는 실전 패턴을 정리한다.
뱅크샐러드의 LLM 코드 안전화 — DSL로 Vibe Coding을 프로덕션에 쓰는 법
LLM이 생성한 코드를 프로덕션에서 안전하게 실행하기 위해 뱅크샐러드가 선택한 DSL 기반 전략을 해부한다.
Context Engineering — 에이전트 품질을 결정하는 진짜 레버
프롬프트 엔지니어링을 넘어선 컨텍스트 엔지니어링의 4가지 구성요소와 실전 패턴을 정리한다.
Cloudflare AI 코드 리뷰 — 48,000건 MR을 AI로 검토한 실전 아키텍처
Cloudflare가 48,095건의 머지 요청에 AI 코드 리뷰를 적용한 방식과 리스크 티어, 조정자 패턴, 프롬프트 주입 방지 구현을 분석한다.
Cloudflare 내부 AI 스택 — 93% 개발자 채택률을 만든 방법
Cloudflare가 자사 제품으로 내부 AI 엔지니어링 인프라를 구축하고 R&D 93%를 1년 안에 채택시킨 아키텍처와 운영 전략을 분석한다.
에이전틱 워크플로우의 멘탈 프레임워크 — AI에게 일을 맡기는 사고 체계
AI 에이전트에게 작업을 위임할 때 필요한 5단계 사고 모델을 정리한다.