Claude Code를 쓰기 전, AI 동작 과정 이해하기

요즘 개발을 하면서 직접 코드를 작성하는 경우는 거의 없다. 코드 작성뿐 아니라 실행 스크립트를 돌리는 것도 Claude Code나 Codex를 통해 지시하게 된다.

얼마 전, Andrej Karpathy가 만든 food app을 알게 됐다. 음식 사진을 업로드하면 AI가 이미지 메뉴판을 생성해 주는 앱이다. 흥미로웠지만 나는 그 앱을 쓰지 않았다. 스페인, 포르투갈 여행 중에 메뉴판을 Claude 앱에 올리고 “한국인 입맛에 맞는 메뉴를 인원수에 맞게 추천해줘”라고 하면 더 정확한 추천을 받을 수 있었기 때문이다. Karpathy는 AI로 글 메뉴판을 이미지 메뉴판으로 바꿨고, 나는 AI로 메뉴 추천을 받았다. 같은 상황에서 AI를 활용하는 방식이 사람마다 달라지고 있다.

개발도 마찬가지다. 직접 코드를 짜는 것보다 AI에게 의도와 계획을 명확히 전달하고 결과를 확인하는 방향으로 역할이 이동했다. 처음엔 AI에 대체될 것 같다는 두려움이 있었지만, 계속 쓰다 보니 즐거움으로 바뀌었다. 그 전환점이 된 것이 AI가 답변을 생성하는 과정을 이해하게 된 것이다.

이 글은 AI가 입력을 받아 답변을 생성하기까지의 과정을 토크나이징 → Context Window → 토큰 예측 순서로 다룬다.

1. 0과 1을 의미로 — 토크나이징과 임베딩

컴퓨터는 0과 1의 체계로 동작한다. LLM에 문장을 전달해도 컴퓨터는 그 의미를 바로 이해할 수 없다.

아버지가 방에 들어가신다.

단순 숫자 ID의 한계

텍스트를 숫자로 변환하는 가장 단순한 방법은 단어마다 ID를 붙이는 것이다.

아버지 → 1006
방     → 2187
가다   → 786

그런데 이 숫자로 연산하면 의미를 잃는다.

아버지(1006) + 방(2187) = 3193  → 이게 무슨 단어?
아버지(1006) - 아빠(?)  = ?     → 의미상 거리를 계산할 수 없음

Sparse Vector

단어에 고유 ID를 붙이는 대신, 단어 수만큼의 배열에서 해당 위치에만 1을 찍는 방식이다.

어휘 사전 크기가 100,000개라면:
아버지 (1006번째) → [0, 0, ..., 1, ..., 0]  ← 1006번 위치에만 1
방     (2187번째) → [0, 0, ..., 1, ..., 0]  ← 2187번 위치에만 1

100,000개 자리 중 딱 1개만 1이고 나머지는 0이라 sparse(희소) 벡터라 부른다. 그러나 모든 단어 쌍이 서로 직교하기 때문에, 아버지와 아빠가 의미상 가깝든, 아버지와 자동차가 의미상 멀든 거리가 동일하다.

Dense Vector(임베딩)

단어를 저차원 실수 벡터로 압축하면 의미가 가까운 단어끼리 벡터 방향이 비슷해진다.

아버지 → [0.82, 0.13, -0.47, ...]  ← 300차원 실수 벡터
아빠   → [0.79, 0.11, -0.51, ...]  ← 아버지와 숫자가 비슷함
자동차 → [-0.21, 0.93, 0.14, ...]  ← 완전히 다른 방향

100,000차원 sparse 벡터를 300차원 dense 벡터로 압축하는 연산이 행렬 곱이다.

[1 x 100,000] × [100,000 x 300] = [1 x 300]

one-hot 벡터    변환 행렬 M       임베딩 벡터

변환 행렬 M은 100,000 × 300 = 3천만 개의 숫자로 이루어져 있어 사람이 직접 채울 수 없다. 딥러닝은 “문맥에서 함께 자주 등장하는 단어는 벡터를 가깝게, 그렇지 않은 단어는 멀게”되도록 M을 자동으로 조정한다.

2. 문장을 이해하기 — RNN과 Transformer

임베딩은 단어 자체에 고정된 벡터를 부여한다. 그래서 아래 두 문장의 “눈”은 벡터가 동일하다.

눈이 내린다  →  "눈" 벡터
눈이 아프다  →  "눈" 벡터

문맥에 따라 의미가 달라지는 걸 표현하려면 문장 전체를 함께 처리해야 한다.

RNN

일반 신경망은 단어를 하나씩만 처리해 앞 단어의 정보를 기억하지 못한다. RNN은 이전 단계의 결과(hidden state)를 다음 단계에 넘겨주는 방식으로 이 문제를 해결했다.

"나는" 처리 → h1
"밥을" 처리 → h2 (h1 참조)
"먹었다" 처리 → h3 (h2 참조)

그러나 두 가지 한계가 있다.

  1. 앞 내용을 잊는다. hidden state에 계속 덮어쓰다 보니 문장이 길어질수록 앞 단어 정보가 희미해진다.
  2. 순차 처리가 느리다. 앞 단어를 처리해야 다음 단어를 처리할 수 있어 병렬 처리가 불가능하다.

Transformer

모든 단어를 한 번에 펼쳐놓고 서로 얼마나 관련 있는지를 계산하는 방식이다.

Attention

"그것이 맛있었다"에서 "그것"이 뭔지 파악할 때:

"나는"   → 관련도 0.1
"밥을"   → 관련도 0.8  ← 그것 = 밥
"먹었다" → 관련도 0.1

단어마다 이 계산을 동시에 수행하니 병렬 처리가 가능하고, 거리가 멀어도 관계를 잡아낼 수 있다.

Positional Encoding

한 번에 다 보기 때문에 순서를 모른다는 문제가 있다. 각 단어 벡터에 위치 정보를 더해주는 방식으로 해결한다.

3. AI가 기억하는 범위 — Context Window

Transformer의 연산량

Transformer는 모든 토큰이 서로를 참조한다. 토큰이 N개면 N×N번 계산한다. 토큰이 늘수록 연산량이 제곱으로 늘기 때문에 한 번에 볼 수 있는 토큰 수에 한계를 둔 것이 Context Window다.

Context Window를 넘으면

[ 질문 + 대화 기록 + 문서 ]  +  [ 모델 답변 ]
       입력 토큰               출력 토큰
         
이 합산이 Context Window를 넘으면 안 됨

Context Window를 넘은 토큰은 Transformer가 아예 보지 못한다. 없는 내용으로 취급된다.

크다고 무조건 좋지는 않다

Context Window가 커도 중간에 있는 내용은 Attention이 약해지는 경향이 있다.

[앞부분]  [===== 긴 중간 =====]  [뒷부분]
 잘 봄         잘 못 봄            잘 봄

이를 Lost in the Middle이라 한다. 중요한 내용을 앞이나 뒤에 배치하는 게 효과적인 이유다.

RAG

긴 문서를 통째로 넣는 대신 관련 있는 부분만 골라서 넣는 패턴이다.

긴 문서 전체 넣기

문서를 청크로 쪼갬

질문과 관련된 청크만 벡터 유사도로 검색

관련 청크만 Context Window에 넣음

답변 생성

앞서 설명한 임베딩과 벡터 유사도가 여기서 쓰인다. “의미가 비슷한 것끼리 벡터가 가깝다”는 성질로 관련 청크를 찾아낸다.

4. 답변이 만들어지는 과정 — 토큰 예측

Transformer의 Decoder

Transformer의 Decoder가 토큰을 하나씩 순서대로 예측해 이어붙인다.

"오늘" → "날씨" → "는" → "맑" → "아요"

Claude Code나 GPT가 답변을 한 글자씩 타이핑하듯 보여주는 건 모델이 실제로 동작하는 방식 그대로다.

LLM은 확률 기계다

다음에 올 토큰이 무엇일 확률이 가장 높은가를 기준으로 토큰을 생성한다. 수십억 개의 문장을 학습해서 “이 다음엔 이 단어가 올 확률이 높다”를 계산한다.

확률적으로 그럴듯한 답변이 좋은 답변은 아니다.

"세종대왕은 1932년에 태어났다"
→ 문장 구조는 자연스럽고 확률적으로 그럴듯함
→ 그러나 틀린 내용

확률 기반으로만 학습하면 유창하지만 틀린 답변, 사용자 의도를 못 잡는 답변이 나온다.

강화학습으로 피드백 제공

사람의 피드백을 3단계로 모델에 반영한다.

1단계 — 좋은 예시로 먼저 학습

사람이 직접 좋은 답변을 작성하고, 그 쌍으로 모델을 파인튜닝한다.

2단계 — Reward Model 학습

같은 질문에 여러 답변을 생성하고 사람이 순위를 매긴다.

답변 A: 길고 어려운 설명     → 3위
답변 B: 친절하고 단계적 설명  → 1위
답변 C: 짧지만 불친절        → 2위

이 데이터로 “좋은 답변을 판별하는 모델”을 따로 학습한다.

3단계 — 강화학습

LLM이 답변 생성

Reward Model이 점수 부여

점수 높은 방향으로 LLM 가중치 업데이트

반복

부작용으로 Reward Hacking이 있다. 점수만 높이기 위해 “최고입니다! 완벽합니다!” 같은 아첨성 답변만 생성하게 된다. 강화학습 알고리즘은 이런 답변을 막으면서 학습을 진행한다.

정리

임베딩 → RNN → Transformer → 강화학습으로 이어지는 흐름을 이해하고 나면, Claude Code에서 쓰는 개념들이 왜 존재하는지 보인다.

  • AGENTS.md: 프로젝트 전체 맥락을 모델에 제공하는 방법
  • Context 관리: Context Window 안에 필요한 정보만 넣어 연산 효율과 답변 정확도를 높이는 것
  • skills, MCP: 확률 기계인 모델이 일관되게 좋은 답변을 내도록 워크플로를 제어하는 것

AI를 활용해 나만의 워크플로를 구축하고, 그 위에서 더 큰 문제를 해결하는 것이 지금 시대 엔지니어의 역량이라고 생각한다.