
【AI 개발 지침서: 제3회】 Prompt에서 Context로: 장문 LLM 시대의 Context Engineering의 비결
요약
장문 LLM 시대에 대응하기 위한 Context Engineering의 개념과 구현 방법을 다룹니다. 'Lost in the Middle' 현상을 방지하기 위해 컨텍스트를 4개의 레이어로 분리하고 동적으로 최적화하는 Context Manager 구현을 목표로 합니다.
핵심 포인트
- LLM 컨텍스트 윈도우가 커져도 정보의 중앙부 정밀도가 떨어지는 'Lost in the Middle' 현상 발생
- 단순 프롬프트 엔지니어링을 넘어 데이터 배치와 토큰 제어를 포함한 시스템 설계 필요
- 컨텍스트를 4개의 층(Layer)으로 분리하여 토큰 상한에 따라 동적 최적화 수행
- Python과 tiktoken 등을 활용한 실무적인 Context Manager 구현 가이드 제공
【
신연재: MCP · 고도화된 RAG · 자율 에이전트의 현장 설계론】 ※본 연재는 MCP (Model Context Protocol), Context Engineering, GraphRAG, Self-Healing Agent, 로컬 SLM 등의 최첨단 기술 스택을 사용하여, 실무 프로덕션에서 진정으로 견딜 수 있는 차세대 AI 시스템을 구축하는 중후한 핸즈온(Hands-on) 연재입니다.
지난 2회에 걸쳐, MCP (Model Context Protocol)를 사용하여 AI 에이전트와 외부 도구 · 데이터베이스를 안전하게 타입 연결하는 기술을 해설했습니다.
하지만 에이전트가 여러 도구를 호출하고, 긴 대화나 방대한 문서를 다루게 되면 개발자는 다음의 심각한 벽에 직면합니다. 그것은 "LLM의 컨텍스트 윈도우(Context Window)가 128k나 1M 토큰으로 확대되었음에도 불구하고, 입력 문장을 길게 할수록 AI의 답변 정밀도가 떨어지고 토큰 비용이 폭발한다"는 문제입니다.
"프롬프트의 텍스트 표현을 궁리한다"는 기존의 Prompt Engineering (프롬프트 엔지니어링) 접근 방식만으로는, 이 장문 컨텍스트에서의 정밀도 저하나 비용 문제를 해결할 수 없습니다. 지금 현장의 개발자에게 요구되는 것은, LLM에 주는 정보 전체의 배치, 구조화, 동적 트리밍(Trimming), 캐시 제어를 시스템으로서 설계하는 "Context Engineering (컨텍스트 엔지니어링)" 사고입니다.
제3회인 이번에는, 장문 프롬프트에서 정보가 잊혀지는 「Lost in the Middle 현상」의 학술적 배경을 해설합니다. 그리고 컨텍스트를 4개의 층(Layer)으로 분리하여, 토큰 상한에 따라 동적으로 최적화하는 「Context Manager」를 Python으로 완전 구현하는 것을 목표로 합니다.
Python 버전: Python 3.10 이상 -
동작 확인 완료 주요 라이브러리:-
tiktoken>=0.7.0
(OpenAI 제공의 고속 토크나이저) -
openai>=1.30.0
(LLM 호출용 라이브러리)
동작 확인 환경: macOS / Linux / Windows (PowerShell)
컨텍스트 윈도우의 거대화(예: GPT-4o의 128k, Claude 3.5의 200k, Gemini 1.5의 2M 토큰)에 따라, 개발 현장에서는 "모든 문서나 대화 이력을 그대로 프롬프트에 채워 넣으면 된다"라는 오해가 퍼졌습니다.
하지만 스탠퍼드 대학교의 Liu et al. (2024)에 의한 유명한 연구 **『Lost in the Middle: How Language Models Use Long Contexts』**는 이 환상을 깨뜨렸습니다.
LLM의 표준적인 Transformer 어텐션(Attention) 메커니즘은 입력된 프롬프트 전체의 정보를 균등하게 처리하고 있는 것이 아닙니다. 실험 데이터에 따르면, 모델은 프롬프트의 "처음(Prefix)"과 "마지막(Suffix)"에 놓인 정보에 대해 가장 높은 어텐션(주목도)을 기울이며, "중앙부(Middle)"에 놓인 정보는 무시되거나 검색에 실패할 확률이 비약적으로 높아진다는 것이 실증되었습니다.
【Lost in the Middle의 정밀도 분포 (U자형 곡선)】
100% | ██ (고정밀) ██ (고정밀)
| ██ ██
...
LLM의 입력을 최적화하는 접근 방식은 단순한 "말투의 궁리"에서 "페이로드(Payload) 전체의 시스템 설계"로 진화하고 있습니다.
| 평가 항목 | 기존의 Prompt Engineering | 차세대 Context Engineering (본 수법) |
|---|---|---|
| 주 대상 | ||
| 시스템 지시문의 표현 방식 · Few-shot 예시 개선 | 프롬프트 전체의 데이터 배치 · 레이어 구조 · 토큰 제어 | |
| 과제에 대한 접근 | ||
| "알기 쉽게 작성"함으로써 LLM의 이해를 촉진 | "Lost in the Middle"을 피할 수 있는 위치로 동적으로 정보를 재배치 | |
| 컨텍스트 관리 | ||
| 정적 (고정 텍스트 복사/붙여넣기) | 동적 (토큰 수에 따른 계층 압축 · 요약 · 캐시 최적화) | |
| 비용 대책 | ||
| 수작업으로 프롬프트를 짧게 깎음 | 애플리케이션이 tiktoken 등으로 토큰 상한을 자동 매니지먼트 |
Lost in the Middle 현상을 물리적으로 회피하고, 토큰 비용을 최소화하기 위해서는 프롬프트를 구성하는 정보를 아래의 **4가지 계층 (Layer)**으로 분리하여 명확한 순서로 조립하는 아키텍처를 채택합니다.
Layer 1: Core System Instruction (최우선 지시 / 선두 배치): 에이전트의 역할, 준수해야 할 제약 규칙, 출력 포맷.
-
어텐션 (Attention)이 가장 높은 프롬프트의 절대 선두에 배치합니다.
Layer 2: User Profile & Persistent Memory (상시 기억 / 전방 배치): 사용자의 속성, 과거의 중요 기억, 프로젝트 설정.
-
후술할 Prompt Caching을 적용하기 위해, 변화가 적은 이 제1·제2 계층을 고정 블록으로 고정화합니다.
Layer 3: Dynamic Middle Buffer (동적 문맥 버퍼 / 중앙 배치): RAG로 취득한 문서, 과거의 대화 로그, 도구 실행 결과.
-
정보가 비대해지기 쉬우므로, **토큰 상한을 초과할 경우 이 내용만을 동적으로 삭제 또는 요약 (Dynamic Truncation)**합니다.
Layer 4: Current Query & Execution Cue (최신 명령 / 말미 배치): 사용자가 이번에 입력한 최신 질문, 그리고 "다음 형식으로 즉시 답변을 시작하라"와 같은 실행 트리거.
- 어텐션이 가장 높아지는 프롬프트의 절대 말미에 배치합니다.
그럼, tiktoken 라이브러리를 사용하여 정확한 토큰 수를 실시간으로 계산하고, 지정된 토큰 상한(예: 2000 토큰)을 초과하지 않도록 내용을 자동으로 압축·4계층 배치하여 프롬프트를 조립하는 완전한 Python 클래스 ContextManager를 구현해 봅시다.
신규 파일 context_engineering_demo.py를 생성하고, 다음 코드를 작성합니다.
# 동작 확인 완료된 라이브러리 버전: tiktoken>=0.7.0, openai>=1.30.0
import os
import sys
...
구현된 ContextManager의 기술적인 포인트를 해부해 보겠습니다.
-
문자열의 길이를
len(text)로 계산하면, 일본어(멀티바이트 문자)나 코드 기호의 토큰 수를 크게 오판하여 컨텍스트 제한 초과를 일으킵니다. -tiktoken을 사용하여encoder.encode(text)를 수행함으로써, LLM이 실제로 소비하는 BPE (Byte Pair Encoding) 토큰 수를 밀리초 단위로 정확하게 가져옵니다. -
reserved_tokens = token_l1 + token_l2 + token_l4를 통해 "절대로 잘라내서는 안 되는 최우선 정보"의 토큰 수를 미리 확보합니다. -available_for_l3 = self.max_allowed_tokens - reserved_tokens를 통해 중앙에 배치할 RAG 문서 (Layer 3)에 사용할 수 있는 잔여 용량을 역산하고, 넘치는 부분만 잘라냅니다. 이를 통해 프롬프트 초과로 인한 에러 (BadRequestError)가 100% 발생하지 않게 됩니다. -
messages배열의 선두에system(Layer 1 + Layer 2)을 배치. - 중앙에user(Layer 3: 검색 문서)를 배치. - 말미에user(Layer 4: 최신 지시)를 배치. - 이를 통해 LLM의 어텐션 메커니즘이 최고의 정밀도를 발휘하는 양 끝단에 중요 명령이 고정되어, "Lost in the Middle 현상"을 구조적으로 회피합니다.
Context Engineering을 실제 서비스에 적용할 때의 실전적인 최적화 테크닉을 해설합니다.
Anthropic (Claude 3.5 Sonnet)이나 OpenAI (GPT-4o)는 프롬프트의 선두 부분이 과거의 요청과 일치할 경우, "입력 토큰 요금을 50%~90% 할인하고 레이턴시를 급격히 줄이는 Prompt Caching"을 제공하고 있습니다.
【Prompt Caching을 최대화하는 레이어 설계】
[Layer 1: System Instruction] <-- 완전 고정 (캐시 적중률 100%)
[Layer 2: User Profile/Memory] <-- 사용자 단위 고정 (캐시 적중)
...
고정된 문맥인 Layer 1과 Layer 2를 프롬프트의 절대적인 최상단에 집약해 둠으로써, LLM 프로바이더의 캐시 버퍼(Cache Buffer)에 100% 적중시켜 대폭적인 비용 절감과 응답 속도 향상을 동시에 달성할 수 있습니다.
Layer 3에 삽입할 문서가 다수 존재하는 경우, 단순한 키워드 검색이나 벡터 검색(Vector Search)의 상위 순서대로 나열하는 것이 아니라, Cohere Rerank와 같은 리랭커(Reranker)를 통해 '가장 관련성이 높은 문서'를 Layer 3의 선두와 말단(버퍼의 양 끝)에 재배치하는 테크닉이 매우 효과적입니다.
이번에는 장문 LLM 시대에 AI의 정밀도 저하를 일으키는 'Lost in the Middle 현상'의 이론적 배경과, 이를 구조적으로 타파하는 Context Engineering의 4층 레이어 설계, 그리고 tiktoken을 활용한 동적 컨텍스트 매니저(Dynamic Context Manager)의 Python 구현을 해설했습니다.
단순히 프롬프트의 문구를 수정하는 단계를 넘어, 토큰 수와 어텐션(Attention) 구조를 계산한 시스템 설계를 수행함으로써 비용 절감과 정밀도 향상을 동시에 얻을 수 있다는 점을 실감하셨으리라 생각합니다.
하지만 문맥을 완벽하게 정리하더라도, 외부 데이터에서 정보를 가져오는 'RAG (검색 증강 생성)'의 검색 쿼리 자체가 미흡할 경우, 애초에 잘못된 문서가 Layer 3로 흘러 들어가게 됩니다. 단 한 번의 검색에 의존하는 기존의 RAG에는 한계가 있습니다.
다음, 제4회.
검색 쿼리를 에이전트(Agent) 스스로가 자율적으로 수정하고, 답변에 할루시네이션(Hallucination)이 없는지 자기 평가하여 재시도하는 고도의 검색 루프, **『Agentic RAG의 실전: Self-RAG와 쿼리 자율 재생성·자기 평가 루프』**로 이어집니다.
검색과 생성의 루프를 자율 제어하며 100%에 가까운 답변 정밀도를 뽑아내는 차세대 RAG의 비결로 나아가 봅시다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Qiita AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기