본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 05. 22. 16:15

하루에 하나의 오픈 소스 프로젝트 (No. 72): Andrej Karpathy Skills — 단 하나의 CLAUDE.md로 만성적인 LLM

요약

Andrej Karpathy의 관찰을 바탕으로 LLM 코딩의 실패 패턴을 방지하기 위한 CLAUDE.md 설정 프로젝트를 소개합니다. 명령형 지침 대신 성공 기준을 제공하여 Claude Code와 Cursor의 동작 방식을 최적화하는 방법을 다룹니다.

핵심 포인트

  • LLM 코딩 실패를 방지하는 4가지 행동 원칙 제공
  • 명령형 지침보다 성공 기준(Success Criteria) 제공이 효과적
  • CLAUDE.md, Claude Code 플러그인, Cursor rules 형식 지원
  • LLM의 제약되지 않은 행동을 제어하는 행동 설정 파일 활용

서론

"LLM은 특정 목표를 달성할 때까지 루프를 도는 데 탁월합니다. 따라서 명령형 지침(imperative instructions)보다는 성공 기준(success criteria)을 제공하십시오." 이것은 "One Open Source Project a Day" 시리즈의 72번째 기사입니다. 오늘은 andrej-karpathy-skills를 살펴봅니다. 이 프로젝트는 독특합니다. 핵심이 도구, 프레임워크, 또는 라이브러리가 아니라 단 하나의 CLAUDE.md 파일이기 때문입니다.

이 이야기는 Andrej Karpathy가 Claude Code를 집중적으로 사용한 후 X(구 트위터)에 게시한 글에서 시작됩니다. 그는 LLM 코딩에서 관찰된 실패 패턴을 기록했습니다: 명확한 확인 없이 구현에 뛰어들기, 단순한 문제를 복잡한 솔루션으로 설계하기, 요청하지 않은 인접 코드를 변경하기 등입니다. multica-ai 팀은 이러한 관찰 내용을 네 가지 실행 가능한 행동 원칙으로 추출하여 CLAUDE.md 파일로 패키징했습니다. 프로젝트에 이 파일을 넣기만 하면 Claude Code의 동작 방식이 바뀝니다. 또한 두 가지 주요 AI 코딩 도구를 아우르는 Claude Code 플러그인 및 Cursor rules 형식으로도 제공됩니다. 이 프로젝트는 자주 간과되는 질문에 답을 제시합니다: LLM에게 정확히 무엇을 할지 가르치는 대신, 어떻게 생각할지를 가르치십시오.

학습 내용

  • Karpathy가 식별한 네 가지 LLM 코딩 실패 모드
  • 네 가지 원칙 뒤에 숨겨진 내용과 실제 사례
  • 세 가지 설치 방법: 독립형 CLAUDE.md / Claude Code 플러그인 / Cursor rules
  • 왜 "단계별 지침을 주는 것"보다 "성공 기준을 주는 것"이 더 효과적인가
  • 가이드라인이 실제로 작동하는지 확인하는 방법

사전 요구 사항

  • Claude Code, Cursor 또는 유사한 AI 코딩 도구에 익숙할 것
  • LLM 코딩의 고충(pain points)을 인식할 수 있을 정도의 충분한 실무 코딩 경험

프로젝트 배경

프로젝트 소개
andrej-karpathy-skills는 근본적으로 행동 설정 파일(behavioral configuration file)입니다. 이 프로젝트의 설계 철학은 한 가지 핵심 통찰에서 비롯되었습니다: LLM 코딩 문제는 종종 능력의 문제가 아니라, 제약되지 않은 행동(unconstrained behavior)의 문제입니다.

모델은 간단한 코드를 작성할 능력은 있지만, "복잡한 코드를 작성하지 마세요"라고 말해주는 것은 아무것도 없습니다. 모델은 먼저 명확한 설명을 요청할 능력도 있지만, 그렇게 하도록 만드는 압박(pressure)이 없습니다. 관련 없는 코드를 건드리면 안 된다는 것을 알고 있지만, "하는 김에 이것도"라는 습관을 억제하기는 어렵습니다. 이 CLAUDE.md 파일은 이러한 제약 사항을 명시적으로 만들어, 모든 대화에 컨텍스트 (context)로서 주입합니다. 이 프로젝트는 다양한 워크플로 (workflow)와 도구를 지원하기 위해 세 가지 형식으로 제공됩니다.

작성자/팀 유지관리자: multica-ai (Multica AI 팀)
영감: X(구 트위터)에서 공유된 LLM 코딩 사용에 관한 Andrej Karpathy의 관찰
원작자: CLAUDE.md의 내용은 원래 forrestchang에 의해 컴파일되었으며, multica-ai가 이를 완전한 플러그인 생태계로 확장했습니다.

Andrej Karpathy 소개: OpenAI의 공동 창립자이자 전 Tesla AI 디렉터이며, 현재는 독립 연구가로 활동하고 있습니다. nanoGPT, Neural Networks: Zero to Hero 및 AI 커뮤니티에서 널리 추종되는 기타 교육 프로젝트들로 잘 알려져 있습니다. AI 도구에 대한 그의 실질적인 피드백은 매우 큰 영향력을 가집니다.

프로젝트 통계 📄 핵심 파일: CLAUDE.md (행동 지침) 🔌 Claude Code 플러그인 + Cursor 규칙 📖 포함 내용: EXAMPLES.md (각 원칙에 대한 대조 사례) 📄 라이선스: MIT 🌐 저장소: multica-ai/andrej-karpathy-skills

주요 기능
핵심 유틸리티
이 CLAUDE.md는 가장 흔한 네 가지 LLM 코딩 실패 모드(failure modes)를 직접적으로 겨냥합니다:

흔한 LLM 코딩 실패 사례
├── 암묵적 가정 (Silent assumptions) (확인 없이 코드로 바로 뛰어듦)
├── 과잉 엔지니어링 (Over-engineering) (단순한 문제를 복잡하게 만듦)
├── 범위 확장 (Scope creep) (

잘못된 행동 예시:
사용자: 사용자 데이터를 내보내는 기능을 추가해줘
LLM: [즉시 코드 작성을 시작함] → CSV 형식을 가정함, 모든 필드를 포함한다고 가정함, 동기식 다운로드를 가정함 → 하지만 사용자가 실제로 필요했던 것은 백그라운드 작업(background job) + 특정 필드 + JSON 형식이었음

올바른 행동 (이 원칙은 불확실성을 먼저 드러낼 것을 요구함):
사용자: 사용자 데이터를 내보내는 기능을 추가해줘
LLM: 시작하기 전에, 몇 가지 명확히 할 사항이 있습니다:

  1. 범위(Scope): 모든 사용자를 내보낼까요, 아니면 필터링된 일부 집합을 내보낼까요?
  2. 형식(Format): CSV / JSON / Excel 중 무엇인가요?
  3. 전달 방식(Delivery): 브라우저 다운로드, 이메일을 통한 백그라운드 작업, 또는 API 엔드포인트 중 어떤 방식인가요?
  4. 필드(Fields): 어떤 필드를 포함할까요? 민감한 데이터에 대한 제한 사항이 있나요?

또 다른 전형적인 예시 — "검색을 더 빠르게 만들어줘"라는 요청은 완전히 다른 세 가지의 유효한 의미를 가집니다:

해석실제 요구사항해결책
응답 시간 (Response time)API 반환이 느림인덱스 추가, 캐싱, 쿼리 최적화
처리량 (Throughput)높은 동시성 (High concurrency)수평적 확장 (Horizontal scaling), 큐잉 (Queuing)
체감 UX 속도 (Perceived UX speed)사용자가 느리다고 느낌프리로딩 (Preloading), 스켈레톤 스크린 (Skeleton screens), 즉각적인 피드백

이 세 가지는 모두 근본적으로 다른 접근 방식을 요구합니다. 그 어떤 것도 "기본값"으로 설정될 수 없습니다. 이 원칙이 요구하는 것: 여러 가지 합리적인 해석이 존재할 때는, 그 모든 것을 제시하고 사용자가 선택하게 하세요. 진정으로 혼란스러울 때는 무리하게 진행하기보다 멈추고 "이것을 어떻게 처리해야 할지 잘 모르겠습니다"라고 말하세요.

원칙 2: 단순성 우선 (Simplicity First)
해결하고자 하는 문제: LLM은 과잉 엔지니어링 (Over-engineering) 경향이 강합니다. 즉, 복잡성이 실제로 필요하기 전에 추상화 (Abstractions), 프레임워크 (Frameworks), 그리고 "유연성 (Flexibility)"을 도입하려 합니다.

잘못된 행동 예시 — 할인 계산:

사용자 요청: 간단한 할인 계산 기능을 구현해줘

❌ LLM의 "해결책" (필요한 코드의 10배):

class DiscountStrategy ( ABC ):
@abstractmethod
def calculate ( self , price : float ) -> float : ...

class PercentageDiscount ( DiscountStrategy ):
def init ( self , config : DiscountConfig ): ...
def calculate ( self , price : float ) -> float : ...

class DiscountCalculator :
def init ( self , strategy : DiscountStrategy ): ...

def apply ( self , cart : Cart ) -> float : ... # ...plus factory class, config class, registry... # ✅ 실제로 필요했던 것 (함수 하나): def apply_discount ( price : float , discount_pct : float ) -> float : return price * ( 1 - discount_pct / 100 )

또 다른 예시 — "사용자 설정 저장(Save user preferences)":
❌ LLM이 구현한 방식:

  • 만료 기능이 포함된 캐싱 레이어 (아무도 요청하지 않음)
  • 입력 유효성 검사 (아직 잘못된 데이터가 나타나지 않음)
  • 충돌 병합 로직 (아무도 이 문제를 겪지 않음)
  • 변경 알림 시스템 (아무도 언급하지 않음)
    ✅ 실제로 필요했던 것:
  • 설정을 데이터베이스에 쓰는 함수 하나

이 원칙이 제공하는 벤치마크: "시니어 엔지니어가 이것을 보고 너무 복잡하다고 말할 것인가?"
만약 200줄로 작성된 코드를 50줄로 줄일 수 있다면, 50줄로 다시 작성하세요.
핵심 격언: "좋은 코드란 내일의 문제를 성급하게 해결하는 코드가 아니라, 오늘의 문제를 단순하게 해결하는 코드이다."
성급한 복잡성 (Premature complexity)은 단순히 낭비일 뿐만 아니라, 인지된 디자인 패턴 (design patterns)을 따르더라도 코드를 이해하기 어렵게 만들고, 더 많은 버그를 유발하며, 개발 속도를 늦춥니다.

원칙 3: 외과적 변경 (Surgical Changes)
타겟팅하는 문제: LLM은 "지나가는 길의 리팩터링 (drive-by refactoring)"을 수행합니다. 즉, 버그를 수정하는 동안 인용구 스타일을 업데이트하고, 타입 어노테이션 (type annotations)을 추가하며, 변수 이름을 바꾸고, 임포트 (imports)를 재구성합니다. 이러한 동작은 도움이 되는 것처럼 느껴지지만 두 가지 심각한 문제를 일으킵니다:

  1. diff 리뷰를 어렵게 만듦: 리뷰어가 어떤 변경 사항이 버그 수정이고, 어떤 것이 "하는 김에" 수행한 개선 사항인지 구분할 수 없습니다.
  2. 예상치 못한 회귀 (regressions) 유발: 요청되지 않은 모든 변경 사항은 잠재적인 리스크 포인트가 됩니다.

올바른 접근 방식:

원본 코드 (버그가 있고, 약간의 "불완전함"이 있음)

def calculate_total ( items ):
total = 0
for item in items:
total += item [ ' price ' ] # 작은따옴표 사용
return total # 타입 어노테이션 없음

❌ LLM의 "포괄적인 개선":

def calculate_total ( items : list [ dict ]) -> float:
# 타입 어노테이션 추가
"""
Calculate total price of items.

""" # docstring 추가
total : float = 0.0 # 변수 타입 변경
for item in items :
total += item [ " price " ] # 큰따옴표로 변경 ("style consistency")
return total

✅ 버그만 수정 (items가 비어있는 경우를 버그라고 가정):

def calculate_total ( items ):
if not items :
# 이 한 줄만 추가됨
return 0
total = 0
for item in items :
total += item [ ' price ' ] # 기존 스타일 유지
return total

원칙의 구체적 요구사항:

  • 변경된 모든 라인은 사용자의 요청과 직접적으로 연결되어야 함
  • 본인이 선호하는 스타일이 있더라도 기존 코드 스타일을 따를 것
  • 명시적으로 요청받지 않는 한, 지나가는 길에 발견한 코드를 개선하지 말 것
  • 본인의 변경 사항으로 인해 생성된 사용하지 않는 import/변수만 정리할 것 — 기존에 존재하던 데드 코드(dead code)는 그대로 둘 것

원칙 4: 목표 중심 실행 (Goal-Driven Execution)
대상 문제:
모호한 작업이 주어지면, LLM은 포괄적으로 보이지만 검증 가능한 결과가 결여된 계획을 생성합니다.
모호한 계획의 예:
작업: "인증(auth) 모듈 리팩토링"
❌ 모호한 계획:

  1. 기존 코드 검토
  2. 문제 식별
  3. 구조 개선
  4. 테스트 실행
    → 단 하나의 단계도 "완료(done)\

명령형 지침("A를 하고, 그다음에 B를 하고, 그다음에 C를 하세요")은 무언가 잘못되었을 때 LLM에게 가이드라인을 제공하지 못합니다. 반면 선언적 목표("이 테스트는 반드시 통과해야 합니다", "이 인터페이스는 호출 가능해야 합니다")는 LLM에게 명확한 완료 기준을 제공하면서도 스스로 경로를 선택할 수 있게 합니다.

왜 도구(Tool)가 아닌 파일인가? 이 프로젝트의 설계 선택은 성찰해 볼 가치가 있습니다. LLM 코딩 동작 문제에 직면했을 때, 가능한 해결책은 많습니다: 동작을 제한하기 위한 에이전트 프레임워크(Agent framework) 구축, 문제를 탐지하고 수정하기 위한 후처리 도구(Post-processing tools) 개발, 더 나은 모델을 미세 조정(Fine-tune)하기 등. andrej-karpathy-skills는 가장 단순한 방법을 선택했습니다: 프로젝트 내에 배치되어 LLM이 스스로 읽고 따르는 텍스트 파일입니다. 이 선택 자체가 "단순성 우선(Simplicity First)"을 가장 잘 보여주는 사례입니다. 최소한의 메커니즘으로 오늘의 문제를 해결한 것입니다. 또한 텍스트 파일은 어떤 도구도 따라올 수 없는 하나의 장점을 가집니다: 블랙박스 없이 누구나 언제든 읽고, 이해하고, 수정할 수 있다는 점입니다.

프로젝트 링크 및 리소스
공식 리소스 🌟
GitHub : https://github.com/multica-ai/andrej-karpathy-skills
📄 CLAUDE.md 직접 다운로드 : curl을 통해 가능 (위의 Quick Start 참조)
📖 예시 : 리포지토리 내의 EXAMPLES.md (각 원칙에 대한 대조적인 예시 포함 — 권장 읽기 자료)

대상 독자
매일 Claude Code / Cursor를 사용하는 사용자 : LLM의 과잉 엔지니어링(Over-engineering)과 불필요한 코드 변경을 줄이고 싶은 분들
팀 엔지니어링 생산성 리드 : 행동 표준을 공유된 CLAUDE.md에 통합하고 팀 전체의 AI 보조 코딩을 표준화하려는 분들
검토 가능한 PR을 중시하는 개발자 : LLM이 생성한 "거대한 diff(super diffs)"에 지쳤으며, 요청된 변경 사항만 포함된 깔끔하고 집중된 풀 리퀘스트(Pull requests)를 원하는 분들

요약
핵심 요점
기원 : Karpathy가 직접 관찰한 LLM 코딩 실패 모드에서 직접 추출 — 실제 사용에 기반함
네 가지 원칙 : 코딩 전 생각하기(Think Before Coding) : 암시적인 가정을 명시적인 질문으로 바꾸기...

AI 자동 생성 콘텐츠

본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
1

댓글

0