Skip to content

9장. 컨텍스트 엔지니어링 #1847

Description

@jongfeel

CHAPTER 09 컨텍스트 엔지니어링

에이전트가 도구를 호출하고 여러 번의 대화를 이어 가면서 입력에 들어가는 내용은 사용자의 한 문장이 아니라 시스템 프롬프트, 도구 정의와 그 호출 결과, 이전 대화 기록, 외부 문서까지 뒤섞인 한 덩어리로 커졌습니다.

이렇게 불어난 입력을 의도적으로 설계하는 일을 ‘컨텍스트 엔지니어링’이라고 합니다.

컨텍스트 엔지니어링은 모델이 답을 잘 만들도록 필요한 정보는 넣고, 주의를 흩뜨리는 군더더기는 빼고, 같은 정보라도 더 잘 작동하는 자리에 배치하는 것입니다.
입력에 담을 수 있는 양은 정해져 있고 모든 토큰은 모델의 주의를 두고 경쟁하므로 무엇을 넣을지만큼이나 무엇을 빼고 어디에 둘지가 결과를 가릅니다.
그런 의미에서 컨텍스트 엔지니어링이란 모델에 건넬 단 하나의 입력을 의도적으로 조립하는 기술입니다.

9.1 컨텍스트 엔지니어링이란 무엇인가?

프롬프트가 ‘AI에 건네는 한마디’라면, 컨텍스트는 ‘AI가 놓인 전체 환경’입니다.

모델의 능력은 고정되어 있지만, 컨텍스트는 우리가 설계할 수 있습니다.
컨텍스트 엔지니어링은 그 설계 기술입니다.

컨텍스트 엔지니어링은 프롬프트 엔지니어링을 대체하는 개념이 아니라 포함하는 개념입니다.
좋은 프롬프트를 쓰는 일은 여전히 컨텍스트 설계의 한 부분입니다.

9.2 컨텍스트의 구성 요소

9.2.1 시스템 프롬프트

시스템 프롬프트는 컨텍스트 윈도우의 가장 앞자리를 차지하는 영역으로, 에이전트의 정체성과 행동 원칙을 선언하는 자리입니다.
사용자의 매 요청마다 가장 먼저 처리되며, 대화가 길어져도 흔들리지 않는 ‘뿌리’와 같은 역할을 합니다.

에이전트의 정체성과 행동 원칙 정의

시스템 프롬프트는 에이전트의 헌법과 같습니다.
“너는 누구고, 무엇을 해야 하며, 무엇을 해서는 안 되는가”를 모델에 선언하는 영역입니다.

  • 역할(role)
  • 행동 원칙(principle)
  • 제약 조건(constraint)

CLAUDE.md 파일이 컨텍스트에 로드되는 방식

로드 우선순위는 다음과 같습니다.

  • 전역 설정: ~/.claude/CLAUDE.md
  • 프로젝트 루트: ./CLAUDE.md
  • 하위 디렉터리: src/CLAUDE.md 등(해당 경로 작업 시)

9.2.2 도구 실행 결과

에이전트가 도구를 호출하면 그 결과는 사라지지 않고 대화 히스토리 안에 누적됩니다.
‘한 번 읽은 파일의 내용, 한 번 실행한 명령의 출력, 한 번 검색한 결과’ 이 모든 것이 ‘이미 본 것’으로 컨텍스트 안에 남아 다음 추론의 재료가 됩니다.

도구 출력이 컨텍스트에 쌓이는 구조

도구 결과 메시지는 일반 사용자 메시지와 동등한 자격으로 컨텍스트를 차지하기 때문에 한 번 들어온 잡음은 명시적으로 정리하지 않는 한 세션이 끝날 때까지 모든 추론에 영향을 미칩니다.
이것이 도구 호출이 강력한 동시에 위험한 이유입니다.
대용량 결과가 한두 번만 쌓여도 컨텍스트 윈도우의 상당 부분이 채워지고, 정작 중요한 추론에 쓸 공간은 줄어듭니다.

도구 결과를 압축하는 세 가지 방법

첫째, 도구 호출 단계에서 범위를 제한합니다.
Read 도구의 offset/limit 파라미터처럼 처음부터 필요한 부분만 가져옵니다.
클로드 코드는 기본적으로 큰 파일을 페이지 단위로 잘라 읽도록 설계되어 있습니다.

둘째, 파이프 가공으로 핵심만 추출합니다.
grep, head, tail, jq 같은 명령어로 1차 가공한 결과만 컨텍스트에 넣습니다.

셋째, 세션 중 명시적으로 정리합니다.
더 이상 참조할 필요가 없는 큰 도구 결과는 /compact로 요약 정리하거나 작업 맥락 자체가 끝났다면 /clear로 비웁니다.

9.2.3 외부 문서

외부 문서를 활용하는 방법은 세 가지입니다.

첫째, 매 세션마다 PDF를 직접 첨부하는 방식입니다.
둘째, PDF를 마크다운으로 추출하여 프로젝트 안에 두고 에이전틱 검색에 맡기는 방식입니다.
셋째, RAG 파이프라인을 구축하는 방식입니다.

pdf를 마크다운으로 전환해야 하는 이유

마크다운은 형식 자체의 이점도 큽니다.
같은 내용이라도 이미지로 읽히는 PDF가 페이지당 약 1,600토큰인 데 비해 마크다운 텍스트는 수백 토큰 수준이라 4~8배 저렴합니다.
또한 #, -, | 같은 기호로 문서의 위계가 명시적으로 드러나 모델이 레이아웃을 추측하지 않아도 되고 그만큼 노이즈가 줄어듭니다.

이런 이유로 약간의 손실을 감수하더라도 PDF를 그대로 두기보다 마크다운으로 변환해 두는 편이 낫습니다.

9.2.4 현재 상태: 파일과 코드 그리고 외부 문서

클로드 코드가 컨텍스트를 읽는 방식

클로드 코드는 세션 시작 시 프로젝트 루트를 기준으로 컨텍스트를 탐색합니다.
단 모든 파일을 한 번에 컨텍스트에 적재하지는 않습니다.
그 대신 다음과 같이 필요한 시점에 필요한 정보만 선택적으로 읽어 옵니다.

  1. 프로젝트 루트의 CLAUDE.md 로드
  2. package.json/pyproject.toml 등 핵심 설정 파일 확인
  3. 디렉터리 구조 파악(파일 트리 탐색)
  4. 사용자 요청과 관련된 특정 파일만 선택적으로 read_file
  5. 필요 시 터미널 명령 실행 후 출력 결과를 컨텍스트에 삽입

9.3 컨텍스트 선택과 설계 패턴

9.3.1 무엇을 넣을 것인가?

컨텍스트 설계의 첫 번째 질문은 항상 “이것을 정말 넣어야 하는가?”입니다.

관련성(relevance) 판단 기준

  • 이 정보가 없으면 모델이 틀린 답을 낼 가능성이 있는가? → 없어도 답을 낼 수 있다면 포함을 재검토합니다.
  • 이 정보는 현재 태스크에 직접적으로 연결되는가? → 간접적으로 유용한 배경지식은 노이즈가 될 수 있습니다.
  • 이 정보가 없을 때 모델이 스스로 합리적으로 추론할 수 있는가? → 모델이 충분히 추론 가능한 내용이라면 굳이 명시하지 않아도 됩니다.

세 질문 모두 “아니요.”로 답했다면 해당 정보는 컨텍스트에서 제거 대상입니다.

작업 유형별 필수 컨텍스트 목록

  • 버그 수정: 에러 메시지, 관련 파일, 재현 절차
  • 신규 기능 구현: 요구 사항, 인접 코드, 컨벤션(CLAUDE.md)
  • 리팩터링: 대상 코드 전체, 테스트 케이스, 사용처
  • 문서화: 대상 코드, 작성 톤·스타일 가이드
  • 코드 리뷰: 변경 diff, 코딩 컨벤션

9.3.2 위치 전략: 어디에 놓을 것인가

앞부분과 뒷부분에 있는 정보는 더 강하게 참조하고, 한가운데에 끼어 있는 정보는 상대적으로 흘려보냅니다.

이것은 그저 경험으로 알아낸 요령이 아니라 LLM이 텍스트를 처리하는 구조 자체에서 비롯된 특성입니다.

트랜스포머와 어텐션 메커니즘

요즘 LLM은 거의 다 '트랜스포머(transformer)'라는 구조 위에서 동작합니다.
트랜스포머의 핵심은 '어텐션(attention) 메커니즘'인데, 쉽게 말해 '문장 안에서 어느 단어에 얼마나 집중해서 볼지를 계산하는 방식'입니다.
그런데 이 어텐션이 입력 시퀀스의 앞쪽과 끝쪽에 실제 정보의 관련성과 무관하게 더 높은 가중치를 부여하는 U자형 편향을 보인다는 사실이 여러 연구에서 확인되었고, 이것이 Lost in the Middle 현상의 주요 원인 중 하나로 지목됩니다.

바늘 찾기(needle in a haystack) 벤치마크

긴 컨텍스트의 어딘가에 특정 정보를 한 줄 숨겨 두고, 모델이 그것을 정확히 찾아내는지 측정하는 테스트입니다.
정보를 컨텍스트의 앞·중간·뒤 어디에 두느냐를 바꾸어 가며 정확도를 비교하면 모델이 위치에 얼마나 민감한지 한눈에 드러납니다.

9.3.3 계층형 컨텍스트 설계

계층형 컨텍스트는 크게 세 단계로 구성됩니다.

  1. 전역(Global) 계층: 모든 작업에 공통으로 적용되는 불변의 규칙입니다.
  • AI 에이전트의 페르소나 및 역할 정의
  • 절대로 해서는 안 되는 행동 목록
  • 출력 언어 및 기본 포맷 규칙
  • 보안 및 윤리 제약 조건
  1. 프로젝트(Project) 계층: 특정 프로젝트나 도메인에만 적용되는 규칙입니다.
  • 프로젝트의 기술 스택 및 아키텍처 개요
  • 코딩 컨벤션 및 네이밍 규칙
  • 프로젝트 특유의 도메인 용어 사전
  1. 작업(Task) 계층: 현재 실행 중인 단일 작업에만 필요한 정보입니다.
  • 현재 처리 중인 파일 또는 코드 스니펫
  • 직전 에러 메시지
  • 사용자의 즉각적인 요청 사항
  • 현재 태스크의 출력 형식 지정
  • CLAUDE.md의 계층 설계

9.4 컨텍스트 오염

9.4.1 컨텍스트 오염이란

컨텍스트 오염(context rot)이란 모델의 현재 판단과 행동에 부정적인 영향을 미치는 잘못되거나 불필요한 정보가 컨텍스트 안에 축적된 상태를 가리킵니다.

잘못된 정보가 끼어드는 세 가지 경로

경로 1: 역사적 잔재(historical residue)

멀티턴 대화에서 이전 턴의 모든 내용이 다음 요청의 입력으로 그대로 포함됩니다.

경로 2: 도구 결과 오염(tool result contamination)

에이전틱 워크플로에서 도구의 반환 값은 그대로 컨텍스트에 삽입됩니다.

경로 3: 사용자 입력 혼선(user input interference)

사용자가 맥락 없이 추가하는 즉흥적인 지시, 서로 모순되는 요구 사항, 혹은 이전 작업과 무관한 새로운 작업이 같은 세션에서 섞이면 컨텍스트가 오염됩니다.

오염된 컨텍스트가 만드는 버그 패턴

  • 이미 삭제한 코드를 다시 참조하거나 수정 제안 -> 예전 상태가 컨텍스트에 잔존
  • 명시적으로 거부한 라이브러리나 접근법을 재추천 -> 이전 시도의 잔재가 현재 판단에 개입
  • 대화 초반에 설정한 제약 조건을 후반에 무시 -> 컨텍스트 로트(context rot)로 초기 지시 가중치 감소
  • 같은 메시지 안에서 앞뒤 모순된 응답 -> 서로 충돌하는 컨텍스트 조각들이 경쟁

9.4.2 오염 사례 분석

사례 1: 이전 작업의 잔여 컨텍스트가 다음 작업을 망치는 경우

가장 흔하게 마주치는 사례입니다.
결제 모듈의 버그를 수정하는 긴 디버깅 세션을 마친 직후 같은 세션에서 인증 모듈 리팩터링을 시작한다고 가정합니다.

사례 2: 도구 결과의 오류가 연쇄 실패를 일으키는 경우

도구 결과는 컨텍스트에 그대로 삽입되기 때문에 잘못된 결과 하나가 이후 모든 추론의 전제를 오염시킵니다.

사례 3: 사용자 입력이 의도치 않게 지시를 덮어쓰는 경우

LLM은 가장 최근 입력에 더 무게를 두는 경향이 있습니다. 이 특성은 짧은 한마디만으로도 세션 초반에 못 박아 둔 강한 제약을 무력화시킬 수 있습니다.

사용자가 “빨리”라고 말하는 순간 이전에 설정한 제약은 암묵적으로 희석됩니다.
클로드 코드의 잘못이 아니라, 가장 최근 사용자 의도가 이전 지시보다 강한 신호로 해석된 결과입니다.

9.4.3 컨텍스트 리셋 전략

현재 컨텍스트의 상태부터 확인하기

/context 명령어로 시스템 프롬프트, MCP 도구 정의, 대화 히스토리, 파일 중 어떤 항목이 토큰을 가장 많이 차지하는지 확인할 수 있습니다.

부분 리셋 vs 완전 리셋의 선택 기준

부분 리셋: /compact 명령어

/compact 명령어는 현재 대화 내역을 요약하여 압축된 형태로 대체합니다.

완전 리셋: /clear 명령어

/clear 명령어는 현재 세션의 대화 기록을 완전히 초기화합니다.

작업 단위 기반 리셋

‘정리 → 비우기 → 다시 읽기’ 세 단계를 사용자가 명시적으로 제어하는 Document & Clear 패턴입니다.

이 방식이 단순한 /compact 명령어보다 우월한 지점이 두 가지 있습니다.
첫째, 압축된 결과가 모델의 요약 알고리즘이 아니라 사용자가 지정한 형식으로 남습니다.
둘째, 결과가 파일로 남기 때문에 세션이 끊겨도, 며칠 뒤에 재개해도, 팀원에게 인계해도 그대로 쓸 수 있습니다.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Projects

Relationships

None yet

Development

No branches or pull requests

Issue actions