AWS AI Practitioner 시험 노트개념 정리17 MIN
토큰·청킹·임베딩·벡터의 관계
생성형 AI 기초 도메인의 첫 편입니다. 토큰이 과금과 한도의 단위가 되는 방식, 문서를 청크로 자르는 기준, 청크가 임베딩 벡터가 되어 유사도로 찾히는 흐름을 계산과 함께 정리합니다.
도메인 2(생성형 AI의 기초)는 낱말 넷에서 시작합니다. 토큰·청크·임베딩·벡터는 따로 외우면 네 가지 용어지만, 실제로는 한 문서가 모델에 들어가기까지 거치는 차례입니다. 모델은 글자를 그대로 읽지 못하므로 글을 토큰으로 쪼개 읽고, 검색에 쓸 문서는 먼저 청크로 자른 뒤 청크마다 임베딩 모델을 거쳐 숫자 목록인 벡터가 됩니다. 시험은 이 차례에서 한 칸을 비워 두고 「여기에 들어갈 것은?」을 묻거나, 토큰 수로 비용을 계산하게 합니다.
토큰
토큰화
토큰은 모델이 한 번에 읽고 쓰는 글의 조각입니다. 단어 하나일 수도 있고, 단어의 일부나 문장부호 하나일 수도 있습니다. 글을 토큰으로 쪼개는 일을 토큰화라 하고, 그 규칙을 가진 도구를 토크나이저라 부릅니다. 토크나이저는 모델마다 다르므로 같은 문장도 모델에 따라 토큰 수가 달라집니다. 시험에서 「한 단어는 한 토큰이다」라는 보기가 나오면 오답입니다.
모델이 읽는 쪽(입력)과 쓰는 쪽(출력)이 모두 토큰으로 세어집니다. 생성 모델은 출력을 한 번에 내놓지 않고 다음 토큰 하나를 고르는 일을 되풀이해 문장을 만듭니다. 그래서 답이 길수록 시간이 오래 걸리고, 응답 길이를 자르는 설정도 글자가 아니라 최대 토큰 수로 적습니다.
컨텍스트 윈도우
컨텍스트 윈도우는 모델이 한 번의 호출에서 입력과 출력을 합쳐 다룰 수 있는 토큰의 최대치입니다. 문서를 통째로 넣고 싶어도 이 한도를 넘으면 들어가지 않습니다. 긴 문서를 잘라야 하는 첫 번째 이유가 여기 있고, 그 자르는 일이 다음 절의 청킹입니다.
토큰 단위 과금
Amazon Bedrock의 온디맨드 방식은 입력 토큰과 출력 토큰을 따로 세어 각각의 단가를 곱합니다. 출력 단가가 입력보다 높게 매겨지는 것이 보통이라 같은 토큰 수라도 어느 쪽이냐에 따라 값이 달라집니다.
가정한 단가로 한 번 계산해 봅시다. 입력 1,000토큰당 0.001달러, 출력 1,000토큰당 0.004달러이고 한 요청에 입력 1,500토큰, 출력 500토큰이 쓰였다면 다음과 같습니다.
요청 한 건에 0.0035달러이고, 하루 1만 건이면 35달러입니다. 비용을 줄이는 문항의 정답이 대개 「프롬프트를 짧게」·「출력 최대 토큰을 제한」·「필요한 청크만 넣기」인 이유가 이 식입니다. 실제로 쓴 토큰 수는 응답에 함께 돌아오므로 추정하지 않고 셀 수 있습니다.
import boto3
client = boto3.client("bedrock-runtime", region_name="us-east-1")
MODEL_ID = "amazon.nova-lite-v1:0" # 리전에 따라 추론 프로파일 ID를 써야 할 수 있다
resp = client.converse(
modelId=MODEL_ID,
messages=[{"role": "user", "content": [{"text": "반품 규정을 세 줄로 요약해 줘"}]}],
inferenceConfig={"maxTokens": 300},
)
usage = resp["usage"]
print(usage["inputTokens"], usage["outputTokens"], usage["totalTokens"])
청킹
청크 크기
청킹(chunking)은 긴 문서를 검색과 임베딩에 알맞은 크기의 조각, 곧 청크로 자르는 일입니다. 청크가 너무 크면 한 조각 안에 여러 주제가 섞여 질문과 정확히 맞는 부분을 가려내지 못하고, 검색된 청크를 프롬프트에 넣을 때 토큰도 많이 씁니다. 너무 작으면 문장이 앞뒤 맥락을 잃어 무슨 말인지 모르는 조각이 됩니다. 정답이 하나로 정해진 값이 아니라 문서의 성격과 질문의 모양을 보고 고르는 값입니다.
겹침
청크 경계가 문장 한가운데를 자르면 그 문장의 뜻이 두 조각으로 갈립니다. 그래서 이웃한 청크가 일부를 겹쳐 갖게 합니다. 겹침이 있으면 청크 수가 늘어나고, 그만큼 임베딩할 토큰도 늘어납니다.
10,000토큰짜리 문서를 500토큰 청크로, 20%(100토큰)를 겹쳐 자르면 청크의 시작점은 400토큰씩 나아갑니다. 청크 수는 이렇게 셉니다.
임베딩 모델에 보내는 토큰은 25 × 500 = 12,500으로, 원문보다 25% 많습니다. 겹침 없이 자르면 20개 청크에 10,000토큰입니다.
Knowledge Bases의 청킹 전략
Amazon Bedrock Knowledge Bases는 데이터 소스를 연결할 때 청킹 방식을 고르게 합니다.
| 전략 | 자르는 기준 |
|---|---|
| 고정 크기 | 정한 토큰 수와 겹침 비율 |
| 계층적 | 큰 부모 청크 안에 작은 자식 청크를 두고, 자식으로 찾아 부모를 돌려준다 |
| 의미 기반 | 문장 사이의 뜻이 크게 바뀌는 자리 |
| 청킹 없음 | 파일 하나를 한 청크로 둔다. 이미 잘게 나눠 둔 문서에 쓴다 |
「문서가 이미 FAQ 한 문항씩 파일로 나뉘어 있다」면 청킹 없음, 「찾을 때는 좁게, 모델에 줄 때는 넓게」라는 요구면 계층적입니다.
임베딩과 벡터
임베딩 모델
임베딩은 글·이미지 같은 입력을 그 뜻을 담은 숫자 목록으로 바꾸는 일이고, 그 결과인 숫자 목록이 벡터입니다. 둘은 과정과 산출물의 관계입니다 — 임베딩 모델이 청크를 받아 벡터를 내놓습니다. 뜻이 비슷한 입력은 비슷한 벡터가 되도록 학습되어 있으므로, 벡터끼리의 거리를 재면 글자가 달라도 뜻이 가까운 문장을 찾을 수 있습니다. 키워드 검색이 「환불」로 「반품」을 못 찾는 자리를 임베딩 검색이 메웁니다.
Bedrock에서는 Amazon Titan Text Embeddings V2 같은 임베딩 모델을 생성 모델과 같은 방식으로 부릅니다.
import json
import boto3
client = boto3.client("bedrock-runtime", region_name="us-east-1")
body = {"inputText": "구매 후 14일 안에 반품할 수 있습니다", "dimensions": 256, "normalize": True}
resp = client.invoke_model(modelId="amazon.titan-embed-text-v2:0", body=json.dumps(body))
out = json.loads(resp["body"].read())
vector = out["embedding"]
print(len(vector), out["inputTextTokenCount"]) # 256, 입력 토큰 수
임베딩 모델도 입력 토큰으로 과금되므로, 앞 절의 겹침이 늘린 12,500토큰이 그대로 임베딩 비용이 됩니다.
임베딩 차원
임베딩 차원은 벡터 하나에 든 숫자의 개수입니다. 위 코드에서 dimensions로 고른 값이 그것이고, Titan Text Embeddings V2는 1,024·512·256 가운데 고를 수 있습니다. 차원이 크면 뜻을 더 섬세하게 담을 여지가 있지만 저장 공간과 검색 계산이 함께 늘어납니다.
숫자 하나를 4바이트로 저장한다면 청크 100만 개의 벡터가 차지하는 공간은 차원에 비례합니다.
256차원이면 약 1.0GB로 4분의 1입니다. 같은 인덱스 안에서는 모든 벡터의 차원이 같아야 합니다. 임베딩 모델이나 차원을 바꾸면 기존 벡터와 비교할 수 없으므로 문서 전체를 다시 임베딩합니다.
코사인 유사도
두 벡터가 얼마나 같은 방향을 가리키는지를 재는 값이 코사인 유사도이고, 1에 가까울수록 뜻이 가깝습니다. 내적을 두 벡터 길이의 곱으로 나눕니다.
질문 벡터 와 청크 벡터 , 을 비교합니다. 이고 두 길이가 모두 3이므로 유사도는 입니다. 이라 유사도가 0이고, 방향이 직각인 무관한 청크입니다. 검색은 을 돌려줍니다. 위 코드처럼 normalize로 길이를 1로 맞춰 두면 분모가 1이 되어 내적만으로 같은 순위가 나옵니다.
차례와 서비스
문서가 답이 되기까지
넷을 차례로 놓으면 한 줄입니다.
- 문서를 청크로 자른다
- 청크마다 임베딩 모델을 거쳐 벡터를 만든다
- 벡터를 벡터 저장소에 넣는다
- 질문도 같은 임베딩 모델로 벡터로 만든다
- 유사도가 높은 청크를 찾아 프롬프트에 붙인다
- 생성 모델이 그 토큰을 읽고 답을 쓴다
4번에서 문서와 같은 임베딩 모델을 써야 한다는 점이 자주 나옵니다. 모델이 다르면 벡터 공간이 달라 유사도가 뜻을 잃습니다. 이 흐름에 검색 결과를 붙여 답하게 하는 것이 RAG이고, 저장소 선택은 뒤의 RAG 편에서 다룹니다.
헷갈리는 짝
| 짝 | 가르는 기준 |
|---|---|
| 토큰 / 청크 | 토큰은 모델이 읽는 최소 단위, 청크는 검색을 위해 사람이 정한 조각. 청크 하나는 토큰 여러 개다 |
| 임베딩 / 벡터 | 임베딩은 바꾸는 일, 벡터는 그 결과 |
| 생성 모델 / 임베딩 모델 | 앞은 토큰을 내놓고 뒤는 벡터를 내놓는다 |
| 차원 / 토큰 수 | 차원은 벡터의 길이로 입력 길이와 무관하게 고정, 토큰 수는 입력마다 다르다 |
마지막 줄이 함정입니다. 긴 청크도 짧은 청크도 256차원 모델을 거치면 똑같이 숫자 256개가 됩니다.
연습 문제
한 요청에 입력 2,000토큰, 출력 800토큰이 쓰였습니다. 입력 단가가 1,000토큰당 0.002달러, 출력 단가가 1,000토큰당 0.006달러라고 가정할 때 요청 한 건의 비용은?
① 0.0056달러
② 0.0088달러
③ 0.0120달러
④ 0.0168달러②. 입력 , 출력 이고 합이 0.0088입니다. ④는 전체 2,800토큰에 출력 단가를 모두 적용한 값이고, ①은 전체에 입력 단가를 적용한 값입니다.6,000토큰짜리 문서를 1,000토큰 청크로, 200토큰씩 겹쳐 자르면 청크는 몇 개입니까?
① 6개
② 7개
③ 8개
④ 10개③. 시작점이 800토큰씩 나아가므로 입니다. 일곱 번째 청크는 4,8005,800이라 끝 200토큰을 덮지 못하고, 여덟 번째가 5,6006,000을 덮습니다.벡터 검색 시스템의 임베딩 모델을 새 버전으로 바꾸기로 했습니다. 해야 할 일을 둘 고르시오.
① 저장된 문서 청크를 새 모델로 다시 임베딩한다
② 사용자의 질문도 새 모델로 임베딩한다
③ 생성 모델의 출력 최대 토큰을 두 배로 늘린다
④ 기존 벡터는 그대로 두고 새 문서만 새 모델로 넣는다
⑤ 청크 겹침을 0으로 바꾼다①과 ②. 문서와 질문이 같은 모델, 같은 차원의 공간에 있어야 유사도가 뜻을 갖습니다. ④처럼 섞으면 한 인덱스에 서로 비교할 수 없는 벡터가 공존합니다.질문 벡터 와 코사인 유사도가 가장 높은 청크 벡터는?
①
②
③
④③. 은 질문 벡터의 두 배라 방향이 같고 유사도가 1입니다. ②는 내적 24를 길이 곱 25로 나눈 0.96, ①은 0, ④는 반대 방향이라 −1입니다. 코사인 유사도는 길이가 아니라 방향을 봅니다.설명과 용어를 짝지으시오.
(가) 모델이 한 번에 읽고 쓰는 글의 조각
(나) 검색을 위해 문서를 자른 조각
(다) 입력을 뜻을 담은 숫자 목록으로 바꾸는 일
(라) 숫자 목록 하나에 든 숫자의 개수
ⓐ 임베딩 ⓑ 임베딩 차원 ⓒ 토큰 ⓓ 청크(가)-ⓒ, (나)-ⓓ, (다)-ⓐ, (라)-ⓑ.사내 FAQ 800문항이 이미 한 문항씩 별도 파일로 저장되어 있습니다. Bedrock Knowledge Bases에서 고를 청킹 전략으로 알맞은 것은?
① 고정 크기, 겹침 50%
② 계층적
③ 의미 기반
④ 청킹 없음④. 파일 하나가 이미 한 주제로 잘려 있어 다시 자르면 질문과 답이 다른 청크로 갈릴 수 있습니다.
여섯 문항이 겨누는 것은 둘입니다. 토큰으로 비용과 청크 수를 계산하는 것과, 넷이 서로 어떤 차례로 이어지는지 아는 것입니다. 계산 문항은 입력·출력 단가를 따로 곱하는지, 겹침이 시작점 간격을 줄이는지만 놓치지 않으면 됩니다.

