1장. 과정 소개와 LLM 의 이해
토큰
가래떡을 떡국에 넣으려면 먼저 썰어야 합니다. 길게 붙은 떡을 그대로 넣지 않고, 한입 크기 조각으로 잘라 넣습니다. LLM 도 글을 그대로 먹지 못합니다. 글을 토큰이라는 조각으로 썰고, 조각마다 붙은 번호로 계산합니다.
윗줄은 우리가 쓴 문장이고, 가운데 줄은 토크나이저가 썬 토큰 조각입니다. 아랫줄 연파랑 칸의 숫자가 조각마다 붙은 번호로, 모델은 이 번호만 봅니다. 조각의 ␣ 는 띄어쓰기를 눈에 보이게 적은 것입니다. "제주도"는 '제', '주', '도' 세 조각으로, " 여행"은 앞의 띄어쓰기와 함께 한 조각으로 썰렸습니다. 실습 3에서 같은 문장을 직접 썰어 봅니다. 여기서 가래떡이 문장, 떡 조각이 토큰, 칼이 토크나이저입니다. 비유와 다른 점은, 떡은 같은 크기로 썰지만 토큰은 자주 쓰는 말일수록 크게, 드문 말일수록 잘게 썬다는 것입니다.
토큰이 중요한 까닭
| 무엇 | 토큰과의 관계 |
|---|---|
| 요금 | API 요금은 보낸 토큰과 받은 토큰의 수로 매깁니다. 택시 요금이 거리에 비례하듯 토큰 수에 비례합니다 |
| 길이 제한 | 모델마다 한 번에 읽는 토큰 수(컨텍스트 창)가 정해져 있습니다 |
| 속도 | 답의 토큰이 많을수록 다 쓰는 데 오래 걸립니다 |
| 언어 차이 | 같은 뜻이라도 언어마다 토큰 수가 다릅니다. 실습 3에서 견줘 봅니다 |
짧은 예시
tiktoken 으로 글을 토큰으로 썰어 봅니다. o200k_base 는 GPT-4o 계열 모델이 쓰는 토큰 사전의 이름입니다. 처음 한 번은 인터넷에서 사전 파일을 받아 오므로 인터넷이 연결되어 있어야 합니다.
import tiktoken
# get_encoding: 이름으로 토큰 사전을 불러온다
enc = tiktoken.get_encoding("o200k_base")
ids = enc.encode("안녕하세요") # encode = 글을 토큰 번호로 바꾼다
print(ids)
print([enc.decode([i]) for i in ids]) # decode = 번호를 다시 글로 바꾼다[14307, 171731]
['안', '녕하세요']"안녕하세요" 다섯 글자가 토큰 두 개로 썰렸습니다. 번호 14307 이 "안", 171731 이 "녕하세요"입니다. 모델은 이 두 번호를 받아 계산합니다.
코드가 의미하는 것
위 코드는 몇 줄 안 되지만, 챗봇에 글을 보낼 때 모델 앞에서 일어나는 일을 그대로 흉내 낸 것입니다. 떡국 비유로 보면 칼을 고르고(사전 불러오기), 떡을 썰고(encode), 썬 조각을 하나씩 들어 보는(decode) 세 동작입니다.
| 코드 | 하는 일 | 챗봇에서 뜻하는 것 |
|---|---|---|
tiktoken.get_encoding("o200k_base") | 토큰 사전(칼)을 고른다 | 모델마다 쓰는 사전이 정해져 있습니다. 같은 글도 사전이 다르면 썰리는 모양과 개수가 달라지므로, 요금을 어림할 때는 쓰는 모델의 사전을 골라야 합니다 |
enc.encode("안녕하세요") | 글을 토큰 번호 목록으로 바꾼다 | API 로 보낸 글이 모델 안으로 들어가기 전에 바뀌는 모습입니다. 모델이 실제로 받는 것은 글자가 아니라 이 번호 목록입니다 |
print(ids) 의 [14307, 171731] | 번호 목록을 보여 준다 | 목록의 길이가 곧 토큰 수입니다. 이 인사말은 토큰 2개로 세어지고, 요금과 길이 제한도 이 2를 기준으로 셉니다 |
[enc.decode([i]) for i in ids] | 번호를 하나씩 글로 되돌린다 | 칼자국이 어디에 났는지 보는 방법입니다. 조각이 글자 단위가 아니라 "안"과 "녕하세요"처럼 사전이 정한 덩어리라는 것을 눈으로 확인합니다 |
결과에서 읽을 것은 세 가지입니다.
- 글자 수와 토큰 수는 다릅니다. 다섯 글자가 두 토큰이 됐습니다. 글이 길면 대체로 토큰도 늘지만, 글자 수에 딱 맞춰 늘지는 않습니다. 그래서 요금이나 길이 제한을 따질 때는 글자 수가 아니라
encode한 목록의 길이를 셉니다. 실습 3은 이 길이를len(ids)로 세어 글자 수와 견줍니다. - 번호 자체에는 뜻이 없습니다. 14307 이나 171731 은 사전 속 자리 번호일 뿐입니다. 도서관 책등의 청구 번호가 책 내용을 말해 주지 않는 것처럼, 번호가 크다고 중요한 말이거나 드문 말이라는 뜻은 아닙니다. 모델은 이 번호들이 어떤 차례로 나오는지를 배워서 다음 토큰을 맞힙니다.
- 조각의 경계는 사전이 정합니다. "녕하세요"가 한 덩어리가 된 것은 이 사전이 그 묶음을 하나의 조각으로 가지고 있기 때문입니다. 사람이 나누는 낱말이나 글자 경계와 다르므로, 모델은 글자 하나하나를 따로 보지 않습니다. LLM 이 글자 수 세기나 거꾸로 쓰기처럼 글자 단위의 일에서 가끔 틀리는 까닭 가운데 하나입니다.
주의할 점
- 토큰 수는 토큰 사전마다 다릅니다. 다른 회사의 모델이나 옛 모델은 같은 글을 다른 개수로 썹니다. 요금을 어림할 때는 쓰는 모델의 사전으로 셉니다.
- 실제 API 는 메시지마다 역할 표시 같은 토큰을 몇 개씩 더 붙입니다. tiktoken 으로 센 수는 어림값으로 봅니다.