하네스 엔지니어링: AI 에이전트 프로덕션을 위한 환경 설계 가이드
AI 에이전트를 프로덕션에 투입해봤다면 한 번쯤 이런 경험을 했을 것이다. 모델은 충분히 똑똑한데, 결과는 영 믿음직스럽지 않다. 프롬프트를 아무리 다듬어도 근본적인 불안정함은 사라지지 않는다. 이 글을 다 읽으면 그 불안정함의 진짜 원인을 이해하고, 에이전트 하네스를 직접 설계해 팀 코드베이스에 즉시 적용할 수 있게 된다. 2026년 초 OpenAI·Anthropic·Thoughtworks가 잇달아 공식 아티클을 발표하며 빠르게 정립되고 있는 하네스 엔지니어링(Harness Engineering) 패러다임을, AI 에이전트를 처음 도입하려는 팀과 이미 운영 중인 에이전트를 안정화하려는 팀 모두를 위해 실전 예시와 함께 정리한다.
핵심 개념
"말(馬)이 아니라 마구(馬具)가 문제다"
하네스(Harness)는 말을 제어하기 위해 씌우는 마구에서 온 메타포다. 공식으로 표현하면 다음과 같다.
AI 모델 (말) + 하네스 (환경·제어) = 에이전트결론부터 말하자면, 에이전트의 실질적 경쟁력은 모델 자체가 아니라 모델 주변에 설계된 시스템에서 온다. Claude든 GPT-4든 Gemini든 2026년 현재 주요 모델들은 비슷한 수준으로 수렴하고 있다. 모델을 바꿔도 성능이 크게 달라지지 않는다는 뜻이다. 진짜 차이를 만드는 건 하네스다.
이 관점은 기존 MLOps나 DevOps와 완전히 단절된 개념이 아니다. MLOps가 모델 학습·배포 파이프라인을 엔지니어링하듯, 하네스 엔지니어링은 이미 배포된 추론 모델이 작동하는 실행 환경 전체를 엔지니어링한다. 차이는 대상이 파이프라인이 아니라 에이전트의 맥락(context)과 권한(authority)이라는 점이다.
하네스가 포함하는 것들
- 에이전트가 호출할 수 있는 도구(Tool) 목록
- 에이전트가 접근하는 정보(컨텍스트)의 출처와 형태
- 에이전트의 의사결정 검증 방식
- 에이전트가 멈춰야 할 시점의 기준
- 리포지터리 구조, CI 설정, 린터, 포매터 등 개발 환경 전반
진화 흐름: 프롬프트 → 컨텍스트 → 하네스
프롬프트 엔지니어링 → 모델에게 무엇을 말할지 설계
컨텍스트 엔지니어링 → 모델이 볼 수 있는 정보를 설계
하네스 엔지니어링 → 모델이 작동하는 환경 전체를 설계컨텍스트 창(Context Window)이란? LLM이 한 번에 처리할 수 있는 텍스트의 최대 범위다. 이 창 안에 들어오지 않은 정보는 에이전트가 참조할 수 없다. Slack 스레드나 Google Docs에 묻혀있는 팀 지식이 바로 여기에 해당한다.
OpenAI 팀이 표현한 것처럼, 에이전트에게 1,000페이지 매뉴얼이 아닌 **지도(map)**를 줘야 한다. 코드베이스 밖에 있는 지식은 에이전트에게 존재하지 않는 것과 같다.
하네스의 3대 구성요소 (Birgitta Böckeler 분류)
Thoughtworks의 Distinguished Engineer Birgitta Böckeler가 martinfowler.com에 정리한 분류다. 흔히 "Martin Fowler 분류"로 불리지만, 실제 저자는 Böckeler다.
| 구성요소 | 설명 |
|---|---|
| 컨텍스트 엔지니어링 | 코드베이스에 내장된 지식 베이스 + 관찰 데이터, 브라우저 탐색 등 동적 소스 |
| 아키텍처 제약 | LLM 기반 가드레일 + 결정론적 구조 테스트 |
| 가비지 컬렉션 | 데드코드, 불필요 파일, 컨벤션 드리프트의 자동/수동 감지 및 제거 |
아키텍처 제약에서 등장하는 ArchUnit은 코드 의존성 규칙을 자동으로 검증하는 테스트 도구다. "서비스 레이어가 컨트롤러를 직접 참조하면 안 된다"처럼 LLM이 위반할 수 있는 아키텍처 규칙을 CI에서 강제할 때 쓴다.
실전 적용
IMPACT 프레임워크로 하네스 설계하기
에이전트 하네스를 처음 설계할 때 쓸 수 있는 체크리스트다. 이후 등장하는 코드 예시에서 각 항목이 어떻게 구현되는지 확인할 수 있다.
| 요소 | 설명 | 실무 질문 |
|---|---|---|
| Intent | 에이전트의 목적과 목표 정의 | 이 에이전트는 무엇을 해야 하는가? |
| Memory | 단기·장기 메모리 관리 | 세션 간 무엇을 기억해야 하는가? |
| Planning | 작업 분해 및 계획 수립 | 큰 작업을 어떻게 쪼갤 것인가? |
| Authority | 에이전트 권한 범위 제한 | 에이전트가 건드리면 안 되는 것은? |
| Control Flow | 실행 흐름 및 에러 처리 | 실패 시 어떻게 복구할 것인가? |
| Tools | 사용 가능한 도구 정의 | 최소한으로 필요한 도구는 무엇인가? |
예시 1: 단기 작업 — 2-에이전트 조사·작성 파이프라인
조사(Research)와 작성(Writing)을 분리한 가장 기본적인 하네스 패턴이다. shared_state가 에이전트 간 공유 메모리 역할을 한다. 아래 코드에서 research_agent는 결과를 shared_state에 기록하고, writing_agent는 직접 읽어 사용한다.
import anthropic
client = anthropic.Anthropic()
# 공유 상태: 에이전트 간 데이터 전달 허브 (Memory)
shared_state: dict = {
"topic": "",
"research_result": "",
}
def research_agent(topic: str) -> str:
"""Intent: 주제를 리서치하고 구조화된 요약을 공유 상태에 저장"""
try:
response = client.messages.create(
model="claude-opus-4-6",
max_tokens=2048,
system="""당신은 기술 조사 전문가입니다.
주어진 주제를 조사하고 핵심 내용을 bullet point로 정리하세요.
결과는 다음 에이전트가 사용할 수 있도록 구조화된 형태로 출력하세요.""",
messages=[{"role": "user", "content": f"다음 주제를 조사하세요: {topic}"}]
)
result = response.content[0].text
shared_state["research_result"] = result # Memory: 공유 상태에 저장
return result
except anthropic.APIError as e:
print(f"[research_agent] API 오류: {e}")
raise
def writing_agent(tone: str = "기술 블로그") -> str:
"""Intent: 공유 상태의 조사 결과를 읽어 블로그 초안 작성"""
research = shared_state.get("research_result", "")
if not research:
raise ValueError("조사 결과가 없습니다. research_agent를 먼저 실행하세요.")
try:
response = client.messages.create(
model="claude-opus-4-6",
max_tokens=4096,
system=f"""당신은 {tone} 전문 작가입니다.
제공된 조사 자료를 바탕으로 독자 친화적인 블로그 포스트를 작성하세요.
마크다운 형식을 사용하고, 코드 예시를 포함하세요.""",
messages=[{
"role": "user",
"content": f"다음 조사 자료로 블로그를 작성하세요:\n\n{research}"
}]
)
return response.content[0].text
except anthropic.APIError as e:
print(f"[writing_agent] API 오류: {e}")
raise
def run_blog_harness(topic: str) -> str:
shared_state["topic"] = topic
research_agent(topic) # → shared_state["research_result"] 업데이트
blog_post = writing_agent() # ← shared_state["research_result"] 읽음
return blog_post
result = run_blog_harness("하네스 엔지니어링")IMPACT 관점에서 이 하네스 분석:
| 요소 | 구현 방식 |
|---|---|
| Intent | 두 에이전트가 각자 한 가지 역할만 수행 (역할 분리) |
| Memory | shared_state["research_result"]가 에이전트 간 공유 메모리 |
| Authority | 각 에이전트는 Claude API 호출만 가능, 파일 시스템 접근 없음 |
| Control Flow | research_agent 실패 시 writing_agent로 진행 불가 (순서 강제) |
| Tools | 에이전트당 단일 도구(Claude API), 최소 권한 원칙 준수 |
예시 2: 장기 작업 — Anthropic 3-에이전트 하네스
멀티시간 코딩 작업처럼 단일 에이전트의 컨텍스트 창을 넘어서는 작업에 쓰인다. 핵심 메커니즘은 컨텍스트 격리다: 각 에이전트가 독립적인 컨텍스트 창을 갖고, 단계 간 전달되는 데이터는 요약된 출력물만이다. 덕분에 어느 한 에이전트의 컨텍스트가 가득 차더라도 전체 파이프라인이 멈추지 않는다.
[계획 에이전트] [생성 에이전트] [평가 에이전트]
Planning Agent → Generation Agent → Evaluation Agent
- 작업 목록 생성 - 실제 코드 작성 - 결과 검증
- 우선순위 결정 - 파일 수정/생성 - 테스트 실행
- 컨텍스트 요약 - API 호출 - 피드백 생성
↑ |
└──────────────── 피드백 루프 ─────────────────┘IMPACT 관점에서 각 단계를 보면:
- Planning: 작업 분해(P)와 의도(I) 정의를 담당
- Generation: 도구(T) 사용과 실행 흐름(C)을 담당
- Evaluation: 권한 경계(A) 검증과 피드백 루프(C)를 담당
예시 3: 팀 환경 — CLAUDE.md로 Claude Code 하네스 설정
Claude Code를 팀 에이전트로 쓴다면, CLAUDE.md가 곧 하네스 설정 파일이다. IMPACT 6개 항목을 그대로 섹션으로 매핑할 수 있다.
# CLAUDE.md (하네스 설정 예시)
## 이 에이전트의 목적 (Intent)
- 이 리포지터리의 백엔드 API를 유지보수하고 기능을 추가한다.
- 프론트엔드 변경은 범위 밖이다.
## 허용된 도구 범위 (Authority)
- 파일 읽기/쓰기: src/ 디렉토리만
- 절대 수정 금지: .env, secrets/, prisma/migrations/
- DB 스키마 변경 시 반드시 사람 검토 요청
## 컨텍스트 가이드 (Context Engineering)
- 아키텍처 결정: /docs/adr/ 참조
- API 규격: /docs/openapi.yaml 참조
- 코딩 컨벤션: /docs/conventions.md 참조
## 실행 흐름 규칙 (Control Flow)
- 외부 API 키 노출 가능성 감지 시 즉시 중단
- 테스트 없이 비즈니스 로직을 수정하지 않는다장단점 분석
장점: 왜 지금 하네스 엔지니어링인가
| 항목 | 내용 |
|---|---|
| 예측 가능성 | 에이전트 동작을 환경 설계로 제어하므로 결과가 안정적 |
| 확장성 | 모델 교체 없이 하네스만 개선해도 성능 향상 가능 |
| 생산성 | OpenAI 실험 기준 수동 대비 10배 속도 향상 |
| 모델 독립성 | 특정 LLM에 종속되지 않고 시스템 레벨에서 경쟁력 확보 |
| 장기 세션 지원 | 3-에이전트 분리로 컨텍스트 창 한계 구조적으로 극복 |
단점 및 주의사항
| 항목 | 내용 | 대응 방안 |
|---|---|---|
| 설계 복잡도 | 하네스 자체가 엔지니어링 복잡성을 증가시킴 | 2-에이전트로 시작해 필요 시 확장 |
| 가비지 누적 | 에이전트가 생성한 데드코드·불필요 파일 | 정기적인 가비지 컬렉션 루틴 필수 |
| 컨텍스트 설계 부담 | 에이전트가 접근할 정보를 구조화해야 함 | CLAUDE.md, ADR, OpenAPI 스펙 정비부터 시작 |
| 과도한 제어 흐름 | 복잡한 조건 분기가 에이전트를 혼란스럽게 함 | 원자적 도구 설계 원칙 준수 |
| 학습 비용 | 기존 프롬프트 엔지니어링과 다른 사고방식 | IMPACT 프레임워크로 체계적 접근 |
원자적(atomic) 도구 설계란 하나의 도구가 하나의 작업만 수행하도록 설계하는 원칙이다.
search_and_update_file()처럼 기능을 묶은 도구보다search_file()과update_file()을 분리하는 게 낫다. 도구가 복합 기능을 가지면 에이전트가 의도치 않은 부수 효과를 내기 쉽다.
실무에서 가장 흔한 실수
- 도구를 너무 많이 준다 — 에이전트에게 모든 도구를 주면 오히려 방황한다. 최소 권한 원칙을 지켜라.
- 컨텍스트를 코드베이스 밖에 둔다 — Slack이나 Confluence에만 있는 지식은 에이전트에게 없는 것과 같다.
- 하네스를 한 번만 설계한다 — 코드베이스가 변하면 하네스도 진화해야 한다. 정기적인 리뷰가 필수다.
마치며
하네스 엔지니어링을 한 줄로 요약하면 이렇다: "AI 에이전트의 성패는 모델이 아니라 모델을 둘러싼 환경에 달려 있다." 프롬프트를 다듬는 시대는 지나갔다. 이제는 에이전트가 올바른 판단을 내릴 수 있는 환경을 설계하는 것이 핵심 역량이다.
지금 바로 시작할 수 있는 3단계:
- 컨텍스트 감사 — 터미널에서
git grep -r "TODO\|FIXME\|slack.com\|notion.so"를 실행해 코드베이스 밖으로 나간 지식 링크를 찾는다. 팀 온보딩 문서도 열어 "여기는 직접 물어봐야 안다"는 항목을 모두/docs안으로 옮긴다. - IMPACT 체크리스트 작성 — 현재 사용 중인 에이전트에 IMPACT 6개 항목을 적용해 빈칸을 찾는다. 특히 Authority가 비어 있다면 에이전트가 건드리면 안 되는 파일 목록부터 정의하라.
- 작게 시작 — 2-에이전트 패턴(조사 + 작성, 또는 계획 + 실행)부터 시작해 패턴에 익숙해진 후 3-에이전트로 확장한다.
모델이 평준화된 세상에서 하네스를 잘 설계하는 팀이 이긴다.
다음 글: 멀티에이전트 오케스트레이션 패턴 — 에이전트가 3개를 넘어서면 어떻게 조율할 것인가? LangGraph와 CrewAI의 상태 머신 접근 방식을 비교한다.
참고 자료
- Harness engineering: leveraging Codex in an agent-first world | OpenAI
- Effective harnesses for long-running agents | Anthropic Engineering
- Harness engineering for coding agent users | martinfowler.com (Birgitta Böckeler)
- OpenAI Introduces Harness Engineering: Codex Agents Power Large-Scale Software Development | InfoQ
- Anthropic Designs Three-Agent Harness for Long-Running AI Development | InfoQ
- The Anatomy of an Agent Harness | Daily Dose of Data Science
- Agent Engineering: Harness Patterns, IMPACT Framework & Coding Agent Architecture
- 하네스 엔지니어링이란? 2026년 AI 에이전트 개발의 핵심으로 떠오른 이유 | Channel.io
- Unlocking the Codex harness: how we built the App Server | OpenAI