Prefill vs Decode
LLM은 먼저 사용자의 프롬프트를 읽고, 그다음 답변을 토큰 하나씩 이어 쓴다. 앞의 단계를 prefill, 뒤의 단계를 decode라고 부른다.
Two Steps
ChatGPT에 질문을 보내면 모델이 곧바로 답변을 쓰는 것처럼 보인다. 실제로는 먼저 질문 전체를 읽는다.
이 단계가 prefill이다. 사용자가 입력한 프롬프트를 한 번 훑고, 뒤에서 재사용할 중간 결과를 KV cache에 채워 넣는다.
그다음 모델은 답변을 한 조각씩 만든다. 한 번에 긴 문장을 통째로 쓰는 게 아니라, 다음에 올 토큰을 하나 고르고, 다시 그다음 토큰을 고른다. 이 반복이 decode다.
flowchart LR
subgraph Prefill["Prefill"]
P["프롬프트 전체를 읽음"]
end
subgraph Decode["Decode"]
D1["토큰 1개"] --> D2["토큰 1개"] --> D3["토큰 1개"] --> DN["..."]
end
Prefill --> Decode
비유하면 prefill은 시험 문제를 읽는 시간이고, decode는 답안을 한 줄씩 쓰는 시간이다.
Prefill
Prefill은 사용자가 보낸 입력을 처리하는 단계다. 프롬프트가 짧으면 금방 끝난다. 반대로 긴 문서, 긴 대화 기록, 많은 예시를 붙이면 이 단계가 오래 걸린다.
사용자가 체감하는 첫 지연은 대부분 여기서 나온다. 질문을 보낸 뒤 첫 글자가 나타나기까지 잠깐 멈춘 것처럼 보이는 시간이 prefill에 가깝다.
이 단계에서 KV cache도 만들어진다. 이후 decode 단계는 이 cache를 읽으면서 답변을 이어간다.
Decode
Decode는 답변을 실제로 쓰는 단계다. 첫 토큰이 나온 뒤부터 화면에 글자가 조금씩 흘러나오는 구간이다.
이때 모델은 매번 새 토큰 하나만 만든다. 하지만 새 토큰을 만들 때마다 지금까지의 문맥을 봐야 하므로 KV cache를 계속 읽는다.
그래서 decode는 답변 길이에 민감하다. 답변이 20토큰이면 20번 반복하고, 2,000토큰이면 2,000번 반복한다.
Speed Metrics
이 차이는 사용자가 느끼는 속도와도 연결된다.
TTFT(Time To First Token)는 질문을 보낸 뒤 첫 토큰이 나오기까지의 시간이다. 프롬프트를 읽는 prefill 시간이 크게 영향을 준다.
TPOT(Time Per Output Token)는 첫 토큰 이후 토큰 하나가 나올 때마다 걸리는 시간이다. 답변이 흘러나오는 속도에 가깝고, decode 성능에 좌우된다.
긴 문서를 붙여 넣고 짧은 답을 받는 경우:
TTFT가 길고, TPOT은 크게 문제되지 않을 수 있다.
짧게 질문했지만 긴 글을 생성하는 경우:
TTFT는 짧고, TPOT이 전체 시간을 좌우한다.
첫 반응이 느린 것과 답변이 천천히 이어지는 것은 다른 문제다. 그래서 LLM 서버도 둘을 다르게 본다.
Why It Slows Down
Prefill은 한 번에 많은 입력을 읽는다. GPU가 할 계산이 많다. 전문 용어로는 계산 쪽 병목이라고 부른다.
Decode는 토큰을 하나씩 만든다. 계산량은 작아 보이지만, 매번 모델 데이터와 KV cache를 읽어야 한다. 이때는 GPU 메모리를 얼마나 빨리 읽느냐가 중요해진다.
그래서 같은 모델, 같은 GPU를 써도 prefill과 decode의 성격이 다르다. 하나는 긴 입력을 빨리 읽는 문제이고, 다른 하나는 답변을 끊기지 않게 계속 이어 쓰는 문제다.
Batching
서비스에서는 여러 사용자의 요청이 동시에 들어온다. 이때 decode 단계에서는 여러 사용자의 “다음 토큰 하나”를 묶어서 처리할 수 있다.
한 명의 토큰 하나를 만들 때도 모델 데이터를 읽어야 한다. 여러 명의 토큰을 한꺼번에 만들면 같은 읽기 비용을 더 잘 활용할 수 있다.
vLLM의 continuous batching 같은 기법은 이 아이디어를 적극적으로 사용한다. 요청이 끝나면 빠지고, 새 요청이 오면 현재 처리 흐름에 합류시킨다.
세부 구현은 몰라도 된다. 핵심은 decode가 반복 작업이기 때문에, 여러 요청을 잘 섞으면 GPU를 더 효율적으로 쓸 수 있다는 점이다.
Summary
Prefill과 decode는 모두 LLM이 답변을 만드는 과정이지만, 느려지는 이유가 다르다.
프롬프트가 길면 첫 토큰이 늦게 나온다. 답변이 길면 토큰이 이어지는 시간이 길어진다. LLM 서버를 빠르게 만드는 일은 이 두 시간을 따로 줄이는 문제다.