콘텐츠로 이동

Karpathy Guidelines

Andrej Karpathy의 LLM 코딩 실수 관찰에서 도출된 행동 가이드라인. LLM 코딩 에이전트가 반복적으로 범하는 실수 패턴을 4가지 원칙으로 분류하고, 각각에 대한 교정 방법을 코드 예제와 함께 제시한다.

1. 가정을 먼저 밝혀라

가정하지 말고, 혼란을 숨기지 말고, 트레이드오프를 제시하라.

2. 단순함 우선

문제를 해결하는 최소한의 코드. 투기적 설계 금지.

3. 외과적 변경

요청된 것만 수정. 인접 코드 “개선” 금지.

4. 목표 중심 실행

성공 기준 정의 → 검증될 때까지 반복.


원칙 1: 가정을 먼저 밝혀라 (Think Before Coding)

섹션 제목: “원칙 1: 가정을 먼저 밝혀라 (Think Before Coding)”

구현 전에 가정을 명시한다. 불확실하면 질문한다. 여러 해석이 가능하면 선택지를 제시하고 조용히 하나를 고르지 않는다. 더 단순한 방법이 존재하면 제안한다.

요청: “사용자 데이터를 내보내는 기능 추가”

def export_users(format='json'):
"""Export all users to a file."""
users = User.query.all()
if format == 'json':
with open('users.json', 'w') as f:
json.dump([u.to_dict() for u in users], f)
elif format == 'csv':
with open('users.csv', 'w') as f:
writer = csv.DictWriter(f, fieldnames=['id', 'email', 'name'])
writer.writeheader()
writer.writerows([u.to_dict() for u in users])
return f"Exported {len(users)} users"

문제점:

  • 전체 사용자를 내보낸다고 가정 (페이지네이션? 개인정보?)
  • 파일 저장 위치를 임의로 결정
  • 포함할 필드를 확인 없이 결정
  • CSV 필드명을 실제 데이터 구조 확인 없이 하드코딩

요청: “검색을 더 빠르게 만들어줘”

# 어떤 "빠르게"인지 확인 없이
# 캐싱, DB 인덱스, 비동기 처리를 모두 추가
@lru_cache(maxsize=1000)
async def search(query: str) -> List[Result]:
# ... 200줄의 최적화 코드

원칙 2: 단순함 우선 (Simplicity First)

섹션 제목: “원칙 2: 단순함 우선 (Simplicity First)”

문제를 해결하는 최소한의 코드만 작성한다. 요청되지 않은 기능, 단일 사용 코드의 추상화, 불가능한 시나리오에 대한 에러 핸들링을 추가하지 않는다. 200줄로 작성했는데 50줄로 가능하면 다시 작성한다.

요청: “할인 계산 함수 추가”

from abc import ABC, abstractmethod
from dataclasses import dataclass
class DiscountStrategy(ABC):
@abstractmethod
def calculate(self, amount: float) -> float:
pass
class PercentageDiscount(DiscountStrategy):
def __init__(self, percentage: float):
self.percentage = percentage
def calculate(self, amount: float) -> float:
return amount * (self.percentage / 100)
class FixedDiscount(DiscountStrategy):
def __init__(self, fixed_amount: float):
self.fixed_amount = fixed_amount
def calculate(self, amount: float) -> float:
return min(self.fixed_amount, amount)
@dataclass
class DiscountConfig:
strategy: DiscountStrategy
min_purchase: float = 0.0
max_discount: float = float('inf')
class DiscountCalculator:
def __init__(self, config: DiscountConfig):
self.config = config
def apply_discount(self, amount: float) -> float:
if amount < self.config.min_purchase:
return 0
discount = self.config.strategy.calculate(amount)
return min(discount, self.config.max_discount)
# 사용하려면 30줄 이상의 설정 코드 필요

문제점: Strategy 패턴, Config 데이터클래스, ABC — 할인 계산 하나에 과잉 설계.

요청: “사용자 설정을 DB에 저장”

class PreferenceManager:
def __init__(self, db, cache=None, validator=None):
self.db = db
self.cache = cache or InMemoryCache()
self.validator = validator or DefaultValidator()
def save(self, user_id: int, prefs: dict,
merge: bool = True,
validate: bool = True,
notify: bool = False) -> bool:
if validate:
errors = self.validator.validate(prefs)
if errors:
raise ValidationError(errors)
existing = self.get(user_id) if merge else {}
if merge:
existing.update(prefs)
prefs = existing
self.db.execute(
"UPDATE users SET preferences = ? WHERE id = ?",
(json.dumps(prefs), user_id)
)
if self.cache:
self.cache.set(f"prefs:{user_id}", prefs)
if notify:
self.notify_preference_change(user_id, prefs)
return True

문제점: 캐싱, 유효성 검사, 병합, 알림 — 모두 요청되지 않은 기능.


원칙 3: 외과적 변경 (Surgical Changes)

섹션 제목: “원칙 3: 외과적 변경 (Surgical Changes)”

요청된 것만 수정한다. 인접 코드의 주석, 포맷팅, 스타일을 “개선”하지 않는다. 기존 스타일을 따른다. 자신의 변경이 만든 고아(orphan)는 정리하되, 기존 dead code는 언급만 한다.

테스트: 모든 변경 줄이 사용자 요청에 직접 연결되어야 한다.

요청: “빈 이메일이 validator를 크래시시키는 버그 수정”

def validate_user(user_data):
# Check email format
if not user_data.get('email'):
"""Validate user data."""
email = user_data.get('email', '').strip()
# Validate email
if not email:
raise ValueError("Email required")
# Basic email validation
if '@' not in user_data['email']:
if '@' not in email or '.' not in email.split('@')[1]:
raise ValueError("Invalid email")
# Check username
if not user_data.get('username'):
# Validate username
username = user_data.get('username', '').strip()
if not username:
raise ValueError("Username required")
if len(username) < 3:
raise ValueError("Username too short")
if not username.isalnum():
raise ValueError("Username must be alphanumeric")
return True

문제점: 이메일 유효성 검사 강화, username 유효성 추가, 주석 변경, docstring 추가 — 모두 요청 범위 밖.

요청: “업로드 함수에 로깅 추가”

def upload_file(file_path, destination):
def upload_file(file_path: str, destination: str) -> bool:
"""Upload file to destination with logging."""
logger.info(f"Uploading {file_path} to {destination}")
try:
with open(file_path, 'rb') as f:
with open(file_path, "rb") as f:
data = f.read()
response = requests.post(destination, files={'file': data})
response = requests.post(destination, files={"file": data})
success = response.status_code == 200
if success:
logger.info(f"Upload successful: {file_path}")
else:
logger.error(f"Upload failed: status={response.status_code}")
if response.status_code == 200:
return True
else:
return False
return success
except Exception as e:
print(f"Error: {e}")
logger.exception(f"Upload error for {file_path}: {e}")
return False

문제점: 따옴표 스타일 변경(''""), 타입 힌트 추가, docstring 추가, 불리언 반환 로직 변경.


원칙 4: 목표 중심 실행 (Goal-Driven Execution)

섹션 제목: “원칙 4: 목표 중심 실행 (Goal-Driven Execution)”

작업을 검증 가능한 목표로 변환한다. 다단계 작업에서는 각 단계의 검증 방법을 먼저 정의한다.

  • “유효성 검사 추가” → “잘못된 입력에 대한 테스트 작성 → 통과시키기”
  • “버그 수정” → “재현 테스트 작성 → 통과시키기”
  • “리팩터링” → “테스트가 전후로 통과하는지 확인”

예제 1: 모호한 vs 검증 가능한 목표

섹션 제목: “예제 1: 모호한 vs 검증 가능한 목표”

요청: “인증 시스템 수정”

인증 시스템을 수정하겠습니다:
1. 코드 리뷰
2. 문제 식별
3. 개선 사항 적용
4. 변경 사항 테스트
[명확한 성공 기준 없이 변경을 시작]

요청: “API에 rate limiting 추가”

# Redis, 다중 전략, 설정 시스템, 모니터링을
# 300줄 단일 커밋으로 한번에 구현
# 명확한 검증 단계 없음

요청: “중복 점수가 있을 때 정렬이 깨진다”

# 버그 재현 없이 바로 정렬 로직 수정
def sort_scores(scores):
return sorted(scores, key=lambda x: (-x['score'], x['name']))

원칙안티패턴교정 방법
가정을 먼저 밝혀라파일 형식, 필드, 범위를 조용히 가정가정을 명시적으로 나열하고 확인 요청
단순함 우선할인 계산 하나에 Strategy 패턴복잡도가 실제로 필요해질 때까지 단일 함수
외과적 변경버그 수정 중 따옴표 변경, 타입 힌트 추가보고된 문제를 수정하는 줄만 변경
목표 중심 실행”코드를 리뷰하고 개선하겠습니다""버그 X의 테스트 작성 → 통과 → 회귀 확인”

이 가이드라인을 6주차 인스트럭션 튜닝의 3-tier Boundary 시스템으로 변환할 수 있다:

Tier가이드라인 적용 예
Always Do구현 전 가정 명시, 다단계 작업 시 검증 계획 수립
Ask First여러 해석이 가능한 경우, 인접 코드 변경이 필요한 경우
Never Do요청 범위 밖의 리팩터링, 투기적 기능 추가, 기존 스타일 변경