같은 AI를 써도, 어떤 팀은 초안에서 멈추고 어떤 팀은 배포 가능한 산출물을 만든다.
차이는 모델 자체보다 모델을 둘러싼 작업 방식에서 나온다.
요즘 AI 코딩 도구를 쓰다 보면 이런 생각이 든다.
“분명 같은 모델을 쓰는데 왜 결과물 차이가 이렇게 크지?”
누군가는 AI에게 간단한 초안만 받고 끝난다. 반면 어떤 팀은 AI 에이전트를 이용해 실제 배포 가능한 코드, 테스트, 문서, PR까지 만들어낸다.
이 차이를 만드는 핵심 개념이 하네스 엔지니어링(Harness Engineering) 이다.
모델은 두뇌에 가깝고, 하네스는 그 두뇌가 일하는 방식이다. 프롬프트 몇 줄을 잘 쓰는 수준이 아니라, AI가 실수하기 어려운 환경을 만들고, 작업 의도와 검증 루프를 설계하는 기술에 가깝다.
개발자의 역할도 조금씩 바뀌고 있다. 예전에는 직접 코드를 작성하는 시간이 대부분이었다면, 이제는 AI 에이전트가 올바르게 일하도록 컨텍스트, 도구, 권한, 검증, 피드백 루프를 설계하는 비중이 커지고 있다.
말하자면 개발자는 이제 단순히 코드를 작성하는 사람이 아니라, AI 에이전트를 관리하는 팀장 혹은 플랫폼 설계자에 가까워지고 있다.
하네스 엔지니어링을 한 문장으로 정리하면 다음과 같다.
Agent = Model + Harness
여기서 하네스는 모델이 아니다. 모델을 둘러싼 모든 코드, 설정, 실행 로직, 검증 구조를 의미한다.
AI 에이전트가 실수했을 때 단순히 프롬프트만 고치는 것은 근본적인 해결이 아닐 때가 많다.
AI 에이전트가 실수했다면,
프롬프트를 고치는 데서 멈추지 말고,
그 실수가 반복될 수 없도록 하네스를 고쳐야 한다.
예를 들어 AI가 계속 테스트 없이 기능을 구현한다면, “다음부터 테스트 먼저 작성해줘”라고 말하는 것만으로는 부족하다.
더 좋은 방식은 다음과 같다.
CLAUDE.md나 AGENTS.md에 TDD 규칙을 명시한다.즉, 하네스 엔지니어링은 AI에게 “잘해줘”라고 부탁하는 것이 아니라, 잘할 수밖에 없는 구조를 만드는 일이다.
AI를 활용하는 방법론은 크게 네 가지 축으로 볼 수 있다. 이들은 순서대로 졸업하는 단계라기보다, 서로 보완되는 개념에 가깝다.
| 축 | 핵심 | 비유 |
|---|---|---|
| Prompt Engineering | AI에게 말을 잘 거는 기술 | 주문을 정확하게 하기 |
| Context Engineering | AI에게 필요한 정보를 적절히 제공하는 기술 | 재료를 잘 골라주기 |
| Harness Engineering | AI가 실수하기 어려운 환경을 만드는 기술 | 말에게 마구를 씌우기 |
| Agentic Engineering | AI 에이전트를 설계하고 조율하는 기술 | 말을 훈련시키고 팀으로 운영하기 |
Prompt Engineering은 여전히 중요하다. 하지만 프롬프트만으로는 작업 규모가 커질 때 한계가 온다.
Context Engineering은 AI에게 필요한 정보를 잘 넣는 기술이다. 하지만 좋은 컨텍스트를 넣어도 검증 구조가 없다면, 그럴듯하지만 틀린 결과물이 나올 수 있다.
Agentic Engineering은 여러 에이전트의 역할과 추론 루프를 설계하는 영역이다. 하지만 에이전트가 아무리 똑똑해도 실행 환경과 권한, 검증 기준이 허술하면 결과물이 흔들린다.
그래서 하네스 엔지니어링이 중요해진다.
하네스는 AI 에이전트가 움직이는 환경 자체를 제어한다. 어떤 정보를 볼 수 있는지, 어떤 도구를 쓸 수 있는지, 어떤 기준을 통과해야 완료로 인정되는지를 시스템으로 강제한다.
AI 에이전트를 거대한 짐말이라고 생각해보자.
말 자체를 훈련시키는 것은 Agentic Engineering에 가깝다.
반면 하네스 엔지니어링은 마구를 만드는 일에 가깝다.
말을 아무리 잘 훈련시켜도, 마구가 없으면 밭을 제대로 갈 수 없다.
AI도 마찬가지다. 모델이 아무리 좋아도, 프로젝트의 규칙과 실행 환경, 검증 루프가 없다면 실제 프로덕션 수준의 결과물을 안정적으로 만들기 어렵다.
하네스를 구성하는 요소는 크게 다섯 가지다.
| 구성 요소 | 예시 | 역할 |
|---|---|---|
| 컨텍스트 | CLAUDE.md, AGENTS.md, docs/ | 모델이 읽어야 할 프로젝트 지식 |
| 도구 | Shell, File System, Browser, MCP, Sandbox | 모델이 실제 작업을 수행하는 인터페이스 |
| 루프 | 실행 → 관찰 → 판단 → 재시도 | 한 번의 답변이 아니라 반복 개선을 만드는 구조 |
| 검증 | Lint, Test, Eval, Grader | 결과물이 맞는지 확인하는 기준 |
| 사람 감독 | 승인, 정책, 리뷰, merge | 최종 판단과 위험 작업 제어 |
좋은 하네스는 모델에게 “알아서 잘해봐”라고 말하지 않는다.
대신 모델이 헤매지 않도록 작업장을 정리해준다.
이 기준들이 시스템 안에 들어갈수록 AI의 결과물은 안정된다.
AI를 단순히 채팅하듯 쓰면 보통 이런 흐름이 된다.
1. 사람이 프롬프트를 작성한다.
2. 모델 결과를 확인한다.
3. 문제가 있으면 다시 설명한다.
4. 이 과정을 반복한다.
이 방식은 빠르게 시작하기 좋다. 하지만 작업이 커질수록 문제가 생긴다.
사람이 계속 상태를 기억해야 하고, 문제를 찾아서 다시 설명해야 한다. AI가 테스트를 통과했다고 말해도 실제로는 실패할 수 있다. 중간에 세션이 끊기면 어디까지 했는지 추적하기 어렵다.
하네스 기반 작업은 조금 다르다.
1. 목표와 검증 기준을 먼저 설정한다.
2. 에이전트가 탐색하고 수정한다.
3. 자동 검증을 실행한다.
4. 실패하면 에러를 다시 전달하고 재시도한다.
5. 사람은 supervisor 역할을 맡는다.
핵심은 사람이 모든 반복을 직접 제어하지 않는다는 점이다.
사람은 목표, 제약, 승인, 최종 판단을 담당한다. 반복 실행과 검증은 하네스가 맡는다.
AI 코딩 결과물의 품질은 보통 세 가지 축에서 갈린다.
이 세 가지는 따로 떨어진 개념이 아니다.
좋은 컨텍스트를 넣어도 도구와 실행 환경이 엉망이면 결과물이 흔들린다. 도구가 좋아도 검증 루프가 없으면 “그럴듯하지만 틀린 코드”가 그대로 남는다.
결국 AI 에이전트를 잘 쓰는 팀은 단순히 프롬프트를 잘 쓰는 것이 아니라, 컨텍스트를 정리하고, 도구 사용 범위를 설계하고, 결과를 계속 평가하는 구조를 만든다.
컨텍스트는 많이 넣을수록 좋아 보인다. 하지만 실제로는 그렇지 않다.
컨텍스트는 제한된 예산이다. 모델이 읽을 수 있는 양이 많아져도, 중요한 신호가 묻히면 결과물은 오히려 나빠진다.
긴 문서를 통째로 넣는 것보다, 지금 작업에 필요한 정보를 정확히 넣는 편이 훨씬 낫다.
작업 시작 시점에 바로 주입해야 하는 정보는 다음과 같다.
이 정보들은 작업의 방향을 결정한다. 초반에 빠지면 모델이 잘못된 기준으로 구조를 잡을 수 있다.
반대로 아래 정보들은 처음부터 전부 넣기보다, 필요할 때 도구로 가져오게 만드는 편이 좋다.
이렇게 해야 컨텍스트가 불필요하게 비대해지지 않는다.
컨텍스트를 매번 감으로 넣으면 재현성이 떨어진다. 그래서 프로젝트 안에 AI가 읽을 지식 지도를 만들어 두는 것이 좋다.
예시는 다음과 같다.
repo-root/
├── AGENTS.md # 짧은 ToC / 진입점
├── ARCHITECTURE.md # 최상위 구조 설명
├── docs/
│ ├── design-docs/ # 설계 문서
│ ├── product-specs/ # 수용 기준 / 제품 스펙
│ ├── references/ # 외부 레퍼런스
│ └── exec-plans/ # 실행 계획과 회고 기록
├── QUALITY_SCORE.md # 품질 루브릭
└── SECURITY.md # 보안 규칙
중요한 점은 루트 문서가 모든 내용을 담는 백과사전이 되면 안 된다는 것이다.
AGENTS.md나 CLAUDE.md 같은 루트 문서는 “여기부터 읽어라”를 알려주는 안내판 역할이면 충분하다. 실제 설계 문서, 수용 기준, 실행 계획, 참고 자료는 docs/ 하위에 분리해 둔다.
이 구조의 장점은 명확하다.
특히 exec-plans/ 같은 실행 계획 폴더는 꽤 중요하다. 단순히 “이번에 이렇게 하자”가 아니라, 어떤 계획으로 실행했고 어떤 문제가 있었는지 회고할 수 있는 근거가 된다.
AI 코딩에서 도구 설정을 가볍게 보는 경우가 많다. 하지만 도구 인터페이스와 권한 경계는 에이전트 자율성의 안전 구역을 결정한다.
도구 설계에서 중요한 기준은 다음과 같다.
| 기준 | 설명 |
|---|---|
| Self-contained | 도구 간 overlap을 최소화한다. |
| 명확한 입출력 계약 | 어떤 입력을 받고 어떤 출력을 내는지 분명해야 한다. |
| 에러 메시지 | 실패했을 때 수정 방향을 알려줘야 한다. |
예를 들어 웹 검색 도구가 여러 개라면, 성능이 낮은 기본 검색 도구를 계속 쓰게 두는 것보다 검색 품질이 좋은 도구를 명시적으로 사용하도록 규칙에 박아두는 편이 낫다.
나쁜 예:
- 아무 웹 검색 도구나 사용한다.
좋은 예:
- 웹 검색은 Tavily 또는 Exa Search를 우선 사용한다.
- 기본 웹 검색 도구는 사용하지 않는다.
- 검색 결과는 최소 2개 출처로 교차 확인한다.
이런 규칙은 사소해 보이지만 결과물 품질에 꽤 큰 영향을 준다.
권한은 보통 세 가지 선택지 사이에서 트레이드오프가 있다.
| 방식 | 장점 | 단점 |
|---|---|---|
| Sandbox | 안전하다. | 유지보수 비용이 증가한다. |
| Skip-perms | 빠르다. | 위험 작업이 실행될 수 있다. |
| 수동 승인 | 안전하다. | 사람이 피로해진다. |
실무에서는 모든 작업을 수동 승인으로 막기 어렵다. 승인 피로가 생기면 결국 사람이 무심코 클릭하게 된다.
그래서 위험 작업을 분류하고, 안전한 작업은 자동화하되 위험한 작업은 반드시 승인하도록 정책을 나누는 편이 현실적이다.
AI가 만든 코드를 보고 “왠지 괜찮아 보인다”는 느낌만으로 판단하면 위험하다. 특히 AI와 대화를 오래 나누다 보면, 대화 흐름상 결과물이 좋아 보이는 착시가 생긴다.
그래서 결과물뿐 아니라 프로세스 품질까지 측정해야 한다.
Evaluation Harness의 구성 요소는 다음과 같다.
| 구성 요소 | 설명 |
|---|---|
| Task | 평가할 작업 정의 |
| Trial | 여러 번 실행해 분산을 줄이는 반복 실행 |
| Grader | 자동 또는 수동 채점 기준 |
| Transcript | 실행 과정 기록 |
| Outcome | 결과 집계와 비교 |
거대한 벤치마크보다 실제 이슈 10~20개를 재현하는 작은 regression set이 더 실용적일 때가 많다. 실제로 우리 코드베이스에서 자주 터지는 문제를 기준으로 평가해야 개선 효과를 체감할 수 있기 때문이다.
또 하나 중요한 점은 자기 평가의 한계다. 같은 세션 안에서 “내가 방금 만든 코드 평가해봐”라고 하면 모델은 자기 결과에 관대해질 수 있다.
가능하면 다른 모델, 다른 세션, 별도 grader로 교차 검증하는 편이 좋다.

앞에서 본 세 가지 축이 품질 차이를 만드는 기준이라면, 실제 하네스는 보통 네 가지 기둥으로 구성된다.
CLAUDE.md, AGENTS.md, .cursorrules 같은 파일들은 단순한 문서가 아니다. AI가 실행하는 런타임 설정 파일에 가깝다.
예를 들어 CLAUDE.md에 다음과 같이 적어둘 수 있다.
# Project Rules
- 새로운 라이브러리를 도입하지 않는다.
- DB 쿼리는 반드시 ORM을 통해서만 작성한다.
- 새 기능 구현 시 테스트를 먼저 작성한다.
- API 키는 코드에 하드코딩하지 않는다.
이렇게 해두면 매번 프롬프트에 반복하지 않아도 된다. AI 에이전트는 이 파일을 프로젝트의 기본 규칙으로 읽는다.
규칙은 문서에만 있으면 약하다. 시스템이 자동으로 강제해야 한다.
예시는 다음과 같다.
핵심은 CI가 실패했을 때 에이전트가 다시 수정 루프에 들어갈 수 있게 만드는 것이다.
사람이 직접 실패 로그를 복사해 다시 설명하는 대신, 실패 결과가 하네스 루프에 들어가야 한다.
AI 에이전트가 어떤 도구를 쓸 수 있고, 어디까지 접근할 수 있는지 명확하게 제한해야 한다.
예시는 다음과 같다.
파일 시스템:
- src/ 읽기·쓰기 가능
- config/ 읽기만 가능
- .env 접근 금지
API:
- 내부 API 호출 가능
- 외부 서비스 호출 금지
데이터베이스:
- SELECT 가능
- DROP TABLE 금지
- 운영 DB 직접 접근 금지
프롬프트는 부탁에 가깝다. 반면 도구 경계는 물리적 차단에 가깝다.
AI에게 “위험한 명령어는 실행하지 마”라고 말하는 것보다, rm -rf, git reset --hard, force push 같은 명령을 hook에서 차단하는 편이 훨씬 안전하다.
하네스는 한 번 만들고 끝나는 것이 아니다.
AI가 실수할 때마다 그 실수는 새로운 규칙이 된다.
즉, 하네스는 실패를 학습해서 점점 더 정교해지는 구조다.
하네스 아키텍처는 크게 네 덩어리로 나눌 수 있다.
User / Spec
↓
Knowledge Map
↓
Agent Harness Controller
↓
Tool Layer
↓
Verification + Observability
↺ feedback loop
각 요소의 역할은 다음과 같다.
| 영역 | 역할 |
|---|---|
| User / Spec | 사람이 목표와 요구사항을 제공한다. |
| Knowledge Map | 프로젝트 지식, 컨벤션, 문서를 제공한다. |
| Agent Harness Controller | 루프, 라우팅, 정책을 제어한다. |
| Tool Layer | Shell, FS, Browser, MCP, Sandbox 등을 실행한다. |
| Verification | lint, test, eval을 통해 검증한다. |
| Observability | trace, log, diff로 과정을 관찰한다. |
여기서 Observability는 단순 모니터링이 아니다. 에이전트가 어떤 파일을 읽고, 어떤 명령을 실행했고, 어디서 실패했는지 기록하는 장치다.
이 기록이 있어야 다음 루프에서 개선이 가능하다.
AI를 단순한 챗봇이 아니라 능력은 뛰어나지만 신뢰할 수 없는 함수로 생각하면 이해하기 쉽다.
하네스는 이 함수를 엄격한 가드레일로 감싼다.
하네스가 하는 핵심 역할은 세 가지다.
1. AI가 볼 수 있는 것을 제한한다. → 컨텍스트 관리
2. AI가 해야 할 일을 통제한다. → 라우팅
3. 작업이 끝날 때까지 루프를 돌린다. → 실행 루프
사용자 입력을 LLM에 바로 보내는 대신, 라우터가 먼저 가로채야 한다.
라우터는 이 요청이 단순 대화인지, 요구사항이 모호한지, 아니면 하네스 루프로 넘길 수 있는 실행 작업인지 판단한다.
// router.ts
import { runHarnessLoop } from "./harness_loop";
import { extractIntent } from "./llm_utils";
function handleUserInput(userPrompt: string) {
const intent = extractIntent(userPrompt);
if (intent.isAmbiguous) {
return triggerDeepInterview(userPrompt);
}
if (intent.isActionable) {
const constraints = buildConstraints(intent);
return runHarnessLoop(userPrompt, constraints);
}
return sendToStandardLLM(userPrompt);
}
핵심은 모호한 요청을 바로 실행하지 않는 것이다.
"관리자 페이지 만들어줘"
이런 요청은 너무 넓다.
하네스는 먼저 되물어야 한다.
엉뚱한 방향으로 달려가는 것을 출발 전에 막는 것이 라우터의 역할이다.
아무런 제어 없는 LLM은 전체 코드베이스를 읽고도 정작 중요한 제약 사항을 잊어버릴 수 있다.
그래서 현재 작업에 필요한 정보만 제공해야 한다.
// context_manager.ts
class ProjectMemory {
getRelevantContext(currentTask: string) {
const activeContext = [];
activeContext.push(this.getGlobalConstraints());
const hotFiles = vectorSearchCodebase(currentTask);
activeContext.push(hotFiles);
this.runGarbageCollection();
return activeContext;
}
runGarbageCollection() {
// 컨텍스트가 커지면 이전 단계는 요약하고,
// 현재 작업과 관련 없는 파일은 제거한다.
}
}
핵심은 말에게 밭 전체를 보여주는 것이 아니라, 지금 갈아야 할 이랑만 보여주는 것이다.
하네스의 심장부는 실행 루프다.
AI를 계획 → 실행 → 검증 → 수정 루프에 밀어 넣고, 테스트를 통과하기 전까지 완료로 인정하지 않는다.
// harness_loop.ts
import { callIsolatedLLMWorker } from "./worker";
import { ProjectMemory } from "./context_manager";
function runHarnessLoop(task: string, constraints: string[]) {
const memory = new ProjectMemory();
let isTaskComplete = false;
let attemptCount = 0;
const MAX_ATTEMPTS = 5;
while (!isTaskComplete && attemptCount < MAX_ATTEMPTS) {
const context = memory.getRelevantContext(task);
const generatedCode = callIsolatedLLMWorker(
"WRITE_CODE",
task,
context,
constraints
);
const verificationResult = runAutomatedTests(generatedCode);
if (verificationResult.passed) {
isTaskComplete = true;
return generatedCode;
}
task = `
코드가 다음 에러를 발생시켰습니다.
${verificationResult.errorTrace}
이 에러만 수정하세요.
`;
attemptCount++;
}
throw new Error(
"하네스 중단: 제한된 시도 횟수 내에 문제를 해결하지 못했습니다."
);
}
핵심은 LLM의 말을 믿지 않는 것이다.
"테스트 통과했습니다."
라는 답변을 믿는 것이 아니라, 실제 테스트를 실행해야 한다.
실패하면 에러 메시지를 다시 AI에게 전달하고, 수정 루프를 돌린다.
코드를 작성하는 역할과 리뷰하는 역할은 분리하는 편이 좋다.
같은 세션에서 작성과 검토를 모두 맡기면 자기 편향이 생길 수 있다.
// worker.ts
function callIsolatedLLMWorker(
role: string,
task: string,
context: string,
constraints: string[]
) {
let systemPrompt = "";
if (role === "WRITE_CODE") {
systemPrompt = `
당신은 실행 에이전트입니다.
코드를 작성하세요.
설명하지 말고 필요한 변경만 수행하세요.
`;
}
if (role === "SECURITY_REVIEW") {
systemPrompt = `
당신은 보안 감사관입니다.
취약점을 찾으세요.
기능 코드는 작성하지 마세요.
`;
}
return llmApi.generate({
system: systemPrompt,
user_message: `작업: ${task}\n제약조건: ${constraints.join("\n")}`,
context_data: context,
temperature: 0,
});
}
사람도 같은 사람이 쓰고 같은 사람이 검토하면 실수를 놓치기 쉽다. AI도 마찬가지다.
역할을 나누면 품질이 올라간다.
전체 흐름은 다음과 같이 정리할 수 있다.
사용자 요청
↓
Router
├─ 모호한 요청 → 인터뷰 / 되물어보기
├─ 일반 대화 → 일반 LLM
└─ 명확한 작업 → Context Manager
↓
Worker
↓
자동 테스트
↓
통과 → 완료
실패 → 에러 피드백 → Worker 재실행
좋은 하네스를 만들 때는 네 가지 원칙을 기억하면 좋다.
처음부터 거대한 프레임워크를 만들 필요는 없다.
작은 성공 사례를 먼저 만들고, 필요한 복잡도만 추가하는 편이 낫다.
컨텍스트는 길다고 좋은 것이 아니다. 목표 달성에 직접 필요한 정보만 남겨야 모델이 집중할 수 있다.
테스트, 규칙, 스크립트, grader가 루프 안에 있어야 한다.
검증이 밖에 있으면 개선 속도가 느려지고 회귀를 놓치기 쉽다.
하네스의 각 구성요소는 모델 한계를 가정하고 만든 것이다.
모델이 좋아지면 예전 구조가 불필요해질 수도 있다. 그래서 정기적으로 구조를 재검토해야 한다.
Claude Code와 Codex는 둘 다 코딩 에이전트지만, 잘하는 지점이 다르다.
Claude Code는 로컬 작업 공간에 깊게 들어온 페어 프로그래머에 가깝다. 탐색, 디버깅, 구조 이해에 강점이 있다.
핵심 특징은 다음과 같다.
하네스 확장 포인트는 다음과 같다.
| 요소 | 역할 |
|---|---|
CLAUDE.md | 영구 컨텍스트 고정 |
| Auto Memory | 세션 간 학습 유지 |
| Skills | 재사용 가능한 워크플로 |
| Hooks | 이벤트 기반 자동화 |
| Subagents | 전문 에이전트 위임 |
| 승인 흐름 | 안전 경계 설정 |
Codex는 GPT 모델이 작업을 계획하고 검증하는 루프에 강한 코딩 에이전트에 가깝다. 명확한 스펙을 바탕으로 계획을 나누고, 검증 루프를 돌리는 작업에 잘 맞는다.
핵심 특징은 다음과 같다.
하네스 구성 요소는 다음과 같다.
| 요소 | 역할 |
|---|---|
AGENTS.md | 영구 컨텍스트 고정 |
| Skills | 재사용 가능한 워크플로 |
| Subagents | 전문 에이전트 위임 |
| Sandbox | 격리된 실행 환경 |
| Approval | 세분화된 권한 정책 |
| JSON-RPC | 통합 프로토콜 |
둘의 차이는 우열이 아니라 운영 표면의 차이에 가깝다.
| 항목 | Claude Code | Codex |
|---|---|---|
| 핵심 강점 | 탐색, 대화, 디버깅 | 계획, 검증, 대량 위임 |
| 실행 모델 | 스트리밍, 실시간 피드백 | 비동기 PR, 백그라운드 실행 |
| 컨텍스트 고정 | CLAUDE.md + Hooks | AGENTS.md + Sandbox 격리 |
| 자율성 제어 | Hooks 기반 세밀한 이벤트 제어 | Approval policy 기반 제어 |
| 병렬성 | Subagents, 로컬 멀티스레드 | 클라우드 기반 다중 인스턴스 |
| 최적 시나리오 | 탐색 → 수정 → 재검사 반복 | 명확한 스펙 → 대량 실행 |
| 공통 추상화 | Skills, Subagents, Persistent Guidance, Safe Autonomy | Skills, Subagents, Persistent Guidance, Safe Autonomy |
Claude Code는 “같이 보면서 고치는” 느낌이 강하고, Codex는 “명확한 스펙을 주고 여러 작업을 맡기는” 느낌이 강하다.
같은 하네스라도 두 모델이 전혀 다른 결과를 낼 때가 있다. 그래서 중요한 작업에서는 2중 검증이 필요하다.
단일 모델 검증에는 한계가 있다.
| 한계 | 설명 |
|---|---|
| 자기 확인 편향 | 자신이 만든 코드의 결함을 스스로 발견하기 어렵다. |
| 동일한 blind spot | 같은 학습 데이터와 추론 패턴으로 같은 실수를 반복할 수 있다. |
| 환경 격리 없음 | 로컬에서만 테스트하고 환경 의존성을 놓칠 수 있다. |
교차 검증을 하면 이런 장점이 생긴다.
| 장점 | 설명 |
|---|---|
| 다른 모델, 다른 시각 | Claude와 GPT가 서로 다른 추론 방식으로 blind spot을 보완한다. |
| 환경 분리 검증 | 로컬과 샌드박스 환경을 각각 통과해야 merge할 수 있다. |
| 수정자와 검증자 분리 | Codex가 고친 코드를 Claude가 확인하는 식으로 역할을 분리할 수 있다. |
핵심은 간단하다.
같은 모델이 만든 것을 같은 모델이 검증하지 않게 한다.
이렇게 하면 blind spot을 줄일 수 있다.
도구를 섞는다는 것은 아무 단계에서나 아무 도구를 쓴다는 뜻이 아니다.
각 도구가 잘하는 단계에 배치해야 한다.
Claude Code: 탐색 + 구현
↓
Artifact: Spec 전달
↓
Codex: 검증 + 수정
↓
Claude Code: 재검증
↓
필요하면 반복
이 패턴은 한 사이클의 출력이 다음 사이클의 입력이 되는 구조다.
핵심은 병렬이 아니라 맞물림이다.
한 에이전트의 출력이 다른 에이전트의 입력이 되고, 품질이 수렴할 때까지 순환한다.
AI 코딩 도구에는 이미 내장 하네스가 있다.
예를 들어 Claude Code, Cursor, Codex는 기본적으로 다음과 같은 장치를 가지고 있다.
하지만 내장 하네스는 범용적이다. 내 프로젝트만의 아키텍처, 기술 스택, 코딩 규칙, 디자인 기준, 배포 정책까지 알지는 못한다.
그래서 그 위에 프로젝트 전용 하네스를 한 층 올릴 수 있다.
내 프로젝트 하네스
- CLAUDE.md
- docs/
- hooks
- scripts
- phases
↓
도구의 내장 하네스
- 시스템 프롬프트
- 권한 체크
- sandbox
- approval policy
핵심은 도구 자체를 바꾸는 것이 아니다.
이미 있는 AI 코딩 도구 위에, 내 프로젝트 규칙을 이해하는 운영 레이어를 얹는 것이다.
가벼운 프로젝트 하네스는 다음과 같은 구조로 시작할 수 있다.
project/
├── CLAUDE.md # 프로젝트 헌법
├── docs/
│ ├── PRD.md # 뭘 만드는지
│ ├── ARCHITECTURE.md # 어떻게 만드는지
│ ├── ADR.md # 왜 이렇게 만드는지
│ └── UI_GUIDE.md # 어떻게 보여야 하는지
├── .claude/
│ ├── commands/
│ │ ├── harness.md # /harness — 원스톱 실행
│ │ └── review.md # /review — 규칙 기반 리뷰
│ └── settings.json # hooks 설정
├── scripts/
│ ├── execute.py # Phase 순차 실행 + 상태 관리
│ └── hooks/
│ ├── tdd-guard.sh # 테스트 없으면 구현 차단
│ ├── dangerous-cmd-guard.sh # 위험 명령어 차단
│ └── circuit-breaker.sh # 반복 에러 감지
└── phases/ # Phase 파일 + 실행 상태
이 구조는 거창해 보이지만, 핵심은 단순하다.
docs/로 맥락을 정리하고,
CLAUDE.md로 절대 규칙을 고정하고,
hooks로 위험한 행동을 차단하고,
execute.py로 큰 작업을 Phase 단위로 나누어 실행한다.
하네스의 품질은 대부분 docs/에서 갈린다.
AI에게 주는 맥락이 얕으면 결과도 얕다. 반대로 문서가 잘 정리되어 있으면 같은 모델을 써도 결과물이 확 달라진다.
PRD는 Product Requirements Document다. 핵심 기능과 MVP 제외 사항을 정의한다.
# PRD: {프로젝트명}
## 목표
{한 줄 요약}
## 핵심 기능
1. {기능 1}
2. {기능 2}
3. {기능 3}
## MVP 제외 사항
- {안 만들 것 1}
- {안 만들 것 2}
여기서 특히 중요한 것은 MVP 제외 사항이다.
AI는 지시가 넓으면 “이것도 추가할까요?” 하면서 scope를 계속 넓히는 경향이 있다.
그래서 “무엇을 만들지”만큼 “무엇을 만들지 않을지”를 명시해야 한다.
좋은 예:
- 이번 MVP에서는 결제 기능을 구현하지 않는다.
- 관리자 대시보드는 읽기 전용으로만 만든다.
- 실시간 알림은 다음 버전으로 미룬다.
아키텍처 문서는 디렉토리 구조, 디자인 패턴, 데이터 흐름을 정의한다.
# 아키텍처
## 디렉토리 구조
{폴더 트리}
## 패턴
{사용하는 디자인 패턴}
## 데이터 흐름
{데이터가 어떻게 흐르는지}
AI는 프로젝트 구조를 명확히 알려주지 않으면 새 폴더를 마음대로 만들거나, 기존 패턴과 다른 방식으로 코드를 작성할 수 있다.
특히 Feature-Sliced Design, Layered Architecture, Clean Architecture처럼 폴더 규칙이 중요한 프로젝트라면 이 문서가 필수에 가깝다.
ADR은 Architecture Decision Records다.
단순히 무엇을 선택했는지가 아니라, 왜 선택했고 무엇을 포기했는지를 기록한다.
# Architecture Decision Records
### ADR-001: 차트 라이브러리 선택
**결정**: Recharts를 사용한다.
**이유**: 대시보드 수준의 차트에는 충분하고, React 컴포넌트 방식으로 다루기 쉽다.
**트레이드오프**: D3.js 대비 세밀한 커스터마이징은 제한된다.
트레이드오프가 특히 중요하다.
이걸 적어두면 AI가 나중에 “D3.js로 바꿀까요?” 같은 제안을 덜 하게 된다. 이미 선택의 이유와 포기한 지점이 명시되어 있기 때문이다.
UI 품질을 원한다면 UI 가이드도 필요하다.
AI에게 “예쁘게 만들어줘”라고 하면 대체로 비슷한 결과물이 나온다.
이런 AI스러운 스타일을 피하고 싶다면 명시적으로 금지해야 한다.
# UI Guide
## Tone
- 차분하고 읽기 쉬운 생산성 도구 느낌
- 과한 장식보다 정보 밀도와 명확성을 우선
## Do
- 충분한 여백
- 명확한 시각적 계층
- 모바일 우선 레이아웃
- 접근성 고려
## Don't
- 과한 glass morphism
- 의미 없는 네온 효과
- 보라색 그라데이션 남용
- 모든 요소를 카드로 감싸는 패턴
실제로 같은 프레임워크와 같은 Phase 구조에서도, UI 가이드 하나가 추가되면 결과물이 크게 달라질 수 있다.
CLAUDE.md는 AI가 코딩할 때 가장 먼저 읽는 파일이다.
여기에는 프로젝트의 절대 규칙을 적어둔다.
# 프로젝트: {프로젝트명}
## 기술 스택
- Next.js
- TypeScript
- Tailwind CSS
- Prisma
## 아키텍처 규칙
- CRITICAL: 모든 API 로직은 app/api/에서만 작성한다.
- CRITICAL: 비즈니스 로직은 UI 컴포넌트 안에 직접 작성하지 않는다.
- CRITICAL: API 키는 환경변수로 관리하고 코드에 하드코딩하지 않는다.
## 개발 프로세스
- CRITICAL: 새 기능 구현 시 반드시 테스트를 먼저 작성한다.
- 커밋 메시지는 conventional commits 형식을 따른다.
## 명령어
- pnpm lint
- pnpm test
- pnpm build
여기서 CRITICAL 같은 우선순위 신호를 주는 것도 도움이 된다.
물론 키워드 하나가 마법처럼 모든 문제를 해결하지는 않는다. 하지만 AI가 읽는 컨텍스트 안에서 어떤 규칙이 절대적인지 분명히 알려주는 효과가 있다.
큰 작업은 한 번의 세션에 넣으면 쉽게 흐트러진다.
그래서 작업을 Phase로 나누고, 각 Phase를 순차적으로 실행하는 엔진을 둘 수 있다.
예를 들어 .claude/commands/harness.md에 /harness 스킬을 정의해둘 수 있다.
실행 흐름은 다음과 같다.
/harness 실행
↓
docs/ 문서를 전부 읽는다
↓
사용자와 논의하며 요구사항을 구체화한다
↓
구현 계획을 Phase로 쪼갠다
↓
phases/ 폴더에 Phase 파일을 생성한다
↓
execute.py가 Phase를 순차적으로 실행한다
사람이 할 일은 docs를 채우고 /harness를 실행하는 것이다.
나머지는 하네스가 작업을 나누고, 실행하고, 검증하는 흐름으로 이어진다.
scripts/execute.py는 Phase를 순차적으로 실행하는 자동화 스크립트다.
동작 방식은 다음과 같다.
1. phases/{task-name}/ 폴더에서 다음 pending Phase를 찾는다.
2. Phase 파일 내용을 읽는다.
3. Claude 헤드리스 모드에 프롬프트를 넘긴다.
4. 작업 결과 상태를 확인한다.
5. completed이면 자동 커밋 후 다음 Phase로 간다.
6. error이면 에러를 기록하고 중단한다.
7. blocked이면 사용자 개입이 필요하다고 표시하고 중단한다.
상태는 보통 다음처럼 나눌 수 있다.
| 상태 | 동작 |
|---|---|
| completed | 자동 커밋 후 다음 Phase 진행 |
| error | 에러 기록 후 중단 |
| blocked | 사용자 개입 필요 후 중단 |
실행 예시는 다음과 같다.
python3 scripts/execute.py mvp
==================================================
Harness Executor
Task: mvp | Phases: 5 | Pending: 5
==================================================
✓ Phase 1: 프로젝트-초기화 [180s]
✓ Phase 2: 타입-+-유틸리티 [300s]
✓ Phase 3: api-라우트 [240s]
✓ Phase 4: ui-컴포넌트 [300s]
✓ Phase 5: 메인-페이지-통합 [150s]
==================================================
Task 'mvp' completed!
==================================================
핵심은 Phase마다 새로운 세션을 호출한다는 점이다.
Phase 1이 끝나면 그 세션은 종료되고, Phase 2는 새로운 세션에서 시작한다. 각 Phase 지시서에는 작업 범위가 문서로 제한되어 있으므로 AI가 자기 범위 밖의 일을 할 가능성이 줄어든다.
/review 스킬을 따로 두면 프로젝트 규칙 기반 자동 리뷰도 가능하다.
체크할 수 있는 항목은 다음과 같다.
ARCHITECTURE.md 폴더 구조 준수 여부CLAUDE.md의 CRITICAL 규칙 준수 여부이렇게 하면 “대충 봤을 때 괜찮다”가 아니라, 문서화된 기준으로 리뷰할 수 있다.
문서만으로는 부족하다. 진짜 지켜야 하는 규칙은 hook으로 강제해야 한다.
예시는 다음과 같다.
| Hook | 기능 | 파일 |
|---|---|---|
| TDD Guard | 구현 파일 수정 시 해당 테스트가 없으면 차단 | scripts/hooks/tdd-guard.sh |
| Dangerous Command Guard | rm -rf, force push, git reset --hard 등 위험 명령어 차단 | scripts/hooks/dangerous-cmd-guard.sh |
| Circuit Breaker | 같은 에러가 짧은 시간 안에 반복되면 전략 변경 경고 | scripts/hooks/circuit-breaker.sh |
이런 hook은 AI의 실수를 줄이는 데 매우 효과적이다.
AI에게 “위험한 명령어를 쓰지 마”라고 말하는 것보다, 위험한 명령어가 실행되지 않게 차단하는 편이 훨씬 안전하다.
팀 단위로 AI 코딩을 운영하려면 개인 프롬프트에 의존하면 안 된다.
규칙과 워크플로를 repo 안의 canonical artifact로 공유해야 한다.
팀이나 회사 차원에서 지켜야 할 규칙을 별도 레포로 운영할 수 있다.
예시는 다음과 같다.
이 규칙을 각 프로젝트에 git submodule 등으로 연결하면, 새로운 프로젝트가 만들어져도 동일한 기준이 자동으로 주입된다.
반복되는 작업은 Skill로 만든다.
예시는 다음과 같다.
팀 내에 Skills 공유 레포를 두면, 팀원들이 같은 워크플로를 사용하고 개선할 수 있다.
규칙은 문서로만 존재하면 잘 지켜지지 않는다. 반드시 실행 레이어가 필요하다.
예시는 다음과 같다.
진짜 지켜야 하는 규칙은 문서가 아니라 코드로 강제해야 한다.
AI 에이전트를 팀 프로세스에 녹이면 이슈에서 PR까지의 흐름도 바꿀 수 있다.
Triage & Spec
↓
Parallel Exec
↓
Eval & Verify
↓
Review & Merge
| 단계 | 주도 | 역할 |
|---|---|---|
| Triage & Spec | 사람 + Claude Code | 이슈 분석, 영향 범위 파악, 변경 스펙 작성 |
| Parallel Exec | Codex | 병렬 워크트리, 백그라운드 실행, A/B 비교 |
| Eval & Verify | 자동화 | 자동 테스트, eval harness, 회귀 검사 |
| Review & Merge | 사람 + Claude Code | 코드 리뷰, 품질 판단, merge 결정 |
이 구조의 장점은 각 단계의 책임이 명확해진다는 점이다.
사람은 모든 실행을 직접 하지 않고, 작업 정의와 최종 판단에 집중할 수 있다.
예를 들어 이런 작업이 있다고 하자.
MSW 도입하고 싶어. 통합 테스트도 같이 짜줘.
처음에는 한 세션에 전부 맡기기 쉽다. 하지만 큰 작업을 한 세션에 모두 넣으면 이런 문제가 생긴다.
/clear를 잘못 누르면 어디까지 했는지 미궁에 빠진다.문제는 작업 단위와 세션 단위를 같다고 가정한 데 있다.
작업 단위 ≠ 세션 단위
큰 기능 하나는 여러 세션에 걸쳐 진행될 수 있다. 그래서 세션을 이어주는 하네스가 필요하다.
처음에는 수동 하네스처럼 Plan Mode와 /clear를 조합할 수 있다.
흐름은 다음과 같다.
1. Plan Mode로 계획을 세운다.
2. 계획을 ~/.claude/plans/TODO.md에 저장한다.
3. /clear로 세션을 비운다.
4. 다음 세션에서 TODO.md를 읽고 다음 단계를 진행한다.
이 방식은 꽤 잘 굴러간다. 하지만 한계가 명확하다.
| 문제 | 실제로 발생하는 일 |
|---|---|
| plan이 휘발성 | 로컬 ~/.claude/plans/에 저장되어 다른 머신에서 못 보고 팀 공유도 어렵다. |
| 검증이 모호 | “테스트 짜라”는 지시만 있고, 어떤 기준으로 통과인지 불명확하다. |
| 자가 교정 없음 | 실패하면 사람이 다시 plan을 다듬고 재시도해야 한다. |
| 실행을 사람이 함 | step이 5개면 사람이 5번 세션을 띄우고 5번 프롬프트를 입력해야 한다. |
이 방식은 1세션짜리 복잡한 작업에는 쓸 만하지만, 여러 세션을 잇는 작업에는 부족하다.
다음 단계는 세션 자체의 품질을 올리는 것이다.
예시는 다음과 같다.
| 항목 | 목적 |
|---|---|
CLAUDE.md 슬림화 | 매 세션 로딩되는 root 문서를 줄이고, 나머지는 docs/로 lazy-load한다. |
| ADR 도입 | 결정의 근거를 git에 남겨 매 세션 같은 결정을 반복하지 않게 한다. |
| Agent eval | 작은 task set으로 회귀를 측정하고 주기적으로 돌린다. |
| Telemetry 자동화 | SessionEnd hook으로 토큰, 비용, 캐시를 일별 스냅샷으로 남긴다. |
| deny-list hooks | 위험 명령을 PreToolUse 단계에서 차단한다. |
CLAUDE.md auto-update | 코드 변경분에서 문서 갱신 후보를 자동 제안한다. |
이렇게 하면 세션 하나의 품질은 올라간다. 하지만 여러 세션을 잇는 운영 문제는 여전히 남는다.
결국 필요한 것은 Plan → Clear → Execute 사이클을 자동화하는 것이다.
큰 작업을 외주 개발자에게 맡길 때를 떠올리면 이해하기 쉽다. PM은 큰 작업을 통째로 던지지 않는다. 작업을 잘게 나눈 SOW나 작업지시서로 쪼개고, 각 단계의 완료 기준을 정한다.
LLM 작업도 마찬가지다.
큰 기능 하나를 한 세션에 통째로 맡기면:
그래서 작업을 step.md로 나누고, 실행 스크립트가 Claude 세션에 step을 하나씩 던지며 결과를 검수하는 구조를 만들 수 있다.
| 역할 | 파일 | 누가 만드나 |
|---|---|---|
| 슬래시 커맨드 정의 | .claude/commands/harness.md | 한 번만 만들어 둔다. |
| 작업 지시서 | phases/<name>/step{N}.md | 사람과 Claude가 합의해서 작성한다. |
| 진행상태 장부 | phases/<name>/index.json | execute.py가 자동 갱신한다. |
| 실행 엔진 | scripts/execute.py | 한 번만 만들어 둔다. |
실제 흐름은 다음과 같다.
/harness를 호출한다MSW 통합 테스트 도입하자.
Claude가 docs/와 ADR을 읽고 step 초안을 만든다.
step0: src/mocks/ 골격 + ADR 0007
step1: tombstone handler 1개
step2: useRespect optimistic 테스트
검토할 때는 다음을 확인한다.
vitest 통과처럼 실행 가능한 명령으로 박아둔다.phases/msw-introduction/
├── index.json # 3 step pending
├── step0.md # 읽어야 할 파일 / 작업 / AC / 금지사항
├── step1.md
└── step2.md
python3 scripts/execute.py msw-introduction
1. feat-msw-introduction 브랜치를 자동 생성한다.
2. 새 Claude 세션을 띄운다. 사실상 /clear와 같다.
3. 프롬프트에 자동 첨부한다.
- CLAUDE.md + docs/*.md
- 이전 step의 summary
- step{N}.md 본문
4. Claude가 코드를 작성한다.
5. AC 명령을 실행한다. 예: pnpm test:run
6. 실패하면 에러 메시지를 보여주고 최대 3회 재시도한다.
7. 성공하면 코드 커밋과 메타데이터 커밋을 남긴다.
8. index.json의 step status를 completed로 바꾸고 summary, completed_at을 기록한다.
9. 다음 step으로 넘어간다.
결과적으로 3 step이라면 보통 이런 산출물이 생긴다.
3 step × 2 commits + 마지막 phase completed commit + 중간 telemetry
즉, 사람이 매번 세션을 열고 프롬프트를 다시 넣는 것이 아니라, 하네스가 step 단위로 새 세션을 띄우고 검증과 커밋까지 자동화한다.
Plan Mode와 Harness는 비슷해 보이지만 핵심이 다르다.
| 방식 | 설명 |
|---|---|
| Plan Mode | 사람이 다음 세션에서 plan을 들고 직접 실행한다. |
| Harness | 로봇이 step 하나씩 새 세션을 띄워 자동 실행, 자동 커밋, 실패 시 자가 교정을 수행한다. |
즉, Harness의 핵심은 다음 사이클을 자동화하는 것이다.
Plan → Clear → Execute
그래서 며칠 걸리는 다단계 작업에 특히 잘 맞는다.
작업 크기에 따라 도구를 다르게 선택하면 된다.
| 상황 | 적합한 방식 |
|---|---|
| 단일 파일 수정, 1세션 안에 끝남 | 그냥 작업 |
| 1세션 안에 끝나지만 절차가 복잡함 | Plan Mode |
| 여러 세션이 필요하고 검증 가능하며 회고가 필요함 | Harness |
본질은 이 한 줄이다.
한 세션 컨텍스트 ≠ 한 phase 작업량
이 부등식을 풀어내는 것이 하네스다.
내 프로젝트에 가볍게 하네스를 적용한다면 다음 순서로 시작할 수 있다.
처음부터 코드부터 시키지 말고, AI와 함께 docs/를 채운다.
예를 들어 YouTube 댓글 감성 분석 대시보드를 만든다고 해보자.
나:
YouTube URL을 넣으면 댓글을 수집해서 감성 분석하는 대시보드를 만들자.
AI:
PRD 초안을 제안한다.
핵심 기능, MVP 제외사항, 데이터 흐름을 정리한다.
나:
댓글은 최대 100개로 제한하자.
실시간 수집은 하지 말고, 버튼 클릭 시 1회 수집만 하자.
AI:
PRD, ARCHITECTURE.md, ADR.md를 수정한다.
혼자 문서를 다 쓰는 것이 아니라, AI와 함께 기획하는 것이 좋다. 이 단계에서 scope creep을 막아야 뒤에서 코드가 안정된다.
프로젝트에 맞는 절대 규칙을 적는다.
# 프로젝트 규칙
- CRITICAL: 모든 API 로직은 app/api/에서만 작성한다.
- CRITICAL: API 키는 환경변수로 관리하고 코드에 하드코딩하지 않는다.
- CRITICAL: 새 기능은 테스트를 먼저 작성한다.
- CRITICAL: UI 컴포넌트는 비즈니스 로직을 직접 포함하지 않는다.
위험한 행동은 문서가 아니라 hook으로 막는다.
예시는 다음과 같다.
- 테스트 없이 구현 파일 수정 차단
- rm -rf, git reset --hard, force push 차단
- 같은 에러 반복 시 전략 변경 경고
큰 작업은 바로 구현하지 말고 Phase로 나눈다.
Phase 1: 프로젝트 초기화
Phase 2: 타입과 유틸리티 작성
Phase 3: API 라우트 구현
Phase 4: UI 컴포넌트 구현
Phase 5: 메인 페이지 통합
Phase 6: 테스트와 문서 정리
Phase는 MVP 기준 5~7개 정도가 적당하다. 너무 많으면 관리 비용이 늘고, 너무 적으면 한 Phase가 너무 커진다.
완성된 결과물을 보고 부족한 부분이 있으면 코드를 바로 고치기보다 docs를 먼저 보강한다.
예시는 다음과 같다.
| 문제 | 원인 | 해결 |
|---|---|---|
| UI가 허접함 | UI 디자인 가이드가 없었음 | docs/UI_GUIDE.md 추가 |
| JSON 파싱 에러 반복 | 응답 포맷 예외 규칙이 없었음 | ADR에 코드블록 strip 규칙 추가 |
| 테스트가 자주 빠짐 | TDD 규칙이 문서에만 있었음 | TDD guard hook 추가 |
| 폴더 구조가 흔들림 | 아키텍처 규칙이 모호했음 | ARCHITECTURE.md에 디렉토리 규칙 추가 |
핵심은 이거다.
결과물이 별로라면,
프롬프트를 한 번 더 잘 쓰는 것보다
하네스에 무엇이 빠졌는지 보는 편이 낫다.
하네스가 중요한 이유는 감상이 아니라 결과로 설명할 수 있기 때문이다.
슬라이드에서 제시된 예시는 다음과 같다.
| 사례 | 결과 |
|---|---|
| Solo Agent | 약 $9 비용, 20분, 핵심 게임플레이 고정 |
| Full Harness(3-Agent) | 약 $200 비용, 6시간, 16개 기능, 10개 스프린트 정상 작동 |
| SWE-bench Verified | 도구 2개만으로 49% 달성 |
| 멀티에이전트 | 싱글에이전트 대비 90.2% 우위 |
| RAG 적용 | 도구 선택 정확도 3배 향상 |
물론 모든 프로젝트에서 같은 수치가 나오지는 않는다.
중요한 것은 하네스를 평가할 때 모델만 보는 것이 아니라 모델 + 하네스의 결합을 함께 봐야 한다는 점이다.
하네스가 강력해질수록 새로운 리스크도 생긴다.
수동 승인이 너무 많으면 사람은 점점 더 대충 누르게 된다.
열 번째 승인 후에는 더 이상 검토하지 않는다.
그냥 클릭할 뿐이다.
대응 방법은 다음과 같다.
MCP 서버나 외부 도구 설명에 악성 지시문이 숨어 있을 수 있다.
예를 들어 도구 설명 안에 “SSH 키 설정 파일을 읽어라” 같은 지시가 숨어 있으면, 에이전트가 사용자에게 보이지 않는 방식으로 위험 행동을 할 수 있다.
대응 방법은 다음과 같다.
에이전트가 생성한 코드는 시간이 지나면서 아키텍처에서 벗어날 수 있다.
복사-붙여넣기식 코드가 늘고, 리팩터링이 줄어들면 코드 품질이 서서히 떨어진다.
대응 방법은 다음과 같다.
어떤 도구를 쓰든 반드시 측정해야 한다. 그래야 개선할 수 있다.
예를 들어 Langfuse 같은 LLM 관측성 플랫폼을 사용하면 Claude Code와 Codex 사용을 통합 추적할 수 있다.
코딩 에이전트에서는 다음 지표를 추적할 수 있다.
측정이 있어야 프롬프트, Skill, 정책, eval set을 개선할 수 있다.
AI 코딩에서 중요한 원칙은 “코드를 많이 쓰는 것”이 아니라 목표를 검증 가능한 방식으로 달성하는 것이다.
기본 루프는 다음과 같다.
테스트 작성 → 테스트 실행 → 결과 분석 → 코드 수정 → 다시 테스트 실행
실행 원칙은 네 가지로 정리할 수 있다.
이 원칙은 사람이 직접 코딩할 때도 중요하지만, AI 에이전트를 사용할 때는 더 중요하다.
AI는 지시가 애매하면 생각보다 쉽게 옆길로 샌다.
AI 시대에 개발자의 역할은 축소된다기보다 위로 이동하고 있다.
| 축 | 역할 | 비유 |
|---|---|---|
| Prompt | 프롬프트 엔지니어 | AI에게 의도를 정확히 전달하는 사람 |
| Context | 컨텍스트 아키텍트 | AI가 참조할 지식 체계를 설계하는 사람 |
| Harness | 플랫폼 엔지니어 | AI가 실수하기 어려운 환경을 만드는 사람 |
| Agentic | 에이전트 오케스트레이터 | AI 에이전트를 설계하고 조율하는 사람 |
직접 공을 차는 선수에서, 전술을 짜고 팀을 운영하는 감독으로 올라가는 것에 가깝다.
물론 개발자가 코드를 몰라도 된다는 뜻은 아니다. 오히려 반대다.
코드를 알아야 좋은 규칙을 만들 수 있고, 아키텍처를 알아야 좋은 컨텍스트를 설계할 수 있고, 테스트를 알아야 좋은 검증 루프를 만들 수 있다.
AI가 코드를 더 많이 작성할수록, 사람은 더 좋은 판단 기준과 시스템을 만들어야 한다.
AI 코딩 도구를 잘 쓴다는 것은 단순히 프롬프트를 잘 쓰는 것이 아니다.
진짜 차이는 이런 부분에서 만들어진다.
결국 하네스 엔지니어링은 AI에게 일을 잘 시키는 기술이라기보다, AI가 실수하기 어려운 작업 환경을 만드는 기술에 가깝다.
AI 에이전트가 실수했을 때 매번 프롬프트를 더 길게 쓰는 방식에는 한계가 있다.
더 나은 접근은 그 실수가 다시 일어나지 않도록 하네스를 고치는 것이다.
프롬프트는 요청이다.
컨텍스트는 재료다.
하네스는 작업 환경이다.
검증 루프는 품질 보증이다.
앞으로 개발자의 역할은 점점 더 “직접 코드를 치는 사람”에서 “좋은 작업 시스템을 설계하는 사람”으로 확장될 것이다.
AI 에이전트를 팀원처럼 쓰고 싶다면, 모델 선택만큼이나 하네스 설계가 중요해진다.