- Published on
AI 하네스란 무엇인가: Skills, Context, Hooks, Permissions로 AI를 제어하는 오케스트레이션 아키텍처
- Authors

- Name
- Youngju Kim
- @fjvbn20031
- 1. AI 하네스란? — 왜 LLM만으로는 부족한가
- 2. 하네스의 7가지 구성 요소
- 3. Claude Code 하네스 아키텍처 심화
- 4. Claude Agent SDK로 커스텀 하네스 만들기
- 5. 다른 AI 하네스 프레임워크 비교
- 6. 하네스 설계 패턴
- 7. 실전: 나만의 코드 리뷰 하네스 만들기
- 8. 하네스 평가 및 모니터링
- 9. 2025-2026 하네스 트렌드
- 10. 퀴즈
- 11. 참고 자료
1. AI 하네스란? — 왜 LLM만으로는 부족한가
Raw LLM의 한계
GPT-4o, Claude Sonnet, Gemini Pro 같은 대형 언어 모델(LLM)은 놀라운 능력을 가지고 있습니다. 하지만 모델 자체만으로는 실용적인 AI 시스템을 만들 수 없습니다.
Raw LLM에게 "우리 프로젝트의 PR을 리뷰해줘"라고 하면 어떻게 될까요?
- 프로젝트 코드를 읽을 수 없습니다 (도구 없음)
- 어떤 코딩 컨벤션을 따르는지 모릅니다 (컨텍스트 없음)
- git diff를 실행할 수 없습니다 (권한 없음)
- 이전 리뷰 히스토리를 기억하지 못합니다 (기억 없음)
- 리뷰 후 자동으로 코멘트를 달 수 없습니다 (워크플로우 없음)
LLM은 강력한 엔진이지만, 엔진만으로는 자동차가 되지 않습니다.
말에게 마구를 씌우는 것
"Harness(하네스)"는 원래 말에게 씌우는 마구(馬具)를 의미합니다. 야생마는 엄청난 힘을 가지고 있지만, 마구 없이는 그 힘을 원하는 방향으로 쓸 수 없습니다. 마구를 씌워야 마차를 끌고, 밭을 갈고, 짐을 나를 수 있습니다.
AI 하네스도 같은 원리입니다:
- 야생마 = Raw LLM (GPT-4, Claude, Gemini)
- 마구 = AI Harness (시스템 프롬프트, 도구, 권한, 스킬, 훅)
- 마차/밭 = 실제 업무 (코드 리뷰, 데이터 분석, 고객 지원)
마구가 잘 설계되면 말의 힘을 최대한 활용할 수 있고, 잘못 설계되면 말이 엉뚱한 방향으로 달리거나 위험한 행동을 합니다.
Raw LLM vs Harnessed LLM 비교
| 항목 | Raw LLM | Harnessed LLM |
|---|---|---|
| 도구 접근 | 없음 | 파일 읽기/쓰기, API 호출, DB 쿼리 |
| 컨텍스트 | 대화 내용만 | 프로젝트 구조, 코드베이스, 문서 |
| 권한 | 무제한 (또는 전혀 없음) | 세밀한 권한 제어 |
| 기억 | 세션 내 대화만 | 장기 기억, 프로젝트 히스토리 |
| 워크플로우 | 없음 | 스킬, 훅, 파이프라인 |
| 안전장치 | 모델 자체 안전 | 가드레일, 권한 모델, 입출력 검증 |
| 일관성 | 프롬프트에 의존 | 시스템 프롬프트로 안정적 |
2025년 AI 엔지니어링의 무게중심 이동
2023년까지 AI 엔지니어링의 핵심은 모델 훈련이었습니다. 더 크고, 더 똑똑한 모델을 만드는 것이 목표였습니다.
2025년, 무게중심이 완전히 이동했습니다: 모델 오케스트레이션이 핵심입니다.
왜냐하면:
- 기반 모델이 충분히 강력해졌습니다 — Claude Sonnet 4, GPT-4o는 대부분의 작업에 충분한 지능을 가지고 있습니다
- 차별화는 하네스에서 일어납니다 — 같은 모델을 사용해도 하네스 설계에 따라 결과가 크게 달라집니다
- 엔터프라이즈 요구사항 — 보안, 감사, 권한 관리, 비용 추적이 필수가 되었습니다
- 에이전트의 부상 — Devin, Claude Code, GitHub Copilot Agent 같은 자율 에이전트들이 모두 정교한 하네스를 사용합니다
AI 하네스는 2025-2026년 AI 엔지니어링의 가장 중요한 개념입니다.
2. 하네스의 7가지 구성 요소
AI 하네스는 7가지 핵심 구성 요소로 이루어져 있습니다. 각 요소를 깊이 있게 살펴보겠습니다.
2-1. System Prompt (기본 규칙)
시스템 프롬프트는 AI의 헌법입니다. AI가 어떤 역할을 맡고, 어떤 규칙을 따르며, 어떤 제약사항을 지켜야 하는지를 최상위 수준에서 정의합니다.
시스템 프롬프트의 구성 요소
- 역할 정의: AI가 무엇인지, 어떤 전문성을 가졌는지
- 행동 규칙: 어떤 방식으로 응답하고 행동해야 하는지
- 제약사항: 절대 해서는 안 되는 것
- 출력 형식: 응답의 형태와 구조
- 안전 규칙: 보안, 프라이버시, 저작권 관련 규칙
Claude Code의 시스템 프롬프트 구조
Claude Code는 매우 정교한 시스템 프롬프트를 사용합니다:
You are Claude Code, Anthropic's official CLI for Claude.
Given the user's message, you should use the tools available
to complete the task.
Your strengths:
- Searching for code across large codebases
- Analyzing multiple files to understand architecture
- Investigating complex questions
- Performing multi-step research tasks
Guidelines:
- For file searches: search broadly when you don't know
where something lives
- NEVER create files unless absolutely necessary
- ALWAYS prefer editing existing files
핵심은 역할(CLI 도구), 강점(코드 검색, 분석), 규칙(파일 생성 최소화)이 명확하게 구분되어 있다는 점입니다.
시스템 프롬프트 작성 베스트 프랙티스
# 좋은 시스템 프롬프트의 구조
## 1. 역할 선언 (Who)
당신은 시니어 백엔드 엔지니어입니다.
Java/Spring Boot 전문가이며, 10년 이상의 경험이 있습니다.
## 2. 행동 규칙 (How)
- 코드 리뷰 시 보안 취약점을 최우선으로 확인하세요
- 성능 문제가 있으면 Big-O 분석과 함께 지적하세요
- 개선 제안은 반드시 코드 예제와 함께 제시하세요
## 3. 제약사항 (Boundaries)
- 코드를 직접 수정하지 마세요, 제안만 하세요
- 외부 라이브러리 추가를 권장하지 마세요
- 기존 아키텍처 패턴을 따르세요
## 4. 출력 형식 (Format)
리뷰 결과는 다음 형식으로 작성하세요:
- [심각도]: 설명 + 제안
실전 예제: 역할별 시스템 프롬프트
코드 리뷰어:
You are a senior code reviewer specializing in security
and performance. Review every PR with these priorities:
1. Security vulnerabilities (SQL injection, XSS, CSRF)
2. Performance bottlenecks (N+1 queries, memory leaks)
3. Code maintainability (naming, structure, SOLID)
Never approve code with critical security issues.
데이터 분석가:
You are a data analyst with expertise in Python, SQL,
and statistical analysis. When analyzing data:
1. Always validate data quality first
2. Provide confidence intervals for estimates
3. Visualize results with appropriate charts
4. Explain findings in business-friendly language
2-2. Tools (도구)
도구(Tools)는 AI가 외부 세계와 상호작용하는 인터페이스입니다. LLM 자체는 텍스트만 생성할 수 있지만, 도구를 통해 파일을 읽고, 명령어를 실행하고, API를 호출할 수 있습니다.
Function Calling의 작동 방식
AI의 도구 사용은 다음 과정을 거칩니다:
- 사용자가 요청을 보냄
- AI가 어떤 도구를 사용할지 결정 (추론)
- AI가 도구 호출을 생성 (JSON 형식)
- 하네스가 실제로 도구를 실행
- 결과를 AI에게 반환
- AI가 결과를 해석하고 다음 행동 결정
도구 정의 구조
도구는 JSON Schema로 정의됩니다:
{
"name": "read_file",
"description": "Reads a file from the local filesystem. Supports text files, images, and PDFs.",
"input_schema": {
"type": "object",
"properties": {
"file_path": {
"type": "string",
"description": "The absolute path to the file to read"
},
"offset": {
"type": "number",
"description": "The line number to start reading from"
},
"limit": {
"type": "number",
"description": "The number of lines to read"
}
},
"required": ["file_path"]
}
}
핵심 원칙:
- 이름: 동사 + 명사 (read_file, search_code, run_command)
- 설명: AI가 언제 이 도구를 사용해야 하는지 명확하게
- 파라미터: JSON Schema로 강타입, required/optional 구분
Claude Code의 핵심 도구들
Claude Code는 다음과 같은 도구들을 제공합니다:
| 도구 | 용도 | 예시 |
|---|---|---|
| Bash | 셸 명령 실행 | git status, npm test |
| Read | 파일 읽기 | 소스 코드, 설정 파일 |
| Write | 파일 생성 | 새 파일 작성 |
| Edit | 파일 수정 | 기존 코드 수정 |
| Grep | 패턴 검색 | 코드베이스 내 검색 |
| Glob | 파일 찾기 | 파일명 패턴 매칭 |
| WebSearch | 웹 검색 | 최신 문서, API 참조 |
| WebFetch | 웹 페이지 가져오기 | URL 내용 읽기 |
MCP(Model Context Protocol)로 도구 확장
MCP는 AI 에이전트가 외부 도구와 데이터 소스에 접근하는 표준 프로토콜입니다. USB-C가 다양한 장치를 하나의 인터페이스로 연결하듯, MCP는 다양한 서비스를 AI에 연결합니다.
{
"mcpServers": {
"github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": {
"GITHUB_TOKEN": "ghp_xxxxxxxxxxxx"
}
},
"postgres": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-postgres"],
"env": {
"DATABASE_URL": "postgresql://user:pass@localhost/db"
}
}
}
}
MCP 서버를 추가하면 AI는 GitHub 이슈를 관리하거나, 데이터베이스를 쿼리하거나, Slack 메시지를 보내는 등의 새로운 도구를 획득합니다.
도구 설계 5원칙
- 단일 책임: 하나의 도구는 하나의 일만 한다
- 명확한 설명: AI가 언제 사용해야 하는지 이해할 수 있어야 한다
- 강타입 파라미터: JSON Schema로 입력을 엄격하게 검증
- 실패 처리: 도구 실행 실패 시 의미 있는 에러 메시지 반환
- 부작용 최소화: 읽기 작업은 안전하게, 쓰기 작업은 확인 후 실행
2-3. Context (맥락)
컨텍스트는 AI가 현재 상황을 이해하는 데 필요한 모든 정보입니다. 같은 질문이라도 컨텍스트에 따라 완전히 다른 답이 필요합니다.
CLAUDE.md: 프로젝트별 지시문
CLAUDE.md는 프로젝트의 사용 설명서입니다. AI가 해당 프로젝트에서 어떻게 행동해야 하는지를 정의합니다.
# Project Guidelines
## Build Commands
- npm run dev: 개발 서버 실행
- npm run build: 프로덕션 빌드
- npm test: 테스트 실행
## Code Conventions
- TypeScript strict mode 사용
- 함수형 컴포넌트만 사용 (클래스 컴포넌트 금지)
- CSS-in-JS 대신 Tailwind CSS 사용
## Architecture
- src/components: 재사용 가능한 UI 컴포넌트
- src/hooks: 커스텀 훅
- src/lib: 유틸리티 함수
- src/app: Next.js App Router 페이지
CLAUDE.md는 계층적으로 로딩됩니다:
- 홈 디렉토리의 CLAUDE.md (전역 설정)
- 프로젝트 루트의 CLAUDE.md (프로젝트 설정)
- 하위 디렉토리의 CLAUDE.md (모듈별 설정)
하위 디렉토리의 설정이 상위를 오버라이드합니다.
코드베이스 인덱싱
AI 하네스는 프로젝트의 파일 구조, 의존성, 아키텍처를 인덱싱합니다:
프로젝트 구조 분석:
- package.json → 의존성, 스크립트
- tsconfig.json → TypeScript 설정
- .eslintrc → 코드 스타일 규칙
- .gitignore → 제외 파일 패턴
- 디렉토리 구조 → 아키텍처 패턴 추론
Memory: 세션 간 기억
.remember/ 디렉토리는 AI의 장기 기억 저장소입니다:
.remember/
core-memories.md # 프로젝트 핵심 정보
now.md # 현재 작업 상태
today.md # 오늘의 작업 기록
recent.md # 최근 작업 히스토리
archive.md # 오래된 기록 보관소
Context Window 관리 전략
Claude의 컨텍스트 윈도우는 200K 토큰(최대 1M)이지만, 효율적으로 관리해야 합니다:
- 요약(Summarization): 긴 파일은 핵심만 추출
- 청크(Chunking): 필요한 부분만 선택적으로 로딩
- 우선순위(Priority): 현재 작업과 관련성 높은 정보 우선
- 동적 로딩: 필요할 때 추가 컨텍스트를 가져오기
- 서브에이전트 위임: 독립 작업은 별도 컨텍스트에서 처리
2-4. Skills (스킬)
스킬은 재사용 가능한 도메인 지식과 워크플로우의 묶음입니다. 프롬프트 템플릿과 비슷하지만, 트리거 조건, 도구 활용 지시, 단계별 워크플로우를 포함하는 더 풍부한 개념입니다.
SKILL.md 파일 구조
---
trigger: 'when user asks to review a PR'
description: 'Comprehensive code review workflow'
---
# Code Review Skill
## Step 1: Gather Information
- Read the PR description and diff
- Identify changed files and their purposes
- Check the PR against project conventions (CLAUDE.md)
## Step 2: Security Review
- Check for SQL injection, XSS, CSRF vulnerabilities
- Verify input validation on all user inputs
- Ensure secrets are not hardcoded
## Step 3: Performance Review
- Identify N+1 query patterns
- Check for unnecessary re-renders (React)
- Verify proper indexing for DB queries
## Step 4: Generate Review
- Use structured format: severity + description + suggestion
- Include code examples for each suggestion
- Summarize with overall assessment
Claude Code의 내장 스킬 예시
Claude Code는 여러 내장 스킬을 가지고 있습니다:
- commit: git 상태 확인, 변경사항 분석, 커밋 메시지 작성, 커밋 실행
- review-pr: PR 분석, 코드 리뷰, 코멘트 작성
- test-driven-development: 테스트 먼저 작성, 구현, 리팩토링
- brainstorming: 아이디어 발산, 구조화, 우선순위 결정
스킬 vs 프롬프트 템플릿
| 항목 | 프롬프트 템플릿 | 스킬 |
|---|---|---|
| 트리거 | 수동 선택 | 자동 감지 |
| 도구 활용 | 없음 | 도구 사용 지시 포함 |
| 워크플로우 | 단일 프롬프트 | 다단계 워크플로우 |
| 컨텍스트 | 정적 | 동적 컨텍스트 로딩 |
| 학습 | 없음 | 결과 피드백 반영 가능 |
스킬 작성 가이드
좋은 스킬을 만드는 핵심 원칙:
- 명확한 트리거: 어떤 상황에서 활성화되는지 정확하게 정의
- 단계별 분해: 복잡한 작업을 작은 단계로 분해
- 도구 매핑: 각 단계에서 어떤 도구를 사용하는지 명시
- 예외 처리: 실패 시나리오와 대안 경로 정의
- 출력 형식: 결과물의 형태를 구체적으로 정의
2-5. Hooks (훅)
훅은 AI의 도구 사용 전후에 자동으로 실행되는 스크립트입니다. 마치 Git의 pre-commit, post-commit 훅처럼, AI의 행동에 자동화된 검증과 처리를 추가합니다.
훅의 4가지 유형
-
PreToolUse: 도구 사용 전에 실행
- 용도: 입력 검증, 권한 확인, 파라미터 변환
- 예: Write 도구 호출 전에 파일 경로 검증
-
PostToolUse: 도구 사용 후에 실행
- 용도: 결과 검증, 포맷팅, 린트, 테스트
- 예: 파일 저장 후 자동으로 ESLint 실행
-
Notification: 알림 전에 실행
- 용도: 알림 내용 가공, 필터링
-
Stop: 에이전트 정지 시 실행
- 용도: 정리 작업, 상태 저장
설정 예시: settings.json
{
"hooks": {
"PreToolUse": [
{
"matcher": "Write|Edit",
"command": "echo 'File modification detected'"
}
],
"PostToolUse": [
{
"matcher": "Write|Edit",
"command": "/bin/sh -c 'cd PROJECT_DIR && npx eslint --fix FILE_PATH 2>/dev/null || true'"
},
{
"matcher": "Bash",
"command": "/bin/sh -c 'if echo TOOL_INPUT | grep -q \"git commit\"; then cd PROJECT_DIR && npm test; fi'"
}
],
"Notification": [
{
"matcher": "",
"command": "/bin/sh -c 'echo NOTIFICATION_CONTENT >> /tmp/ai-notifications.log'"
}
]
}
}
실전 훅 시나리오
시나리오 1: 파일 저장 후 자동 포맷팅
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write",
"command": "/bin/sh -c 'npx prettier --write FILE_PATH'"
}
]
}
}
시나리오 2: 커밋 전 자동 테스트
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"command": "/bin/sh -c 'if echo TOOL_INPUT | grep -q \"git commit\"; then npm test || exit 1; fi'"
}
]
}
}
시나리오 3: 위험한 명령어 차단
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"command": "/bin/sh -c 'if echo TOOL_INPUT | grep -qE \"rm -rf|drop table|format\"; then echo \"BLOCKED: Dangerous command detected\" && exit 1; fi'"
}
]
}
}
2-6. Permissions (권한)
권한 모델은 AI가 수행할 수 있는 작업의 범위를 정의하는 보안 계층입니다. 최소 권한 원칙(Principle of Least Privilege)을 AI에 적용합니다.
작업 위험도 분류
| 위험도 | 작업 유형 | 예시 | 정책 |
|---|---|---|---|
| 안전 | 읽기 | 파일 읽기, 검색, 조회 | 자동 허용 |
| 주의 | 쓰기 | 파일 수정, 생성 | 확인 후 허용 |
| 위험 | 삭제/실행 | 파일 삭제, 배포 | 명시적 승인 필요 |
| 금지 | 시스템 변경 | OS 설정, 계정 변경 | 항상 차단 |
allowedTools, disallowedTools
{
"permissions": {
"allowedTools": [
"Read",
"Glob",
"Grep",
"Bash(git status)",
"Bash(git diff)",
"Bash(npm test)"
],
"disallowedTools": [
"Bash(rm *)",
"Bash(sudo *)",
"Bash(curl * | sh)",
"Write(/etc/*)",
"Write(/usr/*)"
]
}
}
Sandbox 모드 vs 에이전트 모드
Sandbox 모드:
- 네트워크 접근 차단
- 파일 시스템 읽기 전용
- 셸 명령 제한
- 안전한 실험 환경
에이전트 모드:
- 네트워크 접근 허용
- 파일 시스템 읽기/쓰기
- 셸 명령 허용 (패턴 기반 필터링)
- 실제 작업 수행 환경
최소 권한 원칙 적용
AI 에이전트에 최소 권한 원칙을 적용하는 단계:
- 필요한 도구만 제공: 코드 리뷰에 배포 도구는 불필요
- 파일 범위 제한: 프로젝트 디렉토리 외부 접근 차단
- 명령어 화이트리스트: 허용된 셸 명령만 실행 가능
- 시간 제한: 장시간 실행 방지
- 비용 제한: 최대 토큰 사용량 설정
2-7. Memory (기억)
메모리는 AI가 과거의 상호작용과 학습 내용을 유지하는 메커니즘입니다.
단기 기억 vs 장기 기억
단기 기억 (Short-term Memory):
- 현재 대화 세션의 컨텍스트
- 컨텍스트 윈도우 내의 모든 메시지
- 세션 종료 시 사라짐
장기 기억 (Long-term Memory):
.remember/디렉토리에 파일로 저장- 세션 간 지속
- 프로젝트 수준 또는 사용자 수준
기억 파일 구조
# core-memories.md
- 이 프로젝트는 Next.js 14 + TypeScript + Tailwind CSS를 사용합니다
- 배포는 Vercel로 합니다
- DB는 PostgreSQL (Supabase)입니다
# now.md
현재 작업: 사용자 인증 모듈 리팩토링 중
진행 상황: NextAuth.js에서 Lucia Auth로 마이그레이션 진행 중
블로커: 소셜 로그인 콜백 URL 설정 문제
# today.md
- 09:30 인증 모듈 분석 완료
- 10:15 Lucia Auth 설정 파일 생성
- 11:00 세션 관리 로직 마이그레이션
- 14:00 소셜 로그인 통합 시작
에피소딕 메모리 vs 시맨틱 메모리
에피소딕 메모리 (사건 기반):
- "어제 사용자가 인증 버그를 수정해달라고 했다"
- "지난주에 데이터베이스 스키마를 변경했다"
- 구체적인 사건과 시간 정보 포함
시맨틱 메모리 (지식 기반):
- "이 프로젝트는 REST API를 사용한다"
- "팀의 코딩 컨벤션은 Airbnb 스타일이다"
- 일반적인 사실과 규칙
메모리 관리 전략
- 자동 요약: 긴 대화는 핵심 포인트만 추출하여 저장
- 중요도 기반 정리: 자주 참조되는 기억은 유지, 불필요한 기억은 아카이브
- 계층적 구조: 핵심 기억 > 최근 기억 > 아카이브
- 충돌 해결: 새로운 정보가 기존 기억과 충돌하면 업데이트
- 프라이버시: 민감한 정보는 암호화하거나 저장하지 않음
3. Claude Code 하네스 아키텍처 심화
3-1. 에이전트 루프 (Agent Loop)
Claude Code의 핵심은 에이전트 루프입니다. 단순한 질문-응답이 아니라, 도구를 사용하고, 결과를 관찰하고, 다시 행동하는 반복 순환입니다.
에이전트 루프 흐름:
1. User Input (사용자 요청)
|
2. System Prompt + Context 로딩
|
3. LLM 추론 (어떤 행동을 할지 결정)
|
4. Tool Call 결정
|
5. Hook (PreToolUse) 실행
| (검증 실패 시 → 3으로 돌아감)
|
6. Tool 실행
|
7. Hook (PostToolUse) 실행
|
8. 결과 관찰 (Observation)
|
9. 추가 행동 필요? → Yes → 3으로 돌아감
| No
|
10. 최종 응답 생성
이 루프는 max_turns 제한에 도달하거나, AI가 "작업 완료"로 판단할 때까지 계속됩니다.
실전 예시: PR 리뷰 루프
Turn 1: git diff 실행 (Bash 도구)
→ 변경된 파일 목록과 diff 획득
Turn 2: 변경된 파일 읽기 (Read 도구)
→ 전체 컨텍스트 파악
Turn 3: CLAUDE.md 읽기 (Read 도구)
→ 프로젝트 컨벤션 확인
Turn 4: 관련 테스트 파일 찾기 (Grep 도구)
→ 테스트 커버리지 확인
Turn 5: npm test 실행 (Bash 도구)
→ 테스트 통과 여부 확인
Turn 6: 리뷰 결과 생성 (최종 응답)
→ 보안, 성능, 유지보수성 관점 리뷰
3-2. 서브에이전트 아키텍처
복잡한 작업은 하나의 에이전트가 처리하기 어렵습니다. Claude Code는 서브에이전트 아키텍처를 사용합니다.
메인 에이전트와 서브에이전트
메인 에이전트 (Orchestrator)
|
+--- 서브에이전트 A: "src/ 디렉토리 분석"
| (독립 컨텍스트, 파일 읽기/검색 도구)
|
+--- 서브에이전트 B: "tests/ 디렉토리 분석"
| (독립 컨텍스트, 테스트 실행 도구)
|
+--- 서브에이전트 C: "문서 업데이트"
(독립 컨텍스트, 파일 쓰기 도구)
메인 에이전트: 각 서브에이전트의 결과를 통합하여 최종 응답 생성
서브에이전트의 핵심 특징:
- 독립 컨텍스트: 메인 에이전트의 컨텍스트를 오염시키지 않음
- 병렬 실행: 독립적인 작업은 동시에 실행 가능
- 결과 통합: 메인 에이전트가 결과를 수집하고 종합
Background Agent vs Foreground Agent
- Foreground Agent: 사용자와 직접 대화하는 메인 에이전트
- Background Agent: 독립적으로 작업을 수행하는 비동기 에이전트
Background Agent 사용 시나리오:
- 대규모 리팩토링 작업
- 여러 파일에 걸친 테스트 실행
- 문서 자동 생성
Worktree Isolation
Git Worktree를 활용한 격리:
메인 프로젝트 (main branch)
|
+--- .claude/worktrees/feature-auth/
| (독립 브랜치, 독립 작업 디렉토리)
|
+--- .claude/worktrees/fix-bug-123/
(독립 브랜치, 독립 작업 디렉토리)
각 Worktree는 독립적인 파일 시스템을 가지므로, 서로의 작업에 영향을 주지 않습니다.
3-3. settings.json 완전 해부
Claude Code의 설정은 settings.json에서 관리됩니다.
전역 설정 vs 프로젝트 설정
설정 위치 (우선순위 순):
1. 프로젝트/.claude/settings.json (최우선)
2. 홈디렉토리/.claude/settings.json (전역)
3. 기본값
전체 설정 구조
{
"permissions": {
"allowedTools": ["Read", "Glob", "Grep"],
"disallowedTools": ["Bash(rm *)"]
},
"hooks": {
"PreToolUse": [],
"PostToolUse": [],
"Notification": [],
"Stop": []
},
"env": {
"NODE_ENV": "development",
"DEBUG": "true"
},
"model": "claude-sonnet-4-20250514",
"theme": "dark"
}
설정 우선순위
가장 높음 ← 프로젝트 설정 ← 전역 설정 ← 기본값 → 가장 낮음
프로젝트 설정이 전역 설정을 오버라이드하므로, 프로젝트별로 다른 권한과 훅을 설정할 수 있습니다.
4. Claude Agent SDK로 커스텀 하네스 만들기
4-1. Python SDK
Anthropic의 Claude Agent SDK는 커스텀 AI 에이전트를 구축하기 위한 프레임워크입니다.
기본 에이전트 생성
import anthropic
from typing import Any
# Anthropic 클라이언트 초기화
client = anthropic.Anthropic()
# 도구 정의
tools = [
{
"name": "read_file",
"description": "Read the contents of a file at the given path",
"input_schema": {
"type": "object",
"properties": {
"path": {
"type": "string",
"description": "Absolute file path to read"
}
},
"required": ["path"]
}
},
{
"name": "list_directory",
"description": "List files and directories at the given path",
"input_schema": {
"type": "object",
"properties": {
"path": {
"type": "string",
"description": "Directory path to list"
}
},
"required": ["path"]
}
},
{
"name": "search_code",
"description": "Search for a pattern in the codebase",
"input_schema": {
"type": "object",
"properties": {
"pattern": {
"type": "string",
"description": "Regex pattern to search for"
},
"file_type": {
"type": "string",
"description": "File extension to filter (e.g., py, ts)"
}
},
"required": ["pattern"]
}
}
]
def execute_tool(name: str, input_data: dict) -> str:
"""도구를 실행하고 결과를 반환합니다."""
import os
import subprocess
if name == "read_file":
try:
with open(input_data["path"], "r") as f:
return f.read()
except FileNotFoundError:
return f"Error: File not found: {input_data['path']}"
elif name == "list_directory":
try:
entries = os.listdir(input_data["path"])
return "\n".join(entries)
except FileNotFoundError:
return f"Error: Directory not found: {input_data['path']}"
elif name == "search_code":
try:
cmd = ["grep", "-rn", input_data["pattern"], "."]
if "file_type" in input_data:
cmd.extend(["--include", f"*.{input_data['file_type']}"])
result = subprocess.run(cmd, capture_output=True, text=True)
return result.stdout or "No matches found"
except Exception as e:
return f"Error: {str(e)}"
return f"Unknown tool: {name}"
def run_agent(user_message: str, max_turns: int = 10) -> str:
"""에이전트 루프를 실행합니다."""
system_prompt = """You are an expert code reviewer.
Analyze code for security vulnerabilities, performance issues,
and maintainability problems. Use the provided tools to
explore the codebase before giving your review."""
messages = [{"role": "user", "content": user_message}]
for turn in range(max_turns):
# LLM 호출
response = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=4096,
system=system_prompt,
tools=tools,
messages=messages,
)
# 응답 처리
if response.stop_reason == "end_turn":
# 최종 텍스트 응답 추출
for block in response.content:
if hasattr(block, "text"):
return block.text
return "Agent completed without text response"
# 도구 호출 처리
if response.stop_reason == "tool_use":
# assistant 메시지 추가
messages.append({
"role": "assistant",
"content": response.content,
})
# 각 도구 호출 실행
tool_results = []
for block in response.content:
if block.type == "tool_use":
result = execute_tool(block.name, block.input)
tool_results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": result,
})
messages.append({
"role": "user",
"content": tool_results,
})
return "Agent reached maximum turns without completing"
# 실행
if __name__ == "__main__":
review = run_agent("Review the authentication module in src/auth/")
print(review)
권한 모델 추가
class PermissionModel:
"""AI 에이전트의 권한을 관리합니다."""
def __init__(self):
self.allowed_paths = ["/project/src/", "/project/tests/"]
self.blocked_commands = ["rm", "sudo", "chmod"]
self.max_file_size = 1_000_000 # 1MB
def check_file_access(self, path: str) -> bool:
"""파일 접근 권한을 확인합니다."""
return any(path.startswith(p) for p in self.allowed_paths)
def check_command(self, command: str) -> bool:
"""명령어 실행 권한을 확인합니다."""
return not any(cmd in command for cmd in self.blocked_commands)
def validate_tool_call(self, tool_name: str, input_data: dict) -> tuple:
"""도구 호출의 유효성을 검증합니다.
Returns (is_allowed, reason)"""
if tool_name == "read_file":
path = input_data.get("path", "")
if not self.check_file_access(path):
return False, f"Access denied: {path}"
if tool_name == "execute_command":
cmd = input_data.get("command", "")
if not self.check_command(cmd):
return False, f"Blocked command: {cmd}"
return True, "Allowed"
이벤트 처리와 모니터링
import time
from dataclasses import dataclass, field
from typing import Optional
@dataclass
class AgentEvent:
"""에이전트의 행동을 기록하는 이벤트입니다."""
event_type: str # tool_call, tool_result, llm_response, error
timestamp: float = field(default_factory=time.time)
tool_name: Optional[str] = None
input_data: Optional[dict] = None
output_data: Optional[str] = None
tokens_used: int = 0
duration_ms: float = 0
class AgentMonitor:
"""에이전트의 행동을 모니터링합니다."""
def __init__(self):
self.events: list[AgentEvent] = []
self.total_tokens = 0
self.total_cost = 0.0
def log_event(self, event: AgentEvent):
self.events.append(event)
self.total_tokens += event.tokens_used
def get_summary(self) -> dict:
return {
"total_events": len(self.events),
"total_tokens": self.total_tokens,
"tool_calls": sum(
1 for e in self.events if e.event_type == "tool_call"
),
"errors": sum(
1 for e in self.events if e.event_type == "error"
),
"total_duration_ms": sum(
e.duration_ms for e in self.events
),
}
4-2. TypeScript SDK
TypeScript로도 동일한 패턴으로 하네스를 구축할 수 있습니다.
import Anthropic from '@anthropic-ai/sdk'
// 도구 정의
const tools: Anthropic.Tool[] = [
{
name: 'query_database',
description: 'Execute a SQL query against the analytics database',
input_schema: {
type: 'object' as const,
properties: {
query: {
type: 'string',
description: 'SQL query to execute (SELECT only)',
},
database: {
type: 'string',
description: 'Database name',
enum: ['analytics', 'users', 'products'],
},
},
required: ['query', 'database'],
},
},
{
name: 'create_chart',
description: 'Create a data visualization chart',
input_schema: {
type: 'object' as const,
properties: {
chart_type: {
type: 'string',
enum: ['bar', 'line', 'pie', 'scatter'],
},
data: {
type: 'string',
description: 'JSON string of chart data',
},
title: {
type: 'string',
description: 'Chart title',
},
},
required: ['chart_type', 'data', 'title'],
},
},
]
// 권한 모델
class QueryPermissions {
private readonly allowedOperations = ['SELECT']
private readonly blockedPatterns = [
/DROP\s/i,
/DELETE\s/i,
/UPDATE\s/i,
/INSERT\s/i,
/ALTER\s/i,
/TRUNCATE\s/i,
]
validateQuery(query: string): { allowed: boolean; reason: string } {
for (const pattern of this.blockedPatterns) {
if (pattern.test(query)) {
return {
allowed: false,
reason: `Blocked: destructive operation detected`,
}
}
}
return { allowed: true, reason: 'Query is safe' }
}
}
// 도구 실행
async function executeTool(name: string, input: Record<string, unknown>): Promise<string> {
const permissions = new QueryPermissions()
if (name === 'query_database') {
const query = input.query as string
const validation = permissions.validateQuery(query)
if (!validation.allowed) {
return `Permission denied: ${validation.reason}`
}
// 실제 DB 쿼리 실행 (여기서는 시뮬레이션)
return JSON.stringify({
columns: ['date', 'revenue', 'users'],
rows: [
['2025-01', 150000, 12000],
['2025-02', 165000, 13500],
['2025-03', 180000, 15000],
],
})
}
if (name === 'create_chart') {
return `Chart created: ${input.title} (${input.chart_type})`
}
return `Unknown tool: ${name}`
}
// 에이전트 루프
async function runDataAnalysisAgent(question: string): Promise<string> {
const client = new Anthropic()
const systemPrompt = `You are a data analyst agent.
Analyze data by querying databases and creating visualizations.
Always validate data before making conclusions.
Provide insights in clear, business-friendly language.`
const messages: Anthropic.MessageParam[] = [{ role: 'user', content: question }]
const maxTurns = 10
for (let turn = 0; turn < maxTurns; turn++) {
const response = await client.messages.create({
model: 'claude-sonnet-4-20250514',
max_tokens: 4096,
system: systemPrompt,
tools,
messages,
})
if (response.stop_reason === 'end_turn') {
for (const block of response.content) {
if (block.type === 'text') {
return block.text
}
}
return 'Agent completed'
}
if (response.stop_reason === 'tool_use') {
messages.push({
role: 'assistant',
content: response.content,
})
const toolResults: Anthropic.ToolResultBlockParam[] = []
for (const block of response.content) {
if (block.type === 'tool_use') {
const result = await executeTool(block.name, block.input as Record<string, unknown>)
toolResults.push({
type: 'tool_result',
tool_use_id: block.id,
content: result,
})
}
}
messages.push({
role: 'user',
content: toolResults,
})
}
}
return 'Agent reached maximum turns'
}
// 실행
async function main() {
const result = await runDataAnalysisAgent('What was the revenue trend in Q1 2025?')
console.log(result)
}
main().catch(console.error)
5. 다른 AI 하네스 프레임워크 비교
프레임워크 비교표
| 프레임워크 | 언어 | 핵심 개념 | 하네스 수준 | 학습 곡선 |
|---|---|---|---|---|
| Claude Agent SDK | Python/TS | 도구, 권한, 이벤트 | 가장 완전 | 중간 |
| LangGraph | Python | 그래프 기반 워크플로우 | 높음 | 높음 |
| CrewAI | Python | 멀티에이전트 협업 | 중간 | 낮음 |
| AutoGen | Python | 에이전트 대화 | 중간 | 중간 |
| Semantic Kernel | C#/Python | MS 에코시스템 통합 | 중간 | 중간 |
| DSPy | Python | 프롬프트 최적화 | 낮음 | 높음 |
Claude Agent SDK
강점:
- Anthropic 모델과 최적 호환
- 내장 권한 모델, 도구 사용, 이벤트 시스템
- 프로덕션 레벨 안정성
하네스 구현:
- System Prompt + Tools + Permissions가 SDK 레벨에서 통합
- 에이전트 루프가 내장되어 있어 별도 구현 불필요
LangGraph
강점:
- 복잡한 워크플로우를 그래프로 시각화
- 상태 관리, 조건 분기, 병렬 실행 지원
- 체크포인트와 롤백 기능
하네스 구현:
from langgraph.graph import StateGraph, END
from typing import TypedDict
class ReviewState(TypedDict):
code_diff: str
security_issues: list
performance_issues: list
review_summary: str
def analyze_security(state: ReviewState) -> ReviewState:
"""보안 취약점을 분석합니다."""
# LLM 호출로 보안 분석
state["security_issues"] = ["SQL injection in login.py:42"]
return state
def analyze_performance(state: ReviewState) -> ReviewState:
"""성능 이슈를 분석합니다."""
# LLM 호출로 성능 분석
state["performance_issues"] = ["N+1 query in users.py:87"]
return state
def generate_review(state: ReviewState) -> ReviewState:
"""최종 리뷰를 생성합니다."""
issues = state["security_issues"] + state["performance_issues"]
state["review_summary"] = f"Found {len(issues)} issues"
return state
# 그래프 구성
workflow = StateGraph(ReviewState)
workflow.add_node("security", analyze_security)
workflow.add_node("performance", analyze_performance)
workflow.add_node("review", generate_review)
workflow.set_entry_point("security")
workflow.add_edge("security", "performance")
workflow.add_edge("performance", "review")
workflow.add_edge("review", END)
app = workflow.compile()
CrewAI
강점:
- 직관적인 멀티에이전트 모델 (역할 기반)
- "Agent = Role + Goal + Backstory" 패턴
- 에이전트 간 협업이 자연스러움
하네스 구현:
from crewai import Agent, Task, Crew
security_reviewer = Agent(
role="Security Reviewer",
goal="Find all security vulnerabilities in the code",
backstory="You are a senior security engineer with 15 years "
"of experience in application security.",
tools=[], # 도구 목록
)
performance_reviewer = Agent(
role="Performance Reviewer",
goal="Identify performance bottlenecks and optimization opportunities",
backstory="You are a performance engineering specialist "
"who has optimized systems serving millions of users.",
tools=[],
)
review_task = Task(
description="Review the authentication module for security issues",
agent=security_reviewer,
expected_output="List of security vulnerabilities with severity ratings",
)
crew = Crew(
agents=[security_reviewer, performance_reviewer],
tasks=[review_task],
)
result = crew.kickoff()
6. 하네스 설계 패턴
AI 하네스를 설계할 때 활용할 수 있는 주요 패턴들을 살펴봅니다.
6-1. Router Pattern (라우터 패턴)
입력을 분석하여 적절한 전문 에이전트로 라우팅하는 패턴입니다.
사용자 입력
|
v
[Router Agent] → "코드 리뷰 요청" → Code Review Agent
→ "데이터 분석 요청" → Data Analysis Agent
→ "문서 작성 요청" → Documentation Agent
→ "일반 질문" → General Assistant
적합한 상황:
- 다양한 유형의 요청을 처리해야 할 때
- 전문 에이전트가 각 도메인에 최적화되어 있을 때
- 단일 에이전트로는 모든 도메인을 커버하기 어려울 때
6-2. Orchestrator-Worker Pattern (오케스트레이터-워커 패턴)
중앙 오케스트레이터가 작업을 분할하고 워커에게 배분하는 패턴입니다.
[Orchestrator]
|
+--- "파일 A 리뷰해줘" → [Worker 1] → 결과 A
|
+--- "파일 B 리뷰해줘" → [Worker 2] → 결과 B
|
+--- "파일 C 리뷰해줘" → [Worker 3] → 결과 C
|
v
[Orchestrator] → 결과 A + B + C 통합 → 최종 리뷰
적합한 상황:
- 대규모 작업을 병렬로 처리해야 할 때
- 작업을 독립적인 단위로 분할할 수 있을 때
- 결과를 통합하는 로직이 필요할 때
6-3. Pipeline Pattern (파이프라인 패턴)
순차적으로 처리하는 패턴입니다. 각 단계의 출력이 다음 단계의 입력이 됩니다.
[분석 Agent] → 코드 분석 결과
|
v
[계획 Agent] → 리팩토링 계획
|
v
[실행 Agent] → 코드 수정
|
v
[검증 Agent] → 테스트 실행 + 결과 확인
적합한 상황:
- 작업에 명확한 순서가 있을 때
- 각 단계가 이전 단계의 결과에 의존할 때
- 단계별 품질 검증이 필요할 때
6-4. Evaluator-Optimizer Pattern (평가자-최적화 패턴)
결과를 평가하고 기준 미달 시 재시도하는 패턴입니다.
[Generator Agent] → 초안 생성
|
v
[Evaluator Agent] → 품질 평가 (1-10점)
|
+--- 점수 >= 8 → 완료
|
+--- 점수 < 8 → 피드백과 함께 Generator에게 재요청
|
v
[Generator Agent] → 수정본 생성
|
v
[Evaluator Agent] → 재평가
...
적합한 상황:
- 출력 품질이 중요할 때
- 품질을 객관적으로 측정할 수 있을 때
- 반복을 통한 개선이 가능할 때
6-5. Guardrails Pattern (가드레일 패턴)
입출력 검증으로 안전한 AI 행동을 보장하는 패턴입니다.
사용자 입력
|
v
[Input Guardrail] → 유해 콘텐츠 필터링
| 프롬프트 인젝션 탐지
| 입력 정규화
v
[AI Agent] → 작업 수행
|
v
[Output Guardrail] → PII 마스킹
| 환각 탐지
| 형식 검증
v
최종 응답
구현 예시:
class InputGuardrail:
"""입력을 검증하고 정제합니다."""
def validate(self, user_input: str) -> tuple:
# 프롬프트 인젝션 탐지
injection_patterns = [
"ignore previous instructions",
"system prompt",
"you are now",
"disregard all",
]
for pattern in injection_patterns:
if pattern.lower() in user_input.lower():
return False, "Potential prompt injection detected"
# 입력 길이 제한
if len(user_input) > 10000:
return False, "Input too long"
return True, "Valid input"
class OutputGuardrail:
"""출력을 검증하고 정제합니다."""
def validate(self, output: str) -> str:
# PII 마스킹
import re
# 이메일 마스킹
output = re.sub(
r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}",
"[EMAIL_REDACTED]",
output,
)
# 전화번호 마스킹
output = re.sub(
r"\b\d{3}[-.]?\d{4}[-.]?\d{4}\b",
"[PHONE_REDACTED]",
output,
)
return output
7. 실전: 나만의 코드 리뷰 하네스 만들기
실제로 동작하는 코드 리뷰 하네스를 처음부터 끝까지 만들어 보겠습니다.
7-1. 프로젝트 구조
code-review-harness/
src/
agent.py # 에이전트 루프
tools.py # 도구 정의 및 실행
permissions.py # 권한 모델
guardrails.py # 입출력 검증
memory.py # 기억 관리
monitor.py # 모니터링
skills/
code-review.md # 코드 리뷰 스킬
security-audit.md # 보안 감사 스킬
config/
settings.json # 설정 파일
tests/
test_agent.py # 에이전트 테스트
README.md
requirements.txt
7-2. System Prompt 설계
You are an expert code reviewer specializing in Python
and TypeScript applications.
## Your Responsibilities
1. Security: Find vulnerabilities (injection, XSS, auth issues)
2. Performance: Identify bottlenecks (N+1 queries, memory leaks)
3. Maintainability: Check code quality (naming, structure, SOLID)
4. Testing: Verify test coverage and quality
## Rules
- NEVER modify code directly. Only suggest changes.
- Always explain WHY something is an issue, not just WHAT.
- Provide code examples for every suggestion.
- Rate issues by severity: Critical, High, Medium, Low.
## Output Format
For each issue found:
[SEVERITY] file:line - Description
Suggestion: How to fix it
Example: Code snippet showing the fix
7-3. 도구 구현
# tools.py
import subprocess
import os
def git_diff(base_branch: str = "main") -> str:
"""현재 브랜치와 base 브랜치의 diff를 가져옵니다."""
result = subprocess.run(
["git", "diff", f"{base_branch}...HEAD"],
capture_output=True,
text=True,
)
return result.stdout
def read_file(path: str) -> str:
"""파일 내용을 읽습니다."""
try:
with open(path, "r") as f:
lines = f.readlines()
# 줄 번호 추가
numbered = [f"{i+1}: {line}" for i, line in enumerate(lines)]
return "".join(numbered)
except FileNotFoundError:
return f"File not found: {path}"
def search_pattern(pattern: str, directory: str = ".") -> str:
"""코드베이스에서 패턴을 검색합니다."""
result = subprocess.run(
["grep", "-rn", pattern, directory,
"--include=*.py", "--include=*.ts",
"--include=*.tsx", "--include=*.js"],
capture_output=True,
text=True,
)
return result.stdout or "No matches found"
def run_tests(test_path: str = "") -> str:
"""테스트를 실행합니다."""
cmd = ["python", "-m", "pytest", "-v"]
if test_path:
cmd.append(test_path)
result = subprocess.run(cmd, capture_output=True, text=True)
return f"STDOUT:\n{result.stdout}\nSTDERR:\n{result.stderr}"
def get_file_history(path: str, count: int = 5) -> str:
"""파일의 git 히스토리를 가져옵니다."""
result = subprocess.run(
["git", "log", f"-{count}", "--oneline", "--", path],
capture_output=True,
text=True,
)
return result.stdout
7-4. 스킬 정의
# skills/code-review.md
---
trigger: "when user asks to review code or a PR"
description: "Comprehensive code review workflow"
---
## Code Review Workflow
### Step 1: Gather Context
1. Run git diff to see all changes
2. Read the changed files completely
3. Check project conventions (CLAUDE.md, .eslintrc)
4. Identify the purpose of the changes
### Step 2: Security Analysis
Check for these common vulnerabilities:
- SQL injection (raw queries, string interpolation)
- XSS (unescaped user input in HTML)
- Authentication issues (weak tokens, missing checks)
- Authorization issues (missing role checks)
- Sensitive data exposure (API keys, passwords in code)
### Step 3: Performance Analysis
Check for these common issues:
- N+1 database queries
- Missing database indexes
- Unnecessary re-renders (React)
- Memory leaks (unclosed resources)
- Blocking operations in async code
### Step 4: Code Quality Analysis
Check for these issues:
- Unclear naming conventions
- Functions exceeding 50 lines
- Missing error handling
- Duplicated code
- SOLID principle violations
### Step 5: Generate Review Report
Format each issue as:
[SEVERITY] file:line - Description
Use severity levels: Critical, High, Medium, Low, Info
7-5. 권한 모델
# permissions.py
class ReviewPermissions:
"""코드 리뷰 에이전트의 권한을 정의합니다."""
# 읽기만 허용 - 코드 수정 불가
ALLOWED_TOOLS = [
"git_diff",
"read_file",
"search_pattern",
"run_tests",
"get_file_history",
]
BLOCKED_TOOLS = [
"write_file",
"delete_file",
"execute_command",
"deploy",
]
# 접근 가능한 디렉토리
ALLOWED_PATHS = [
"src/",
"tests/",
"lib/",
"config/",
]
# 접근 불가 디렉토리
BLOCKED_PATHS = [
".env",
"secrets/",
"credentials/",
".git/",
]
def is_tool_allowed(self, tool_name: str) -> bool:
if tool_name in self.BLOCKED_TOOLS:
return False
return tool_name in self.ALLOWED_TOOLS
def is_path_allowed(self, path: str) -> bool:
# 차단 경로 확인
for blocked in self.BLOCKED_PATHS:
if blocked in path:
return False
# 허용 경로 확인
return any(path.startswith(p) for p in self.ALLOWED_PATHS)
8. 하네스 평가 및 모니터링
하네스 품질 메트릭
AI 하네스의 품질을 측정하는 주요 메트릭:
| 메트릭 | 설명 | 목표값 |
|---|---|---|
| 도구 사용 정확도 | 올바른 도구를 올바른 파라미터로 호출하는 비율 | 95% 이상 |
| 태스크 완료율 | 사용자 요청을 성공적으로 완료하는 비율 | 90% 이상 |
| 안전 위반 빈도 | 가드레일을 우회하거나 권한을 위반하는 빈도 | 0% |
| 평균 턴 수 | 작업 완료까지의 평균 에이전트 루프 반복 횟수 | 5 이하 |
| 비용 효율성 | 작업당 평균 토큰 사용량과 API 비용 | 업무에 따라 상이 |
LLM-as-Judge
다른 LLM을 사용하여 에이전트의 출력 품질을 평가하는 방법입니다:
def evaluate_review_quality(
original_code: str,
review_output: str,
evaluator_model: str = "claude-sonnet-4-20250514"
) -> dict:
"""LLM을 사용하여 코드 리뷰 품질을 평가합니다."""
evaluation_prompt = f"""
Evaluate this code review on a scale of 1-10 for each criterion:
1. Accuracy: Are the identified issues real problems?
2. Completeness: Were important issues missed?
3. Actionability: Are suggestions specific and implementable?
4. Communication: Is the review clear and constructive?
Original Code:
{original_code}
Review Output:
{review_output}
Respond in JSON format:
accuracy, completeness, actionability, communication, overall, feedback
"""
# LLM 호출하여 평가 수행
# ... (실제 API 호출 코드)
return evaluation_result
A/B 테스트
프롬프트나 도구 변경 시 A/B 테스트로 비교합니다:
- Baseline 설정: 현재 하네스의 성능 측정
- 변경 적용: 새로운 시스템 프롬프트, 도구, 스킬 적용
- 동일 입력 테스트: 같은 테스트 케이스로 두 버전 실행
- 메트릭 비교: 정확도, 완료율, 비용 비교
- 통계적 유의성 확인: 차이가 우연이 아닌지 검증
비용 추적
class CostTracker:
"""에이전트의 API 호출 비용을 추적합니다."""
# 모델별 토큰당 가격 (USD)
PRICING = {
"claude-sonnet-4-20250514": {
"input": 0.003 / 1000,
"output": 0.015 / 1000,
},
"claude-opus-4-20250514": {
"input": 0.015 / 1000,
"output": 0.075 / 1000,
},
}
def __init__(self):
self.total_input_tokens = 0
self.total_output_tokens = 0
self.model = "claude-sonnet-4-20250514"
def add_usage(self, input_tokens: int, output_tokens: int):
self.total_input_tokens += input_tokens
self.total_output_tokens += output_tokens
def get_total_cost(self) -> float:
pricing = self.PRICING[self.model]
return (
self.total_input_tokens * pricing["input"]
+ self.total_output_tokens * pricing["output"]
)
def get_report(self) -> str:
cost = self.get_total_cost()
return (
f"Input tokens: {self.total_input_tokens:,}\n"
f"Output tokens: {self.total_output_tokens:,}\n"
f"Total cost: ${cost:.4f}"
)
9. 2025-2026 하네스 트렌드
Model-Native 도구 호출
초기 LLM은 도구 사용법을 프롬프트로 가르쳐야 했습니다. 2025년의 최신 모델들은 학습 과정에서 도구 사용법을 내재화했습니다. Claude Sonnet 4, GPT-4o 등은 Function Calling을 네이티브로 지원합니다.
이것이 하네스에 미치는 영향:
- 도구 설명이 간결해도 정확하게 사용
- 복잡한 도구 조합을 자율적으로 계획
- 에러 복구 능력 향상
자율 에이전트의 부상
2025년은 자율 에이전트의 원년입니다:
- Devin: Cognition이 만든 AI 소프트웨어 엔지니어
- Claude Code: Anthropic의 CLI 기반 코딩 에이전트
- OpenAI Codex (CLI): OpenAI의 코딩 에이전트
- GitHub Copilot Agent Mode: GitHub의 에이전트 모드
이들은 모두 정교한 하네스를 사용합니다. 차이를 만드는 것은 모델의 능력이 아니라 하네스의 설계입니다.
멀티모달 하네스
텍스트만 처리하던 하네스가 이미지, 오디오, 비디오로 확장됩니다:
- 스크린샷 분석: UI 버그 탐지, 디자인 리뷰
- 다이어그램 이해: 아키텍처 다이어그램을 코드로 변환
- 음성 인터페이스: 음성으로 코딩 지시
- 비디오 분석: 사용자 세션 녹화 분석
Agent-to-Agent 프로토콜
MCP(Model Context Protocol)가 AI 에이전트 간의 표준 통신 프로토콜로 진화하고 있습니다:
- 에이전트 A가 에이전트 B의 도구를 사용
- 에이전트 간 작업 위임과 결과 공유
- 이기종 에이전트(Claude + GPT + Gemini) 간 협업
하네스의 표준화
현재 각 프레임워크마다 하네스 구현 방식이 다르지만, 표준화 움직임이 시작되고 있습니다:
- MCP: 도구 연결 표준
- Agent Protocol: 에이전트 인터페이스 표준
- OpenAPI for Agents: API 기반 에이전트 정의
2026년에는 "하네스 표준"이 등장하여, 어떤 프레임워크에서든 동일한 구성 요소를 사용할 수 있게 될 것으로 전망됩니다.
10. 퀴즈
Q1: AI 하네스의 비유에서 "야생마"에 해당하는 것은 무엇인가요?
정답: Raw LLM (GPT-4, Claude, Gemini 등의 기반 모델)
야생마는 엄청난 힘(지능)을 가지고 있지만, 마구(하네스) 없이는 그 힘을 원하는 방향으로 쓸 수 없습니다. Raw LLM도 마찬가지로, 도구, 컨텍스트, 권한, 스킬 등의 하네스 없이는 실용적인 작업을 수행하기 어렵습니다.
Q2: 하네스의 7가지 구성 요소를 모두 나열하세요.
정답:
- System Prompt (시스템 프롬프트)
- Tools (도구)
- Context (컨텍스트)
- Skills (스킬)
- Hooks (훅)
- Permissions (권한)
- Memory (기억)
이 7가지가 결합하여 Raw LLM을 실용적인 AI 에이전트로 변환합니다.
Q3: PreToolUse 훅과 PostToolUse 훅의 차이점은 무엇인가요?
정답:
- PreToolUse: 도구 사용 전에 실행됩니다. 입력 검증, 권한 확인, 위험한 명령어 차단 등의 용도로 사용됩니다. 검증 실패 시 도구 실행을 중단할 수 있습니다.
- PostToolUse: 도구 사용 후에 실행됩니다. 결과 검증, 자동 포맷팅(prettier, eslint), 자동 테스트 등의 용도로 사용됩니다.
Git 훅의 pre-commit(커밋 전 검증)과 post-commit(커밋 후 알림)과 유사한 개념입니다.
Q4: Orchestrator-Worker 패턴과 Pipeline 패턴의 차이점은 무엇인가요?
정답:
- Orchestrator-Worker 패턴: 중앙 오케스트레이터가 작업을 분할하고 여러 워커에게 병렬로 배분합니다. 각 워커는 독립적으로 작업하고, 오케스트레이터가 결과를 통합합니다. 예: 여러 파일을 동시에 리뷰하기.
- Pipeline 패턴: 작업이 순차적으로 처리됩니다. 각 단계의 출력이 다음 단계의 입력이 됩니다. 예: 분석 후 계획 후 실행 후 검증.
핵심 차이는 병렬 실행(Orchestrator-Worker) vs 순차 실행(Pipeline)입니다.
Q5: 2025년 AI 엔지니어링의 무게중심이 "모델 훈련"에서 무엇으로 이동했나요? 그 이유는?
정답: 모델 오케스트레이션 (Model Orchestration)
이유:
- 기반 모델이 충분히 강력해져서 대부분의 작업에 별도 훈련이 불필요해졌습니다
- 같은 모델을 사용해도 하네스 설계에 따라 결과가 크게 달라집니다
- 엔터프라이즈에서 보안, 감사, 권한 관리, 비용 추적이 필수가 되었습니다
- Devin, Claude Code 같은 자율 에이전트들이 정교한 하네스를 사용하여 차별화를 만들고 있습니다
따라서 "어떤 모델을 쓸까?"보다 "모델을 어떻게 감싸고 제어할까?"가 핵심 질문이 되었습니다.
11. 참고 자료
- Anthropic, "Claude Agent SDK Documentation," 2025
- Anthropic, "Model Context Protocol (MCP) Specification," 2025
- Anthropic, "Claude Code: An Agentic Coding Tool," 2025
- Harrison Chase, "LangGraph: Building Stateful Agent Workflows," LangChain Blog, 2025
- CrewAI, "Multi-Agent Orchestration Framework Documentation," 2025
- Microsoft, "AutoGen: Enabling Next-Gen LLM Applications," 2025
- Microsoft, "Semantic Kernel Documentation," 2025
- OpenAI, "Function Calling Guide," 2025
- Anthropic, "Building Effective Agents," Research Blog, 2025
- Lilian Weng, "LLM Powered Autonomous Agents," OpenAI Blog, 2024
- Shunyu Yao et al., "ReAct: Synergizing Reasoning and Acting in Language Models," ICLR, 2023
- Andrew Ng, "Agentic Design Patterns," DeepLearning.AI, 2025
- Simon Willison, "Building AI-Powered Tools with LLMs," Blog, 2025
- Chip Huyen, "Building LLM Applications for Production," 2025
- Devin AI, "How Devin Works: Architecture and Design," Cognition Blog, 2025
- GitHub, "Copilot Agent Mode: Architecture Deep Dive," GitHub Blog, 2025