AI/엔지니어링

3. Harness Engineering(하네스 엔지니어링) — AI가 실수를 못하게 하기위해 규칙과 울타리를 설계하는 기술

조슈아。 2026. 4. 8. 15:32
반응형

하네스 엔지니어링(Harness Engineering)

AI가 실수를 못하게 하기위해 규칙과 울타리를 설계하는 기술 — 제어의 기술

  • 하네스(Harness)는 원래 말에 채우는 마구(馬具)에서 유래한 단어로, AI 맥락에서는 AI 모델을 안전하고 제어 가능하게 “장착”하는 구조적 틀을 의미
  • 강력한 것을 제어하여 유익하게 활용한다는 의미로 쓰이며, AI에서는 올바른 방향으로 제어하면서 최대한 활용하기 위한 구조를 일컫는 표현

[말을 비유로 이해]

AI 에이전트를 거대한 짐말(draft horse)이라고 생각

  • 에이전틱 엔지니어링 = 말 훈련
    • 추론 루프 설계, 멀티 에이전트 조율, 도구 사용법 교육 → 말 자체를 더 강하게 만드는 것
  • 하네스 엔지니어링 = 마구 제작
    • 가죽 끈, 고삐, 수레를 만드는 것 → 말이 밭을 갈 수 있도록 방향과 한계를 정해주는 장비

말을 아무리 잘 훈련시켜도, 마구 없이는 밭을 갈 수 없음

하네스란 AI 에이전트가 가장 안전하고 예측 가능한 방식으로 작동하도록 설계된 제어 구조의 전체

  • AI의 불확실성(환각, 편향 등)을 억제하고 비즈니스 로직 안에서만 작동하게 만드는 울타리
  • 가드레일(Guardrails) 설정, 출력 형식의 강제(JSON 등), 에러 핸들링, 그리고 결과물이 정확한지 검증하는 Evals(평가) 체계 구축
  • 아무리 똑똑한 에이전트라도 하네스(안전장치)가 없다면 실제 서비스로 출시하기 어려움

AI에게 잘 일할 수 있는 환경을 설계하는 것 - [팀원처럼 위임하는 방식]

  • 규칙, 작업구조를 미리 합의
  • 검증 기준을 사전에 정의
  • 실행 루프로 반복 개선
  • 일관된 고품질 결과물

하네스의 역할

하네스는 단순히 AI 에이전트를 동작시키는 데 그치지 않고, 3가지 기능을 통합적으로 담당

  • 제어(Control) : 에이전트가 허용된 범위 밖의 행동을 하지 않도록 제안하는 구조
  • 감시(Monitoring) : 에이전트 동작 상태와 출력 결과를 실시간으로 추적 및 기록하는 구조
  • 개선(Feedback) : 오류나 이상 동작을 감지하고 다음 동작에 반영하는 피드백 루프

하네스 엔지니어링의 4가지 구성 요소

AI - 새로 들어온 팀원

“나는 바쁜 팀장이에요. AI한테 일을 위임하고 싶어요.”

1. 규칙, 헌법, 가드레일(Rule, Constitution, Guardrails) -- 의도를 잘 전달하기 위해 규칙을 적어놓은 문서(소통)

[Rule, Constitution] — 우리팀은 이렇게 일해

  • 에이전트가 적시에 적절한 정보(아키텍처 사양, 스타일 가이드, 프로젝트 규칙 등)를 갖도록 보장하는 것으로, 정적 파일(CLAUDE.md, AGENTS.md)을 활용하여 에이전트에게 필요한 컨텍스트를 구조화하여 주입
[예시] CLAUDE.md에 "새로운 라이브러리를 도입하지 마세요. DB 쿼리는 반드시 ORM을 통해서만 해주세요”라고 작성하면, AI 에이전트는 이 규칙을 자신의 행동 제약으로 인식. 매번 프롬프트에 반복할 필요가 없다.
  • [Guardrails] — AI가 입력을 받거나 답변을 내보내기 직전에 필터링하는 단계
    • Input Guardrail: 유해한 질문, 개인정보 유출 시도(Prompt Injection), 범위를 벗어난 요청을 차단
    • Output Guardrail: 모델이 욕설, 편향된 발언, 혹은 기업 비밀을 답변에 포함하는지 실시간으로 감시하고 차단
  • 컨텍스트 엔지니어링 (Context Engineering / Structured Context)을 작성
    • 에이전트에게 필요한 정보를 적시에 제공하는 기술. 단, 모든 지침을 하나의 파일에 몰아넣는 것은 지양
      • 거대한 AGENTS.md 피하기: 하나의 거대한 지침 파일은 에이전트에게 혼란을 주고, 금방 유지보수가 안 되는 '낡은 규칙들의 무덤'이 되버림
      • 점진적 정보 제공 (Progressive Disclosure): 메인 지침 파일은 100줄 이내의 '목차' 역할만 하도록 유지하고, 상세한 내용은 docs/ 하위 디렉터리에 구조화하여 에이전트가 필요할 때 깊이 탐색하게 만든다.
      • 단일 진실 공급원 (SSOT): Slack 스레드나 개발자의 머릿속에 있는 지식은 에이전트에게 존재하지 않는 것과 같으므로, 모든 계획과 설계 내역은 리포지터리 내부에 아티팩트(Artifact)로 저장해야 한다.

2. 아키텍처 제약 조건 및 스캐폴딩(Architectural Constraints & Scaffolding) — 어떤 정보를 참조하게 할 것인가(지식)

규칙은 문서로 남기는 것이 아니라, 코드로 강제해야 한다. 에이전트의 자유도를 제한할수록 오히려 올바른 결과물에 더 빨리 도달한다.

  • [작업 구조(Task Structure)] - 무엇을 어떻게 만드는지 정의하는 작업 지시서
    • 이건 꼭 지켜야 해(Linter)
    • 이건 하면 안돼(제약)
    • 수정 지침 주입: 린터 에러 메시지에 '해결 방법'을 포함시켜 작성. 에러 발생 시 에이전트가 메시지를 읽고 즉시 자체 수정할 수 있는 피드백 루프를 형성
    • AI에게 "좋은 코드를 짜라"고 말하는 대신, 구조적으로 실수할 수 없는 환경을 만든다.
    • 화이트리스트 방식을 통해 필요한 최소한의 도구 권한만 부여하거나, 작업 공간을 완전히 격리하여 외부 영향을 차단
  • [출력 검증 및 구조화 (Output Parsing & Validation)]
    • AI의 답변이 프로그램이 이해할 수 있는 형태인지 확인하고 강제
    • Schema Enforcement: 답변이 반드시 정해진 JSON 형식을 따르도록 정의. 형식이 틀리면 에이전트가 스스로 수정하게 하거나 에러 처리
      • ex) 반드시 {"status": "success", "data": ...} 형식으로 답해줘. 아니면 에러야.
    • Hallucination Check: 답변 내용이 제공된 컨텍스트(Context)에 실제로 존재하는 내용인지 사실 관계를 교차 검증
      • AI가 "A는 B다"라고 답하면, 시스템이 컨텍스트 문서에서 "A"와 "B"의 관계를 재검색하여 일치 여부 확인
  • [CI/CD Gate]
    • 코드 린터, 구조 테스트, pre-commit hook 등을 통해 규칙을 시스템이 자동으로 강제
      • 린터(Linter) — 코드가 규칙을 어기면 자동으로 에러를 띄움
      • 구조 테스트 — 의존성 규칙을 테스트로 강제
      • Pre-commit Hook — 코드를 커밋하기 전에 자동으로 검사
CI가 실패하면 에이전트가 스스로 수정하고 사람이 개입하지 않음

3. 검증 및 피드백 루프 (Verification & Feedback Loops / Hooks) — 어떤 구조와 제약 속에서 움직이게 할 것인가(규칙)

에이전트가 자신이 작성한 코드를 스스로 평가하게 하면 편향이 발생하므로, AI가 생성한 결과물을 코드로 자동 검증하는 장치이다. 오류가 발생하면 3단계 검사(오류 식별 -> 관련 테스트 실행 -> 자동 수정)를 수행하고, 성공할 때까지 반복하거나 사람에게 보고

  • [검증(Validation)]
    • 결과물이 괜찮은지 기준을 미리 정의해두는 것
      • 이런 결과물이 나와야 해
      • 작업 지시서와 검증 기준 합의
  • [평가 체계 (Evaluations, Evals)]
    • "이 프롬프트가 이전보다 나아졌는가?"라는 질문에 데이터로 답하는 과정
      • LLM-as-a-Judge: 더 똑똑한 모델(예: GPT-4o)을 심판으로 세워, 서비스 모델의 답변 품질을 점수로 매긴다.
      • Regression Testing: 프롬프트를 수정했을 때, 기존에 잘 되던 답변들이 망가지지 않았는지 수백 개의 테스트 케이스를 돌려 확인
      • Ground Truth: 정답셋을 만들어 놓고 AI의 답변과 유사도를 비교
      • 회의적인(Skeptical) 평가자 구성: 코드를 생성한 에이전트와 독립된 평가용 인스턴스를 두어, "이 PR의 문제점만 찾아라"와 같은 회의적인 프롬프트로 리뷰를 요청
      • 무한 루프 방지 및 해결: 에이전트가 리뷰 코멘트를 반영하고, 수정하고, 다시 평가받는 과정을 루프(Ralph Wiggum Loop)로 구축하여 사람의 개입 없이 기준을 통과할 때까지 반복
  • [명시적 도구 경계]
    • AI 에이전트가 어떤 도구를 쓸 수 있고, 어디까지 접근할 수 있는지를 명확하게 제한
      • 파일 시스템: src/ 읽기·쓰기 가능, config/ 읽기만 가능
      • API: 내부 API 호출 가능, 외부 서비스 호출 불가
      • 데이터베이스: SELECT 가능, DROP TABLE 절대 불가
프롬프트는 부탁이고, 도구 경계는 물리적 차단

4. 엔트로피 관리 및 가비지 컬렉션 (Entropy Management / Garbage Collection) — 결과물을 어떻게 신뢰할 것인가(품질)

AI가 작업을 수행하면서 발생하는 기술 부채나 불필요한 데이터를 정리하는 과정입니다. 이전 단계에서 쌓인 오정보나 중복된 코드를 에이전트가 직접 정리하여 효율성을 유지

  • [관측성 및 로깅 (Observability & Monitoring)]
    • 실제 서비스 중 AI가 어떻게 작동하는지 추적하는 'CCTV'와 같다.
      • Traceability: 에이전트가 어떤 도구를 써서 어떤 답변을 냈는지 전체 경로를 추적
      • Token & Cost Control: 예상치 못한 무한 루프나 과도한 토큰 사용으로 인한 '비용 폭탄'을 방지하기 위한 한계선(Threshold)을 설정
      • Feedback Loop: 사용자의 '좋아요/싫어요' 데이터를 수집하여 다시 프롬프트나 컨텍스트 개선에 활용
  • [지속적 피드백 루프]
    • AI가 만든 코드를 주기적으로 점검하고 품질이 떨어지는 부분을 자동으로 감지 및 정리
      • 실행루프(Agent Loop)
        • 수정 → 검증 → 수정 → 확인 을 만족할 때까지 반복
        • workflow 반복
      • 코딩 규칙 위반 자동 감지
      • 중복 코드 발견 및 리팩토링 PR 자동 생성
      • 사용하지 않는 코드 자동 제거
에이전트가 실수할 때마다, 그 실수는 새로운 규칙이 된다. 린터 규칙이 추가되고, 테스트가 추가되고, 제약이 추가되고, 마구가 점점 더 정교해짐

에이전트의 위임 범위

제대로 구축된 하네스 환경에서 에이전트는 단순한 코드 스니펫을 넘어 다음과 같은 광범위한 작업을 수행할 수 있다.

  • 제품 코드 및 테스트 작성
  • CI/CD 파이프라인 구성 및 릴리스 툴링
  • 내부 개발자 도구 및 리포지터리 관리 스크립트 작성
  • 문서화 및 설계 내역 정리
  • PR 리뷰 코멘트 작성 및 응답
  • 생산 대시보드 및 관측성(Observability) 정의 파일 설정

4대 축의 상호작용 (The Synergy)

하네스 엔지니어링이 완성되면 비로소 다른 축들이 빛을 발한다.

  1. Prompt(프롬프트) + Harness(하네스): 아무리 프롬프트를 잘 짜도 AI는 1%의 확률로 헛소리를 하는데, 하네스는 그 1%를 잡아낸다.
  2. Context(컨텍스트) + Harness(하네스): 외부 지식을 가져올 때(RAG), 하네스는 그 지식이 질문과 관련이 있는지, 혹은 오염된 데이터인지 검사한다.
  3. Agentic(에이전틱) + Harness(하네스): 자율적으로 행동하는 에이전트에게 "최대 5단계까지만 생각하라"거나 "이 API는 호출하지 마라"는 물리적 제약(Constraints)을 부여한다.

개발자 역할의 진화

엔지니어링역할비유

엔지니어링 역할 비유
Prompt 프롬프트 엔지니어 AI에게 의도를 정확히 전달하는 사람
Context 컨텍스트 아키텍트 AI가 참조할 지식 체계를 설계하는 사람
Harness 플랫폼 엔지니어 AI가 실수할 수 없는 환경을 만드는 사람

하네스 엔지니어링의 두 단계의 역할

Repository 하네스

우리회사는 이렇다!


  • AI가 이 저장소 전체에서 어떻게 일할지
  • 문서 구조, 팀 규칙, 코드 린터
  • 아키텍처 제약 같은 공통환경
  • 모든 프로젝트에 적용되는 기반

Application 하네스

이 프로젝트는 이렇다!


  • 프로젝트 별로 만들고 싶은 앱, 서비스
  • 어떤 기능과 경험을 줘야 하는지
  • AI가 이 앱을 위해 어떻게 판단할지
  • 해당 프로젝트에만 적용되는 규칙

https://openai.com/ko-KR/index/harness-engineering/

 

아래와 같은 구조로 시작

AGENTS.md
ARCHITECTURE.md
docs/
├── design-docs/
│   ├── index.md
│   ├── core-beliefs.md
│   └── ...
├── exec-plans/
│   ├── active/
│   ├── completed/
│   └── tech-debt-tracker.md
├── generated/
│   └── db-schema.md
├── product-specs/
│   ├── index.md
│   ├── new-user-onboarding.md
│   └── ...
├── references/
│   ├── design-system-reference-llms.txt
│   ├── nixpacks-llms.txt
│   ├── uv-llms.txt
│   └── ...
├── DESIGN.md
├── FRONTEND.md
├── PLANS.md
├── PRODUCT_SENSE.md
├── QUALITY_SCORE.md
├── RELIABILITY.md
└── SECURITY.md

구조분석

파일/폴더 역할 작성 주체

AGENTS.md 에이전트 행동 규칙 인간 (한 번)
ARCHITECTURE.md 시스템 전체 지도 인간 (한 번 + 업데이트)
design-docs/ 설계 원칙 및 결정 인간
exec-plans/active/ 현재 작업 지시서 인간이 작성 → 에이전트가 실행
product-specs/ 기능 명세 인간
references/ 압축된 라이브러리 문서 인간 (or 에이전트가 생성)
DESIGN.md API 포맷·네이밍 등 내부 설계 기준 인간 (한 번 + 협의 시 업데이트)
FRONTEND.md 클라이언트 연동 계약·에러코드 정의 인간 (클라이언트팀과 협의)
QUALITY_SCORE.md 코드 품질 자체 평가 체크리스트 인간
RELIABILITY.md 장애 대응·타임아웃·재시도 기준 인간
SECURITY.md 보안 체크리스트·금지 패턴 인간
docs/generated/ 에이전트가 생성한 산출물 에이전트

에이전트 제어 레이어

AGENTS.md

에이전트가 어떻게 행동해야 하는지 정의하는 메타 지시서 [행동 헌법]

- 너는 어떤 역할이야
- 코드 작성할 때 이 규칙을 따라
- 모르면 이렇게 해
- 절대 하면 안 되는 것

사람으로 치면 "신입 개발자 온보딩 문서"인데, 읽는 대상이 AI 이기 때문에 모호한 표현 없이 명확하게 작성해야 한다. Claude Code 기준으로는 이 파일을 프로젝트 루트에 두면 매 세션마다 자동으로 읽음

ARCHITECTURE.md

시스템 전체 구조를 에이전트가 참조하는 지도

- 서비스 구성 (모듈, 레이어)
- 주요 데이터 흐름
- 외부 의존성
- 레이어 간 책임 경계

에이전트가 새 기능을 추가할 때 "이게 어디에 들어가야 하지?"를 판단하는 근거. 이게 없으면 엉뚱한 레이어에 코드를 추가하게됨

의사결정 문서 레이어 (docs/)

design-docs/

기술적 의사결정 기록. ADR(Architecture Decision Record)과 비슷

  • index.md — 전체 설계 문서 목록
  • core-beliefs.md — "우리는 이런 이유로 이렇게 설계한다"는 원칙
# core-beliefs.md
- DB 트랜잭션 경계는 Service 레이어에서만 관리한다
- 외부 API 호출은 반드시 별도 Client 클래스로 분리한다
- 도메인 객체는 인프라 의존성을 가지지 않는다

exec-plans/

실행 계획 관리.

exec-plans/
├── active/        ← 지금 진행 중인 작업
├── completed/     ← 완료된 작업 (히스토리)
└── tech-debt-tracker.md  ← 기술 부채 목록

active/ 안에 파일 하나가 하나의 작업 단위

# feat/sensor-api.md

## 목표
쿠폰 API 구현

## 범위
- [ ] CouponController
- [ ] CouponService
- [ ] CouponRepository

## 제약
- 쿠폰 중복 등록은 안됨
- 쿠폰은 최대 2개까지만 가능

## 완료 기준
- 단위 테스트 커버리지 80% 이상

product-specs/

기능 명세서 (AI 에이전트가 "무엇을 만들지" 참조)

  • index.md — 전체 기능 목록 및 상태
  • new-user-onboarding.md — 기능별 상세 명세
## 사용자 스토리
신규 가입자가 앱 첫 실행 시 3단계 온보딩을 완료한다

## 화면 흐름
1. 환영 화면
2. 관심사 선택
3. 알림 동의

## API 요구사항
- POST /onboarding/complete
- 완료 시 웰컴 쿠폰 발급 (CouponService 연동)

references/

외부 라이브러리 LLM 최적화 문서

라이브러리 공식 문서를 그대로 넣으면 토큰 낭비가 심해서, AI가 읽기 좋게 압축한 버전을 따로 만들어둔 것

[예: Spring Data JPA 문서]

# Spring Data JPA - LLM Reference
## Repository 정의
interface UserRepository extends JpaRepository<User, Long> {}

## 쿼리 메서드
findByEmailAndStatus(String email, Status status)
→ WHERE email = ? AND status = ?

## 주의사항
- N+1 문제: @EntityGraph 또는 fetch join 사용

품질 기준 레이어

QUALITY_SCORE.md — 에이전트가 코드를 생성할 때 지켜야 할 기준

## 체크리스트
- [ ] 메서드 단위 테스트 존재
- [ ] 예외 처리 명시
- [ ] 로깅 포함
- [ ] 매직 넘버 없음

RELIABILITY.md — 장애 대응 기준

- 외부 API 호출은 timeout 설정 필수
- 재시도 로직은 exponential backoff 적용
- 서킷브레이커 적용 대상 목록

SECURITY.md — 보안 체크리스트

- SQL 인젝션 방어 (파라미터 바인딩 필수)
- 민감 정보 로그 출력 금지
- 인증 없는 엔드포인트 목록 명시

DESIGN.md — 디자인 시스템 제약: 시스템의 미적/구조적 일관성 기준

프론트엔드가 있으면 UI 디자인 시스템이 들어가지만, 백엔드 전용 프로젝트라면 API 구조 포멧 정의

에이전트가 새 API를 만들 때마다 이 파일을 참조해서 포맷을 통일시킴. 이게 없으면 어떤 API는 data, 어떤 건 result, 어떤 건 response로 제각각 만들게됨

**# DESIGN.md

## API 응답 포맷
모든 응답은 아래 구조를 따른다

{
  "success": true,
  "data": {},
  "error": null
}

## 에러 응답 구조
{
  "success": false,
  "data": null,
  "error": {
    "code": "USER_NOT_FOUND",
    "message": "사용자를 찾을 수 없습니다"
  }
}

## 네이밍 컨벤션
- URL: kebab-case  → /car-wash-missions
- JSON 필드: camelCase → userId, createdAt
- 에러 코드: UPPER_SNAKE_CASE → INVALID_TOKEN

## 페이지네이션 구조
{
  "content": [],
  "page": 0,
  "size": 20,
  "totalElements": 100
}**

FRONTEND.md — 디자인 시스템 제약 : 외부(클라이언트)와의 연동

프론트팀이 없어도, 앱 클라이언트나 외부 연동이 있다면 필요

## 클라이언트 연동 원칙
- 필드 삭제 금지, 추가만 허용 (하위 호환성 유지)
- Null 필드는 응답에서 제외하지 않고 명시적으로 null 반환
- 날짜 포맷: ISO 8601 (2024-01-15T09:00:00Z)

## 인증
- Authorization: Bearer {token} 헤더 방식
- 토큰 만료 시 401 응답, refresh는 클라이언트 책임

## 에러 코드 목록
| 코드 | 의미 | HTTP Status |
|------|------|-------------|
| USER_NOT_FOUND | 사용자 없음 | 404 |
| INVALID_TOKEN | 토큰 오류 | 401 |
| MISSION_EXPIRED | 미션 만료 | 410 |

## 비동기 작업 처리
- 즉시 응답: 202 Accepted + jobId 반환
- 상태 조회: GET /jobs/{jobId}
반응형