프롬프트보다 더 중요한 것은 AI가 필요한 문맥을 찾고, 안전한 범위에서 도구를 사용하고, 결과를 스스로 검증할 수 있도록 일하는 환경 자체를 설계하는 것이다.
하네스 엔지니어링이란
하네스(harness)는 원래 무언가를 연결하고 제어하는 장치를 뜻한다. 소프트웨어 테스트에서는 테스트 대상에 입력을 넣고 결과를 관찰하는 테스트 하네스라는 표현으로 오래전부터 사용해 왔다.
AI 에이전트에서 하네스는 모델을 둘러싼 실행 환경 전체를 의미한다.
┌─ 프로젝트 지식과 규칙
사용자의 목표 ───→ AI 에이전트 ─┼─ 파일·터미널·브라우저 같은 도구
├─ 권한과 승인 경계
├─ 테스트·정적 분석·리뷰
└─ 실패 기록과 피드백 루프
따라서 하네스 엔지니어링(Harness Engineering)은 모델에게 멋진 한 문장을 쓰는 기술이 아니다. 에이전트가 반복해서 신뢰할 만한 결과를 내도록 다음 요소를 함께 설계하고 개선하는 일이다.
- 무엇을 알아야 하는가: 프로젝트 문서, 아키텍처, 계약, 현재 상태
- 무엇을 할 수 있는가: 검색, 수정, 빌드, 테스트, 배포 등의 도구
- 무엇을 하면 안 되는가: 보안 규칙, 변경 범위, 승인 게이트
- 무엇을 성공으로 볼 것인가: 테스트, 린트, 명세 비교, 완료 조건
- 실패에서 무엇을 고칠 것인가: 프롬프트가 아니라 누락된 문맥·도구·검증 루프
OpenAI는 하네스 엔지니어링을 소개하며 엔지니어의 역할이 코드를 직접 작성하는 것에서 환경을 설계하고, 의도를 명세하고, 피드백 루프를 만드는 것으로 이동한다고 설명한다. 또한 거대한 지침서 하나보다 짧은 진입 문서와 구조화된 저장소 지식을 권한다. Harness engineering: leveraging Codex in an agent-first world
프롬프트 엔지니어링, 컨텍스트 엔지니어링과 무엇이 다른가
세 개념은 경쟁 관계가 아니라 포함 관계에 가깝다.
| 구분 | 핵심 질문 | 주요 산출물 |
|---|---|---|
| 프롬프트 엔지니어링 | 모델에게 어떻게 지시할까? | 역할, 요청 문장, 출력 형식, 예시 |
| 컨텍스트 엔지니어링 | 지금 어떤 정보를 보여줄까? | 관련 문서, 코드, 작업 이력, 검색 결과 |
| 하네스 엔지니어링 | 에이전트가 어떻게 끝까지 올바르게 일하게 할까? | 문맥 라우팅, 도구, 권한, 워크플로우, 검증, 관찰 가능성 |
Anthropic은 컨텍스트 엔지니어링을 제한된 컨텍스트 창에 어떤 정보를 넣을지 선별하고 유지하는 작업으로 설명한다. 핵심은 가능한 모든 정보를 넣는 것이 아니라 원하는 행동을 만들 가능성이 높은 최소한의 고신호 정보를 넣는 것이다. Effective context engineering for AI agents
하네스 엔지니어링은 여기서 한 걸음 더 나간다. 좋은 정보를 제공하는 것뿐 아니라 에이전트의 행동을 실제 시스템 안에서 제약하고, 결과를 기계적으로 검사하고, 실패하면 다시 작업하게 만든다.
예를 들어 “기존 스타일에 맞게 안전하게 구현하고 테스트해 줘”라는 프롬프트는 의도는 좋지만 약하다. 다음 항목이 하네스에 포함되면 같은 요청이 훨씬 구체적인 실행 계약이 된다.
1. 변경 대상 경로에 맞는 규칙을 읽는다.
2. 기존 구현과 외부 계약을 조사한다.
3. 위험도에 따라 사용자 승인을 받는다.
4. 승인된 범위만 수정한다.
5. 관련 테스트와 정적 검사를 실행한다.
6. 변경 파일, 검증 결과, 미검증 위험을 보고한다.
하네스의 실행 루프 설계
에이전트는 보통 한 번의 모델 호출로 일을 끝내지 않는다. 현재 상태를 보고 다음 행동을 결정하고, 도구의 실행 결과를 다시 문맥으로 받아 다음 행동을 선택한다.
관찰 → 계획 → 도구 실행 → 결과 확인 → 수정
↑ │
└──── 완료 조건을 만족할 때까지 ──┘
루프 엔지니어링(Loop Engineering)은 이 반복 과정이 목표를 향해 수렴하도록 설계하는 일이다. 무엇을 반복할지만큼 언제 반복을 끝내거나 사람에게 넘길지가 중요하다.
아직 널리 표준화된 학술 용어라기보다는, 에이전트의 실행·평가·재시도 구조를 설명하는 실무적 표현에 가깝다. 하나의 루프는 대체로 다음 요소로 구성된다.
상태 → 판단 → 행동 → 관찰 → 평가
├─ 통과: 종료
├─ 수정 가능: 상태를 갱신하고 재시도
└─ 해결 불가·고위험: 사람에게 전달
- 성공 조건: 테스트와 계약 검사가 모두 통과했는가
- 재시도 조건: 실패 원인을 바탕으로 수정 가능한가
- 중단 조건: 최대 횟수·시간·비용을 넘었는가
- 에스컬레이션 조건: 권한, 계약, 요구사항이 불명확한가
- 상태 보존: 다음 반복에서 이전 실패와 시도 내용을 알 수 있는가
종료 조건이 없으면 같은 실패를 무한히 반복할 수 있고, 조건이 너무 느슨하면 테스트를 실행하지 않은 채 완료할 수 있다. 반대로 검증 결과를 구조화해 다시 제공하면 에이전트는 “실패했으니 다시 해 봐”가 아니라 어떤 파일과 조건을 고쳐야 하는지 알 수 있다.
좋은 루프의 목적은 반복 횟수를 늘리는 것이 아니라 검증 가능한 목표에 수렴하는 것이다. 같은 명령을 그대로 되풀이하기보다 각 반복에서 테스트 결과나 도구 출력으로 상태가 갱신되어야 한다. 새로운 근거 없이 같은 실패가 계속되면 재시도 횟수나 비용을 제한하고 사람에게 제어권을 넘겨야 한다.
OpenAI의 에이전트 가이드도 에이전트 실행을 종료 조건에 도달할 때까지 모델과 도구 호출을 반복하는 run으로 설명한다.
하네스 엔지니어링 사례에서는 코드 작성 후 리뷰와 피드백 반영을 검증이 만족될 때까지 반복하는 루프를 사용한다. A practical guide to building agents, Harness engineering: leveraging Codex in an agent-first world
즉 루프 엔지니어링은 하네스와 별개의 개념이라기보다, 하네스가 에이전트의 실행과 피드백을 제어하는 핵심 설계 영역으로 볼 수 있다.
좋은 하네스를 구성하는 여섯 가지 요소
1. 짧은 진입점과 탐색 가능한 지식
AI 지침 파일 하나에 모든 내용을 넣으면 처음에는 편하다. 하지만 프로젝트가 커질수록 컨텍스트를 많이 차지하고, 규칙의 최신 여부와 소유권도 불분명해진다.
더 나은 구조는 진입 문서를 지도로 사용하는 것이다.
AI 진입 문서
├── 항상 지킬 보안·행동 원칙
├── 작업 유형별로 읽을 문서 안내
└── 상세 문서의 위치
├── architecture
├── api-contracts
├── security
├── testing
└── workflow
에이전트는 모든 문서를 매번 읽지 않고, API 작업이면 API 계약과 보안 규칙을, DB 작업이면 스키마와 마이그레이션 규칙을 추가로 읽는다. 이것이 컨텍스트 라우팅이다.
2. 단일 진실 공급원(SSOT)
Claude, Codex 등 여러 에이전트를 함께 사용하면 도구별 진입 파일을 따로 둘 수 있다. 그러나 아키텍처 규칙까지 복사해 관리하면 곧 내용이 어긋난다.
공통 규칙은 한 위치에서 관리하고, 도구별 진입 파일에는 다음만 남기는 편이 낫다.
- 해당 도구에서 파일을 읽고 수정하는 방법
- 공통 규칙으로 이동하는 인덱스
- 도구에만 적용되는 예외
중복이 불가피하다면 규칙마다 소유 문서와 충돌 우선순위를 명시해야 한다. 그래야 에이전트가 서로 다른 두 문장을 만났을 때 주변 코드만 보고 임의로 결정하지 않는다.
3. 위험도에 따른 권한과 승인 게이트
모든 변경을 같은 방식으로 다루면 두 가지 문제가 생긴다. 사소한 오타에도 매번 승인을 기다리거나, 반대로 DB와 인증 변경까지 바로 실행해 버린다.
위험 등급을 나누면 행동 경계가 명확해진다.
| 위험도 | 예시 | 처리 방식 |
|---|---|---|
| 낮음 | 조회, 분석, 상태 확인 | 바로 수행 |
| 보통 | 국소적인 코드 수정, 테스트 보강 | 범위와 검증 방법 확인 |
| 높음 | API 계약, 여러 모듈, 데이터 모델 변경 | 계획과 영향 범위 승인 |
| 매우 높음 | 인증, 개인정보, 운영 인프라, 외부 부작용 | 롤백을 포함한 명시적 승인 |
중요한 것은 자연어로 “조심하라”고만 쓰지 않는 것이다. 파일 쓰기 범위, 실행 가능한 명령, 시크릿 출력 금지, 파괴적 작업 승인 같은 제약을 실행 환경에서도 함께 적용해야 한다. 가드레일은 하나의 거대한 방어막보다 입력·도구·출력 단계의 여러 방어층으로 설계하는 편이 안전하다. A practical guide to building agents
4. 작업을 끝까지 이끄는 표준 워크플로우
에이전트에게 자유만 주면 구현부터 시작하기 쉽다. 안정적인 하네스는 작업 순서를 명시한다.
Discovery → Contract Survey → Plan → Confirm → Implement → Verify → Refresh Docs
- Discovery: 영향 받는 모듈과 도메인 경계를 찾는다.
- Contract Survey: API, DB, 레거시 동작 같은 외부 계약을 확인한다.
- Plan: 각 구현 단계와 검증 방법을 짝지어 적는다.
- Confirm: 위험한 변경은 구현 전에 승인을 받는다.
- Implement: 승인 범위만 최소한으로 수정한다.
- Verify: 컴파일, 테스트, 린트, 구조 검사를 실행한다.
- Refresh Docs: 실제 코드와 명세·시스템 지도를 동기화한다.
이 순서는 에이전트를 느리게 만드는 절차가 아니다. 잘못된 방향으로 빠르게 많은 코드를 만드는 비용을 줄이는 장치다. 작업 규모에 따라 단순한 수정은 일부 단계를 축약할 수 있어야 한다.
5. 자연어 규칙을 기계적 검증으로 바꾸기
“컨트롤러가 저장소를 직접 호출하지 않는다”는 문서만으로는 언젠가 위반이 생긴다. 가능한 규칙은 린트나 구조 테스트로 옮겨야 한다.
자연어 규칙 기계적 검증
────────────────────────────────────────────
레이어 의존 방향을 지킨다 → 아키텍처 테스트
시크릿을 커밋하지 않는다 → secret scanner
API 계약을 유지한다 → OpenAPI diff / contract test
관련 테스트를 작성한다 → CI 테스트와 커버리지 기준
포맷을 통일한다 → formatter / linter
문서는 판단의 기준을 설명하고, 자동화는 반복 가능한 부분을 강제한다. 자동 검사를 통과시키려고 검사를 끄거나 기준선을 무조건 갱신하지 못하도록 하는 규칙도 필요하다. 그렇지 않으면 에이전트가 목표가 아니라 “초록색 결과”만 최적화할 수 있다.
6. 완료 증거와 피드백 루프
“수정했습니다”는 완료 증거가 아니다. 좋은 하네스는 최종 보고 형식까지 계약으로 만든다.
Changed
- 무엇을 왜 바꿨는가
Verified
- 어떤 명령을 실행했고 결과가 어땠는가
- 실행하지 못한 검증과 이유는 무엇인가
Contracts
- API, DB, 보안, 아키텍처 경계에 영향이 있는가
여기서 테스트 실패, 환경이 없어 미실행, 애초에 해당 없음은 서로 구분해야 한다. 실패 기록이 쌓이면 다음 질문도 바뀐다.
“AI가 왜 또 틀렸지?”가 아니라 “하네스에 어떤 능력이나 피드백이 빠져 있었지?”
사례 1 — 개인 MSA 프로젝트의 문맥 라우팅
개인적으로 운영하는 주식 분석 MSA 프로젝트에서는 여러 마이크로서비스와 공통 모듈, 프론트엔드, Docker 인프라를 한 저장소에서 관리한다. 처음에는 AI 지침에 프로젝트 설명을 계속 추가했지만, 문서가 길어질수록 정작 현재 작업과 관련된 규칙을 놓치는 문제가 생겼다.
이를 다음과 같이 바꿨다.
짧은 AI 진입 문서
├── 항상 적용: 시크릿 보호, 사용자 변경 보존, 최소 수정
├── API 작업: MSA 구조 + API 계약 + 보안 규칙
├── DB 작업: 서비스 경계 + migration + 테스트 규칙
├── 외부 API 작업: 보안 + 쿼터 + 재시도 규칙
└── 인프라 작업: 프로필 + 포트 + 배포 문서
핵심은 세 가지다.
첫째, 상세 규칙의 단일 진실 공급원을 두었다. 도구별 진입 파일은 달라도 아키텍처, 보안, API, 워크플로우 규칙은 같은 원문을 참조한다. 어떤 AI 도구를 사용하더라도 프로젝트의 핵심 원칙이 달라지지 않는다.
둘째, MSA의 Bounded Context를 행동 규칙으로 만들었다. 한 서비스가 다른 서비스의 데이터베이스를 직접 사용하거나 다른 도메인의 외부 API 호출 책임을 복제하지 못하도록 했다. 단순히 “MSA 원칙 준수”라고 쓰는 대신, 작업 시작 시 영향 서비스와 DB를 목록으로 만들고 경계 침범 여부를 확인하게 했다.
셋째, 구현과 검증을 하나의 루프로 묶었다. API 변경은 실제 실행 결과에서 생성한 명세와 비교하고, 구조가 바뀌면 시스템 지도를 갱신한다. 완료 보고에는 테스트 명령뿐 아니라 API 계약, DB 변경, 시크릿 노출 여부를 함께 적는다.
이 구조의 효과는 AI가 더 많은 내용을 외우게 된 것이 아니다. 필요한 순간에 필요한 근거로 이동할 수 있게 된 것이다.
사례 2 — 사내 레거시 CMS 현대화 프로젝트의 제약 설계
두 번째 사례는 회사나 서비스가 식별되지 않도록 일반화한 사내 레거시 CMS 현대화 프로젝트다. 오래된 서버 애플리케이션을 Spring 기반으로 전환하지만, 기존 데이터베이스와 프로시저 계약, 화면 동작을 상당 부분 유지해야 하는 프로젝트다.
이런 전환 작업에서 AI에게 “기존 기능과 똑같이 Java로 바꿔 줘”라고 요청하는 것은 위험하다. 코드 문법은 바꿀 수 있어도 다음 사실은 추론해서는 안 되기 때문이다.
- 프로시저 파라미터의 순서와 타입
- 여러 결과 집합의 인덱스와 컬럼 의미
- 데이터베이스 간 트랜잭션 경계
- 권한과 개인정보 공개 범위
- 레거시 화면의 숨은 상태 전이
그래서 이 프로젝트의 하네스는 추측 금지를 중심으로 구성했다.
사용자 요구
↓
적용 경로에 맞는 규칙 선택
↓
주변 Java 코드 + 원본 레거시 코드 + DB 계약 대조
↓
계약이 명확한가? ── 아니오 → 질문하고 대기
│
예
↓
레이어·네이밍·트랜잭션 규칙에 따라 구현
↓
Controller / Service / E2E 테스트로 역할별 검증
↓
자동 준수 검사 + diff 검사 + 완료 보고
규칙은 파일 경로에 따라 선택적으로 적용한다. Java 코드에는 네이밍·예외·레이어 규칙을, 컨트롤러에는 뷰 반환과 요청 처리 규칙을, 템플릿에는 UI 규칙을, 테스트에는 테스트 유형별 규칙을 적용한다. 모든 규칙을 모든 작업에 넣지 않으면서도 해당 파일을 수정할 때 필요한 제약은 빠지지 않는다.
또한 자연어 지침을 자동 준수 검사로 옮겼다. 예를 들면 다음과 같은 항목이다.
- 컨트롤러가 저장소를 직접 의존하지 않는가
- 화면에 영속 엔티티를 직접 전달하지 않는가
- 쓰기 작업에 감사 로그와 올바른 트랜잭션 경계가 있는가
- 테스트가 비활성화되어 실패를 우회하지 않는가
- 기존 위반 목록을 새 변경의 면제 수단으로 넓히지 않았는가
이 사례에서 하네스의 역할은 AI에게 프로젝트 지식을 많이 주는 데 그치지 않는다. 레거시 계약을 모르면 멈추고, 확인된 사실만 구현하며, 결과를 역할별 테스트로 증명하게 하는 것이다.
두 사례에서 공통으로 배운 것
| 원칙 | 개인 MSA 프로젝트 | 사내 레거시 현대화 프로젝트 |
|---|---|---|
| 진입점 | 짧은 인덱스에서 작업별 문서로 이동 | 변경 경로에 맞는 규칙만 적용 |
| 핵심 위험 | 서비스 경계 침범, 시크릿, 외부 부작용 | 레거시·DB 계약 추측, 개인정보, 트랜잭션 |
| 검증 | 모듈 테스트, API 명세, 시스템 지도 | 컴파일, 계층별 테스트, 자동 준수 검사 |
| 중단 조건 | 위험 변경의 승인 부재 | 계약 근거가 불명확하거나 규칙이 충돌함 |
| 완료 증거 | 변경·검증·계약 영향 보고 | 변경·검증·미실행 사유 보고 |
도메인은 다르지만 공통점은 분명하다.
- AI에게 모든 것을 기억시키지 않고 찾는 방법을 준다.
- 권고로 끝낼 규칙과 기계적으로 강제할 규칙을 구분한다.
- 구현 전에 성공 조건과 중단 조건을 정한다.
- 테스트 결과뿐 아니라 계약과 보안 영향까지 완료 증거에 포함한다.
- 실패할 때 같은 프롬프트를 반복하지 않고 환경의 결손을 고친다.
하네스를 처음 만들 때의 순서
처음부터 거대한 에이전트 플랫폼을 만들 필요는 없다. 저장소 안에서 다음 순서로 시작할 수 있다.
1단계 — 반복되는 실패 세 가지를 기록한다
AI가 자주 틀리는 지점을 구체적으로 적는다. “코드 품질이 낮다”가 아니라 “다른 모듈의 저장소를 직접 호출한다”, “테스트를 실행하지 않고 완료했다고 한다”처럼 관찰 가능한 문장이어야 한다.
2단계 — 짧은 진입 문서를 만든다
프로젝트 개요, 항상 지킬 원칙, 상세 문서로 가는 링크만 둔다. 진입 문서가 백과사전이 되기 시작하면 내용을 별도 문서로 분리한다.
3단계 — 성공과 중단 조건을 쓴다
각 작업은 무엇을 통과해야 완료인지, 어떤 위험에서는 사용자에게 제어권을 돌려줘야 하는지 정한다.
4단계 — 검증 명령을 저장소에 둔다
빌드, 관련 테스트, 린트, 계약 검사를 에이전트가 그대로 실행할 수 있는 명령으로 제공한다. 문서에 “충분히 테스트”라고만 쓰는 것보다 실행 가능한 한 줄이 낫다.
5단계 — 반복 위반을 자동화한다
모든 규칙을 한 번에 린트로 만들지 않는다. 실제로 반복되는 실수, 피해가 큰 실수, 문자열이나 구조로 안정적으로 판단 가능한 규칙부터 자동화한다.
6단계 — 실패를 하네스 개선 작업으로 환류한다
실패 원인을 다음 중 하나로 분류하면 개선 지점을 찾기 쉽다.
- 지식 부족: 문서나 시스템 지도가 없었다.
- 탐색 실패: 문서는 있었지만 진입점에서 찾을 수 없었다.
- 도구 부족: 확인하거나 실행할 방법이 없었다.
- 경계 부족: 위험한 행동을 막는 승인·권한 장치가 없었다.
- 피드백 부족: 잘못된 결과를 잡아낼 테스트나 린트가 없었다.
주의할 점
문서를 많이 쓰는 것이 목적이 아니다
문서가 많아도 오래되었거나 서로 충돌하면 오히려 성능을 떨어뜨린다. 각 문서의 소유권, 갱신 조건, 실제 코드와의 연결이 중요하다.
에이전트를 지나치게 절차에 가두지 않는다
모든 오타 수정에 긴 계획과 승인을 요구하면 하네스가 병목이 된다. 변경 위험도에 따라 절차를 축약할 수 있어야 한다.
자연어 가드레일만 믿지 않는다
“절대 시크릿을 출력하지 마라”는 중요한 지침이지만, 접근 권한 제한과 시크릿 스캔이 함께 있어야 한다. 모델의 준수와 시스템의 강제는 서로 다른 방어층이다.
테스트 통과를 목표 그 자체로 만들지 않는다
에이전트는 주어진 평가 기준을 최적화한다. 실패한 테스트를 비활성화하거나 검증을 약화해도 성공으로 보이는 구조라면 하네스가 잘못 설계된 것이다. 테스트 우회 금지와 변경된 계약의 직접 검증이 함께 필요하다.
마무리
프롬프트 엔지니어링은 AI에게 일을 잘 설명하는 기술이다. 하네스 엔지니어링은 AI가 일을 잘할 수밖에 없는 환경에 가깝게 만드는 기술이다.
좋은 하네스가 있어도 모델은 실수한다. 하지만 실수가 테스트에서 드러나고, 위험한 작업에서는 멈추며, 실패 원인이 다음 실행의 규칙과 도구로 축적된다. 이 피드백 루프가 만들어지면 AI 활용은 개인의 프롬프트 감각에서 팀과 저장소가 공유하는 엔지니어링 자산으로 바뀐다.
결국 중요한 질문은 “어떤 모델이 코드를 가장 잘 쓰는가?” 하나가 아니다.
이 에이전트가 우리 프로젝트에서 올바른 문맥을 찾고, 허용된 행동만 하고, 결과가 맞는지 증명할 수 있는가?
그 질문에 프로젝트 구조와 자동화로 답하는 일이 하네스 엔지니어링이다.
