하네스 엔지니어링이란?
댓글 0
댓글을 작성하려면 로그인이 필요합니다.
아직 댓글이 없습니다. 첫 번째 댓글을 작성해보세요!
같은 모델을 쓰는데 왜 결과가 다를까? Claude Code가 증명한 '모델 바깥'의 기술
2026년 초, Anthropic의 코딩 에이전트 Claude Code의 소스코드 약 50만 줄이 npm 업데이트 과정에서 실수로 공개되었습니다. 몇 시간 만에 GitHub 스타 5만 개를 돌파했고, 엔지니어들은 회의를 취소하고 코드를 분석하기 시작했습니다.
그런데 사람들이 주목한 건 모델의 프롬프트가 아니었습니다. 스트리밍 에이전트 루프, 권한 기반 도구 디스패치, 세션 간 컨텍스트 관리 레이어. 모델 '주변'에 설계된 구조, 즉 하네스(Harness) 였습니다.
그 이후 "하네스 엔지니어링"이 AI 엔지니어링에서 가장 뜨거운 키워드가 되었습니다. 이 글에서는 하네스 엔지니어링이 무엇인지, 왜 중요한지, 그리고 실무에서 어떻게 적용할 수 있는지를 정리합니다.
개발자라면 테스트 하네스(Test Harness)라는 용어가 익숙할 겁니다. 테스트 대상 코드를 감싸서 입력을 제어하고, 출력을 검증하고, 실행 환경을 관리하는 구조물입니다. AI에서의 하네스도 같은 역할을 합니다. 모델이 무엇을 보고, 무엇을 실행할 수 있으며, 실패했을 때 어떻게 복구하는지를 결정하는 바깥 구조입니다.
Thoughtworks의 Birgitta Böckeler는 이를 하나의 공식으로 정리했습니다.
Agent = Model + Harness
Docker 컨테이너에 비유하면 이해가 빠릅니다. 같은 애플리케이션(모델)이라도 Dockerfile, 네트워크 설정, 볼륨 마운트, 헬스체크(하네스)를 어떻게 구성하느냐에 따라 프로덕션에서의 안정성이 완전히 달라지는 것과 같습니다. Claude Code가 출시 이후 폭발적으로 성장할 수 있었던 것도 더 좋은 모델 덕분이 아니라, 더 좋은 하네스 덕분이라는 것이 업계의 분석입니다.
AI를 잘 활용하기 위한 기술은 단계적으로 진화해왔습니다. 개발자에게 익숙한 비유로 대응시키면 이렇습니다.
| 단계 | 핵심 질문 | 개발 비유 | 설명 |
|---|---|---|---|
| 프롬프트 엔지니어링 | "무엇을 물어볼까?" | 함수 시그니처 설계 | 모델에게 보내는 지시문을 최적화하는 기술. 역할 부여, 예시 제공, 단계별 사고 유도 등 |
| 컨텍스트 엔지니어링 | "무엇을 보여줄까?" | 의존성 주입(DI) | 모델이 좋은 답을 하도록 적절한 맥락을 설계하여 주입하는 기술 |
| 하네스 엔지니어링 | "전체 시스템을 어떻게 운영할까?" | 인프라 & 오케스트레이션 | 도구, 권한, 상태 관리, 실패 복구, 평가, 재시도까지 포함한 전체 런타임 환경 설계 |
프롬프트 엔지니어링이 "좋은 함수를 만드는 것"이라면, 컨텍스트 엔지니어링은 "함수에 적절한 인자를 넣는 것"이고, 하네스 엔지니어링은 "그 함수가 동작하는 전체 시스템—CI/CD, 모니터링, 장애 복구, 권한 관리—을 설계하는 것"입니다.
프롬프트와 컨텍스트를 아무리 잘 만들어도, 전체 운영 구조가 부실하면 에이전트는 프로덕션에서 무너집니다. 로컬에서 잘 도는 코드가 배포만 하면 터지는 것과 같은 이치입니다.
200줄짜리 유틸 함수를 완벽하게 작성하는 모델이 왜 2,000줄짜리 프로젝트에서는 길을 잃을까요? Anthropic 엔지니어링 팀이 밝힌 핵심 문제는 두 가지입니다.
서버 메모리가 무한하지 않듯, 모델의 컨텍스트 윈도우에도 한계가 있습니다. 장시간 작업을 하면 윈도우가 가득 차면서 일관성이 떨어집니다.
더 심각한 건 "컨텍스트 불안(Context Anxiety)" 이라는 현상입니다. 모델이 컨텍스트 한계에 가까워졌다고 감지하면, 아직 구현해야 할 기능이 남아 있는데도 작업을 조기 마무리하려 합니다. 배포 데드라인에 쫓기는 개발자가 "일단 이 정도면 됐다"고 PR을 올리는 것과 비슷하지만, 모델의 경우 이것이 시스템적으로 반복된다는 점이 문제입니다.
자기가 작성한 코드를 자기가 리뷰하면 문제를 잘 못 찾습니다. 모델도 마찬가지입니다. 자신이 생성한 결과물을 평가해보라고 하면, 품질이 떨어지는 코드도 자신 있게 칭찬합니다. 코드처럼 테스트로 검증 가능한 영역에서도 이 편향이 나타나는데, 디자인이나 UX처럼 주관적 판단이 필요한 영역에서는 더 극명합니다.
핵심 관점 전환: 하네스 엔지니어링의 출발점은 "이 모델이 부족하다"가 아닙니다. "내 시스템이 이 실패 모드를 허용했다" 는 관점입니다. 모델 업그레이드를 기다리는 대신, 지금의 환경을 개선하여 같은 실패가 반복되지 않도록 만드는 것이 핵심입니다. 버그가 발생했을 때 "언어가 나빠서"라고 하지 않고 방어 코드와 테스트를 추가하는 것과 같은 사고방식입니다.
하네스의 구성을 웹 애플리케이션 아키텍처에 대응시키면 이렇게 정리할 수 있습니다.
| 하네스 구성 요소 | 웹 앱 대응 개념 | 역할 |
|---|---|---|
| 에이전트 루프 | 이벤트 루프 / 메인 스레드 | 인식 → 추론 → 도구 실행 사이클을 반복하며, 결과를 컨텍스트에 재주입. 작업이 종료 상태에 도달할 때까지 계속 |
| 도구 디스패치 | API 라우터 + 스키마 검증 | bash, 파일 읽기/쓰기, grep, glob 등 사용 가능한 도구를 엄격한 입력 스키마로 정의. 모델의 행동 범위를 제어 |
| 권한 관리 | RBAC / 미들웨어 | 파일 삭제, 외부 서비스 접근, 코드 실행 시 사용자 승인 요구. sudo 없이는 위험한 명령을 실행할 수 없는 것과 같은 원리 |
| 컨텍스트 관리 | 캐시 + 세션 관리 | 요약(Compaction)으로 이전 대화를 압축하거나, 컨텍스트 리셋으로 새 세션을 시작하되 구조화된 핸드오프 아티팩트로 상태 전달 |
| 상태 추적 | 데이터베이스 + Git | claude-progress.txt, Git 커밋, JSON 기능 목록 등을 통해 여러 세션에 걸쳐 작업 상태를 영속적으로 추적 |
이것은 마이크로서비스 아키텍처에서 API Gateway가 하는 역할과 비슷합니다. 개별 서비스(모델)의 성능이 아무리 좋아도, 라우팅, 인증, 레이트 리밋, 서킷 브레이커 같은 게이트웨이(하네스) 없이는 프로덕션 운영이 불가능한 것과 같은 맥락입니다.
Anthropic의 하네스 설계는 실전 경험을 통해 계속 진화해왔습니다.
init.sh, claude-progress.txt, JSON 기능 목록 생성 등 프로젝트 환경을 세팅이 구조는 Git의 브랜치 전략과 유사합니다. 각 세션이 하나의 feature branch처럼 동작하고, 진행 파일이 PR description 역할을, Git 커밋이 변경 이력 역할을 합니다.
이 구조는 GAN(Generative Adversarial Network)에서 영감을 받았습니다. 핵심은 "코드를 작성한 에이전트와 리뷰하는 에이전트를 분리한 것" 입니다. 팀에서 셀프 리뷰 대신 피어 리뷰를 강제하는 것과 같은 원리이며, 생성자와 평가자 사이에는 "스프린트 계약" 이 존재합니다. 코드를 작성하기 전에 "완료 기준이 무엇인지"를 두 에이전트가 미리 합의하는 것입니다. 에이전트들은 파일을 통해 소통합니다. 한 에이전트가 파일을 작성하면 다른 에이전트가 읽고 응답하는 비동기 방식입니다.
[사용자 요청]
↓
┌─────────┐
│ Planner │ → 작업 분해 & 스프린트 정의
└────┬────┘
↓
┌─────────────┐ 스프린트 계약 ┌───────────┐
│ Generator │ ←──── 합의 ────→ │ Evaluator │
└──────┬──────┘ └─────┬─────┘
↓ ↓
코드 구현 Playwright로 검증
↓ 점수 & 비평
└──────── 피드백 반영 ←───────┘
↻ 반복
Anthropic의 프론트엔드 디자인 실험에서는 5~15회의 반복을 수행했는데, 평가자가 4개의 기준(디자인 품질, 독창성, 완성도, 기능성)으로 매 반복마다 점수를 매기며 구체적인 개선 피드백을 제공했습니다. 특히 독창성 기준에서 "보라색 그라데이션 위에 화이트 카드"같은 전형적인 AI 생성 패턴을 명시적으로 감점하도록 설계한 점이 인상적입니다.
하네스의 각 구성 요소는 "모델이 스스로 할 수 없는 것"에 대한 가정을 인코딩합니다. 그런데 모델이 발전하면 이 가정은 낡아집니다.
실제로 Anthropic은 Sonnet 4.5에서 심각했던 컨텍스트 불안이 Opus 4.5에서 자연스럽게 사라진 것을 발견하고, 하네스에서 컨텍스트 리셋 로직을 제거했습니다. 레거시 코드에서 더 이상 필요 없는 워크어라운드를 제거하는 것과 같습니다. 새 모델이 나올 때마다 하네스를 재점검하고, 더 이상 load-bearing하지 않은 부분을 걷어내는 것이 중요합니다.
모든 지시와 도구를 시스템 프롬프트에 한꺼번에 넣으면 에이전트는 오히려 더 나빠집니다. 작업 시작 전에 이미 인스트럭션 버짓을 소진해버리기 때문입니다.
"스킬(Skills)" 개념은 lazy loading과 같습니다. 에이전트가 특정 작업이 필요하다고 판단했을 때에만 해당 지식이나 도구를 로드합니다. 모든 모듈을 앱 시작 시 import하는 대신, dynamic import로 필요할 때 불러오는 것과 같은 원리입니다.
⚠️ 보안 주의: 외부 스킬 레지스트리에서 이미 악성 스킬이 수백 건 발견된 사례가 있습니다. npm 패키지를 설치할 때처럼, 설치 전에 반드시 내용을 확인하세요.
하네스 설정을 최적화하는 데 실제 코드를 배포하는 것보다 더 많은 시간을 쓰게 되는 함정이 있습니다. 에이전트가 실패할 때 그 실패를 반복하지 않도록 개선하되, 미리 문제를 찾아 해결하려고 하지 않는 것이 실용적입니다.
실제로 어떤 서브 에이전트가 어떤 도구에 접근할 수 있는지를 세밀하게 최적화하려 했더니 도구 호출이 오히려 혼란스러워지면서(tool thrash) 더 나쁜 결과가 나왔다는 사례도 있습니다. 과도한 추상화가 오히려 성능을 떨어뜨리는 것과 같은 현상입니다.
복잡한 판단(설계, 오케스트레이션)은 고성능 모델(Opus)에, 단순 작업(코드베이스 grep, bash 실행)은 경량 모델(Sonnet, Haiku)에 분배하는 전략도 하네스 설계의 핵심입니다. 각 서브 에이전트는 더 작고 명확한 태스크를 받기 때문에 작은 인스트럭션 버짓으로도 충분히 동작합니다. 마이크로서비스에서 각 서비스의 스펙을 워크로드에 맞게 조절하는 것과 같은 원리입니다.
하네스 엔지니어링의 핵심을 한 문장으로 요약하면 이렇습니다.
모델이 발전할수록 하네스 조합의 가능성은 줄어들지 않는다. 다만 이동할 뿐이다. AI 엔지니어의 일은 다음의 새로운 조합을 계속 찾아가는 것이다.
— Prithvi Rajasekaran, Anthropic Labs
좋은 프롬프트를 쓰는 것에서 시작해, 좋은 컨텍스트를 설계하는 것으로 나아가고, 궁극적으로 좋은 하네스를 구축하는 것. 이것이 AI와 함께 일하는 기술의 자연스러운 진화 방향입니다.
그리고 그 출발점은 생각보다 가까이에 있습니다. 에이전트가 실패했을 때 "모델이 부족하다"가 아니라 "내 시스템이 이 실패를 허용했다" 고 생각하는 것. 버그를 만나면 언어를 탓하지 않고 방어 코드를 추가하는 개발자의 사고방식으로 AI를 대하는 것. 바로 거기에서 하네스 엔지니어링은 시작됩니다.
claude-progress.txt 설계 등 하네스 엔지니어링의 기초 개념을 다룬 원문