하네스를 만들다 하네스에 잡히지 않으려면
하네스 엔지니어링을 도입하면서 실패하는 팀의 패턴은 놀랍도록 일관적이다. OpenAI, Anthropic, LangChain, 그리고 수많은 팀이 각자의 현장에서 같은 실수를 겪고, 같은 교훈을 얻었다. 이 편에서는 가장 빈번하고 치명적인 실패 패턴 다섯 가지를 다룬다. 무엇이 잘못되고, 왜 잘못되고, 어떻게 고치는지를 구체적으로.
안티패턴 1: 천 페이지 매뉴얼
증상
AGENTS.md가 수백 줄을 넘어가면서 에이전트의 성능이 오히려 떨어진다. 규칙을 추가할수록 에이전트가 규칙을 더 자주 어긴다.
왜 발생하는가
직관적으로는 합리적인 접근이다. “에이전트가 이 규칙을 어겼으니, 규칙을 더 명시적으로 추가하자.” 이런 반응이 반복되면서 AGENTS.md가 거대해진다. OpenAI 팀도 초기에 이 접근을 시도했다가 실패했다.
문제의 근본 원인은 세 가지다.
첫째, 컨텍스트는 희소 자원이다. 거대한 지침 파일이 컨텍스트 윈도우를 차지하면, 정작 실제 코드와 관련 문서를 위한 공간이 줄어든다. 컨텍스트 활용률이 약 40%를 초과하면 성능이 저하된다는 실험 결과도 있다.
둘째, 모든 것이 “중요”하면 아무것도 중요하지 않다. 100가지 규칙 중 지금 이 작업에 관련된 3가지를 골라내는 것은 에이전트에게 어려운 일이다. 에이전트는 의도적으로 탐색하는 대신 지역적 패턴 매칭에 의존하게 된다.
셋째, 즉시 진부해진다. 거대한 매뉴얼은 유지보수의 무덤이 된다. 규칙이 바뀌어도 문서는 업데이트되지 않고, 에이전트는 유효한 것과 유효하지 않은 것을 구분하지 못한다.
해결 방법
❌ 하나의 거대한 파일에 모든 규칙
✅ 계층적 구조로 분리
프로젝트 루트/
├── CLAUDE.md # 핵심 규칙만 (50줄 이내)
│ - 프로젝트 개요
│ - 디렉토리 구조
│ - 최상위 의존성 규칙
│ - 공통 컨벤션
├── src/
│ ├── domain/
│ │ └── CLAUDE.md # 도메인 레이어 전용 (30줄 이내)
│ ├── infrastructure/
│ │ └── CLAUDE.md # 인프라 레이어 전용 (30줄 이내)
루트 CLAUDE.md는 50줄을 넘기지 않는다. 에이전트가 src/domain/ 안에서 작업할 때는 루트 + 도메인 CLAUDE.md만 로드된다. 전체 규칙을 한꺼번에 읽을 필요가 없다.
규칙의 기준도 바뀌어야 한다. **”에이전트가 알아야 할 모든 것”이 아니라 “이 작업 범위에서 지켜야 할 것”**을 적는다.
안티패턴 2: 과도한 제어 흐름 설계
증상
에이전트의 모든 행동을 미리 정의하려 한다. “1단계에서 파일 목록을 조회하고, 2단계에서 각 파일을 분석하고, 3단계에서…” 식의 세밀한 워크플로우를 설계한다. 모델이 업데이트될 때마다 제어 흐름이 깨진다.
왜 발생하는가
전통적인 소프트웨어 설계 습관에서 온다. 프로그래밍에서는 제어 흐름을 명시적으로 정의하는 것이 좋은 습관이다. 하지만 LLM 기반 에이전트는 결정론적(deterministic) 시스템이 아니다. 같은 입력에 대해 다른 출력을 낼 수 있고, 모델 버전이 올라가면 행동 패턴이 달라진다.
해결 방법
❌ 절차를 정의한다 (How)
"1. 파일 목록 조회 → 2. 각 파일의 import 분석 → 3. 위반 목록 생성 → 4. 수정"
✅ 목표와 제약을 정의한다 (What + Boundary)
"목표: 레이어 위반을 수정하라
제약: src/domain/은 어디에도 의존하지 않아야 한다
검증: npm run test:architecture가 통과해야 한다"
에이전트에게 목적지와 경계를 알려주되, 어떤 경로로 가는지는 맡긴다. 제약은 아키텍처 테스트와 린터로 기계적으로 강제하고, 과정은 에이전트의 재량에 둔다.
이 접근은 모델이 업데이트되어도 깨지지 않는다. 목표와 제약은 변하지 않고, 에이전트가 그 안에서 더 나은 경로를 찾을 수 있다.
안티패턴 3: 도구 과다 제공
증상
에이전트에 10개 이상의 MCP 서버를 연결하고, 수십 개의 도구를 제공한다. 에이전트가 작업 시작 전에 도구 선택에 시간을 과도하게 소비하거나, 부적절한 도구를 사용한다.
왜 발생하는가
“도구가 많으면 더 다양한 작업을 할 수 있을 것”이라는 가정. 인간에게는 맞을 수 있지만, 에이전트에게는 역효과를 낳는다. 도구 목록 자체가 컨텍스트를 차지하고, 선택지가 많을수록 잘못된 도구를 고를 확률이 높아진다.
해결 방법
❌ 가능한 모든 도구를 한꺼번에 제공
- 파일 시스템 MCP
- GitHub MCP
- Slack MCP
- DB 쿼리 MCP
- 브라우저 MCP
- 이미지 생성 MCP
- 번역 MCP
- ...
✅ 작업 유형별로 필요한 도구만 선별 제공
코딩 작업:
- 파일 시스템
- 린터/테스트 실행
- Git
디버깅 작업:
- 파일 시스템
- 브라우저 (E2E 확인)
- 로그 쿼리
리뷰 작업:
- 파일 시스템
- GitHub PR API
- 린터
스킬(Skills) 패턴을 활용하면, 에이전트가 필요한 시점에 필요한 도구에만 접근할 수 있다. 모든 도구를 시스템 프롬프트에 넣는 대신, 에이전트가 특정 작업을 수행할 때 관련 스킬 파일을 로드하는 방식이다.
단, 스킬 레지스트리의 보안에 주의해야 한다. 외부 스킬은 npm 패키지처럼 다뤄야 한다. 출처를 확인하고, 내용을 검토한 후 사용한다.
안티패턴 4: 실패를 모델 탓으로 돌리기
증상
에이전트가 잘못된 코드를 생성하면 “이 모델은 아직 부족하다”, “더 좋은 모델이 나오면 해결될 것이다”라고 판단한다. 모델 업그레이드 비용을 지출하지만 결과가 크게 나아지지 않는다.
왜 발생하는가
모델의 능력이 결과를 좌우한다는 가정은 틀리지 않다. 하지만 불완전하다. LangChain의 사례가 증명했듯이, 같은 모델로도 하네스만 바꾸면 Top 30에서 Top 5로 뛸 수 있다. 더 좋은 모델이 더 좋은 결과를 만들지만, 하네스가 없으면 그 차이는 제한적이다.
또한 반직관적이지만, 더 좋은 모델은 더 좋은 하네스를 요구한다. 모델이 강력해질수록 더 많은 자율성을 부여할 수 있고, 더 많은 자율성은 더 정교한 가드레일을 필요로 한다.
해결 방법
에이전트가 실패할 때마다 이 질문을 던진다:
"어떤 능력이 빠져있는가?
그리고 그것을 어떻게 에이전트가 읽고 검증할 수 있는 형태로 만들 것인가?"
구체적인 진단 흐름:
에이전트가 잘못된 코드를 생성했다
│
├→ 규칙을 몰랐나?
│ └→ CLAUDE.md에 해당 규칙이 있는가?
│ ├→ 없다 → 규칙 추가 (컨텍스트 문제)
│ └→ 있다 → 에이전트가 읽었는데 무시한 건가?
│ └→ 강제할 수 있나? → 린터/테스트로 강제 (제약 문제)
│
├→ 피드백이 없었나?
│ └→ 에이전트가 결과를 확인할 수 있었는가?
│ ├→ 테스트가 없다 → 테스트 추가 (피드백 문제)
│ └→ 테스트가 있지만 잡지 못했다 → 테스트 보강
│
└→ 위 모두 해당되지 않는다
└→ 그때 모델 한계를 의심한다
대부분의 경우, 모델 한계까지 도달하기 전에 환경의 문제가 발견된다.
안티패턴 5: 하네스 오버엔지니어링
증상
하네스를 구축하는 데 제품 개발보다 더 많은 시간을 쓴다. 아직 혼자 사이드 프로젝트를 하고 있는데, 엔트로피 대시보드와 주간 리포트 자동화를 만들고 있다. 하네스의 하네스를 만들기 시작한다.
왜 발생하는가
하네스 엔지니어링의 가치를 이해한 후에 빠지기 쉬운 함정이다. “완벽한 하네스를 먼저 만들고, 그 위에서 개발하겠다”는 접근. 하지만 완벽한 하네스는 존재하지 않고, 프로젝트가 진행되면서 필요한 하네스의 형태도 바뀐다.
해결 방법
❌ "완벽한 하네스를 먼저 만들고 개발을 시작하자"
✅ "지금 가장 아픈 문제를 해결하는 최소한의 하네스를 만들고,
문제가 바뀌면 하네스도 진화시키자"
실용적인 기준:
하네스 구축에 쓰는 시간의 가이드라인:
개인 프로젝트: 전체 시간의 5% 이하
소규모 팀: 전체 시간의 10% 이하
조직 규모: 전체 시간의 15% 이하
이 비율을 넘기고 있다면, 오버엔지니어링을 의심하라.
하네스는 제품이 아니다. 제품을 더 잘 만들기 위한 도구다. 도구를 만드는 데 제품보다 시간을 쏟고 있다면 본말이 전도된 것이다.
실패를 하네스로 전환하는 사이클
모든 안티패턴에 공통적으로 적용되는 원칙이 있다. Mitchell Hashimoto의 정의에서 나온 것이다.
“에이전트가 실수할 때마다, 그 실수를 다시는 하지 않도록 해결책을 엔지니어링하라.”
이것을 구체적인 사이클로 만들면:
1. 에이전트가 실수한다
│
2. 실수의 원인을 분류한다
├→ 컨텍스트 부족 → CLAUDE.md 보강
├→ 제약 부재 → 린터/테스트 추가
├→ 엔트로피 축적 → 정리 스크립트 추가
└→ 피드백 부족 → 검증 도구 연결
│
3. 해결책을 저장소에 코드로 반영한다
(문서가 아니라 기계적으로 실행 가능한 형태로)
│
4. 같은 종류의 실수가 구조적으로 불가능해진다
│
5. 에이전트가 다른 종류의 실수를 한다
│
6. 1번으로 돌아간다
이 사이클이 반복되면서 하네스는 점진적으로 강화된다. 한 번에 완벽한 하네스를 설계하는 것이 아니라, 실패를 연료로 삼아 하네스를 성장시키는 것이다.
OpenAI 팀은 이 접근을 극단적으로 실천했다. 에이전트가 막힐 때마다 “더 열심히 해”가 아니라, 부족한 것을 식별하고 환경에 반영했다. 그 반영 자체도 Codex에게 시켰다. 슬랙에 “@codex 우리 코드베이스에 가드레일을 추가해줘”라고 쓰면, 15분 안에 4개의 PR이 제안되었다.
하네스는 완성되는 것이 아니라 진화하는 것이다.