본문으로 건너뛰기

© 2026 Molayo

Qiita헤드라인2026. 06. 24. 06:22

Claude Code가 '폐기된' 설계를 반복적으로 부활시키는 현상 방지하기 — 컨텍스트 엔지니어링으로 해결

요약

Claude Code 사용 시 발생하는 '컨텍스트 드리프트(context drift)' 현상과 이를 해결하기 위한 컨텍스트 엔지니어링 전략을 다룹니다. 단순히 많은 정보를 제공하는 것이 아니라, 정보의 상태(현재/폐기/미결)를 명확히 구분하여 최소한의 고신호 정보만 전달하는 것이 핵심입니다.

핵심 포인트

  • 컨텍스트 드리프트: 폐기된 설계나 오래된 전제를 LLM이 다시 사용하는 현상
  • 컨텍스트 파일의 역설: 과도한 컨텍스트는 성공률을 낮추고 비용을 증가시킴
  • 컨텍스트 엔지니어링: 양보다 정보의 질과 상태(status)를 관리하는 것이 중요
  • 스펙 기반 개발: 정보에 지위를 부여하여 LLM이 현재 사양을 명확히 구분하게 함

반나절을 들여 Claude Code와 이렇게 결정했다. '사용자의 주소는 서버에 저장하지 않는다. 클라이언트 측에서만 처리한다.' 이유도 적었고, ADR(Architecture Decision Record)도 남겼다. 만족하며 세션을 종료했다.

세션이 3번 정도 지난 후에야 Claude Code는 아무 일 없었다는 듯, 서버 측에 주소를 저장하는 구현을 작성하기 시작했다.

폐기했던 설계가 되살아나고 있다.

이 현상에는 지금 이름이 붙어 있다. **context drift (컨텍스트 드리프트)**다. 같은 경험을 하지 않았나요? 자세히 보면, 항상 비슷한 네 가지 형태를 띠고 있습니다.

  • 폐안의 부활 — 한 번 폐기한 안건을 현재 안건인 것처럼 다시 작성함 -
  • 미결정된 확정화 — 아직 결정하지 않은 것을 이미 결정된 것처럼 구현함 -
  • 사양과 구현의 혼동 — '이렇게 작동해야 한다'와 '이렇게 쓰여 있다'를 혼동함 -
  • 오래된 전제의 채택 — 이미 바뀐 전제를 여전히 살아있는 것인 양 사용함

그리고 많은 사람이 처음으로 같은 대책을 세웁니다. '잊어버릴 거면, 전부 CLAUDE.md / AGENTS.md에 적어두면 된다'라고요.

이것이 실증적으로 역효과라는 이야기부터 시작하겠습니다.

2026년 2월, ETH Zürich와 LogicStar.ai가 이 직감을 정면으로 검증했습니다(arXiv:2602.11988). 공개 직후 Hacker News에서 확산되었기 때문에 본 적이 있는 사람도 있을 것입니다.

그들은 실제 리포지토리에서 가져온 138개의 태스크로 AGENTBENCH를 구성하고, 네 가지 프론티어 모델을 세 가지 조건(컨텍스트 파일 없음 / LLM 생성 있음 / 개발자 수기 작성 있음)으로 구동했습니다.

결과는 이렇습니다. 컨텍스트 파일이 있는 쪽이 아무것도 없을 때보다 태스크 성공률을 낮추고, 추론 비용을 20% 이상 증가시키는 경향을 보였습니다. 개발자가 손으로 작성한 파일조차도 성적 개선에 거의 도움이 되지 않았습니다.

'리포지토리의 지식을 많이 담아줄수록 더 똑똑해진다'는 벤더사들의 권장 사항은, 적어도 순수한 형태로는 성립하지 않습니다. 많이 붙일수록 서툴러지고, 주머니도 아파집니다.

여기서 사고방식을 전환해야 합니다. 문제는 양(量)이 아닙니다.

2024년은 프롬프트 엔지니어링의 해였습니다. 2026년, 그 자리를 차지한 것이 컨텍스트 엔지니어링입니다. 핵심 발견은 간단합니다. '컨텍스트가 많을수록 좋은 것은 아니다. 최소한으로 고신호(high signal)인 집합으로 좁힐수록 좋다.'

그렇다면 왜 Claude Code는 폐안을 부활시키는 걸까요? 답은 이렇습니다.

당신의 리포지토리 안에서, 현재 사양도, 폐기된 제안도, 미결 논점도, 단순한 조사 메모도 전부 '같은 모양・같은 단위'로 나열되어 있기 때문입니다.

사람이 나중에 읽어도 무엇이 현재이고 무엇이 죽었는지 알 수 없습니다. 지위(현재인지, 폐안인지, 미결인지)가 문서 어디에도 쓰여 있지 않습니다. 인간이 구별할 수 없는 것은 LLM도 구별하지 못합니다. 그래서 LLM은 오래된 로그나 죽은 제안을 건져서 현재 사양으로 재채택하는 것입니다.

여기 효과적인 시각을 하나 제시합니다.

문서는 자산이 아니라,

부채입니다.

생성 비용은 거의 0에 가까워졌습니다. 하지만 읽고, 유지보수하고, 신뢰하는 비용은 인간에게 계속 남아 있습니다. 해야 할 일은 '많이 써서 전부 읽게 하는 것'이 아니라, 각 정보에 지위를 부여하여 추적 가능하게 만들고, LLM에게는 최소한만 전달하는 것입니다.

여기서 보통은 '전용 플러그인을 패키징해서 배포한다'로 가고 싶어집니다. 한 번 시도했다가 포기했습니다. 리포지토리는 하나하나 다릅니다. 딱딱하게 포장된 물건보다, 각 프로젝트에 맞춰 조합되는 '설계서'가 더 효과적입니다.

이것은 유행어로 말하자면 스펙 기반 개발(spec-driven development) 그 자체입니다. 구호는

레이어성질비유담당
Hook결정론적 (Deterministic). 매번 반드시 실행됨Linter / CI불변 조건의 기계적 강제
Skill확률적 (Probabilistic). 문맥에 따라 모델이 판단전문 지식을 가진 파트너절차와 판단의 지원
CLAUDE.md상시 투입. 매 턴 읽힘안내 데스크의 안내도얇은 라우터 (지식을 쌓아두지 않음)

퇴행 (context drift)을 "부탁 기반"으로 막는 것을 그만두어야 한다. 결정론적으로 지킬 수 있는 것은 Hook이 기계적으로 지키고, 판단이 필요한 것만 Skill에 맡긴다. 그리고 양자는 동일한 하나의 사양을 참조한다 (규칙을 이중으로 가지지 않는다). 구체적인 방법은 4가지다.

상태(status)는 자유어를 금지하고, 통제된 7개 단어만 사용한다. 자유롭게 늘리면 기계적 검증도 인간의 탐색성도 즉시 무너진다.

의미
draft초안. 아직 현행이 아님
proposed제안 중. 승인 대기 중
current현행. 현재의 진실
deprecated폐안. 철회됨
superseded후속 버전이 있어 대체됨
archived퇴역. 증적(evidence)으로서 보관
open미결. 결정되지 않음

각 문서의 상단에 최소한의 YAML을 배치한다. 필수 항목은 의도적으로 제한한다 (너무 많으면 반드시 형식적으로 변한다).

---
id: SPEC-014
title: 환불 정책
...

이것이 "CI에서 Linter를 돌려 메타데이터 누락이나 죽은 참조(dead reference)를 빌드 에러로 걸러내는" 실체다. Claude가 문서를 수정한 직후에, 수정된 파일만 검증한다 (단일 파일이므로 빠르다). 위반 사항이 있으면 턴을 중단하지 않고 Claude에게 지적을 돌려주어 수정하게 한다.

스크립트는 표준 라이브러리만 사용하여 작성한다. pip install이 필요한 시점에서 "어디서든 실행 가능함"을 잃기 때문이다. 본질만 추출하면 이것만으로 작동한다.

#!/usr/bin/env python3
# .claude/scripts/docs-linter.py — PostToolUse Hook 이 stdin으로 받는 파일
import json, sys, re
...

실제로는 여기에 "참조 대상 ID가 실재하는지 (dead link 탐지)", "type과 폴더가 일치하는지"를 추가한다. continueOnBlock: true가 핵심이다. Claude를 멈추는 것이 아니라 지적 사항을 tool_result로 반환한다. Claude는 이를 읽고 스스로 수정 및 재시도한다. 인간이 개입하지 않아도 품질이 한 단계 올라간다.

퇴역한 문서 (/99-archive)는 불변의 증적이다. 편집이 가능해지면 그로부터 context drift가 발생한다. ADR(Architecture Decision Record)도 마찬가지로 **추가형(append-only)**으로 작성한다. 내용을 뒤집을 때는 오래된 ADR을 삭제하는 것이 아니라, 새로운 ADR을 만들고 구 ADR에 superseded_by를 붙인다. 이것은 판단이 아니라 규율이므로, PreToolUse Hook이 대상 경로에 대한 편집을 deny하기만 하면 된다. "과거로 돌아가는" 사고가 물리적으로 발생할 수 없게 된다.

이 부분이 가장 실수하기 쉽지만 효과적이다.

퇴행을 방지하기 위해 확정된 사실, 비목표, 철회 사항을 매 세션마다 주입하고 싶어질 것이다. 맞는 말이다. 하지만 철회된 안의 "본문"을 전달해서는 안 된다. 폐안된 내용의 본문을 읽게 하면, 그 내용 자체가 부활의 연료가 된다. 전달하는 것은 "이것은 철회됨 / 철회일 / 후속은 이것임"이라는 사실의 라벨뿐이어야 한다.

그리고 ETH의 논문처럼, 여기서도 최소한을 고수한다. SessionStart Hook에서 흘려보내는 것은 확정된 사실, 비목표, 철회 사항(사실만), 퇴행 모니터링 리스트의 요점뿐이다. 본문 전체가 아니라 불렛 포인트 형태의 요점만 넣는다. CLAUDE.md 본체는 지식을 저장하는 곳이 아니라, 입구로 향하는 링크만을 나열한 얇은 라우터 상태로 유지한다.

# CLAUDE.md (얇은 라우터)
이 리포지토리의 정보 통치는 /docs에 있다. 여기에는 지식을 쌓아두지 않는다.
## 먼저 읽을 것 (상시)
...

태스크 고유의 깊은 내용은 모두 링크된 곳에 둔다. 상시 투입되는 것은 확정된 사실뿐이다. 이를 통해 CLAUDE.md의 비대로 인한 성능 저하와 비용 증가를 피할 수 있다.

여기까지 자신 있게 써 내려왔지만, 효능의 범위를 속이고 싶지는 않다. 공유할 가치가 있는지 여부는 아마 여기서 결정될 것이다.

구조와 Hook을 통해 탐지 및 조기 발견할 수 있는 것은 메타데이터 누락, 상태 이탈, dead link, 아카이브에 대한 편집, 폐기된 안의 지속적인 부재로 인한 퇴행(regression) 정도다.

반면, 구조만으로는 해결할 수 없는 영역도 분명히 존재한다. 사양이 구현된 대로 작동하는지에 대한 최종 검증은 인수 테스트(acceptance test) 및 퇴행 테스트(regression test)의 역할이며, 문서는 의도를, 테스트는 동작을 보장한다(역할이 다르다). 인간이 쓰는 것을 잊어버린 암묵적인 비즈니스 전제는 구조만으로 보완할 수 없다. LLM의 확률적인 이탈이나 외부 API, 가격, 법령의 예고 없는 변경 또한 예방할 수 없다. '100%의 예방'은 구조상 불가능하며, 가능한 것은 적절하게 운용될 경우 특정 실패 유형을 탐지하는 것에 국한된다.

그리고——이것이 가장 중요하지만——최대의 리스크는 기술이 아니라 운용에 있다. 메타데이터가 업데이트되지 않고 모니터링 리스트가 유지보수되지 않게 되는 순간, 이 체계는 '관리되고 있다는 느낌'만을 주는 장식품으로 변질된다. 도구는 규율의 결여를 고칠 수 없다. 1년 뒤에 이것이 무너진다면, 원인은 거의 'Hook이 너무 무거워서 모두가 꺼버렸거나' 혹은 '메타데이터가 번거로워서 아무도 쓰지 않게 되었거나' 둘 중 하나일 것이다. 따라서 설계 측면에서도 린터(linter)는 매 턴 단일 파일만 검증하고, 필수 메타데이터는 7개 항목으로 압축하며, 빈 폴더 그룹은 미리 만들지 않고 첫 사용 시점에 지연 생성(lazy generation)해야 한다——피하고 싶었던 산만함을 발판(scaffolding)의 형태로 미리 만들지 않기 위해서 말이다.

AI 자동 생성 콘텐츠

본 콘텐츠는 Qiita AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0