← 블로그

Claude API 프롬프트 엔지니어링 실패 패턴 5가지

2026년 9월 22일

생성형 AI를 위한 프롬프트 엔지니어링 실패 패턴 5가지를 진단하고, Claude API에서 즉시 쓸 수 있는 수정 코드를 함께 정리했다.

생성형 AI를 위한 프롬프트 엔지니어링에서 가장 흔한 실패 원인은 기술 부족이 아니라 패턴 인식 부재다. 역할 미지정, 출력 형식 공백, 예시 없음, 부정형 지시어 남용, 컨텍스트 과부하 — 이 다섯 가지 패턴이 실무에서 반복되는 프롬프트 품질 문제의 대부분을 차지한다. 각 패턴의 진단 기준과 Claude API에서 바로 쓸 수 있는 수정 코드를 함께 정리했다.

생성형 AI를 위한 프롬프트 엔지니어링이란 무엇인가?

생성형 AI를 위한 프롬프트 엔지니어링은 모델에서 원하는 출력을 끌어내기 위해 입력 텍스트를 설계하는 기술이다. "잘 써달라"고 요청하는 것과는 다르다. 모델이 어떤 역할로, 어떤 형식으로, 어떤 기준에 맞게 생성해야 하는지를 구조적으로 전달하는 과정이다.

Claude API 기준으로 프롬프트는 크게 세 레이어로 구성된다.

  • system: 모델의 페르소나, 제약 조건, 응답 형식을 정의하는 운영자 지시어
  • user: 실제 작업 요청
  • assistant: 멀티턴 대화에서 이전 응답을 맥락으로 제공

이 세 레이어가 어떻게 구성되느냐에 따라 같은 요청도 전혀 다른 결과를 낸다. 실무에서 프롬프트 품질 문제는 대부분 세 레이어 중 하나가 비어 있거나 서로 충돌할 때 발생한다.

※ 이 글은 Plinth Prep이 독자적으로 작성했으며, Anthropic과는 제휴·후원·인증 관계가 없습니다.

왜 같은 프롬프트가 매번 다른 결과를 내는가?

생성형 AI는 확률적으로 동작한다. 동일한 입력이라도 매 요청마다 다른 토큰 샘플링 경로를 거치므로 출력이 완전히 같을 수는 없다. 그런데 "다름"에도 정도가 있다. 허용 범위 내의 자연스러운 변동이 있는가 하면, 요청과 전혀 무관한 방향으로 튀는 경우도 있다.

후자의 원인은 거의 항상 프롬프트 설계 문제다. 모델이 판단해야 할 모호성이 많을수록 출력 분산이 커진다. 역할이 없으면 모델은 "적당한 어조"를 직접 추론해야 하고, 형식이 없으면 "어떻게 구조화할지"를 매번 새로 결정한다. 이 결정 포인트 하나하나가 출력 불안정성을 쌓는다.

프롬프트 엔지니어링의 핵심은 모델이 내려야 할 불필요한 결정을 줄이는 데 있다. 클로드 코드(Claude Code) CLI를 쓰든 API를 직접 호출하든 이 설계 원칙은 동일하게 적용된다.

역할과 출력 형식이 없으면 Claude API 출력이 왜 흔들리는가?

패턴 1: 역할 미지정

역할(Role)은 모델이 어떤 관점에서 응답할지를 결정한다. 시스템 프롬프트에 역할을 지정하지 않으면, 모델은 "일반적인 어시스턴트"로 동작한다. 이 상태에서는 전문성, 어조, 응답 깊이가 요청마다 달라진다.

진단 기준: system 파라미터가 비어 있거나, 역할 정의 없이 바로 규칙 나열로 시작하면 패턴 1에 해당한다.

패턴 2: 출력 형식 공백

"분석해줘"라는 요청에 모델은 불릿 리스트를 쓸 수도, 산문을 쓸 수도, 표를 만들 수도 있다. 파이프라인에 이 출력이 들어간다면, 형식이 흔들리는 순간 하위 처리가 깨진다.

진단 기준: 출력 결과를 json.loads()나 정규식으로 파싱하는 코드가 있다면, 출력 형식을 프롬프트로 고정하지 않는 한 언제든 깨질 수 있다.

비포:

import anthropic

client = anthropic.Anthropic()

response = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    messages=[
        {"role": "user", "content": "이 계약서의 주요 리스크를 분석해줘."}
    ]
)
print(response.content[0].text)

애프터:

import anthropic

client = anthropic.Anthropic()

response = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    system=(
        "당신은 기업 법무팀 소속 계약 검토 전문가다. "
        "리스크 항목은 반드시 JSON 배열로 반환하며, 각 항목에 "
        "risk_type, severity(high/medium/low), description 필드를 포함한다."
    ),
    messages=[
        {"role": "user", "content": "이 계약서의 주요 리스크를 분석해줘.\n\n[계약서 본문]"}
    ]
)
print(response.content[0].text)

역할을 지정하면 모델은 법무 전문가라는 좌표계 안에서 동작한다. 출력 형식을 고정하면 하위 처리 코드가 json.loads()로 바로 파싱할 수 있다.

실패 패턴 3: 예시(Few-shot)가 없으면 모델은 무엇을 기준으로 생성하는가?

예시가 없으면 모델은 학습 데이터에서 "가장 흔한 패턴"을 기준으로 생성한다. 문제는 그 기준이 내 서비스의 기준과 다를 수 있다는 점이다. "정중하게 답하라"는 지시만으로는 부족하다. 의료 서비스의 정중함과 패션 커머스의 정중함은 전혀 다르기 때문이다.

입출력 예시를 1~2개 포함하면 어조, 문장 길이, 정보 구성 방식이 암묵적으로 정의된다. 별도의 긴 지시어 없이도 원하는 스타일을 유지할 수 있다.

비포:

system = "고객 문의에 정중하게 답변한다."
user_message = "환불 가능한가요?"

애프터:

system = """고객 문의에 답변한다.

[답변 예시]
문의: 배송이 언제 되나요?
답변: 주문일 기준 영업일 3~5일 내에 도착합니다. 정확한 일정은 '마이페이지 > 주문 현황'에서 확인하실 수 있습니다.

문의: 반품 절차가 어떻게 되나요?
답변: 수령일 기준 7일 이내에 고객센터로 연락주시면 안내해 드립니다. 택배비는 제품 하자의 경우 저희가 부담합니다.
"""

두 개의 예시만으로도 어조, 문장 길이, 정보 구성 방식이 모두 정의된다. Few-shot 프롬프팅은 가장 적은 비용으로 출력 품질을 높이는 수단이다.

실패 패턴 4·5: 부정형 지시어 남용과 컨텍스트 과부하

패턴 4: 부정형 지시어 남용

"~하지 마라"는 지시어는 금지 공간을 알려주지만, 허용 공간을 정의하지 않는다. 부정형이 쌓이면 모델은 점점 좁아지는 제약 안에서 출력 경로를 스스로 찾다가 예기치 않은 방향으로 빠진다.

진단 기준: 프롬프트 안에 "~하지 마라", "~를 피해라", "~는 금지" 표현이 3개 이상이면 패턴 4에 해당한다.

  • 비포: "허위 정보를 제공하지 말고, 과장하지 말고, 비교 발언도 하지 마라."
  • 애프터: "검증된 정보만 답변한다. 확실하지 않으면 '확인이 필요합니다'라고 명시한다."

긍정형 지시어는 모델이 따라야 할 명확한 경로를 제공한다. 같은 의도를 전달하면서 출력 예측 가능성이 높아진다.

패턴 5: 컨텍스트 과부하

시스템 프롬프트에 모든 규칙을 집어넣으면 모델의 주의가 분산된다. 서로 충돌하는 지시어가 섞이면 모델은 어떤 규칙을 우선할지 스스로 결정해야 하고, 이 결정은 매 요청마다 달라진다.

진단 기준: 시스템 프롬프트가 500토큰을 초과하면서 출력 일관성이 낮다면 컨텍스트 과부하를 의심한다.

수정 방향: XML 태그를 사용해 역할, 출력 형식, 제약 조건을 블록으로 구분하면 모델이 지시어를 더 명확하게 파싱한다.

system = """<role>
당신은 B2B SaaS 영업 지원 전문가다. 기술적 질문과 구매 관련 질문을 모두 처리한다.
</role>

<format>
답변은 3문장 이내로 한다. 추가 자료가 필요하면 문서 링크를 제시한다.
</format>

<constraints>
가격 협상 권한은 없다. 견적 요청은 영업팀으로 연결한다.
</constraints>"""

다섯 가지 패턴을 한 번에 고친 Claude API 코드는 어떤 모습인가?

다섯 가지 패턴을 한 번에 수정한 통합 예제다. claude-sonnet-4-6 모델 기준으로 작성했다.

import anthropic
import json

client = anthropic.Anthropic()

system_prompt = """<role>
당신은 소프트웨어 기업의 기술 문서 작성 전문가다.
</role>

<output_format>
응답은 반드시 다음 JSON 구조로 반환한다:
{"summary": "한 줄 요약", "steps": ["단계1", "단계2"], "caution": "주의 사항 또는 null"}
</output_format>

<examples>
질문: Redis 캐싱을 설정하는 방법은?
응답: {"summary": "Redis를 연결하고 TTL을 설정한다", "steps": ["Redis 서버 설치 및 실행", "클라이언트 라이브러리 연결", "TTL 설정으로 자동 만료 구현"], "caution": "maxmemory 정책으로 메모리 용량을 제한한다"}
</examples>

<constraints>
확실하지 않은 정보는 steps에 포함하지 않는다.
불확실한 경우 caution 필드에 "추가 확인 필요"를 명시한다.
</constraints>"""

response = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    system=system_prompt,
    messages=[
        {"role": "user", "content": "Docker 컨테이너 간 네트워크 통신을 설정하는 방법은?"}
    ]
)

result = json.loads(response.content[0].text)
print(f"요약: {result['summary']}")
print(f"단계: {', '.join(result['steps'])}")

이 구조는 파이프라인 어느 단계에 들어가도 json.loads()로 파싱 가능하며, 출력 일관성을 높게 유지한다.

Claude API 프롬프트를 배포하기 전에 무엇을 확인해야 하는가?

  1. 역할이 정의되어 있는가? system 프롬프트에 "당신은 ___다"로 시작하는 역할 정의가 있어야 한다.
  2. 출력 형식이 명시되어 있는가? JSON, 마크다운, 불릿 리스트 등 구체적인 형식이 지정되어 있어야 한다. 파이프라인에 들어가는 출력이라면 필수다.
  3. 예시가 1개 이상 포함되어 있는가? 어조, 길이, 스타일이 중요한 경우 최소 1개의 입출력 예시가 있어야 한다.
  4. 부정형 지시어를 긍정형으로 전환했는가? "~하지 마라" 문장을 "~한다"로 바꿀 수 있으면 바꾼다.
  5. 시스템 프롬프트 토큰 수를 확인했는가? Claude API의 count_tokens로 실제 토큰 수를 사전에 확인할 수 있다. 500토큰 초과 시 XML 블록으로 구조화를 권장한다.
# 배포 전 토큰 수 확인
token_count = client.messages.count_tokens(
    model="claude-sonnet-4-6",
    system=system_prompt,
    messages=[{"role": "user", "content": "테스트 요청"}]
)
print(f"시스템 프롬프트 포함 입력 토큰: {token_count.input_tokens}")

이 다섯 가지 항목을 배포 전에 확인하는 것만으로도 프롬프트 품질 문제의 대부분을 사전에 차단할 수 있다.

자주 묻는 질문

생성형 AI 프롬프트 엔지니어링에서 역할(Role)을 지정해야 하는 이유는?

역할을 지정하지 않으면 모델은 매 요청마다 어조, 전문성 수준, 응답 깊이를 스스로 결정해야 한다. 이 판단이 요청마다 달라지면서 출력이 불안정해진다. 반면 시스템 프롬프트에 명확한 역할을 정의하면 모델은 해당 페르소나의 좌표계 안에서 일관되게 동작한다. Claude API에서는 system 파라미터에 '당신은 X 전문가다'처럼 역할을 명시하는 것이 가장 기본적인 시작점이다.

프롬프트에 Few-shot 예시를 포함해야 하는 이유는?

예시가 없으면 모델은 학습 데이터에서 가장 흔한 패턴을 기준으로 생성한다. 같은 '정중하게 답하라'는 지시도 서비스마다 다르게 해석된다는 뜻이다. 프롬프트에 입출력 예시를 1~2개 포함하면 어조, 길이, 정보 구성 방식을 별도 지시어 없이도 정의할 수 있다. 품질 좋은 기존 응답을 예시로 넣으면 가장 빠르게 출력 수준을 끌어올릴 수 있다.

부정형 지시어 대신 긍정형 지시어를 써야 하는 이유는?

'~하지 마라'는 지시어는 모델에게 금지 공간을 알려주지만 허용 공간을 정의하지 않는다. 부정형이 쌓이면 모델은 좁아지는 제약 안에서 출력 경로를 스스로 찾다가 예기치 않은 방향으로 빠진다. '허위 정보를 제공하지 마라' 대신 '검증된 정보만 답변한다'처럼 긍정형으로 바꾸면 모델이 따라야 할 명확한 경로가 생겨 출력 예측 가능성이 높아진다.

컨텍스트 과부하란 무엇이며 어떻게 해결하는가?

시스템 프롬프트에 지시어를 지나치게 많이 쌓으면 서로 충돌하는 규칙이 생기고, 모델은 어떤 규칙을 우선할지 매 요청마다 다르게 결정한다. 이를 컨텍스트 과부하라고 한다. XML 태그를 사용해 역할, 출력 형식, 제약 조건을 명확히 구분하면 파싱이 안정되고 출력 일관성이 높아진다. 500토큰 초과 시 구조화를 권장한다.

생성형 AI 프롬프트를 배포 전에 확인해야 할 항목은 무엇인가?

다섯 가지를 확인한다. 역할 정의가 있는지, 출력 형식이 명시됐는지, 입출력 예시가 포함됐는지, 부정형 지시어를 긍정형으로 전환했는지, 시스템 프롬프트가 500토큰 미만인지다. Claude API의 count_tokens 메서드로 토큰 수를 사전에 확인하면 컨텍스트 과부하로 인한 품질 저하를 배포 전에 차단할 수 있다.

이 글에서 다룬 다섯 가지 패턴은 CCA-F 시험의 핵심 출제 영역이기도 하다. 개념을 읽는 것과 실제로 이해한 것을 구분하고 싶다면, PlinthPrep의 연습 문제로 확인해볼 수 있다. PlinthPrep은 Anthropic과 무관한 독립 학습 사이트다. plinthprep.com에서 연습 문제를 확인하세요.

자주 묻는 질문

생성형 AI 프롬프트 엔지니어링에서 역할(Role)을 지정해야 하는 이유는?
역할을 지정하지 않으면 모델은 매 요청마다 어조, 전문성 수준, 응답 깊이를 스스로 결정해야 한다. 이 판단이 요청마다 달라지면서 출력이 불안정해진다. 반면 시스템 프롬프트에 명확한 역할을 정의하면 모델은 해당 페르소나의 좌표계 안에서 일관되게 동작한다. Claude API에서는 system 파라미터에 '당신은 X 전문가다'처럼 역할을 명시하는 것이 가장 기본적인 시작점이다.
프롬프트에 Few-shot 예시를 포함해야 하는 이유는?
예시가 없으면 모델은 학습 데이터에서 가장 흔한 패턴을 기준으로 생성한다. 같은 '정중하게 답하라'는 지시도 서비스마다 다르게 해석된다는 뜻이다. 프롬프트에 입출력 예시를 1~2개 포함하면 어조, 길이, 정보 구성 방식을 별도 지시어 없이도 정의할 수 있다. 품질 좋은 기존 응답을 예시로 넣으면 가장 빠르게 출력 수준을 끌어올릴 수 있다.
부정형 지시어 대신 긍정형 지시어를 써야 하는 이유는?
'~하지 마라'는 지시어는 모델에게 금지 공간을 알려주지만 허용 공간을 정의하지 않는다. 부정형이 쌓이면 모델은 좁아지는 제약 안에서 출력 경로를 스스로 찾다가 예기치 않은 방향으로 빠진다. '허위 정보를 제공하지 마라' 대신 '검증된 정보만 답변한다'처럼 긍정형으로 바꾸면 모델이 따라야 할 명확한 경로가 생겨 출력 예측 가능성이 높아진다.
컨텍스트 과부하란 무엇이며 어떻게 해결하는가?
시스템 프롬프트에 지시어를 지나치게 많이 쌓으면 서로 충돌하는 규칙이 생기고, 모델은 어떤 규칙을 우선할지 매 요청마다 다르게 결정한다. 이를 컨텍스트 과부하라고 한다. XML 태그를 사용해 역할, 출력 형식, 제약 조건을 명확히 구분하면 파싱이 안정되고 출력 일관성이 높아진다. 500토큰 초과 시 구조화를 권장한다.
생성형 AI 프롬프트를 배포 전에 확인해야 할 항목은 무엇인가?
다섯 가지를 확인한다. 역할 정의가 있는지, 출력 형식이 명시됐는지, 입출력 예시가 포함됐는지, 부정형 지시어를 긍정형으로 전환했는지, 시스템 프롬프트가 500토큰 미만인지다. Claude API의 count_tokens 메서드로 토큰 수를 사전에 확인하면 컨텍스트 과부하로 인한 품질 저하를 배포 전에 차단할 수 있다.

이 글 공유하기

Plinth Prep는 독립적인 학습 자료이며 Anthropic과 제휴, 보증, 후원 관계가 없습니다. 연습 문제는 Plinth Prep가 직접 제작한 것이며 실제 시험 문제를 옮긴 것이 아닙니다.