컨텍스트 엔지니어링, 프롬프트 튜닝 다음에 오는 것
- 1. 하네스 엔지니어링, AI 에이전트에 고삐를 채우는 기술
- 2. 컨텍스트 엔지니어링, 프롬프트 튜닝 다음에 오는 것
2023년쯤에는 “프롬프트 엔지니어링”이 이력서 한 줄에 올릴 만한 스킬이었다. “Let’s think step by step”을 붙이느냐 마느냐로 답변 품질이 갈리던 시기. 그로부터 2년쯤 지난 지금, 같은 단어가 좀 낡아 보인다. Claude Code, Codex, Gemini CLI 같은 에이전트가 일상 도구가 되면서, 개발자가 실제로 고민하는 문제가 바뀌었기 때문이다.
프롬프트 한 문장을 다듬는 대신, 에이전트가 들어와서 일할 “작업 환경”을 어떻게 설계할지가 더 중요해졌다. 이 글에서는 그 작업을 컨텍스트 엔지니어링이라는 이름으로 정리해본다. 한국어 자료가 아직 많지 않은 주제라, 내가 쓰면서 정리한 내용을 남기는 쪽이다.
1편 하네스 엔지니어링에서는 정체성, 도구 권한, 컨텍스트, 메모리, 오케스트레이션, 모듈화를 묶어 에이전트를 소프트웨어처럼 다루는 큰 그림을 다뤘다. 그중 “컨텍스트 설계” 축만 따로 떼서 깊게 파는 글이 이번 편이다.
프롬프트 엔지니어링만으로는 왜 모자란가
프롬프트 엔지니어링은 “한 번의 chat completion”을 잘 뽑아내기 위한 튜닝이었다. 입력 한 번, 출력 한 번. 이 좁은 창에서 단어 선택, 예시 배치, 역할 부여 따위로 결과를 끌어올리는 기술이다.
에이전트가 도는 환경은 다르다. 실제 세션 한 판을 보자.
- 에이전트가
ls로 디렉토리를 훑는다 README.md와package.json을 읽는다- 소스 파일 몇 개를 골라 읽는다
- 변경안을 제안하고, 테스트를 돌리고, 실패하면 다시 읽는다
- 커밋을 만들거나 사용자에게 확인을 묻는다
이 루프 동안 모델 호출은 수십 번 발생한다. 각 호출의 시스템 메시지는 비슷하지만, 매번 다른 도구 출력이 붙는다. 이때 “프롬프트”가 결과에 미치는 영향은 생각보다 작다. 더 큰 영향은 “에이전트가 어떤 파일을 어떤 순서로 읽었는가”, “워크스페이스에 어떤 문서가 놓여 있었는가”, “쓸데없는 파일을 읽지 않도록 막혀 있었는가”에서 온다.
한 번의 호출을 튜닝하는 것에서, 루프 전체의 정보 흐름을 설계하는 쪽으로 무게가 옮겨간 것이다.
컨텍스트 엔지니어링이란
컨텍스트 엔지니어링을 한 줄로 정의하면, 에이전트가 “무엇을, 얼마만큼, 어떤 순서로 보게 할 것인가”를 설계하는 일이다. 프롬프트 엔지니어링과 결이 다르다.
| 프롬프트 엔지니어링 | 컨텍스트 엔지니어링 | |
|---|---|---|
| 대상 | 한 번의 호출 | 에이전트 루프 전체 |
| 주요 산출물 | 잘 다듬은 프롬프트 문자열 | 워크스페이스 문서, ignore 설정, 도구 정책 |
| 비유 | 카피라이팅 | 정보 아키텍처 |
| 성공 지표 | 답변 품질 | 작업 완주율, 토큰 효율 |
| 실패 모드 | 어색한 답변 | 엉뚱한 파일 수정, 컨텍스트 초과, 루프 진동 |
프롬프트 엔지니어링이 카피라이팅에 가깝다면, 컨텍스트 엔지니어링은 라이브러리 사서의 일에 가깝다. 어떤 자료를 어디에 배치하고, 어떤 자료는 서고에 넣어두고 요청이 올 때만 꺼내고, 어떤 자료는 열람 자체를 막을지 설계한다.
다섯 가지 핵심 스킬
여기서부터가 이 글의 본 내용이다. 실무에서 컨텍스트 엔지니어링을 하려면 결국 다음 다섯 가지를 다룰 수 있어야 한다.
(1) 컨텍스트 윈도우 예산 관리
모델의 컨텍스트 윈도우가 200K, 1M 토큰으로 늘어나면서 “무제한으로 넣으면 되지”라는 유혹이 생긴다. 그런데 윈도우 크기와 “실효 사용 구간”은 다르다.
긴 컨텍스트에서 모델이 중간 부분을 놓치는 현상은 꽤 잘 알려져 있다(lost in the middle). 앞쪽과 뒤쪽 정보는 잘 쓰지만, 가운데 끼어 있는 내용은 있어도 없는 것처럼 무시되는 식이다. 1편에서 짧게 언급만 하고 지나간 현상인데, 실전에서는 이것 하나로 답변이 어긋나는 경우가 꽤 있다.
예산 관리의 실제 행동은 세 가지로 나뉜다.
첫째, 상주시킬 정보와 on-demand로 가져올 정보를 구분한다. 에이전트가 매 호출마다 필요한 것(프로젝트 규칙, 주요 디렉토리 맵)은 시스템 메시지 계열에 두고, 상황에 따라 필요한 것(특정 모듈 구현)은 파일을 열게 시킨다.
둘째, 긴 세션에서 주기적으로 요약/압축을 넣는다. Claude Code 같은 도구는 기본으로 자동 컴팩션을 돌리지만, 수동으로도 “여기까지를 한 단락으로 요약해”를 넣어 메모리를 정리하는 게 좋다.
셋째, 툴 응답을 가지치기한다. ls -R로 만 개짜리 파일 목록을 그대로 넣어두면 윈도우가 증발한다. 에이전트에게 “필요한 디렉토리만 열어서 보라”고 유도하는 게 훨씬 싸다.
# Claude Code 세션 힌트 예시
- 저장소 전체 트리를 한 번에 훑지 말 것. 필요한 디렉토리만 `ls`.
- 큰 파일(>2K 라인)은 필요한 범위를 grep/sed로 좁혀서 읽을 것.
- 한 작업이 끝나면 "지금까지 요약" 한 단락을 남기고 다음 단계로 넘어갈 것.이 정도만 워크스페이스 규칙 문서에 박아둬도 장기 세션의 토큰 지출이 체감 수준으로 내려간다.
(2) 에이전트용 정보 아키텍처
사람이 읽는 문서와 에이전트가 읽는 문서는 목적이 다르다. 사람은 스토리텔링과 맥락을 따라간다. 에이전트는 “이 파일이 무엇을 위한 것이고, 지금 내가 어떤 액션을 해야 하는가”를 빠르게 추출해야 한다.
그래서 에이전트용 문서는 이렇게 쓰는 게 좋다.
- 파일 맨 앞에 한 줄 메타. “이 문서는 무엇을 위한 것인가”
- 명령형 액션 지시. “만약 X라면 Y를 실행한다” 식
- 얕고 넓은 헤더 구조. 계층을 너무 깊게 파면 모델이 섹션 간 관계를 잃는다
- 예시는 실제로 실행 가능한 코드/명령으로
한 저장소 안에서 문서가 많아지면 루트에 CLAUDE.md 하나를 놓고, 서브디렉토리별 보조 문서를 두는 구조가 편하다. 루트 문서에는 “프로젝트 전체에 적용되는 규칙”만, 서브디렉토리 문서에는 “이 디렉토리에 들어올 때만 필요한 규칙”을 둔다. 전역과 로컬을 분리하는 개념이다.
(3) CLAUDE.md / AGENTS.md 마스터리
CLAUDE.md(또는 에이전트 중립적으로 쓰고 싶다면 AGENTS.md)는 에이전트에게 주는 입장 오리엔테이션이다. 세션이 시작될 때 자동으로 로드돼서, “너는 이 프로젝트에서 이렇게 행동하면 된다”는 규칙을 박아준다.
실전에서 자주 쓰는 구조는 이렇다.
# CLAUDE.md
## 프로젝트 개요
주문 처리 API 서비스. Go 1.22 + gRPC. PostgreSQL 14, Redis 7.
## 디렉토리 맵
- `cmd/api`: 서비스 엔트리포인트
- `internal/order`: 주문 도메인 로직
- `internal/payment`: 결제 연동 어댑터
- `pkg/proto`: 공유 protobuf 정의
- `migrations/`: DB 마이그레이션. golang-migrate 포맷
## 자주 쓰는 명령
- 개발 서버: `make dev`
- 유닛 테스트: `make test`
- 통합 테스트(DB 띄움): `make integration`
- 마이그레이션 생성: `make migrate-create name=<설명>`
- 프로토 코드 생성: `make proto`
## 컨벤션
- 에러 래핑은 `errors.Wrap` 금지. `fmt.Errorf("%w", err)`로 통일
- 구조체 필드 태그 순서: `json`, `db`, `validate`
- 로그는 구조화 로그. `slog` 외 로거 사용 금지
## 금지 사항
- `migrations/` 기존 파일 수정 금지. 새 파일 생성만
- `pkg/proto/*.pb.go` 수동 편집 금지. `make proto`로만 갱신
- `internal/*` 도메인 간 직접 참조 금지. 인터페이스 경유
## 아키텍처 결정 맥락
- 결제 어댑터는 pluggable 구조. PG 한 곳에 묶이지 않게 설계
- 이벤트 발행은 outbox 패턴. Kafka 직접 호출 금지
- 인증은 Keycloak. 서비스 안에 사용자 테이블을 별도로 두지 않는다각 섹션이 하는 일이 명확하다. “디렉토리 맵”은 에이전트가 코드베이스를 탐색할 때 드는 비용을 줄이고, “자주 쓰는 명령”은 실행할 때 머뭇거리지 않게 하고, “금지 사항”은 사고를 예방한다. 맨 아래 “아키텍처 결정 맥락”은 초보적인 실수(예: “결제 PG를 바꿀 겸 모듈을 하나로 합치겠습니다”)를 막아준다.
안티패턴도 몇 가지 짚고 간다.
- 너무 긴 문서. 500줄짜리
CLAUDE.md를 만들면 에이전트가 그 안을 다 못 본다. 300줄 이내를 목표로 하고, 넘치면 서브디렉토리 문서로 분리한다 - 바뀌지 않는 것들을 매번 다시 설명. “Git은 버전 관리 시스템이다” 같은 상식은 넣지 않는다
- 액션 없는 추상론. “코드를 깔끔하게 짜주세요”는 아무 효과가 없다. “함수는 60줄 이내, 줄 넘으면 분리” 같이 기계가 지킬 수 있는 규칙으로 쓴다
Claude Code 외 에이전트와의 호환은 AGENTS.md라는 사실상 표준이 형성되는 중이다. Cursor는 .cursor/rules/*.mdc, Codex는 루트 AGENTS.md를 기본으로 찾고, Claude Code도 CLAUDE.md와 함께 AGENTS.md를 읽도록 세팅할 수 있다. 팀이 여러 에이전트를 섞어 쓰고 있다면 AGENTS.md를 단일 소스로 두는 편이 포팅 비용이 낮다.
(4) .claudeignore 최적화
에이전트가 “보지 않아야 할 것”을 설계하는 것도 컨텍스트 엔지니어링의 일부다. 이게 빠진 저장소를 Claude Code에 열면, 에이전트가 node_modules나 build/ 하위를 굳이 훑다가 토큰을 다 써버리는 광경을 볼 수 있다.
.claudeignore(또는 .aiignore, .cursorignore 등 도구별 이름)는 이걸 막는 파일이다. 문법은 대체로 .gitignore와 같다.
# .claudeignore 예시
# 패키지 산출물
node_modules/
dist/
build/
.next/
.vite/
# 대용량 바이너리/미디어 원본
static/videos/
*.psd
*.sketch
*.mp4
# 생성 가능한 코드
src/generated/
prisma/generated/
# 비밀 정보
.env
.env.*
*.key
secrets/
# 로그와 캐시
*.log
.cache/
coverage/.gitignore와의 관계는 겹치기도 하고 갈리기도 한다. 보통 .gitignore는 에이전트 입장에서도 읽으면 안 되는 것이 많아서(빌드 산출물, 비밀) 기본 골격을 복사해놓고 시작하면 편하다. 다만 .gitignore에는 안 들어가는데 에이전트에게는 무의미한 것들이 있다. 예를 들어 대형 목데이터 JSON이나 번역된 스크린샷 같은 것들. 이런 건 .claudeignore에만 추가한다.
반대로 .gitignore에는 들어가 있지만 에이전트가 보면 유용한 파일도 있다. .env.example 같은 것. 이건 .claudeignore에는 추가하지 않는다. “버전 관리에서 빠진다”와 “에이전트가 읽지 않는다”는 같은 개념이 아니다.
(5) 툴 접근 설계
에이전트가 쓰는 도구, 즉 셸, 파일시스템, 네트워크, MCP 서버의 권한 범위를 설계하는 일이다. 1편에서 “도구 권한 관리”로 한 번 짚었던 축인데, 컨텍스트 엔지니어링 관점에서 실행 레벨로 좀 더 들어가본다.
원칙은 최소권한이다. 주니어 엔지니어에게 처음부터 sudo를 주지 않듯, 에이전트에게도 처음부터 모든 셸 명령을 열어두지 않는다.
Claude Code의 permissions 설정을 예로 들면 이렇다.
{
"permissions": {
"allow": [
"Bash(git status:*)",
"Bash(git diff:*)",
"Bash(npm run build)",
"Bash(npm test:*)"
],
"deny": [
"Bash(rm -rf *)",
"Bash(git push:*)",
"Bash(npm publish:*)"
]
}
}자주 쓰지만 안전한 명령은 화이트리스트로 미리 열어 두고, 돌이킬 수 없는 명령(force push, publish, rm -rf)은 명시적으로 막는다. 회색지대에 있는 명령은 매번 확인을 받도록 기본값을 둔다.
MCP 서버를 쓴다면 도메인별로 쪼개서 붙이는 편이 안전하다. “DB를 읽고 쓰는 MCP”, “사내 문서 검색 MCP”, “Slack 전송 MCP”를 하나의 거대한 서버로 묶는 대신, 각각 별도 서버로 두고 워크스페이스마다 필요한 것만 활성화한다. 프론트엔드 작업을 하는데 DB MCP가 붙어 있을 필요는 없다.
실전에서 자주 보이는 실수는 이거다. 초기 셋업 때 “일단 다 열어두고 쓰자”고 타협한 뒤 그대로 굳는 것. 사고 한 번 터지고 나서야 뒤늦게 권한을 조인다. 초기 허들을 견디고 allow-list로 시작하는 편이, 길게 보면 고통이 적다.
실전 예시: 오픈소스 코드베이스 온보딩
새 오픈소스를 Claude Code에 맡겨 이해하는 시나리오를 놓고, before/after로 비교해본다.
맨 상태
그냥 claude 실행하고 “이 코드베이스 요약해줘”라고 한다.
cd some-oss-repo
claude
# > 이 코드베이스가 뭘 하는지 요약해줘에이전트는 루트의 파일을 아무 순서로나 읽기 시작한다. node_modules 안쪽까지 들여다볼 수도 있고, README를 보기 전에 무작위 소스 파일을 열 수도 있다. 답변은 그럴듯해 보이지만 피상적이다. 엔트리포인트가 어디인지, 빌드가 어떻게 돌아가는지는 놓치기 쉽다.
컨텍스트 엔지니어링 적용
먼저 .claudeignore를 넣는다. node_modules, 빌드 산출물, 큰 테스트 픽스처를 제외한다. 그 다음 CLAUDE.md 초안을 짧게 쓴다.
# CLAUDE.md
## 이 저장소는
<한 문단 요약>
## 엔트리포인트
- `src/main.ts`: CLI 실행점
- `src/server.ts`: HTTP 서버 실행점
## 빌드와 테스트
- 빌드: `pnpm build`
- 테스트: `pnpm test --run`
## 탐색 순서 힌트
1. `README.md`
2. `package.json`의 scripts
3. `src/main.ts`부터 호출 트리를 따라간다이 상태에서 같은 질문을 하면, 에이전트가 루틴처럼 돈다. README를 먼저 보고, package.json의 스크립트를 확인하고, 엔트리포인트로부터 호출 관계를 읽어내려간다. 토큰 지출도 적고, 답변이 훨씬 구체적이다. 중간에 긴 세션이 되면 “지금까지 요약”을 한 단락 남기라고 시켜두면 컨텍스트 예산이 잘 유지된다.
눈여겨볼 건, 이 전환 과정에서 새로 쓴 “프롬프트”는 하나도 없다는 점이다. 모두 워크스페이스의 정보 환경을 바꾼 것이다. 이게 컨텍스트 엔지니어링이다.
프롬프트 엔지니어링은 여전히 쓸모 있다
제목이 센 글이 많지만, 프롬프트 튜닝이 쓸모없어진 건 아니다. 한 번의 호출에서 중요한 디테일을 뽑아내는 능력은 여전히 가치 있다. 특히 사용자용 UX에 들어가는 LLM 호출, 예를 들어 챗봇의 응답 톤이나 요약 스타일 같은 건 결국 프롬프트로 제어된다.
다만 자율 에이전트 시스템에서는 프롬프트가 전체 결과 품질의 극히 일부만 차지한다. 외부 자료 중에는 “컨텍스트 엔지니어링이 프롬프트 엔지니어링보다 성능이 크게 앞선다”는 실험 결과를 제시하는 글도 있다. getbeam.dev에 따르면 복잡 태스크에서 성능 개선 폭이 프롬프트 튜닝보다 훨씬 크다는 주장이다. 숫자 자체를 확신체로 단정하기는 조심스럽지만, 현장 체감과 방향은 맞다.
두 기술은 대체재라기보단 계층이 다르다. 프롬프트 엔지니어링은 “한 호출을 잘 뽑는 기술”이고, 컨텍스트 엔지니어링은 “여러 호출이 일어나는 환경을 설계하는 기술”이다. 에이전트 시대에 후자의 비중이 올라갔을 뿐이다.
정리
컨텍스트 엔지니어링은 에이전트가 일할 환경을 설계하는 일이다. 토큰 예산을 어떻게 쓸지, 문서를 어떻게 배치할지, 무엇을 보게 하고 무엇을 가릴지, 어떤 도구를 어디까지 허용할지. 이 네 다섯 가지만 손에 익혀도 에이전트 활용 품질은 눈에 띄게 올라간다.
1편에서 본 하네스 엔지니어링의 여섯 축 중 하나를 풀어쓴 글이다. 나머지 축(툴 정책, 메모리 아키텍처, 멀티 에이전트 오케스트레이션)은 다음 시리즈에서 하나씩 이어갈 예정이다.
참고 자료
- Prompt Engineering is Dead. Context Engineering 5 Skills (getbeam.dev): 컨텍스트 엔지니어링 5가지 스킬을 체계적으로 정리한 글
- Context Engineering, the Post-Prompt Era (particula.tech): 9,649건 실험 기반으로 컨텍스트 설계 효과를 분석한 연구 요약
- Context Architecture Replaced Prompt Engineering (markaicode): 정보 아키텍처 관점에서 접근하는 컨텍스트 설계
- AI Context Engineering vs Prompt Engineering 2026 (contextarch.ai): 두 접근의 차이와 현장 적용 사례
- Manage Claude’s memory (Anthropic): Claude Code의 CLAUDE.md/AGENTS.md 로딩 구조 공식 문서
- Prompt caching (Anthropic): 시스템 프롬프트와 컨텍스트 재사용 시 토큰 비용을 줄이는 공식 가이드