Skip to main content

Command Palette

Search for a command to run...

LLM은 어떻게 글을 읽고 쓰는가 — 입력부터 출력까지

Updated
4 min read

대화형 AI에게 질문을 던지면, 마치 사람처럼 문장을 이해하고 답을 써 내려가는 것처럼 보인다.
하지만 그 안에서 벌어지는 일은 생각보다 단순하고, 또 생각보다 기계적이다.
이 글에서는 두 가지 질문에 답해 본다.
LLM은 어떻게 글을 만들어내는가,
그리고 우리가 입력한 프롬프트는 모델에 어떤 모습으로 들어가는가.


1부. LLM은 어떻게 글을 만들어내는가

핵심은 "다음 토큰 맞히기"

먼저 결론부터. LLM이 하는 일의 본질은 "지금까지의 맥락 다음에 올 단어 조각을 확률적으로 예측하는 것" 하나다. 거대한 통계 모델이 "이 문맥 다음에는 이 조각이 올 가능성이 높다"는 패턴을 방대한 텍스트로부터 익혔고, 그 패턴을 매 순간 적용할 뿐이다. 우리가 보기엔 사고하고 작문하는 것 같지만, 내부적으로는 "다음 조각 예측 → 선택 → 반복"을 빠르게 수행하고 있다.

이 과정을 단계별로 풀어 보자.

토큰화: 문장을 조각내기

모델은 글자를 직접 다루지 않는다. 입력 문장은 먼저 **토큰(token)**이라는 작은 조각으로 쪼개진다. 토큰은 하나의 단어일 수도 있고, 단어의 일부일 수도 있다. 예를 들어 영어의 " the"는 공백을 포함해 한 토큰이 되기도 하고, 한국어 한 글자가 두세 토큰으로 나뉘기도 한다. 토큰과 글자는 1:1이 아니라는 점만 기억하면 된다.

임베딩: 숫자로 바꾸기

쪼갠 토큰은 곧바로 숫자 벡터로 변환된다. 컴퓨터는 글자를 직접 계산하지 못하므로, 각 토큰을 수백~수천 차원의 숫자 배열로 바꾼다. 이 벡터에는 토큰의 의미와 문맥적 성격이 담긴다. 비슷한 의미의 토큰은 비슷한 벡터로 표현되는 식이다.

어텐션: 문맥을 읽기

여기가 핵심이다. 어텐션(attention) 메커니즘은 각 토큰이 문장 안의 다른 모든 토큰과 얼마나 관련 있는지를 계산한다. "그 사과는 빨갛다"라는 문장에서 "빨갛다"가 "사과"와 강하게 연결되는 것을 모델이 스스로 알아내는 식이다. 이 계산을 수십 개의 층(layer)에 걸쳐 반복하면서, 모델은 점점 더 풍부한 문맥 표현을 쌓아 올린다.

확률 분포, 그리고 선택

마지막 층을 지나면 모델은 어휘집에 있는 모든 토큰에 대해 "이게 다음에 올 확률"을 계산한다. 예를 들어 "하늘은 ___" 다음에는 "파랗다 80%, 맑다 10%, 높다 5%…" 같은 확률 분포가 나온다.

그다음 이 분포에서 실제 토큰 하나를 **샘플링(sampling)**으로 고른다. 항상 1등만 고르는 게 아니라 약간의 무작위성(temperature 같은 설정으로 조절된다)을 주어, 자연스럽고 다양한 문장이 나오게 한다.

자기회귀: 한 글자씩 쌓기

고른 토큰을 입력의 끝에 다시 붙이고, 위 과정을 처음부터 되풀이한다. "파랗다"를 골랐다면 입력은 "하늘은 파랗다"가 되고, 다시 모델에 넣어 그다음 토큰을 예측한다. 이렇게 한 토큰씩 차례로 문장을 완성해 가는 방식을 자기회귀(autoregressive)라고 부른다. LLM이 답을 또박또박 흘려 쓰듯 출력하는 모습은, 바로 이 한 토큰씩 생성하는 과정이 화면에 비치는 것이다.


2부. 프롬프트는 어떻게 모델에 들어가는가

출력의 원리를 봤으니, 이번엔 반대편이다. 우리가 입력하는 다양한 종류의 프롬프트는 모델에 어떤 모습으로 들어갈까. 핵심을 먼저 말하면, "여러 종류"라는 건 사람이 보기에 그런 것이고, 모델 입장에서는 결국 하나의 토큰 시퀀스로 합쳐져서 들어간다.

역할(role)이라는 개념

대화형 AI의 입력은 보통 "역할"이 붙은 메시지들로 구성된다.

  • 시스템(system): 모델의 역할, 성격, 지켜야 할 규칙을 지정한다. 보통 맨 앞에 한 번 들어가고, 사용자에게는 보이지 않는 경우가 많다.

  • 사용자(user): 실제로 사람이 입력하는 질문이나 요청.

  • 어시스턴트(assistant): 모델이 이전에 했던 답변. 대화가 이어질 때 맥락을 유지하기 위해 다시 포함된다.

채팅 템플릿과 특수 토큰

이 역할별 메시지들은 모델에 들어가기 직전에 **채팅 템플릿(chat template)**을 거쳐 하나로 합쳐진다. 각 메시지의 경계에는 <|system|>, <|user|>, <|assistant|> 같은 **특수 토큰(special token)**이 붙어서, 모델이 "여기부터 시스템 지시, 여기부터 사용자 질문"이라고 구분할 수 있게 한다.

그 결과물은 색으로 구분되던 메시지들이 특수 토큰을 경계로 한 줄로 이어진, 평평한 토큰 시퀀스다. 모델이 실제로 "보는" 것은 바로 이 한 줄이다. 그리고 이 시퀀스가 1부에서 설명한 생성 과정의 입력이 된다.

모델은 기억이 없다

여기서 자주 오해하는 부분이 있다. 모델 자체에는 대화를 기억하는 기능이 없다. 무상태(stateless) 구조다. 그래서 멀티턴 대화에서는 매 턴마다 지금까지의 시스템·사용자·어시스턴트 메시지 전체를 다시 합쳐서 입력한다. 대화가 길어질수록 입력 토큰이 계속 늘어나는 이유가 바로 이것이다. "AI가 앞 대화를 기억한다"기보다는, 매번 전체 대화록을 다시 읽혀 주는 셈이다.

다양한 입력도 결국 한 줄

형태가 다양해 보이는 다른 입력들도 결국 같은 시퀀스에 섞여 들어간다.

  • 퓨샷 예시(few-shot): "이렇게 입력하면 이렇게 답해라"는 예시 몇 개를 시스템이나 사용자 메시지 안에 넣는다.

  • 검색·문서 맥락(RAG): 외부에서 찾아온 문서를 사용자 메시지 앞에 붙여 함께 넣는다.

  • 도구·함수 정의: 모델이 쓸 수 있는 도구 명세도 보통 시스템 영역에 토큰으로 들어간다.

  • 첨부 파일·이미지: 텍스트는 토큰으로, 이미지는 별도 인코딩을 거친 뒤 같은 시퀀스에 합류한다.

즉 입력의 본질은 단 하나다. "특수 토큰으로 구획된, 하나의 긴 토큰 열을 만들어 모델에 넣는 것."


맺으며

두 편의 이야기는 사실 하나로 이어진다. 우리가 입력한 프롬프트는 역할 토큰으로 구분된 하나의 토큰 시퀀스로 합쳐지고, 모델은 그 시퀀스를 받아 다음 토큰을 한 개씩 예측하며 답을 써 내려간다. 입력도 출력도, 결국은 토큰이라는 같은 언어로 흐른다.

LLM이 신비롭게 느껴지는 건, 이 단순한 "다음 토큰 예측"이 충분히 큰 규모에서 반복될 때 놀라울 만큼 그럴듯한 결과를 내놓기 때문이다. 다음 글에서는 한 발 더 안쪽으로 들어가, 이 토큰들의 정체와 생성 속도를 결정하는 요인을 살펴본다.


작성 참고

이 글은 Claude의 도움을 받아 내용을 정리하였습니다.

More from this blog

useEffect 지옥이란 무엇이며, 어떻게 안전하게 사용하는가

React를 어느 정도 사용하다 보면 한 번쯤은“useEffect 지옥에 빠졌다”는 말을 듣거나 직접 느껴본 적이 있을 것이다. useEffect가 계속 늘어나고 의존성 배열은 점점 길어지고 왜 실행되는지 이해하기 어려워지며 eslint-disable-next-line 이 늘어나는 상태 하지만 많은 사람들이 오해한다.useEffect 지옥은 useEffect가 많아서 생기는 문제가 아니다. 이 글에서는 ‘useEffect 지옥’의 ...

Jan 12, 20263 min read

Zod란 무엇인가: TypeScript에서 런타임 검증과 타입 안정성을 동시에 해결하는 방법

TypeScript 프로젝트를 하다 보면 반드시 마주치는 문제가 있다.바로 “타입은 있는데, 데이터는 믿을 수 없다”는 것이다. TypeScript는 컴파일 타임에는 강력하지만,런타임에 들어오는 데이터에 대해서는 아무런 보장을 해주지 않는다. API 요청 데이터 사용자 입력(Form) 환경 변수 (process.env) 외부 JSON / 설정 파일 이 모든 것은 타입 시스템 바깥에서 들어온다. 이 문제를 해결하기 위해 등장한 라이브러...

Jan 10, 20263 min read

Flatpak을 이해하기 위한 배경 지식

배포판, 라이브러리 충돌, 그리고 OSTree까지 리눅스 데스크톱에서 Flatpak이 표준처럼 자리 잡은 데에는 분명한 이유가 있다.그 이유를 이해하려면 단순히 “Flatpak은 패키징 시스템이다”를 넘어서,리눅스 배포판 구조, 라이브러리 버전 충돌, OSTree라는 기술까지 함께 이해해야 한다. 이 글에서는 다음 질문에 답해본다. 리눅스에서 말하는 배포판이란 무엇인가? 라이브러리 버전 충돌은 왜 발생하는가? Flatpak은 이 문제를 어...

Jan 8, 20265 min read

npm SemVer 실무 가이드

이 글은 npm의 Semantic Versioning(SemVer) 을 처음 접하는 개발자부터, 실무에서 이미 사용하고 있지만 헷갈리는 포인트가 많은 개발자까지를 대상으로 한다. 단순한 규칙 나열이 아니라, 실제 업무에서 어떻게 쓰이고, 어디서 사고가 나며, 어떤 관습이 굳어졌는지를 중심으로 정리했다. 1. SemVer란 무엇인가? SemVer(Semantic Versioning)는 버전 번호에 의미를 부여하는 규칙이다. 기본 형식은 다음과 ...

Jan 7, 20263 min read

Dev note

31 posts