코드베이스가 곧 프롬프트다
요약
LLM은 데이터베이스가 아닌 패턴 재구성 엔진이며, 코드베이스 자체가 프롬프트의 일부로 작용한다는 점을 강조합니다. 코드의 명명 규칙, 아키텍처, 주석 등이 모델의 출력에 결정적인 영향을 미침을 설명합니다.
핵심 포인트
- 프롬프트는 데이터 검색 키가 아닌 패턴 재구성을 위한 퍼지 쿼리임
- 코드베이스의 구조와 스타일이 모델의 출력 품질을 결정하는 프롬프트 역할을 함
- Claude Code(Fable)와 같은 도구는 복잡한 기존 프로젝트를 재활성화하는 데 강력함
- 코드의 일관성과 추상화 수준이 AI 에이전트의 성능에 직결됨
사람들이 AI를 설명할 때 사용하는 데이터베이스 비유는 대개 틀렸습니다.
언어 모델 (Language Model)은 사실, 문서, 또는 답변으로 가득 찬 데이터베이스가 아닙니다. 질문을 던졌을 때, 모델은 기록을 찾아보고 일치하는 행을 반환하는 것이 아닙니다. 모델 내부에는 "JavaScript 버그"나 "API 설계 방법"과 같은 이름의 테이블이 숨겨져 있지 않습니다.
하지만 이 비유가 완전히 쓸모없는 것은 아닙니다. 단지 대개 잘못된 수준에서 적용될 뿐입니다.
프롬프트 (Prompt)는 저장된 답변을 검색하는 키 (Key)가 아닙니다. 그것은 학습된 패턴의 압축된 공간에 대한 퍼지 쿼리 (Fuzzy Query)에 더 가깝습니다. 모델은 답변을 가져오는 것이 아닙니다. 프롬프트가 관련성을 부여하는 패턴으로부터 그럴듯한 연속성을 재구성 (Reconstruct)합니다.
이것이 중요한 이유는 사람들이 종종 프롬프트와 데이터를 정신적으로 분리하기 때문입니다.
"내 지시사항이 프롬프트다. 코드베이스는 모델이 작업하는 재료다."
하지만 모델에는 그러한 분리가 없습니다.
코드베이스 작업에서, 코드베이스가 곧 프롬프트입니다.
주변 코드는 직접 입력한 요청만큼이나 출력에 영향을 미칩니다. 명명 규칙 (Naming), 아키텍처 (Architecture), 숨겨진 가정 (Hidden Assumptions), 테스트 (Tests), 누락된 테스트, 파일 레이아웃 (File Layout), 주석 (Comments), 추상화 (Abstractions), 그리고 불일치 (Inconsistencies)가 모두 쿼리의 일부가 됩니다.
이 사실은 Fable 5를 사용한 후 저에게 명확해졌습니다.
저는 완전히 압도되었습니다. 저는 개인용과 업무용으로 두 개의 Claude Code 구독을 빠르게 소진했고, 거의 전적으로 Fable 덕분에 Max 플랜으로 업그레이드했습니다. 저는 수년 동안 개인 프로젝트들을 방치해 왔는데, 이는 관심이 없어서가 아니라 그 프로젝트들이 요구하는 복잡함에 다시 뛰어들 시간과 에너지를 찾을 수 없었기 때문입니다. 이전에도 가끔씩 초기 모델들을 사용하여 기능을 추가하거나 프로젝트를 진행시키려 시도해 보았지만, 매번 처참하게 실패했습니다.
Fable 5와 함께, 그 모든 것이 바뀌었습니다.
그것은 제가 개인적으로 몇 시간 동안 해결하지 못해 골머리를 앓았던 여러 문제들을 해결해 주었습니다. 더 중요한 것은, 그것이 제가 이해할 수 있는 방식으로 문제를 해결했다는 점입니다. 단순히 저에게 코드를 쏟아붓는 것이 아니라, 솔루션의 형태를 볼 수 있도록 도와주었습니다. 한동안은 거의 신과 같은 느낌마저 들었습니다. 천국에 있는 기분이었습니다. 수면 부족으로 완전히 미쳐버리지 않게 붙잡아준 유일한 것은 토큰 제한(token limits)뿐이었습니다.
그래서 저는 실험을 확장했습니다. 시간 제약, 삶의 변화, 그리고 어린 아이들 때문에 손대지 못했던 수년 전의 개인 프로젝트들을 포함하여 더 많은 프로젝트에 사용해 보았습니다. 다시 한번, 똑같은 일이 일어났습니다. 오래된 프로젝트들이 움직이기 시작했습니다. 다시 시작하기에는 비용이 너무 많이 든다고 느껴졌던 문제들이 갑자기 해결 가능한 것들이 되었습니다.
하지만 직장에서는 Fable이 주는 것과 같은 추진력을 얻을 수 없었습니다.
처음에는 프로세스(process)가 명백한 이유라고 생각했습니다. 어쩌면 제가 도구를 사용하는 방식이 이전과 달랐을지도 모릅니다. 어쩌면 엄격한 수락 기준(acceptance criteria), 가드레일(guardrails), 리뷰 요구 사항, 그리고 회사의 제약 사항들이 동일한 흐름(flow)을 방해했을지도 모릅니다.
그러다 금지 조치가 내려졌습니다.
그 중단 기간 덕분에 실제로 어떤 일이 일어났는지 검토할 시간을 가질 수 있었습니다. Fable이 저를 위해 작성했던 코드들을 다시 살펴보았습니다. 또한 Fable로 생성된 다른 개발자들의 코드도 검토했습니다. 상황은 더 복잡해졌습니다.
때때로 Fable은 훌륭한 코드를 만들어냈습니다. 때로는 진정으로 어려운 문제들을 해결하기도 했습니다. 하지만 때로는 명백한 문제가 있는 나쁜 코드를 만들어내기도 했습니다.
결국, 무언가 깨달음이 왔습니다.
출력물의 품질은 그것이 작업하고 있는 코드베이스(codebase)의 품질과 밀접하게 연결되어 있었습니다.
당연한 소리처럼 들릴 것입니다. 하지만 그 해결책은 당연하지 않습니다.
단순한 반사 작용은 다음과 같이 말하는 것입니다. 만약 모델이 나쁜 코드베이스에서 성능이 떨어진다면, 더 좋은 코드를 주면 된다. 베스트 프랙티스(best practices)를 제공하라. 깨끗한 예시를 제공하라. 아키텍처 가이드라인(architecture guidelines)을 제공하라. 지저질한 코드베이스가 답변을 지배하지 않도록 프롬프트(prompt)에 상쇄 요소를 추가하라.
하지만 이것은 기대만큼 도움이 되지 않습니다.
그 이유는 좋은 코드는 국소적(local)이기 때문입니다.
좋은 코드베이스에서는 캡슐화 (encapsulation)와 명확한 인터페이스 (interface) 덕분에 함수의 시그니처 (signature)와 그 주변의 작은 범위만으로도 해당 함수를 이해할 수 있습니다. 한 부분을 안전하게 변경하기 위해 시스템 전체를 읽을 필요가 없습니다. 관련 정보가 근처에 있기 때문입니다. 또한 동일한 패턴이 반복되기 때문에 코드는 압축이 잘 됩니다. 모델은 국소적인 형태 (local shape)를 보고 누락된 부분을 추론할 수 있습니다.
나쁜 코드는 비국소적 (non-local)입니다.
함수가 숨겨진 전역 상태 (global state)에 의존합니다. 멀리 떨어진 파일에 있는 무언가 때문에 동작이 변합니다. 어떤 메서드는 누군가 먼저 init()을 호출하는 것을 기억했을 때만 작동합니다. 실제 의존성이 암시적 (implicit)이기 때문에, 무해해 보이는 변경이 관련 없는 기능을 망가뜨립니다. 중요한 정보가 변경 중인 코드 근처에 있지 않습니다.
이 지점이 바로 LLM이 어려움을 겪는 부분입니다.
모델이 정확해지기 위해 필요한 정보가 단순히 컨텍스트 윈도우 (context window) 안에 없을 수도 있습니다. 더 나쁜 것은, 사용자도 모델도 어떤 멀리 떨어진 코드가 제공해야 할 관련 컨텍스트인지 반드시 알고 있는 것은 아니라는 점입니다. 그래서 모델은 볼 수 있는 것만을 바탕으로 추론하고, 공백을 사전 지식 (priors)으로 채우며, 확신에 차 있지만 틀린 결과물을 만들어냅니다.
이것이 바로 “그저 베스트 프랙티스 (best practices)를 추가하라”는 조언이 자주 실패하는 이유입니다.
베스트 프랙티스는 중립적이지 않습니다. 그것들 또한 쿼리 (query)의 일부가 됩니다. 모델에게 엉망인 코드베이스를 주고 깨끗한 예시를 추가한다면, 당신은 다음과 같이 말하고 있다고 생각할지도 모릅니다: “이 좋은 원칙을 사용하여 이 나쁜 코드를 수정해줘.”
하지만 프롬프트 (prompt)는 다음과 같이 말하고 있습니다: “이 패턴을 따라서 계속해줘.”
이것들은 서로 다른 작업입니다.
모델은 실제 문제로부터 멀어질 수 있습니다. 고립된 상태에서는 더 좋아 보이지만 시스템의 숨겨진 제약 조건 (constraints)에는 맞지 않는 코드를 생성할 수 있습니다. 코드가 애초에 왜 지저분해졌는지에 대한 이유는 놓친 채 베스트 프랙티스만 따를 수도 있습니다.
따라서 나쁜 코드베이스는 단순히 좋은 프롬프트에 대한 어려운 쿼리가 아닙니다.
그것은 나쁜 프롬프트입니다.
당신은 모델에게 더 나쁜 입력을 건네면서, 그 입력이 지원할 수 있는 것보다 더 나은 출력을 요구하고 있는 것입니다.
이는 다시 압축 (compression)의 문제로 돌아갑니다. 코드를 인간에게 나쁘게 만드는 바로 그 특성 — 불규칙성 (irregularity), 불일치성 (inconsistency), 특수 사례 (special cases), 높은 엔트로피 (high entropy) — 은 예측 모델 (predictive model)이 작업하기 어렵게 만드는 특성과 동일합니다. 좋은 코드는 규칙적이기 때문에 압축이 잘 됩니다. 언어 모델 (language model)은 근본적으로 규칙성 (regularities)의 압축기입니다. 따라서 규칙적인 코드는 모델의 홈그라운드이며, 불규칙한 코드는 모델이 가장 취약한 영역입니다.
인간을 좌절시키는 요소와 모델을 패배시키는 요소는 결국 하나입니다.
이것이 바로 인컨텍스트 러닝 (in-context learning)이 자주 오해받는 이유이기도 합니다. 모델은 개발자가 하는 방식대로 당신의 코드베이스를 학습하는 것이 아닙니다. 모델은 지속 가능한 정신적 모델 (mental model)을 구축하는 것이 아닙니다. 모델은 프롬프트 (prompt)에 들어가는 무엇인가에 의해 일시적으로 조건화 (conditioned)될 뿐입니다. 만약 관련 불변량 (invariants)이 누락되었거나, 암시적이거나, 시스템 전체에 흩어져 있다면, 단순히 더 많은 텍스트를 제공한다고 해서 모델이 이를 신뢰성 있게 추론할 수는 없습니다.
그리고 이것은 컨텍스트 부패 (context rot) 현상도 설명해 줍니다.
컨텍스트 부패는 단순히 컨텍스트 윈도우 (context window)가 길어질 때 발생하는 현상만이 아닙니다. 그것은 쿼리 (query)가 쇠퇴할 때 발생하는 현상입니다. 오래된 가정, 버려진 해결책, 오래된 파일, 절반만 맞는 설명, 그리고 무관한 예시들이 대화 속에 남아 있게 됩니다. 모델은 그것들이 모델의 관점에서는 여전히 프롬프트의 일부이기 때문에, 그 모든 것을 만족시키려고 계속 시도합니다.
실질적인 결론은 LLM이 나쁜 코드베이스에서 쓸모없다는 것이 아닙니다.
그것은 해결책이 대개 더 똑똑한 프롬프트가 아니라는 점입니다.
해결책은 모델이 볼 수 없는 비국소적 컨텍스트 (non-local context)를 제공하고, 국소성 (locality)이 다시 유지될 때까지 작업을 축소하는 것입니다. 모델에게 시스템을 수정하라고 요청하는 대신, 하나의 경계 (boundary)를 검사하라고 요청하십시오. 엉킨 모듈을 리팩터링 (refactor)하라고 요청하는 대신, 먼저 숨겨진 불변량 (invariants)을 식별하라고 요청하십시오. 일반적인 모범 사례 (best practices)를 주는 대신, 이 코드베이스를 특이하게 만드는 구체적인 제약 조건 (constraints)을 제공하십시오.
나쁜 코드베이스에서 LLM으로부터 진정한 가치를 얻어내는 사람들은, 대개 모델을 위해 그 혼돈을 압축할 수 있을 만큼 이미 코드를 충분히 잘 이해하고 있는 사람들입니다.
모델은 **쿼리 (query)**를 날카롭게 만들 수 있는 사람에게 보상을 제공합니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기