코딩 프롬프트는 명세서입니다. 모델은 여러분의 프로젝트를 본 적이 없고, 어떤 버전의 언어를 쓰는지 모르고, 입력이 비어 있으면 어떻게 해야 하는지 물어볼 수도 없습니다. 프롬프트가 빠뜨린 것은 무엇이든 학습 데이터에서 가장 흔했던 선택으로 채우는데, 가장 흔한 선택이 여러분의 선택이 아닌 경우가 많습니다. 아래 프롬프트들은 모델이 추측할 것을 줄여 줍니다.
코드보다 명세를 먼저 쓰기
아래 블록은 작은 Python 함수를 요청합니다. 프롬프트의 각 부분은 그렇지 않았다면 모델이 대신 답했을 질문에 답합니다. 부분을 하나씩 끄고 그것이 없을 때의 답을 상상해 보세요. 제약 조건이 없으면 서드파티 라이브러리가 나올 수 있고, 맥락이 없으면 모델이 무엇이 올바른 입력인지 추측해야 하고, 형식이 없으면 테스트가 빠질 수 있습니다.
이 함수는 생략 가능한 세 부분을 순서대로 맞춰 보고, 세 부분이 모두 비어 있는 경우는 거부합니다.
import re
_PATTERN = re.compile(r"(?:(\d+)h)?(?:(\d+)m)?(?:(\d+)s)?")
def parse_duration(text: str) -> int:
match = _PATTERN.fullmatch(text)
if not match or not any(match.groups()):
raise ValueError(f"invalid duration: {text!r}")
hours, minutes, seconds = (int(g) if g else 0 for g in match.groups())
return hours * 3600 + minutes * 60 + seconds
import pytest
from duration import parse_duration
@pytest.mark.parametrize("text, expected", [
("1h30m", 5400), ("45m", 2700), ("2h", 7200), ("90s", 90),
])
def test_valid(text, expected):
assert parse_duration(text) == expected
@pytest.mark.parametrize("text", ["", "1m1h", "1.5h"])
def test_invalid(text):
with pytest.raises(ValueError):
parse_duration(text)
이 프롬프트에서 일의 대부분을 하는 세부 사항은 네 가지입니다.
- 답이 붙은 예시. "1h30m은 5400을 돌려줘"는 모델이 자기 코드를 확인할 수 있는 테스트이고, 단위에 대한 의심도 없애 줍니다.
- 언어 버전과 허용되는 라이브러리. 이것이 없으면 설치하지 않은 라이브러리나 인터프리터보다 새로운 문법이 나올 수 있습니다.
- 무엇이 올바르지 않은 입력이고, 그때 어떻게 해야 하는지. 아무도 요청하지 않으면 모델은 에러 처리를 빠뜨리기 쉽습니다.
- 답에 포함된 테스트. 테스트는 "맞아 보인다"를 실행해 볼 수 있는 것으로 바꿉니다. 테스트가 실패하면 그 실패를 붙여 넣으면 되는데, 이것이 "안 돼요"보다 훨씬 좋은 후속 요청입니다.
any(match.groups()) 검사도 눈여겨볼 만합니다. 모든 부분이 생략 가능하므로 패턴만으로는 빈 문자열도 일치합니다. 프롬프트의 빈 문자열에 대한 줄 덕분에 이 경우가 코드와 테스트 모두에 나타납니다.
버전, 기술 스택, 이미 있는 것을 밝히기
모델은 학습 데이터에서 가장 흔했던 스타일 쪽으로 기웁니다. JavaScript라면 ES 모듈을 쓰는 프로젝트에 CommonJS require를 쓸 수 있고, Python이라면 그 뒤로 바뀐 라이브러리 API를 쓸 수 있으며(Pydantic 1과 2가 흔한 예), 빠르게 변하는 프레임워크라면 두 메이저 버전 전의 패턴을 쓸 수 있습니다. 보통 한 줄이면 해결됩니다. "Node 22, ES 모듈, TypeScript 없음"이나 "React 19, 함수형 컴포넌트, 일반 CSS 모듈" 같은 식입니다.
기존 프로젝트에 코드를 추가할 때는 새 코드가 건드릴 부분을 모델이 봐야 합니다. 호출해야 할 함수 시그니처, 받게 될 데이터 모양, 여러분의 규칙을 보여 주는 기존 파일 하나를 붙여 넣으세요. "아래 파일의 db.query(sql, params) 헬퍼를 써"라고 하면 프로젝트에 맞는 코드가 나오고, 그렇지 않으면 데이터베이스 연결을 처음부터 새로 만드는 코드가 나올 수 있습니다. 변경과 관계없는 파일은 빼세요. 관계없는 줄 하나하나가 모델이 재사용하려 들 수 있는 것이기 때문입니다.
한 번에 작은 단계 하나씩 요청하기
AI에게 설명해서 앱을 만드는 "바이브 코딩"에서 가장 흔한 실패는 앱 전체를 한 번에 요청하는 것입니다. 모델은 답변 하나에서 프레임워크, 데이터베이스, 폴더 구조, 기능 열두 개를 모두 골라야 하고, 답변 하나에 그 전부를 위한 동작하는 코드가 담기는 경우는 드물어서 흔히 뼈대만 돌아옵니다. 두 탭을 비교해 보세요.
React, Node.js와 Express, MongoDB를 쓴 풀스택 할 일 앱입니다.
프로젝트 구조
todo-app/
client/ (React front end)
server/ (Express API, auth, reminders)
server/index.js
const express = require("express");
const mongoose = require("mongoose");
const app = express();
app.use(express.json());
// ... auth routes, todo routes and the reminder scheduler go here
인증에는 jsonwebtoken으로 JWT를 추가할 수 있고, 알림에는 node-cron 같은 스케줄러를 쓸 수 있습니다. 이 중 채워 넣고 싶은 부분이 있으면 알려 주세요.
첫 번째 답이 틀린 것은 아니지만 뼈대일 뿐입니다. 여러분 대신 기술 세 가지를 골랐고, 실제 작업은 주석으로 남겨 두었습니다. 두 번째 답은 읽을 수 있을 만큼 짧고, 파일을 열자마자 실행되며, 2단계("이제 새로고침해도 남도록 목록을 localStorage에 저장해 줘")를 위한 동작하는 기반이 됩니다. 각 단계가 충분히 작아서, 무언가 깨지면 어떤 변경 때문인지 알 수 있습니다.
이것은 손으로 하는 프롬프트 체이닝입니다. 한 요청의 출력이 다음 요청의 출발점이 됩니다. 새 단계마다 파일의 현재 버전을 붙여 넣으세요. 그래야 모델이 자기가 썼다고 기억하는 코드가 아니라 여러분이 실제로 가진 코드를 수정합니다.
큰 변경 전에는 계획부터 요청하기
함수 하나보다 큰 작업이라면 계획을 먼저, 코드를 나중에 요청하세요. "바꿀 파일과 각 변경이 하는 일을 나열해 줘. 아직 코드는 쓰지 마." 계획은 읽기도 고치기도 빠릅니다. 원하지 않는 새 의존성을 제안하거나 관련된 파일을 빠뜨렸다면, 코드 300줄에 걸쳐 발견하는 대신 한 문장으로 고칠 수 있습니다.
돌아온 코드 확인하기
생성된 코드는 몇 가지 예측 가능한 방식으로 실패하고, 각각을 잡아내는 프롬프트 습관이 있습니다.
- 지어낸 API. 모델은 이름이 그럴듯하다는 이유로 존재하지 않는 함수를 호출하거나 패키지를 import할 수 있습니다. 설치하기 전에 낯선 import를 찾아보세요. 왜 이런 일이 생기는지는 AI 할루시네이션에서 설명합니다.
- 조용히 빠진 예외 상황. 정상 경로에서는 동작하고 빈 리스트에서는 죽는 코드입니다. 프롬프트에 예외 상황을 나열하고 테스트를 요청하는 것이 가장 싼 해결책입니다.
- 몰래 바뀐 부분. 긴 파일에서 수정을 요청하면 모델이 요청하지 않은 이름을 바꾸거나 코드를 재구성할 수 있습니다. "필요한 것만 바꾸고, 바꾼 것을 모두 나열해 줘"를 더하세요.
코드가 실행되지만 이상하게 동작한다면 디버깅 프롬프트로 바꾸세요. 무엇을 붙여 넣어야 하는지는 디버깅 프롬프트에서 다룹니다. 중요한 코드를 머지하기 전에는 코드 리뷰 프롬프트로 한 번 더 확인하면, 작성 프롬프트가 미처 요청하지 못한 문제를 잡을 수 있습니다.
자주 묻는 질문
ChatGPT나 Claude로 코딩할 때 가장 좋은 프롬프트는 무엇인가요?
마법 같은 프롬프트 하나는 없습니다. 잘 통하는 프롬프트는 짧은 명세서처럼 읽힙니다. 언어와 버전, 코드가 받고 돌려주는 것, 입력과 출력 예시 두세 개, 예외 상황, 코드가 쓰면 안 되는 것을 담습니다. "이 경우들에 대한 테스트도 써 줘"로 끝내면 답을 믿는 대신 확인할 수단이 생깁니다.
바이브 코딩 프롬프트란 무엇인가요?
"바이브 코딩"은 원하는 것을 AI에게 설명하고, AI가 쓴 코드를 대개 꼼꼼히 읽지 않고 받아들이면서 소프트웨어를 만드는 방식을 말합니다. 바이브 코딩 프로젝트가 계속 돌아가게 해 주는 프롬프트는 작은 프롬프트입니다. 요청 하나에 기능 하나, 이미 있는 것에 대한 명확한 설명, 다음으로 넘어가기 전에 결과를 실행하거나 테스트하라는 요청입니다. 한 번에 모든 것을 요청하는 큰 요청에서 이런 프로젝트가 망가지기 쉽습니다.
AI에게 프로그래밍 언어 버전을 알려 줘야 하나요?
네. 언어와 라이브러리는 버전마다 달라지고, 버전을 말하지 않으면 모델은 학습 데이터에서 가장 흔했던 스타일로 쓰는데, 그것이 여러분의 환경보다 오래된 것일 수 있습니다. 버전을 밝히면("Python 3.12", "React 19, 함수형 컴포넌트", "Node 22, ES 모듈") 여러분에게 없는 API로 만든 답을 피할 수 있습니다.
AI가 쓴 코드를 믿어도 되나요?
새로 온 동료가 쓴 코드처럼 다루세요. 아마 거의 맞겠지만, 가끔 맞아 보이는 방식으로 틀립니다. 실행하고, 중요한 예외 상황으로 테스트하고, 돈, 보안, 사용자 데이터를 다루는 부분은 직접 읽으세요. 모델은 존재하지 않는 함수나 패키지를 지어낼 수도 있으니, 무언가를 설치하기 전에 낯선 import를 확인하세요.
프로젝트가 커지면 AI가 만든 코드는 왜 깨지나요?
모델은 대화에 있는 것만 봅니다. 프로젝트가 커지면 보여 주지 않은 파일은 보지 못하게 되고, 이름, 구조, 이전 결정에 대한 빈틈을 추측으로 채웁니다. 관련 파일을 붙여 넣고, 프로젝트가 따르는 규칙을 밝히고, 요청마다 변경을 하나로 제한하세요.