← Lecture Note
M2이론45분 · ~15 슬라이드

LLM 기초

모델·토큰·컨텍스트·비용을 손에 잡히게

학습 목표

LLM 을 블랙박스가 아니라 '파라미터로 제어 가능한 비용 있는 엔진'으로 다룬다.

LLM을 "잘 쓴다"는 것은 모델의 특성과 파라미터를 이해하고, 비용까지 예측하며 설계할 수 있다는 뜻입니다. 이 모듈에서는 Claude를 주축으로 한 우리 강의 스택이 왜 이 선택을 했는지, 그 근거를 LLM 내부 동작부터 짚어봅니다.


주요 LLM 비교

현시점(2025~2026 기준)에서 프로덕션에서 자주 선택되는 모델들의 특성을 정리합니다.

모델제공사강점Context Window비고
Claude Sonnet/OpusAnthropic긴 문서 이해, 지시 준수, 안전성200k이 강의의 주력
GPT-4o / o-seriesOpenAI생태계, 멀티모달, Function Calling 성숙128k보조 선택지
Gemini 1.5/2.0Google초장문 컨텍스트, 멀티모달1M대용량 문서 처리 특화
Llama 3.xMeta (OSS)자체 서버 배포, 데이터 통제128k비용 0, 운영 부담 있음

이 강의에서는 Claude를 주축으로 두되, callLLM() 함수 하나로 OpenAI도 통합합니다. Vercel AI Gateway의 "provider/model" 문자열(예: "anthropic/claude-sonnet-4-5", "openai/gpt-4o")을 파라미터로 넘기면 됩니다. 모델을 바꿔도 코드는 그대로입니다.


Token과 한국어 토큰 효율

LLM은 문자가 아닌 토큰 단위로 텍스트를 처리하고, 비용도 토큰 수로 청구됩니다.

  • 영어: 평균 1단어 ≈ 1~1.3 토큰
  • 한국어: 평균 1어절 ≈ 2~3 토큰 (영어 대비 약 2.5배)
"Hello world"  →  2 tokens
"안녕하세요"    →  5~6 tokens

즉, 한국어 서비스를 만들 때는 동일한 내용이라도 영어 대비 약 2.5배 토큰이 소모됩니다. 프롬프트 최적화(불필요한 조사/어미 제거, 영문 약어 활용)가 비용에 직접 영향을 줍니다.

: 시스템 프롬프트처럼 반복 전송되는 텍스트는 한국어보다 영어로 작성하면 토큰을 절약할 수 있습니다. 단, 출력 언어 지시는 명확히 남겨두세요.


Context Window

Context Window는 모델이 한 번의 API 호출에서 처리할 수 있는 최대 토큰 수입니다. 입력(프롬프트 + 대화 이력 + RAG 청크) + 출력을 합산한 값이 이 한도를 넘으면 오류가 납니다.

  • Claude: 200k 토큰 → 약 A4 150페이지 분량
  • Gemini 1.5 Pro: 1M 토큰 → 초장문 처리 가능하지만 비용도 그만큼

이 강의의 RAG는 별도 벡터 DB 없이 코사인 유사도를 직접 구현(in-memory / Vercel Blob) 합니다. 200k 컨텍스트면 청크 몇 개를 넣어도 충분하며, 외부 인프라 의존성을 줄이는 것이 이 강의의 설계 원칙입니다.


파라미터 제어

LLM 호출 시 동작을 조정하는 핵심 파라미터입니다.

파라미터역할권장 범위
temperature출력 다양성. 높을수록 창의적, 낮을수록 결정적창작: 0.7~1.0 / 보고서·분류: 0.2 이하
top_p누적 확률 토큰 풀 제한. temperature와 함께 조정보통 0.9, temperature 조정 시 고정 권장
max_tokens출력 최대 토큰 수. 비용 상한선 역할용도별 명시 필수
seed동일 seed → 재현 가능한 출력(OpenAI 지원)테스트·디버깅 시 유용

이 강의에서 보고서 생성에는 temperature: 0.2를 사용합니다. 결정적 Markdown 조립이 목표이기 때문입니다.


System vs User 권한 분리

프롬프트는 역할에 따라 반드시 분리해야 합니다.

System: 서비스 운영자 지시 (규칙, 페르소나, 보안 경계)
User:   실제 사용자 입력 (신뢰 낮음)

System 프롬프트는 모델이 더 높은 권위로 처리합니다. 사용자 입력을 System에 섞으면 Prompt Injection 취약점이 생깁니다. 이 강의는 4가지 방어 기법을 다루며, 그 전제가 바로 이 권한 분리입니다.


Structured Output (JSON Mode)

Agent가 LLM 출력을 파싱해서 다음 액션을 결정하려면 구조화된 응답이 필수입니다.

  • OpenAI: response_format: { type: "json_object" } 또는 json_schema 지정
  • Anthropic (Claude): 공식 JSON Mode 없음 → 시스템 프롬프트에 스키마를 명시하고, 출력에서 JSON 블록을 파싱하는 방식 사용
// 두 모델 모두에 통용되는 패턴
systemPrompt: `반드시 아래 JSON 형식으로만 응답하세요:
{"intent": "string", "slots": {"key": "value"}}
다른 텍스트는 포함하지 마세요.`

주의: Claude는 JSON 앞뒤에 설명 문구를 붙이는 경향이 있습니다. 정규식이나 JSON.parse() 전에 코드 블록 파싱을 추가하세요.


Native Function Calling을 왜 쓰지 않는가

OpenAI와 Claude 모두 Native Function Calling(Tool Use)을 지원합니다. 그럼에도 이 강의는 명시적 라우트 Dispatcher 패턴을 선택했습니다.

  • Native Function Calling은 모델이 "언제 어떤 함수를 부를지"를 결정합니다 → 비결정적
  • Dispatcher는 개발자가 라우팅 로직을 코드로 명시합니다 → 결정적, 디버깅 가능, 비용 예측 가능
  • 멀티 LLM 환경(Claude + OpenAI 혼용)에서 Function Calling 스키마가 달라 추상화 비용이 큼
사용자 입력 → callLLM(intent 분류) → dispatcher switch(intent) → 각 핸들러

프레임워크(LangChain 등) 없이 이 흐름을 직접 짜는 것이 이 강의의 핵심 학습 포인트입니다.


비용 모델 + Prompt Caching

API 비용 구조: (입력 토큰 × 입력 단가) + (출력 토큰 × 출력 단가)

출력 토큰이 입력보다 단가가 높습니다. 긴 출력을 요청할수록 비용이 급증합니다.

**Prompt Caching (Claude)**은 동일한 프롬프트 앞부분이 반복될 때 캐시 히트 시 최대 90% 비용 절감이 가능합니다.

  • System 프롬프트, RAG 청크처럼 매 요청마다 반복되는 부분을 캐시 대상으로 지정
  • cache_control: { type: "ephemeral" } 마킹으로 활성화
  • 캐시 유효 시간: 약 5분 (TTL은 변경될 수 있음)

설계 원칙: 자주 바뀌지 않는 컨텍스트(시스템 프롬프트, 공통 지식 청크)는 프롬프트 앞부분에 배치하고 캐시 마킹을 합니다. 사용자별 동적 데이터는 뒤에 붙입니다.


핵심 정리

  • 한국어는 영어 대비 약 2.5배 토큰을 소모하므로, 반복 프롬프트의 언어 선택이 비용에 직결됩니다.
  • temperature: 0.2는 결정적 보고서·분류에, 높은 값은 창의적 생성에 씁니다. 두 값을 혼용하지 마세요.
  • System / User 역할 분리는 Prompt Injection 방어의 가장 기본 전제입니다.
  • Structured Output은 Claude에서 공식 JSON Mode 대신 프롬프트 스키마 명시 + 파싱으로 처리합니다.
  • Native Function Calling 대신 Dispatcher 패턴을 선택한 이유는 결정성과 멀티 LLM 추상화입니다.
  • Prompt Caching으로 반복 컨텍스트 비용을 최대 90% 절감할 수 있으며, 캐시 대상은 프롬프트 앞부분에 배치합니다.