하네스 엔지니어링에 대해
2026-04-05#ai#claude-code#harness
AI 코딩 도구를 컨트롤 하기위해 하네스 엔지니어링이라는 개념이 생겼다. 하네스의 개념과 구성요소를 정리하고, 그 구성요소를 팀 환경에 하나씩 적용해본 기록..
AI 코딩 도구의 사용 방식은 단계적으로 바뀌어왔다. 처음엔
프롬프트였다 — "이 함수 고쳐줘" 한 줄이면 충분했다.
그다음은
컨텍스트였다 — 파일을 붙여넣고 배경을 설명하니 결과가
좋아졌다.
지금은 에이전트다 — AI가 스스로 파일을 읽고, 도구를
실행하고, 여러 단계를 이어서 일한다.
그런데 에이전트로 넘어오면서 우리 팀 대화 기록에 이런 문장들이 쌓이기 시작했다.
- "어제 Mockito 쓰라고 했잖아. 왜 또 MockK를 써?" — 기억이 없다. 세션이 끝나면 어제의 합의도 사라진다.
- "왜 서브에이전트 안 쓰고 직접 해?" — 일관성이 없다. 같은 상황에서 매번 다르게 행동한다.
- "빌드 깨져있는데 왜 완료라고 해?" — 검증이 없다. 결과를 확인하지 않고 완료를 선언한다.
스스로 움직이는 만큼, 스스로 어긋나는 폭도 커진 것이다. 이 간극을 다루는 분야에 이미 이름이 붙어 있었다 — 하네스 엔지니어링.
하네스 엔지니어링이란#
하네스(harness)는 모델을 감싸서 실제 행동을 하게 만드는 실행 계층이다. 모델은 "다음에 뭘 할지"만 결정하고, 그걸 행동으로 만드는 나머지 전부가 하네스다. Claude Code, Codex, Cursor의 차이가 곧 하네스의 차이고, 그래서 이 분야의 정설은 **"같은 모델도 하네스가 다르면 전혀 다른 결과를 낸다"**이다.
하네스 엔지니어링 입문은 하네스를 이런 구성요소들로 정리한다.
- 지시문서 — 모델이 매번 참조할 규칙과 맥락 (CLAUDE.md 등)
- 아키텍처 제약 — 벗어날 수 없게 만드는 구조적 장치
- 피드백 루프 — 행동의 결과를 모델에게 되돌려주는 회로
- 지식 저장소 — 세션이 끝나도 남는 기억
- 가비지 컬렉션 — 쌓인 설정·컨텍스트를 걷어내는 청소
Claude Code는 설정면(CLAUDE.md, 규칙, 훅, 서브에이전트, MCP)을 열어두고 있어서 그 위에 팀의 하네스를 한 겹 더 얹을 수 있다. 아래는 위 구성요소를 우리 팀 환경에 하나씩 적용해본 기록이다.
지시문서 — 매 턴 실리는 것은 최소로#
지시문서는 늘리고 싶은 유혹이 가장 큰 곳이고, 그래서 가장 먼저 오염되기 쉬운곳이다. 문서가 길어지면 모델이 중간에 있는 규칙부터 무시하기 시작한다 — 이걸 겪고 나서 로딩 시점 기준 3계층으로 나눴다.
| 계층 | 로딩 시점 | 내용 |
|---|---|---|
| L1 | 매 세션 자동 주입 | CLAUDE.md, 메모리 인덱스 — 합쳐서 ~60줄 |
| L2 | 필요할 때만 | 서브에이전트, 스킬, 도메인별 규칙 |
| L3 | 검색할 때만 | 과거 세션 기록, 변경 이력 문서 |
L1의 CLAUDE.md는 60줄 이내로 못 박았고, 도메인별 규칙은 L2로
내렸다. 우아한형제들의 AI 개발환경
구축기도 같은 결론을 냈다.
— 규칙 파일에 globs 옵션으로 파일 경로별로 규칙을
선택 활성화해서, 지금 작업과 무관한 규칙이 토큰을 낭비하지
않게 한다. LLM이 이미 아는 것(React·TypeScript 기초)은 빼고
프로젝트 특화 규칙만 담는다는 원칙도 동일하다.
아키텍처 제약 — 역할과 모델을 미리 정해둔다#
모델이 매번 자의적으로 판단하게 두는 대신, 판단의 틀을 구조로 박아뒀다. 팀 직무를 따라 서브에이전트 11개(백엔드, DBA, 리뷰어, QA, 프론트 구현체들)를 만들고 모델을 계층화했다 — 판단이 필요한 역할(아키텍트, 리뷰어)은 상위 모델, 구현 위주 역할은 하위 모델. 계층화만으로 작업당 비용이 이론치 3분의 1까지 내려간다.
측정해보니 과했던 부분도 있었다. 하위 모델에게 깊은 추론 도구를 쥐여줘도 소용없었다 — 추론의 깊이 자체가 얕아서 도구를 호출해도 진전이 없었고, 판단이 조금이라도 섞이는 역할은 중간 모델로 되돌렸다. 구조는 미리 정하되, 측정이 반박하면 고친다.
피드백 루프 — 성공은 침묵, 실패만 표면화#
"빌드를 꼭 확인해"라고 지시문서에 적어도, 확인했다고 말만 하는 경우가 생긴다. 검증은 말이 아니라 훅(hook) — 도구 실행 후 자동으로 도는 스크립트 — 에게 맡겼다. 원칙은 "성공은 침묵, 실패만 컨텍스트에 표면화하라". 성공 메시지까지 매번 얹으면 그것대로 토큰 낭비라서, 훅은 실패했을 때만 입을 연다.
# build-failure-backpressure.sh — 빌드/테스트 실패 감지 훅 (일부)
# exit code를 먼저 보고, 텍스트 패턴은 보조로만 쓴다
EXIT_CODE=$(echo "$INPUT" | jq -r '.tool_output.exit_code // "0"')
if [ "$EXIT_CODE" != "0" ] && [ "$EXIT_CODE" != "null" ]; then
FAILED=true
elif echo "$COMBINED" | grep -qE "(BUILD FAILED|CompilationError|Test.*failed)"; then
FAILED=true # exit 0인데 BUILD FAILED를 출력하는 도구도 있다
fi
# ...실패면 모델에게 실패 사실을 강제로 주입...
# 성공 시 침묵
exit 0이 훅이 붙은 뒤로 "빌드 깨졌는데 완료 선언"이 구조적으로 불가능해졌다. 하네스에서 가장 확실하게 효과 본 부분이다.
지식 저장소 — 파일이 세션 사이를 잇는다#
모델은 세션이 끝나면 전부 잊는다. 우리는 "하나의 사실 = 하나의
파일" 규칙으로 메모리를 운영했다. 유형별
접두사(사용자/피드백/프로젝트/참조)를 붙인 파일 49개가 쌓였고,
L1에는 그 인덱스만 올라간다. "어제 Mockito 쓰라고 했잖아"는 이제
feedback_ 파일 하나가 대신 기억한다.
가비지 컬렉션 — 만들면 끝이 아니라 운영이다#
몇 주 운영하며 확실해진 것: 하네스는 한 번 세팅하고 끝나는 설정이 아니라 측정하고 걷어내기를 반복하는 운영이다. 규칙을 넣으면 과잉 작동하는 규칙이 생기고, 도구를 붙이면 매 턴 토큰을 갉아먹는 도구가 생긴다. 그때마다 수치를 재고, 기준에 못 미치는 것은 뺐다.
우아한형제들 글의 한 문장이 이 전환을 정확히 요약한다 — "예전에는 프롬프트를 잘 작성하는 것이 중요했다면, 이제는 AI가 일할 환경과 맥락을 설계하고 데이터를 최적화하는 것이 생산성의 핵심". 개인의 프롬프트 잘 쓰기가 아니라 팀 차원의 환경 설계로 무게가 옮겨간 것이다.
참고: 하네스 엔지니어링 입문 (위키독스) · 프론트엔드 개발자의 AI 개발환경 구축기 (우아한형제들) · Effective harnesses for long-running agents (Anthropic) · Claude Code 공식 문서