Context Engineering이란? 컨텍스트 윈도우 설계 전략
프롬프트를 잘 쓰는 시대는 끝났다. 이제는 컨텍스트 윈도우를 설계하는 시대다.
들어가며: 프롬프트를 잘 쓰는 것만으로는 부족하다
9편에서 우리는 AI 출력을 코드로 처리하려면 신뢰를 설계해야 한다는 것을 배웠습니다. JSON 스키마를 강제하고, 파싱 실패 시 복구 파이프라인까지 구축하는 기술이었습니다.
그런데 이 시점에서 한 가지 근본적인 질문을 던져야 합니다.
"프롬프트를 잘 쓰는 것이 진짜 문제의 전부인가?"
아닙니다. 프롬프트는 AI가 처리하는 전체 정보의 일부에 불과합니다. 실제로 AI 성능을 결정하는 건 "어떤 말을 했느냐"가 아니라 "모델이 추론하는 순간, 눈앞에 어떤 정보가 놓여있느냐" 입니다.
이것이 Context Engineering(컨텍스트 엔지니어링) 입니다.
Andrej Karpathy(전 Tesla AI 총괄, OpenAI 공동창업자)는 2025년 이렇게 말했습니다.
"The hottest new programming language is English. And the real skill is not prompt engineering — it's context engineering."
프롬프트를 작성하는 기술에서, 컨텍스트 윈도우 전체를 설계하는 기술로. 이 전환이 하네스 시대의 핵심입니다. 10편에서 그 전환을 완전히 이해합니다.
1. 컨텍스트 윈도우: AI의 작업 책상
1.1. AI는 과거를 기억하지 않는다
LLM을 이해하는 데 가장 중요한 사실 하나:
AI는 과거를 기억하지 않는다. 매 추론마다 주어진 정보만 본다.
AI가 일하는 방식은 매번 새 책상을 받는 것과 같습니다. 책상 위에 올려놓은 서류만 볼 수 있고, 어제 책상 위에 뭐가 있었는지는 전혀 모릅니다. 어제 대화, 어제 검색 결과 — 책상이 새로 세팅되면 다 사라집니다.
그 책상의 크기가 컨텍스트 윈도우입니다.
| 책상 위에 올라가는 것들 |
|---|
| 📋 지시서 (System Prompt) |
| 📄 참고 문서들 (Retrieved Documents) |
| 📜 대화 기록 (Conversation History) |
| 🔧 도구 실행 결과 (Tool Outputs) |
| 💬 지금 질문 (Current User Turn) |
이 안에 있는 것만 보고 추론한다.
1.2. 책상이 클수록 좋은 건 아니다
2026년 기준 주요 모델의 컨텍스트 한도:
| 모델 | 최대 컨텍스트 |
|---|---|
| Claude Sonnet 4.6 | 200K 토큰 (≈ 소설 한 권) |
| GPT-4o | 128K 토큰 |
| Gemini 2.5 Pro | 1M 토큰 |
한도가 클수록 더 많은 정보를 넣을 수 있지만, 동시에 무엇을 어디에 배치할지를 더 정교하게 설계해야 합니다. 책상이 작으면 자연스럽게 중요한 것만 올려놓게 됩니다. 책상이 넓어질수록 오히려 설계가 필요해집니다. 이게 컨텍스트 엔지니어링이 등장한 이유입니다.
2. 프롬프트 ≠ 컨텍스트
2.1. 두 개념의 명확한 구분
혼용되는 개념이지만 완전히 다릅니다.
| 프롬프트 | 컨텍스트 | |
|---|---|---|
| 범위 | 사용자가 입력하는 지시문 | 모델이 보는 전체 정보 |
| 관계 | 컨텍스트의 일부 | 프롬프트를 포함하는 더 큰 개념 |
| 예시 | "이 글을 요약해줘" | 지시문 + 글 내용 + 이전 대화 + 검색된 문서 + ... |
2.2. 왜 구분이 중요한가
1~9편에서 배운 기술들은 모두 "좋은 프롬프트 쓰기"에 관한 것이었습니다. 그런데 아무리 프롬프트를 잘 써도, 책상 위에 엉뚱한 서류가 쌓여있거나 중요한 자료가 빠져있으면 AI는 제대로 일할 수 없습니다.
컨텍스트 엔지니어링은 책상 위 서류 전체를 설계하는 기술입니다. 프롬프트는 그 중 하나의 서류일 뿐입니다.
3. 컨텍스트의 4개 레이어
3.1. 레이어 구조 개요
책상 위 서류들을 역할별로 분류하면 4개의 레이어가 됩니다.
| 레이어 | 역할 | 특징 |
|---|---|---|
| Layer 1 System Prompt | 모델의 역할, 규칙, 출력 형식 정의 | 모든 대화에 고정 적용 |
| Layer 2 Retrieved Context | 검색된 외부 문서, API 응답, DB 조회 결과 | 실시간 주입, 가장 많은 토큰 |
| Layer 3 Conversation History | 이전 대화 내용 | 무한정 쌓이면 안 됨 |
| Layer 4 Current User Turn | 지금 사용자가 입력한 메시지 | 컨텍스트 최하단 위치 |
모델은 이 4개를 동시에 보고 추론합니다.
3.2. Layer 1: System Prompt — 절대 바뀌지 않는 헌법
모든 대화에 걸쳐 동일하게 적용되는 근본 지시서입니다. 모델의 정체성, 행동 규칙, 금지 사항, 출력 형식이 여기 들어갑니다.
[System Prompt 예시]
당신은 Dechive의 지식 사서입니다.
## 절대 규칙
- 컨텍스트에 없는 정보는 답변하지 않는다
- 불확실한 경우 "확인이 필요합니다"라고 말한다
- 한국어로만 답변한다
## 출력 형식
- 핵심 답변: 3문장 이내
- 출처 문서 번호를 [Doc 1]처럼 명시
가장 흔한 실수: 시스템 프롬프트에 동적인 정보를 하드코딩하는 것입니다.
# ❌ 잘못된 방식
시스템 프롬프트: "오늘은 2026년 4월 18일입니다."
→ 내일이 되면 틀린 정보가 된다
# ✅ 올바른 방식
시스템 프롬프트는 불변의 규칙만.
날짜 같은 동적 정보는 Retrieved Context 레이어에서 주입.
3.3. Layer 2: Retrieved Context — 실시간 주입 지식
모델이 알아야 할 외부 지식을 주입하는 레이어입니다. 가장 많은 토큰을 차지하며, 11편 RAG에서 이 레이어를 어떻게 채우는지 상세히 다룹니다.
<doc id="1" relevance="0.95">
컨텍스트 엔지니어링은 모델이 추론할 때 무엇을 보게 할지를...
</doc>
<doc id="2" relevance="0.82">
Lost in the Middle 현상은 2023년 Stanford 연구에서...
</doc>
문서에 관련도 점수를 명시하면 모델이 더 신뢰도 높은 문서를 우선 참조합니다.
3.4. Layer 3: Conversation History — 관리해야 하는 기억
대화가 쌓일수록 이 레이어가 컨텍스트를 잠식합니다. 방치하면 두 가지 문제가 생깁니다.
- 컨텍스트 한도 초과 → 응답이 중간에 잘림
- 오래된 잡담이 중요한 최신 정보를 밀어냄
반드시 관리 전략이 필요합니다. 5장에서 상세히 다룹니다.
3.5. Layer 4: Current User Turn — 지금 이 질문
사용자가 방금 입력한 메시지입니다. 컨텍스트의 가장 끝에 위치하며, 모델은 이를 기반으로 위 3개 레이어를 참조해 답변을 생성합니다.
4. Lost in the Middle: 긴 컨텍스트의 함정
4.1. 현상의 발견
2023년 Stanford 연구팀이 발견한 현상입니다. LLM에 긴 문서를 줬을 때, 앞부분과 뒷부분의 정보는 잘 활용하지만 중간에 있는 정보는 무시하는 경향이 있습니다.
컨텍스트 위치에 따른 모델의 정보 활용률:
앞부분 ████████████████ 높음 ✅
중간부분 ████░░░░░░░░░░ 낮음 ⚠️
뒷부분 ████████████████ 높음 ✅
RAG 시스템에서 여러 문서를 검색해 컨텍스트에 넣을 때, 가장 중요한 문서를 중간에 배치하면 모델이 무시할 수 있습니다.

4.2. 대응 전략
전략 1 — 중요한 정보를 앞 또는 뒤에 배치
[System Prompt]
[★ 가장 중요한 문서 → 앞에]
[보조 문서들 → 중간]
[★ 두 번째로 중요한 문서 → 뒤에]
[User Message]
전략 2 — 모델에게 어디를 봐야 할지 명시
# 모호한 지시 (피해야 할 방식)
"아래 문서들을 참고해 답해줘."
# 명확한 지시
"[Doc 1]의 3번 항목과 [Doc 3]의 결론을 핵심 근거로 사용해 답변하라."
5. 컨텍스트 오염: 노이즈가 성능을 낮춘다
5.1. 정보가 많을수록 좋다는 오해
관련 없는 정보를 컨텍스트에 넣으면 오히려 성능이 떨어집니다. 이를 컨텍스트 오염(Context Pollution)이라 합니다.
실제로 측정된 결과:
- 관련 없는 문서 5개 추가 주입 → 정확도 15~20% 하락
- 길고 장황한 시스템 프롬프트 < 짧고 정확한 시스템 프롬프트
5.2. 왜 이런 일이 생기는가
모델은 컨텍스트 안의 모든 정보에 어텐션(주의)을 분산시킵니다. 관련 없는 정보가 많으면 진짜 중요한 정보에 집중되어야 할 어텐션이 흩어집니다.
컨텍스트에 들어가는 모든 토큰은 이유가 있어야 한다.
6. 토큰 예산: 한정된 책상 공간을 배분하는 법
6.1. 예산 개념으로 바라보기
컨텍스트 윈도우를 한정된 책상 공간으로 생각해야 합니다. 200K 토큰 기준 기본 배분 예시:
총 예산: 200,000 토큰
├── System Prompt: 10,000 토큰 (5%)
├── Retrieved Documents: 80,000 토큰 (40%)
├── Conversation History: 50,000 토큰 (25%)
├── Tool Outputs: 20,000 토큰 (10%)
├── Current User Turn: 5,000 토큰 (2.5%)
└── 출력 여유분: 35,000 토큰 (17.5%)
출력 여유분은 반드시 남겨야 합니다. 입력 + 출력의 합이 컨텍스트 한도를 초과하면 모델이 응답을 중간에 잘라버립니다.

6.2. 쿼리 유형에 따른 동적 배분
def build_context_budget(query_type: str, total: int) -> dict[str, int]:
if query_type == "simple_qa":
# 간단한 질문 → 검색 문서 적게, 출력 여유 크게
return {
"system": int(total * 0.05),
"retrieved": int(total * 0.25),
"history": int(total * 0.10),
"output": int(total * 0.30),
}
elif query_type == "deep_analysis":
# 심층 분석 → 검색 문서 최대한
return {
"system": int(total * 0.05),
"retrieved": int(total * 0.55),
"history": int(total * 0.15),
"output": int(total * 0.20),
}
7. 대화 기록 관리: 3가지 전략
7.1. 슬라이딩 윈도우 — 최근 N턴만 유지
MAX_TURNS = 10 # 최근 10턴만 유지
def trim_history(messages: list) -> list:
return messages[-(MAX_TURNS * 2):] # user + assistant 쌍
가장 단순하고 구현이 쉽습니다. 단점: 초반 대화의 중요한 정보가 잘릴 수 있습니다.
7.2. 요약 압축 — 오래된 대화를 한 줄로
오래된 대화를 LLM으로 요약해 토큰을 절약합니다.
[대화 요약]
사용자는 Python 백엔드 개발자. FastAPI 프로젝트 구축 중.
JWT 인증 오류가 있었고, 미들웨어 레이어에서 해결함.
[최근 3턴]
User: 이번엔 DB 연결 풀링 설정을 보고 싶어요.
Assistant: SQLAlchemy에서 풀링 설정은...
[현재 질문]
User: 비동기 방식으로 바꾸면 어떻게 되나요?
정보 손실이 적고 토큰 절약이 큽니다. 실제 서비스에서 가장 많이 쓰이는 방식입니다.

7.3. 선택적 보존 — 관련된 과거만 꺼내오기
전체 대화를 저장해두되, 현재 질문과 관련성이 높은 대화만 골라 컨텍스트에 주입합니다. 벡터 임베딩으로 유사도 검색을 하는 방식으로, 11편 RAG에서 상세히 다룹니다.
8. 실전 패턴
8.1. 역할별 태그 구조
긴 컨텍스트에서 모델이 각 섹션의 역할을 명확히 인식하도록 태그를 씁니다.
<instructions>
당신은 Dechive의 지식 사서입니다.
컨텍스트에 없는 정보는 답변하지 않습니다.
</instructions>
<knowledge>
<doc id="1" relevance="0.95">컨텍스트 엔지니어링은...</doc>
<doc id="2" relevance="0.82">Lost in the Middle 현상은...</doc>
</knowledge>
<history>
User: 컨텍스트 윈도우가 뭔가요?
Assistant: 컨텍스트 윈도우는...
</history>
<task>
지금 사용자 질문
</task>
8.2. 동적 시스템 프롬프트
시스템 프롬프트 중 사용자별로 달라지는 부분은 런타임에 채웁니다.
def build_system_prompt(user: User) -> str:
return f"""당신은 Dechive의 지식 사서입니다.
현재 사용자: {user.name}
선호 언어: {user.preferred_lang}
## 규칙
{"- 프리미엄 콘텐츠 접근 가능" if user.plan == "premium" else "- 무료 콘텐츠만 안내"}
"""
결론: 컨텍스트가 설계될 때 AI는 제대로 일한다
프롬프트를 아무리 잘 써도, 책상 위에 엉뚱한 서류가 쌓여있으면 AI는 제대로 일할 수 없습니다. 반대로 프롬프트가 단순해도, 책상이 완벽하게 세팅되어 있으면 AI는 기대 이상의 결과를 냅니다.
컨텍스트 엔지니어링의 시각 전환은 이것입니다.
"어떤 말을 할 것인가" → "모델이 추론할 때 무엇을 보게 할 것인가"
핵심 원칙
| 원칙 | 내용 |
|---|---|
| 레이어를 구분하라 | System / Retrieved / History / Current — 각각 역할이 다르다 |
| 중요한 건 앞뒤에 | Lost in the Middle을 피하려면 중간에 두지 마라 |
| 노이즈를 제거하라 | 관련 없는 정보는 어텐션을 분산시키고 성능을 낮춘다 |
| 예산을 설계하라 | 출력 여유분을 항상 남겨라 |
| 기억을 관리하라 | 대화 기록은 무한정 쌓지 않는다 |
11편을 향하여: RAG와 프롬프트
10편에서 우리는 컨텍스트의 구조와 설계 원칙을 다뤘습니다. 그 중 Retrieved Context 레이어 — 즉, 외부 지식을 어떻게 주입하느냐의 문제는 아직 열려있습니다.
이어지는 [11편: RAG와 프롬프트 – 외부 지식을 실시간으로 주입하기] 에서는 이 레이어를 채우는 기술을 완전히 다룹니다. 어떤 문서를 검색하고, 어떻게 정제하고, 어떤 순서로 배치해야 모델이 가장 잘 활용하는지. 컨텍스트 엔지니어링과 RAG가 만나는 지점입니다.
