Chapter 2

프롬프트 작성의 비법

  • 2.1 프롬프트 엔지니어링 기초
  • 2.2 구체성과 명확성
  • 2.3 반복적 정제
  • 2.4 프롬프트 작성 기법
  • 2.5 고급 프롬프트 전략

프롬프트 엔지니어링은 "요청을 잘 하는 법"이 아니라 문제를 구조화하는 기술이야. 코드를 직접 짜는 대신 의도를 전달하는 시대에서, 프롬프트 품질이 곧 코드 품질이거든.

출발점은 단순해 — AI는 마음을 읽지 못해. 머릿속에 있는 걸 정확히 텍스트로 표현해야 원하는 결과가 나오지.

좋은 프롬프트의 기본 구성요소는 이래:

  • 역할(Role) — AI에게 어떤 관점에서 답변할지 지정. "시니어 백엔드 개발자로서" 같은 것
  • 맥락(Context) — 프로젝트의 기술 스택, 기존 코드 구조, 제약 조건 등
  • 작업(Task) — 실제로 해야 할 일을 명확하게
  • 출력 형식(Format) — 코드만 원하는지, 설명도 원하는지, 어떤 언어로 원하는지

나쁜 프롬프트의 전형적인 패턴도 있어. "로그인 페이지 만들어줘"는 나쁜 프롬프트야. 어떤 프레임워크? 어떤 인증 방식? UI 라이브러리는? 에러 처리는? 이런 정보가 전부 빠져 있으니 AI가 임의로 결정하게 되고, 그 결정이 우리가 원하는 것과 맞을 확률은 낮지.

가장 반복적으로 강조할 원칙이 있어 — 구체적이고 명확하게.

같은 요청을 두 가지로 비교해보면 차이가 극명하거든.

모호한 프롬프트: "데이터베이스 연결 코드 짜줘"

구체적인 프롬프트: "TypeScript로 PostgreSQL 연결 모듈을 작성해줘. pg 라이브러리 사용하고, 커넥션 풀링 적용해서 최대 20개 연결을 유지해. 환경변수에서 DB 접속 정보를 읽고, 연결 실패 시 3회까지 재시도하는 로직 포함해줘. 에러는 커스텀 DatabaseError 클래스로 래핑해서 던져."

두 번째 프롬프트가 길지만, AI가 추측해야 할 부분이 거의 없어. 추측이 줄어들면 환각도 줄어들지. 프롬프트에 들이는 시간은 디버깅 시간을 줄여주거든.

구체성에서 또 중요한 건 기술적 제약 조건을 명시하는 거야:

  • 사용할 라이브러리 버전
  • 코딩 스타일 (함수형 vs 객체지향)
  • 에러 처리 전략
  • 네이밍 컨벤션
  • 성능 요구사항

한 번의 프롬프트로 완벽한 결과를 얻는 건 환상이야. 프롬프트는 반복적으로 정제(iterate)해야 해.

반복 정제의 일반적인 흐름은 이렇지:

  1. 초기 프롬프트 — 큰 그림을 그리며 첫 버전 생성
  2. 결과 평가 — 생성된 코드가 의도와 맞는지 확인
  3. 구체화 — 부족한 부분을 지적하고 수정 요청
  4. 확장 — 추가 기능이나 엣지 케이스 처리 요청
  5. 다듬기 — 코드 스타일, 성능, 가독성 개선

여기서 중요한 건 이전 대화의 맥락을 활용하는 거야. "아까 만든 함수에서 에러 처리 부분을 try-catch 대신 Result 타입으로 바꿔줘"처럼 대화의 흐름을 유지하면서 정제하는 게 효과적이지.

안티패턴도 하나 알아둬야 해 — 대화가 너무 길어지면 AI가 초반 맥락을 잃어버려. 컨텍스트 윈도우의 한계 때문에 생기는 문제인데, 이럴 때는 새 대화를 시작하면서 지금까지의 결과물을 붙여넣는 게 낫지.

실전 프롬프트 기법들을 보면:

퓨샷 프롬프팅(Few-Shot Prompting) — 원하는 결과의 예시를 함께 제공하는 기법이야. "이런 입력이 들어오면 이런 출력이 나와야 해"라고 예시를 2~3개 보여주면 AI가 패턴을 파악해서 일관된 결과를 내거든.

체인 오브 소트(Chain of Thought) — "단계별로 생각해봐"를 명시적으로 요청하는 거야. 복잡한 알고리즘이나 비즈니스 로직을 구현할 때 효과적이지. AI가 바로 코드를 쓰는 대신 먼저 접근 방법을 설명하고 나서 구현하게 하면 품질이 올라가.

제약 조건 명시 — "하지 말아야 할 것"을 분명히 하는 기법이야. "외부 라이브러리 쓰지 마", "클래스 대신 함수로 작성해", "console.log는 넣지 마" 같은 네거티브 제약이 결과물의 방향을 잡아주지.

분할 정복 — 복잡한 기능을 한 번에 요청하지 않고 작은 단위로 나눠서 요청하는 거야. 먼저 데이터 모델을 만들고, 그다음 API 엔드포인트, 그다음 프론트엔드 통합. 이렇게 하면 각 단계에서 검증할 수 있어서 오류가 누적되지 않아.

코드 리뷰 요청 — AI가 생성한 코드를 다시 AI한테 리뷰시키는 기법이지. "이 코드에서 보안 취약점이 있는지 검토해줘" 같은 식. 생성과 검증을 분리하면 품질이 올라가.

기본을 넘어서는 고급 전략들도 있어.

시스템 프롬프트 활용 — 모든 대화에 공통으로 적용될 지침을 시스템 프롬프트에 넣어두는 거야. 코딩 스타일 가이드, 프로젝트 구조, 선호하는 패턴 등. Cursor의 .cursorrules나 Claude의 CLAUDE.md 같은 파일이 이 역할을 하지.

멀티턴 전략 — 하나의 기능을 여러 번의 대화로 나눠서 완성하되, 전체 계획을 먼저 세우는 거야. "지금부터 인증 시스템을 만들 건데, 먼저 전체 아키텍처를 설명해줘. 코드는 아직 쓰지 마."로 시작해서, 아키텍처에 동의한 후에 구현으로 넘어가는 방식이지.

페르소나 활용 — 단순한 역할 지정을 넘어서 구체적인 페르소나를 부여하는 거야. "너는 10년 경력의 보안 전문가고, OWASP Top 10을 기준으로 모든 코드를 검토하는 습관이 있어"라고 하면 보안 관점의 코드 리뷰 품질이 확 올라가.

메타 프롬프트 — 프롬프트를 생성하는 프롬프트야. "이 기능을 구현하기 위해 AI에게 어떤 프롬프트를 써야 할지 제안해줘"라고 하면, AI가 최적의 프롬프트 구조를 제안해주지. 프롬프트 작성 자체가 어려울 때 유용해.

이 기법들을 외우는 게 아니라 왜 효과가 있는지를 이해하는 게 중요해. 결국 모든 기법의 핵심은 하나야 — AI가 추측해야 하는 부분을 줄이고, 명확한 방향을 제시하는 거지.


정리

2장에서 기억할 거 세 가지:

  1. 프롬프트의 구체성이 곧 코드 품질이야. 모호하게 요청하면 모호한 결과가 나오지. 기술 스택, 제약 조건, 예상 동작을 명시해
  2. 한 번에 완벽을 기대하지 마. 반복적 정제가 핵심이야. 초기 결과를 평가하고, 방향을 조정하고, 다시 요청하는 사이클을 돌려
  3. 시스템 프롬프트로 공통 맥락을 설정해. 매번 같은 제약 조건을 반복하는 대신, .cursorrules나 CLAUDE.md 같은 설정 파일로 기본 맥락을 잡아두면 효율이 올라가