이미지 로딩 중...

프롬프트 엔지니어링 완벽 가이드 - 슬라이드 1/9
A

AI Generated

2025. 11. 17. · 4 Views

프롬프트 엔지니어링 완벽 가이드

AI와 대화하는 기술, 프롬프트 엔지니어링의 모든 것을 알려드립니다. 초급 개발자도 쉽게 따라할 수 있는 실전 기법과 예제로 AI를 200% 활용하는 방법을 배워보세요.


목차

  1. 프롬프트_엔지니어링이란
  2. 역할_부여_기법
  3. 개선 방법 제시
  4. Few-Shot_학습_기법
  5. Chain-of-Thought_기법
  6. 제약조건_명시_기법
  7. 출력_형식_지정_기법
  8. 반복적_개선_기법
  9. None 값 처리 (name이나 email이 None일 수 있음)
  10. 맥락_제공_기법

1. 프롬프트_엔지니어링이란

시작하며

여러분이 ChatGPT나 Claude 같은 AI에게 질문했는데, 엉뚱한 답변이 돌아온 적 있나요? "파이썬 코드 좀 짜줘"라고 했더니 너무 간단하거나 복잡한 코드를 받았던 경험 말이에요.

이런 문제는 실제로 많은 개발자들이 겪는 일입니다. AI는 똑똑하지만, 우리가 원하는 걸 정확히 알려주지 않으면 제대로 된 답을 주기 어렵습니다.

마치 식당에서 "맛있는 거 주세요"라고 주문하면 주방장이 난감해하는 것과 비슷하죠. 바로 이럴 때 필요한 것이 프롬프트 엔지니어링입니다.

AI에게 정확하게 원하는 것을 요청하는 기술이죠. 이 기술을 익히면 AI로부터 원하는 답변을 정확하게 받을 수 있습니다.

개요

간단히 말해서, 프롬프트 엔지니어링은 AI에게 질문이나 요청을 효과적으로 작성하는 기술입니다. 마치 검색엔진에서 검색어를 잘 입력해야 원하는 결과를 찾듯이, AI에게도 명확한 지시를 내려야 정확한 답을 얻을 수 있어요.

왜 이것이 중요할까요? 개발자로서 여러분은 코드 리뷰, 버그 수정, 새로운 기능 구현 등 다양한 작업에서 AI의 도움을 받게 될 겁니다.

예를 들어, "이 함수 최적화해줘"보다 "이 함수의 시간 복잡도를 O(n²)에서 O(n)으로 개선하고, 메모리 사용량도 줄여줘"라고 요청하면 훨씬 정확한 결과를 받을 수 있죠. 전통적으로는 구글링하고, 문서 뒤지고, 스택오버플로우를 검색했다면, 이제는 AI에게 정확히 질문해서 즉시 답을 얻을 수 있습니다.

하지만 그러려면 질문을 잘해야 해요. 프롬프트 엔지니어링의 핵심 특징은 명확성, 구체성, 맥락 제공입니다.

이 세 가지만 잘 지켜도 AI의 답변 품질이 월등히 좋아집니다. 좋은 프롬프트는 개발 생산성을 2~3배 높일 수 있어요.

코드 예제

# 나쁜 프롬프트 예시
bad_prompt = "파이썬 함수 만들어줘"

# 좋은 프롬프트 예시
good_prompt = """
Python으로 CSV 파일을 읽어서 데이터를 분석하는 함수를 작성해주세요.

요구사항:
- 함수명: analyze_sales_data
- 입력: CSV 파일 경로 (문자열)
- 출력: 딕셔너리 (총 매출, 평균 매출, 최고 매출)
- 에러 처리: 파일이 없을 때 FileNotFoundError 발생
- 타입 힌트 포함
- docstring 작성

예시 CSV 형식:
date,product,amount
2024-01-01,A,1000
2024-01-02,B,1500
"""

설명

이것이 하는 일: 위 예시는 나쁜 프롬프트와 좋은 프롬프트를 비교합니다. 나쁜 프롬프트는 너무 모호해서 AI가 어떤 함수를 만들어야 할지 모르지만, 좋은 프롬프트는 정확히 무엇을 원하는지 알려줍니다.

첫 번째로, bad_prompt는 "파이썬 함수 만들어줘"라는 한 줄짜리 요청입니다. 이렇게 요청하면 AI는 "어떤 함수를 만들까요?"라고 되물어보거나, 아주 간단한 예제만 줄 수 있어요.

왜냐하면 함수의 목적, 입력, 출력이 무엇인지 전혀 모르기 때문이죠. 두 번째로, good_prompt는 완전히 다릅니다.

함수의 정확한 이름(analyze_sales_data), 입력 타입(CSV 파일 경로), 출력 형식(딕셔너리), 에러 처리 방법, 코딩 스타일(타입 힌트, docstring)까지 모두 명시했어요. 심지어 CSV 파일의 예시 형식까지 보여줬습니다.

세 번째로, AI는 이 상세한 정보를 받으면 여러분이 원하는 정확한 함수를 만들어줄 수 있습니다. 추가 질문 없이 바로 실무에서 쓸 수 있는 코드를 받게 되죠.

이것이 바로 프롬프트 엔지니어링의 힘입니다. 여러분이 이 방식을 사용하면 개발 시간을 크게 절약할 수 있습니다.

AI와의 왕복 대화 횟수가 줄어들고, 첫 번째 답변부터 높은 품질의 코드를 받을 수 있어요. 또한 코드의 일관성이 유지되고, 프로젝트 표준을 지킬 수 있습니다.

실전 팁

💡 항상 구체적인 요구사항을 나열하세요. "좋은 코드"보다 "PEP 8 준수, 타입 힌트 포함, docstring 작성"이 훨씬 명확합니다.

💡 예시를 함께 제공하면 AI가 정확히 이해합니다. 입력 예시, 출력 예시를 보여주면 오해의 여지가 없어요.

💡 프롬프트를 템플릿으로 저장해두세요. 자주 쓰는 요청 패턴은 파일로 만들어두면 재사용이 편리합니다.

💡 한 번에 너무 많은 것을 요청하지 마세요. 복잡한 작업은 단계별로 나눠서 요청하는 게 더 좋은 결과를 냅니다.

💡 AI의 답변이 마음에 들지 않으면 프롬프트를 개선하세요. "더 자세히", "다르게"보다 "X를 Y로 바꿔서"가 효과적입니다.


2. 역할_부여_기법

시작하며

여러분이 AI에게 코드 리뷰를 부탁했는데, 너무 기초적인 피드백만 받았거나 반대로 너무 어려운 조언을 받은 적 있나요? "코드가 좋네요"나 "디자인 패턴을 13개 적용하세요" 같은 극단적인 답변 말이에요.

이런 문제는 AI가 어떤 관점에서 답변해야 할지 모를 때 발생합니다. AI는 기본적으로 중립적인 입장에서 답변하는데, 때로는 특정 전문가의 시각이 필요할 때가 있죠.

바로 이럴 때 필요한 것이 역할 부여 기법입니다. AI에게 특정 전문가의 역할을 맡기면, 그 관점에서 일관되고 전문적인 답변을 받을 수 있습니다.

개요

간단히 말해서, 역할 부여는 AI에게 "당신은 ~입니다"라고 명시하여 특정 전문가나 페르소나의 관점에서 답변하도록 하는 기법입니다. 마치 배우에게 역할을 주는 것과 비슷해요.

왜 이것이 필요할까요? 개발할 때 코드 리뷰는 시니어 개발자처럼, 보안 검토는 보안 전문가처럼, 성능 최적화는 성능 엔지니어처럼 생각해야 하기 때문입니다.

예를 들어, "당신은 10년 경력의 백엔드 시니어 개발자입니다. 이 API 코드를 리뷰해주세요"라고 하면 훨씬 실용적인 피드백을 받을 수 있죠.

기존에는 "코드 리뷰해줘"라고만 했다면, 이제는 "당신은 보안 전문가입니다. 이 코드의 보안 취약점을 찾아주세요"라고 구체적인 역할을 부여할 수 있습니다.

역할 부여의 핵심 특징은 일관성, 전문성, 맥락 유지입니다. 역할이 명확하면 AI는 그 역할에 맞는 용어, 관점, 우선순위로 답변합니다.

이는 답변의 품질과 유용성을 크게 높여줘요.

코드 예제

# 역할 없이 요청
simple_request = "이 코드 리뷰해줘"

# 역할을 부여한 요청
role_based_request = """
당신은 10년 경력의 파이썬 백엔드 시니어 개발자입니다.
다음 관점에서 코드를 리뷰해주세요:
- 코드 가독성과 유지보수성
- 성능 이슈 (N+1 쿼리, 메모리 누수 등)
- 보안 취약점 (SQL 인젝션, XSS 등)
- 에러 처리의 적절성
- 파이썬 베스트 프랙티스 준수 여부

각 이슈에 대해:

3. 개선 방법 제시

설명

이것이 하는 일: 위 예시는 역할 부여 기법을 사용하여 코드 리뷰 품질을 높이는 방법을 보여줍니다. 단순한 요청과 역할이 부여된 요청의 차이를 비교할 수 있어요.

첫 번째로, simple_request는 "이 코드 리뷰해줘"라는 간단한 요청입니다. 이렇게 요청하면 AI는 일반적인 수준의 피드백만 줍니다.

"코드가 작동은 하지만 비효율적입니다" 정도의 표면적인 코멘트만 받을 수 있죠. 두 번째로, role_based_request는 완전히 다른 접근입니다.

"10년 경력의 파이썬 백엔드 시니어 개발자"라는 명확한 역할을 부여했어요. 그리고 코드 가독성, 성능, 보안, 에러 처리, 베스트 프랙티스라는 5가지 구체적인 검토 관점을 제시했습니다.

심지어 답변 형식까지 "문제점 → 이유 → 개선 방법"으로 지정했죠. 세 번째로, code_to_review는 실제로 문제가 있는 코드입니다.

데이터베이스에서 모든 포스트를 가져와서 파이썬 레벨에서 필터링하는 비효율적인 방식이에요. 역할이 부여된 프롬프트를 사용하면 AI는 "N+1 쿼리 문제", "메모리 낭비", "Post.query.filter_by(user_id=user_id).all() 사용 권장" 같은 구체적이고 실용적인 피드백을 줄 겁니다.

여러분이 이 기법을 사용하면 코드 리뷰, 아키텍처 설계, 디버깅 등 다양한 상황에서 전문가 수준의 조언을 받을 수 있습니다. 실제 시니어 개발자에게 물어보는 것처럼 깊이 있고 실용적인 답변을 얻게 되죠.

또한 답변의 일관성도 유지되어 프로젝트 전체에 걸쳐 동일한 기준을 적용할 수 있어요.

실전 팁

💡 역할은 구체적일수록 좋습니다. "개발자"보다 "5년 경력의 React 프론트엔드 개발자"가 훨씬 명확해요.

💡 여러 역할을 순차적으로 사용하세요. 같은 코드를 "보안 전문가", "성능 엔지니어", "UX 개발자" 관점에서 각각 리뷰받으면 종합적인 피드백을 얻을 수 있습니다.

💡 역할에 맞는 제약조건을 추가하세요. "초급 개발자를 가르치는 멘토"라면 "쉬운 용어로 설명해주세요"를 덧붙이면 더 좋아요.

💡 팀의 코딩 스타일을 역할에 포함시키세요. "우리 팀은 Google Python Style Guide를 따릅니다"라고 명시하면 일관된 리뷰를 받습니다.


3. Few-Shot_학습_기법

시작하며

여러분이 AI에게 "이 형식으로 코드를 짜줘"라고 했는데, 막상 받아보니 원하는 스타일이 아니었던 적 있나요? "함수형으로 짜줘"라고 했는데 객체지향으로 오거나, 간결하게 해달라고 했는데 너무 장황하게 온 경우 말이에요.

이런 문제는 말로만 설명하면 AI가 정확히 이해하기 어렵기 때문에 발생합니다. "간결하게"의 기준은 사람마다 다르고, "우리 스타일로"라고 해도 AI는 여러분의 스타일을 모르니까요.

바로 이럴 때 필요한 것이 Few-Shot 학습 기법입니다. 예시를 몇 개 보여주면 AI가 패턴을 파악하고 똑같은 스타일로 작성해줍니다.

개요

간단히 말해서, Few-Shot 학습은 AI에게 원하는 형식의 예시를 2~5개 보여주고, 같은 패턴으로 답변하도록 하는 기법입니다. 마치 선생님이 예제 문제를 풀어주고 "이렇게 풀어"라고 하는 것과 같아요.

왜 이것이 필요할까요? 코딩 스타일, 문서 형식, 테스트 케이스 작성 등은 말로 설명하는 것보다 예시를 보여주는 게 훨씬 명확하기 때문입니다.

예를 들어, "docstring을 Google 스타일로 짜줘"보다 실제 Google 스타일 예시 2개를 보여주면 AI가 정확히 따라합니다. 기존에는 장황하게 "함수명은 동사로 시작하고, 파라미터는 타입 힌트를 붙이고, docstring은 한 줄 요약 후 빈 줄을 넣고..."라고 설명했다면, 이제는 예시 코드 2~3개만 보여주면 됩니다.

Few-Shot 학습의 핵심은 일관성 있는 예시 제공입니다. 예시들이 같은 패턴을 따라야 AI가 규칙을 정확히 학습해요.

이 기법은 코드 생성, 테스트 작성, 문서 작성 등 형식이 중요한 모든 작업에서 유용합니다.

코드 예제

# Few-Shot 프롬프트 예시
few_shot_prompt = """
다음 예시들과 같은 스타일로 함수를 작성해주세요:

예시 1:
def calculate_total_price(items: list[dict], tax_rate: float = 0.1) -> float:
    '''Calculate total price including tax.

    Args:
        items: List of item dicts with 'price' key
        tax_rate: Tax rate as decimal (default 0.1)

    Returns:
        Total price with tax applied
    '''
    subtotal = sum(item['price'] for item in items)
    return subtotal * (1 + tax_rate)

예시 2:
def filter_active_users(users: list[dict]) -> list[dict]:
    '''Filter users by active status.

    Args:
        users: List of user dicts with 'is_active' key

    Returns:
        List of active users only
    '''
    return [user for user in users if user.get('is_active', False)]

이제 다음 함수를 같은 스타일로 작성해주세요:
- 함수명: get_recent_orders
- 기능: 최근 N일 이내의 주문만 반환
- 파라미터: orders (list[dict]), days (int)
"""

설명

이것이 하는 일: 위 예시는 Few-Shot 학습 기법을 사용하여 AI에게 정확한 코딩 스타일을 학습시키는 방법을 보여줍니다. 두 개의 예시 함수를 통해 패턴을 제시하고, 새로운 함수를 같은 스타일로 작성하도록 요청합니다.

첫 번째로, 예시 1(calculate_total_price)은 여러 패턴을 보여줍니다. 타입 힌트 사용, 기본값 파라미터 설정, Google 스타일 docstring, 간결한 한 줄 요약, Args와 Returns 섹션, 리스트 컴프리헨션 사용 등이죠.

AI는 이 예시에서 "아, 이런 스타일을 원하는구나"라고 학습합니다. 두 번째로, 예시 2(filter_active_users)는 첫 번째 예시의 패턴을 강화합니다.

같은 타입 힌트 스타일, 같은 docstring 형식, 같은 리스트 컴프리헨션 사용 방식이 반복되죠. 두 개의 예시를 보면 AI는 "이게 일관된 규칙이구나"라고 확신합니다.

또한 .get() 메서드를 사용한 안전한 딕셔너리 접근 방법도 보여줍니다. 세 번째로, 실제 요청 부분에서는 "이제 다음 함수를 같은 스타일로"라고 명확히 지시합니다.

함수의 이름, 기능, 파라미터만 알려주면 AI는 앞서 본 두 예시의 패턴을 그대로 따라서 get_recent_orders 함수를 작성할 거예요. 타입 힌트, docstring, 코드 스타일 모두 예시와 일치하게 만들어집니다.

여러분이 이 기법을 사용하면 팀의 코딩 컨벤션을 정확히 지킬 수 있습니다. 코드 리뷰에서 "스타일이 다르네요"라는 피드백을 받을 일이 줄어들죠.

또한 프로젝트 전체의 코드 일관성이 높아져서 유지보수가 훨씬 쉬워집니다. 새로운 팀원이 와도 예시 코드를 보여주면 바로 같은 스타일로 개발할 수 있어요.

실전 팁

💡 예시는 2~5개가 적당합니다. 1개는 우연일 수 있고, 10개는 너무 많아서 AI가 혼란스러워해요.

💡 예시들은 복잡도를 다양하게 하세요. 간단한 예시 하나, 중간 복잡도 하나, 복잡한 예시 하나를 섞으면 AI가 더 잘 일반화합니다.

💡 예시에 주석을 달아서 중요한 패턴을 강조하세요. "# 주목: 항상 타입 힌트 사용" 같은 코멘트가 도움됩니다.

💡 예시와 요청을 명확히 구분하세요. "위 예시들처럼" 또는 "같은 패턴으로"라는 표현을 사용하면 AI가 무엇을 모방해야 할지 알아요.

💡 예시 선택이 중요합니다. 가장 이상적인 코드를 예시로 보여주세요. AI는 예시의 모든 패턴을 따라하니까요.


4. Chain-of-Thought_기법

시작하며

여러분이 AI에게 복잡한 알고리즘 문제를 풀어달라고 했는데, 갑자기 답만 딱 나오고 설명이 없어서 당황한 적 있나요? 또는 답이 틀렸는데 어디서 잘못됐는지 알 수 없었던 경험 말이에요.

이런 문제는 AI가 중간 사고 과정을 건너뛰고 바로 결론으로 점프할 때 발생합니다. 사람도 복잡한 문제는 단계별로 생각해야 하는데, AI도 마찬가지예요.

특히 논리적 추론이 필요한 문제에서는 더욱 그렇죠. 바로 이럴 때 필요한 것이 Chain-of-Thought(생각의 사슬) 기법입니다.

AI에게 "단계별로 생각하고 설명해줘"라고 요청하면 훨씬 정확하고 이해하기 쉬운 답변을 받을 수 있습니다.

개요

간단히 말해서, Chain-of-Thought는 AI에게 답을 바로 내놓지 말고 중간 사고 과정을 단계별로 설명하도록 하는 기법입니다. 마치 수학 문제 풀 때 풀이 과정을 쓰는 것과 같아요.

왜 이것이 필요할까요? 복잡한 알고리즘, 버그 디버깅, 아키텍처 설계 같은 작업은 여러 단계의 논리적 사고가 필요합니다.

예를 들어, "이 코드의 시간 복잡도를 분석해줘"라고 할 때 "O(n²)입니다"보다 "외부 루프가 n번, 내부 루프가 n번 도니까 n × n = O(n²)입니다"가 훨씬 이해하기 쉽죠. 기존에는 "답만 알려줘"라고 했다면, 이제는 "단계별로 생각하면서 풀어줘"라고 요청할 수 있습니다.

이렇게 하면 AI의 답변 정확도가 높아지고, 여러분도 왜 그런 답이 나왔는지 이해할 수 있어요. Chain-of-Thought의 핵심은 명시적인 추론 과정입니다.

AI가 "1단계: ~를 확인, 2단계: ~를 계산, 3단계: ~를 결론"처럼 단계를 밟으면 오류가 줄어들고 설명이 명확해집니다. 특히 복잡한 문제일수록 효과가 큽니다.

코드 예제

# Chain-of-Thought 없이 요청
simple_request = "이 함수의 시간 복잡도를 알려줘"

# Chain-of-Thought를 사용한 요청
cot_request = """
다음 함수의 시간 복잡도를 분석해주세요.
단계별로 사고 과정을 보여주세요:

1단계: 각 루프가 몇 번 실행되는지 확인
2단계: 중첩된 루프의 관계 파악
3단계: 가장 지배적인 항 찾기
4단계: Big-O 표기법으로 표현
5단계: 최종 결론과 개선 방법 제시

def find_duplicates(arr):
    duplicates = []
    for i in range(len(arr)):           # 이 루프는?
        for j in range(i + 1, len(arr)):  # 이 루프는?
            if arr[i] == arr[j]:
                duplicates.append(arr[i])
                break
    return duplicates
"""

# 더 나은 Chain-of-Thought 프롬프트
better_cot = """
아래 코드를 분석할 때 다음처럼 생각해주세요:

<생각>
- 외부 루프: range(len(arr)) → n번 반복
- 내부 루프: range(i+1, len(arr)) → 평균 n/2번 반복
- 중첩: n × n/2 = n²/2
- 지배 항: n²
- 결론: O(n²)
</생각>

개선안:
<생각>
- set을 사용하면 → O(n) 조회
- 한 번만 순회 → O(n)
- 총 시간: O(n)
</생각>
"""

설명

이것이 하는 일: 위 예시는 Chain-of-Thought 기법을 사용하여 복잡한 알고리즘 분석을 더 정확하고 이해하기 쉽게 만드는 방법을 보여줍니다. 단순 요청과 단계별 사고를 요구하는 요청의 차이를 비교할 수 있어요.

첫 번째로, simple_request는 "시간 복잡도를 알려줘"라는 직접적인 질문입니다. 이렇게 물으면 AI는 "O(n²)입니다"라고 답만 던져줄 수 있어요.

왜 그런지, 어떻게 계산했는지 알 수 없죠. 또한 AI가 실수했을 때 그 오류를 발견하기도 어렵습니다.

두 번째로, cot_request는 완전히 다른 접근입니다. 5단계로 사고 과정을 나눠서 각 단계마다 무엇을 확인해야 하는지 명시했어요.

"1단계: 각 루프가 몇 번 실행되는지"처럼 구체적인 분석 방법을 제시하고, 코드에 주석으로 "이 루프는?"이라고 물어보면서 AI가 각 부분을 꼼꼼히 분석하도록 유도합니다. 이렇게 하면 AI는 건너뛰지 않고 모든 단계를 차근차근 설명해요.

세 번째로, better_cot는 더 발전된 형태입니다. <생각> 태그를 사용하여 사고 과정을 구조화했어요.

이렇게 하면 AI는 "생각 과정"과 "최종 답변"을 명확히 구분합니다. 또한 단순히 분석만 하는 게 아니라 개선안까지 같은 방식으로 제시하도록 요청했죠.

AI가 "현재 코드는 O(n²)이지만, set을 사용하면 O(n)으로 개선 가능"이라는 실용적인 조언까지 줄 수 있어요. 여러분이 이 기법을 사용하면 복잡한 알고리즘 문제, 디버깅, 성능 최적화 등에서 훨씬 정확한 분석을 받을 수 있습니다.

AI의 사고 과정을 볼 수 있으니까 틀렸을 때 어디서 잘못됐는지 바로 알 수 있고, 맞았을 때는 그 논리를 배울 수 있어요. 또한 주니어 개발자를 가르칠 때도 이 방식으로 설명하면 이해가 훨씬 쉽습니다.

실전 팁

💡 "단계별로 생각하세요"라는 명령어를 추가하세요. 이 한 문장만으로도 AI의 추론 품질이 크게 향상됩니다.

💡 <생각>, <분석>, <추론> 같은 태그를 사용하면 AI가 사고 과정을 더 구조적으로 정리합니다.

💡 복잡한 문제는 단계를 미리 나눠주세요. "1단계: ~, 2단계: ~"처럼 로드맵을 제시하면 AI가 길을 잃지 않아요.

💡 중간 검증을 요청하세요. "각 단계마다 결과가 맞는지 확인하면서 진행해줘"라고 하면 오류가 줄어듭니다.

💡 실수를 인정하도록 하세요. "확실하지 않으면 '불확실함'이라고 표시해줘"라고 하면 AI가 추측하지 않고 정직하게 답합니다.


5. 제약조건_명시_기법

시작하며

여러분이 AI에게 "함수 만들어줘"라고 했는데, 외부 라이브러리를 잔뜩 사용한 코드가 와서 당황한 적 있나요? 프로젝트에서는 특정 라이브러리만 써야 하는데, AI는 그걸 모르고 numpy, pandas, requests를 마음대로 쓰는 경우 말이에요.

이런 문제는 AI가 여러분의 프로젝트 환경과 제약사항을 모를 때 발생합니다. AI는 기본적으로 "최선의 방법"을 제시하는데, 그게 여러분의 상황에 맞지 않을 수 있죠.

레거시 코드베이스, 특정 버전 제약, 성능 요구사항 같은 현실적인 제약들이 있으니까요. 바로 이럴 때 필요한 것이 제약조건 명시 기법입니다.

AI에게 지켜야 할 규칙과 제한사항을 명확히 알려주면, 여러분의 환경에 딱 맞는 코드를 받을 수 있습니다.

개요

간단히 말해서, 제약조건 명시는 AI에게 "이것은 사용해도 되고, 저것은 안 돼"라는 구체적인 규칙을 알려주는 기법입니다. 마치 요리할 때 "견과류 알러지가 있어요"라고 미리 말하는 것과 같아요.

왜 이것이 필요할까요? 실제 개발 환경에는 다양한 제약이 있기 때문입니다.

Python 3.8만 쓸 수 있거나, 표준 라이브러리만 허용되거나, 메모리는 100MB 이하로 제한되거나, API 호출 비용 때문에 캐싱이 필수이거나 하는 경우들이죠. 예를 들어, "Python 표준 라이브러리만 사용하고, 메모리는 O(1)로 제한"이라고 명시하면 AI가 그에 맞는 솔루션을 제시합니다.

기존에는 AI가 제시한 코드를 받고 "아, 이건 우리 환경에서 안 돼"라고 수정 요청을 여러 번 했다면, 이제는 처음부터 제약조건을 명시해서 한 번에 맞는 코드를 받을 수 있습니다. 제약조건 명시의 핵심은 명확성과 구체성입니다.

"빠르게 해줘"보다 "시간 복잡도 O(n log n) 이하", "적은 메모리로"보다 "공간 복잡도 O(1)"처럼 측정 가능한 제약을 제시하면 AI가 정확히 따릅니다. 이는 불필요한 반복을 줄이고 개발 속도를 높여줍니다.

코드 예제

# 제약조건 없이 요청
no_constraints = "리스트에서 중복 제거하는 함수 만들어줘"

# 제약조건을 명시한 요청
with_constraints = """
리스트에서 중복을 제거하는 함수를 작성해주세요.

제약조건:
- Python 3.8 이상 표준 라이브러리만 사용 (numpy, pandas 금지)
- 원본 리스트의 순서 유지 필수
- 공간 복잡도: O(n) 허용
- 시간 복잡도: O(n) 이하
- 타입 힌트 필수: list[int] → list[int]
- 빈 리스트 입력 시 빈 리스트 반환
- docstring 필수 (Google 스타일)

예상 사용:
>>> remove_duplicates([1, 2, 2, 3, 1, 4])
[1, 2, 3, 4]
>>> remove_duplicates([])
[]
"""

# 실제로 생성될 코드 예시
def remove_duplicates(items: list[int]) -> list[int]:
    '''Remove duplicates while preserving order.

    Args:
        items: List of integers that may contain duplicates

    Returns:
        New list with duplicates removed, order preserved

    Time Complexity: O(n)
    Space Complexity: O(n)
    '''
    if not items:  # 빈 리스트 처리
        return []

    seen = set()  # 공간 복잡도 O(n)
    result = []
    for item in items:  # 시간 복잡도 O(n)
        if item not in seen:  # set 조회는 O(1)
            seen.add(item)
            result.append(item)
    return result

설명

이것이 하는 일: 위 예시는 제약조건 명시 기법을 사용하여 프로젝트 환경에 정확히 맞는 코드를 받는 방법을 보여줍니다. 제약이 없는 요청과 상세한 제약이 있는 요청을 비교할 수 있어요.

첫 번째로, no_constraints는 "중복 제거 함수 만들어줘"라는 간단한 요청입니다. 이렇게 요청하면 AI는 list(set(items))처럼 간단하지만 순서를 보장하지 않는 코드를 줄 수 있어요.

또는 pandas나 numpy를 사용한 코드를 줄 수도 있죠. 프로젝트에 맞지 않을 가능성이 높습니다.

두 번째로, with_constraints는 7가지 구체적인 제약조건을 명시했습니다. "Python 3.8 표준 라이브러리만"이라고 하여 외부 라이브러리 사용을 막았고, "원본 순서 유지"로 set() 단독 사용을 방지했어요.

"시간/공간 복잡도"로 성능 기준을 제시하고, "타입 힌트"와 "docstring"으로 코드 품질을 요구했습니다. 심지어 예상 사용 예시까지 보여줘서 정확히 어떤 동작을 원하는지 명확히 했죠.

세 번째로, 실제 생성될 코드 예시를 보면 모든 제약조건이 지켜진 것을 확인할 수 있습니다. 표준 라이브러리(set, list)만 사용했고, for 루프로 순서를 유지했으며, seen set으로 O(n) 시간/공간 복잡도를 달성했어요.

타입 힌트가 정확하고, Google 스타일 docstring에는 시간/공간 복잡도까지 명시되어 있습니다. 빈 리스트 처리도 요청대로 구현했죠.

여러분이 이 기법을 사용하면 불필요한 수정 요청을 크게 줄일 수 있습니다. 첫 번째 시도부터 프로젝트 요구사항에 맞는 코드를 받으니까 시간이 절약되죠.

또한 팀 전체가 같은 제약조건 템플릿을 공유하면 코드의 일관성도 높아집니다. 레거시 시스템, 임베디드 환경, 특정 라이브러리 버전 같은 까다로운 환경에서 특히 유용해요.

실전 팁

💡 제약조건은 카테고리별로 분류하세요. "기술 제약", "성능 제약", "코드 스타일", "보안 요구사항"으로 나누면 읽기 쉬워요.

💡 측정 가능한 제약을 사용하세요. "빠르게"보다 "100ms 이하", "적은 메모리"보다 "10MB 이하"가 명확합니다.

💡 "금지 목록"도 명시하세요. "pandas 사용 금지", "전역 변수 금지", "eval() 사용 금지"처럼 하면 안 되는 것을 알려주면 실수를 방지합니다.

💡 버전을 명확히 하세요. "Python 3.8"과 "Python 3.12"는 사용 가능한 기능이 다릅니다. "asyncio (Python 3.11+)" 같은 식으로 명시하세요.

💡 제약조건 템플릿을 만들어두세요. 프로젝트마다 공통된 제약사항을 템플릿으로 저장해두고 재사용하면 편리합니다.


6. 출력_형식_지정_기법

시작하며

여러분이 AI에게 "데이터를 JSON으로 변환해줘"라고 했는데, 막상 받아보니 코드로 감싸져 있거나 설명이 섞여 있어서 바로 사용할 수 없었던 적 있나요? 또는 "테이블로 정리해줘"라고 했는데 마크다운 테이블이 아니라 텍스트로 나열되어 온 경우 말이에요.

이런 문제는 AI가 어떤 형식으로 출력해야 할지 정확히 모를 때 발생합니다. "JSON으로"라고만 하면 AI는 JSON을 설명할 수도 있고, JSON 예시를 보여줄 수도 있고, JSON을 생성하는 코드를 줄 수도 있어요.

여러분이 원하는 게 뭔지 명확하지 않으니까요. 바로 이럴 때 필요한 것이 출력 형식 지정 기법입니다.

AI에게 정확히 어떤 형식으로 답변해야 하는지 템플릿을 제시하면, 바로 복사-붙여넣기할 수 있는 깔끔한 결과를 받을 수 있습니다.

개요

간단히 말해서, 출력 형식 지정은 AI에게 "답변은 정확히 이 형식으로 해줘"라고 템플릿을 제시하는 기법입니다. 마치 양식을 주고 빈칸을 채워달라고 하는 것과 같아요.

왜 이것이 필요할까요? 개발할 때는 특정 형식의 데이터가 필요한 경우가 많기 때문입니다.

API 응답은 JSON이어야 하고, 설정 파일은 YAML이어야 하고, 문서는 마크다운이어야 하고, 로그는 특정 포맷을 따라야 하죠. 예를 들어, "사용자 데이터를 아래 JSON 스키마에 맞춰서 생성해줘"라고 템플릿을 주면 AI가 정확히 그 형식으로 만들어줍니다.

기존에는 AI의 답변을 받고 수동으로 파싱하고 정리했다면, 이제는 원하는 형식을 미리 지정해서 바로 사용 가능한 출력을 받을 수 있습니다. 출력 형식 지정의 핵심은 명확한 템플릿 제공입니다.

빈칸이 있는 예시를 보여주거나, 스키마를 제시하거나, "오직 ~만 출력"처럼 제약을 걸면 AI가 딱 그 형식으로만 답변해요. 이는 자동화와 통합을 훨씬 쉽게 만들어줍니다.

코드 예제

# 형식 지정 없이 요청
vague_request = "사용자 정보를 JSON으로 만들어줘"

# 출력 형식을 명확히 지정한 요청
structured_request = """
아래 JSON 스키마에 정확히 맞춰서 샘플 사용자 데이터 3개를 생성해주세요.
추가 설명 없이 오직 JSON만 출력하세요.

스키마:
{
  "users": [
    {
      "id": "string (UUID v4)",
      "name": "string (2-50자)",
      "email": "string (유효한 이메일)",
      "age": "number (18-100)",
      "role": "string (enum: admin, user, guest)",
      "created_at": "string (ISO 8601 datetime)",
      "is_active": "boolean"
    }
  ]
}

출력 조건:
- 유효한 JSON만 출력 (코드 블록 없이)
- 설명이나 주석 제거
- 실제 사용 가능한 데이터 (테스트 값 말고)
- pretty-print (들여쓰기 2칸)
"""

# 예상 출력 (AI가 이렇게 생성)
expected_output = '''{
  "users": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "김철수",
      "email": "chulsoo@example.com",
      "age": 28,
      "role": "user",
      "created_at": "2024-01-15T09:30:00Z",
      "is_active": true
    },
    {
      "id": "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
      "name": "이영희",
      "email": "younghee@example.com",
      "age": 35,
      "role": "admin",
      "created_at": "2024-01-10T14:22:00Z",
      "is_active": true
    },
    {
      "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
      "name": "박민수",
      "email": "minsoo@example.com",
      "age": 42,
      "role": "guest",
      "created_at": "2024-01-20T11:15:00Z",
      "is_active": false
    }
  ]
}'''

설명

이것이 하는 일: 위 예시는 출력 형식 지정 기법을 사용하여 AI로부터 정확히 원하는 형식의 데이터를 받는 방법을 보여줍니다. 모호한 요청과 구조화된 요청의 차이를 비교할 수 있어요.

첫 번째로, vague_request는 "JSON으로 만들어줘"라는 애매한 요청입니다. 이렇게 요청하면 AI는 JSON의 구조를 어떻게 해야 할지, 어떤 필드를 포함해야 할지, 값의 형식은 어떻게 할지 모릅니다.

결과적으로 간단한 {"name": "홍길동"} 수준의 예시만 받거나, 코드 블록으로 감싸진 설명이 섞인 출력을 받을 수 있어요. 두 번째로, structured_request는 완전히 다릅니다.

JSON 스키마를 명확히 제시했어요. 각 필드의 이름, 데이터 타입, 제약조건("UUID v4", "2-50자", "enum: admin, user, guest")을 상세히 명시했습니다.

더 중요한 건 "출력 조건"에서 "유효한 JSON만", "코드 블록 없이", "설명이나 주석 제거"처럼 출력 방식까지 정확히 지정했다는 거예요. 세 번째로, expected_output은 AI가 실제로 생성할 결과입니다.

요청한 스키마에 정확히 맞게 users 배열에 3개의 객체가 있고, 각 객체는 7개 필드를 모두 포함하며, 타입과 제약조건을 준수합니다. UUID는 실제 UUID v4 형식이고, 이메일은 유효한 형식이며, role은 지정된 enum 값만 사용했어요.

들여쓰기도 요청대로 2칸이고, 코드 블록이나 설명 없이 순수 JSON만 있습니다. 여러분이 이 기법을 사용하면 AI의 출력을 수동으로 파싱하거나 정리할 필요가 없습니다.

받은 데이터를 바로 파일에 저장하거나 API로 전송할 수 있죠. 특히 자동화 스크립트나 CI/CD 파이프라인에서 AI를 사용할 때 필수적입니다.

또한 여러 번 요청해도 항상 같은 형식으로 받으니까 일관성이 보장돼요.

실전 팁

💡 "오직 ~만 출력"이라는 표현을 사용하세요. "오직 JSON만", "오직 코드만", "오직 숫자만"처럼 명확히 하면 불필요한 설명이 제거됩니다.

💡 스키마나 예시 템플릿을 제공하세요. 빈 JSON 구조를 보여주고 "이 형식으로 채워줘"라고 하면 정확도가 높아져요.

💡 검증 조건을 명시하세요. "유효한 JSON (JSON.parse로 파싱 가능)", "유효한 YAML (문법 오류 없음)"처럼 검증 기준을 알려주면 AI가 더 신경 씁니다.

💡 구분자를 명확히 하세요. CSV라면 "쉼표 구분", TSV라면 "탭 구분"처럼 정확히 지정하세요. "구분자: |"처럼 특수한 구분자도 가능해요.

💡 여러 형식이 필요하면 명확히 나누세요. "먼저 JSON으로, 그 다음 줄에 요약을 마크다운으로"처럼 순서와 형식을 모두 지정하면 혼란이 없어요.


7. 반복적_개선_기법

시작하며

여러분이 AI에게 코드를 요청했는데, 결과가 60% 정도만 만족스러워서 "이것도 추가해줘", "저것도 바꿔줘"를 몇 번이나 반복한 적 있나요? 매번 새로운 요청을 하면서 이전 맥락을 다시 설명해야 해서 피곤했던 경험 말이에요.

이런 문제는 복잡한 요구사항을 한 번에 완벽히 표현하기 어렵기 때문에 발생합니다. 실제로 원하는 게 뭔지는 결과를 보고 나서야 명확해지는 경우가 많죠.

또한 AI도 첫 시도에서 100% 완벽한 결과를 내기는 어려워요. 바로 이럴 때 필요한 것이 반복적 개선 기법입니다.

첫 번째 결과를 보고 구체적인 피드백을 주면서 점진적으로 개선해나가는 방식이죠. 이렇게 하면 최종적으로 훨씬 좋은 결과를 얻을 수 있습니다.

개요

간단히 말해서, 반복적 개선은 AI와 여러 번의 대화를 통해 결과물을 점점 더 나은 방향으로 다듬어가는 기법입니다. 마치 조각가가 돌을 조금씩 깎아서 완성하는 것과 같아요.

왜 이것이 필요할까요? 복잡한 기능, 정교한 알고리즘, 세밀한 UI 같은 건 한 번에 완벽하게 만들기 어렵기 때문입니다.

예를 들어, "데이터 대시보드 만들어줘"라고 하면 기본적인 것만 나오지만, "차트 크기 키워줘", "색상 테마 변경", "툴팁 추가", "필터 기능 추가"처럼 단계적으로 요청하면 점점 완성도가 높아지죠. 기존에는 "안 되면 처음부터 다시"였다면, 이제는 "좋은 부분은 유지하고 아쉬운 부분만 개선"할 수 있습니다.

이전 대화의 맥락을 AI가 기억하니까 효율적이에요. 반복적 개선의 핵심은 구체적인 피드백입니다.

"더 좋게"보다 "함수명을 calculate_sum에서 get_total_amount로 변경", "에러 처리 추가", "타입 체크 강화"처럼 정확히 무엇을 바꿀지 말하면 AI가 딱 그 부분만 수정합니다. 이는 개발 과정을 더 유연하고 효율적으로 만들어줘요.

코드 예제

# 첫 번째 요청
initial_request = """
사용자 검색 함수를 만들어주세요.
- 함수명: search_users
- 입력: 검색어 (문자열)
- 출력: 매칭되는 사용자 리스트
"""

# AI가 생성한 첫 번째 버전
def search_users(query: str) -> list[dict]:
    users = get_all_users()  # 모든 사용자 조회
    return [u for u in users if query in u['name']]

# 개선 요청 1: 성능 개선
feedback_1 = """
좋습니다! 그런데 몇 가지 개선이 필요해요:

3. None 값 처리 (name이나 email이 None일 수 있음)

설명

이것이 하는 일: 위 예시는 반복적 개선 기법을 사용하여 간단한 함수를 프로덕션 수준의 코드로 발전시키는 과정을 보여줍니다. 세 단계의 요청과 개선을 통해 점점 완성도가 높아지는 걸 볼 수 있어요.

첫 번째로, initial_request는 아주 기본적인 요청입니다. 함수의 핵심 기능만 명시했어요.

AI는 이를 바탕으로 첫 번째 버전을 만들었는데, 작동은 하지만 여러 문제가 있습니다. 대소문자를 구분하고, 이름만 검색하며, 빈 검색어 처리가 없죠.

하지만 이게 나쁜 게 아니에요. 오히려 빠르게 프로토타입을 받고 구체적으로 무엇이 필요한지 확인할 수 있는 좋은 출발점입니다.

두 번째로, feedback_1은 첫 번째 결과를 보고 발견한 3가지 개선사항을 명확히 지적합니다. "좋습니다!"라고 긍정적인 피드백을 먼저 주고, 번호를 매겨서 구체적인 요구사항을 나열했어요.

AI는 이 피드백을 받고 두 번째 버전을 만들었는데, 세 가지 요구사항이 모두 반영됐습니다. 대소문자 구분 없이 검색하고, 이름과 이메일을 모두 확인하며, 빈 검색어를 처리하죠.

세 번째로, feedback_2는 기능적으로는 완성됐지만 코드 품질을 높이는 요청입니다. TypedDict로 타입 안정성을 강화하고, docstring으로 문서화하며, None 값 처리로 견고성을 높이라고 했어요.

최종 완성 버전은 이 모든 것을 반영했습니다. TypedDict로 User 타입을 정의했고, 상세한 docstring과 예시를 추가했으며, .get()과 or ''로 None 값을 안전하게 처리합니다.

여러분이 이 기법을 사용하면 완벽한 요구사항을 처음부터 작성하는 부담에서 벗어날 수 있습니다. 일단 빠르게 프로토타입을 받고, 실제로 보면서 "아, 이것도 필요하구나"를 발견하고 추가하면 돼요.

이는 애자일 개발 방식과도 잘 맞고, AI의 장점인 빠른 반복을 최대한 활용하는 방법입니다. 또한 각 단계마다 검증할 수 있어서 버그를 조기에 발견할 수 있어요.

실전 팁

💡 긍정적인 피드백을 먼저 하세요. "좋습니다만", "잘했어요, 그런데"처럼 시작하면 AI가 좋은 부분은 유지하고 지적한 부분만 바꿉니다.

💡 한 번에 3~5가지만 개선 요청하세요. 너무 많으면 AI가 놓치는 부분이 생길 수 있어요. 여러 번 나눠서 요청하는 게 정확합니다.

💡 "이전 코드는 유지하고"라고 명시하세요. 특정 부분만 바꾸고 싶을 때 "나머지는 그대로 두고 X만 변경"이라고 하면 불필요한 변경이 없어요.

💡 변경 이유를 설명하세요. "성능을 위해", "보안을 위해", "유지보수를 위해"처럼 왜 바꾸는지 말하면 AI가 그 맥락에 맞게 개선합니다.

💡 각 버전을 저장하세요. Git 커밋처럼 각 개선 단계를 저장해두면 나중에 "2단계로 롤백"처럼 되돌릴 수 있어요.


8. 맥락_제공_기법

시작하며

여러분이 AI에게 "이 에러 고쳐줘"라고 했는데, 에러 메시지만 보내서 AI가 "코드를 보여주세요"라고 되묻는 경우가 있었나요? 또는 "이 함수 최적화해줘"라고 했는데 전체 시스템을 모르니까 엉뚱한 방향으로 최적화한 경우 말이에요.

이런 문제는 AI에게 충분한 맥락을 제공하지 않았을 때 발생합니다. AI는 여러분의 프로젝트 구조, 사용 중인 라이브러리, 코드의 의도를 모릅니다.

마치 소설의 중간 한 페이지만 보고 이야기를 이해하려는 것과 같죠. 바로 이럴 때 필요한 것이 맥락 제공 기법입니다.

문제가 발생한 환경, 관련 코드, 기대 동작, 실제 동작을 함께 알려주면 AI가 정확한 해결책을 제시할 수 있습니다.

개요

간단히 말해서, 맥락 제공은 AI에게 문제를 이해하는 데 필요한 모든 배경 정보를 함께 주는 기법입니다. 마치 의사에게 "배가 아파요"가 아니라 "어제 뭘 먹었고, 언제부터 어떻게 아프고, 다른 증상은..."처럼 상세히 설명하는 것과 같아요.

왜 이것이 필요할까요? 같은 에러도 상황에 따라 원인과 해결책이 완전히 다르기 때문입니다.

"NullPointerException"이 나왔을 때, 데이터베이스 연결 실패 때문인지, API 응답이 null인지, 잘못된 초기화인지에 따라 해법이 달라지죠. 예를 들어, "Django 3.2 환경에서 PostgreSQL 사용 중, async view에서 ORM 쿼리 시 에러 발생"처럼 맥락을 주면 정확한 진단을 받을 수 있습니다.

기존에는 AI가 여러 번 질문하고 여러분이 추가 정보를 주는 왕복이 필요했다면, 이제는 처음부터 필요한 맥락을 모두 주면 한 번에 정확한 답을 얻을 수 있습니다. 맥락 제공의 핵심은 환경, 코드, 에러, 기대값의 4가지입니다.

어떤 환경에서 어떤 코드를 실행했더니 어떤 에러가 나고, 원래는 어떻게 되어야 하는지를 모두 알려주면 AI가 정확히 진단할 수 있어요. 이는 디버깅 시간을 크게 단축시켜줍니다.

코드 예제

# 맥락 없는 요청 (나쁜 예시)
bad_request = "이 에러 고쳐줘: AttributeError: 'NoneType' object has no attribute 'id'"

# 맥락을 충분히 제공한 요청 (좋은 예시)
good_request = """
다음 에러를 해결해주세요:

환경:
- Python 3.11
- Django 4.2
- PostgreSQL 14
- 비동기 뷰 사용 (async def)

관련 코드:
# views.py
async def get_user_profile(request, user_id):
    user = await User.objects.get(id=user_id)
    posts = await Post.objects.filter(author=user)  # 여기서 에러 발생
    return JsonResponse({
        'user': user.id,
        'posts': [p.id for p in posts]
    })

# models.py
class User(models.Model):
    username = models.CharField(max_length=100)

class Post(models.Model):
    author = models.ForeignKey(User, on_delete=models.CASCADE)
    content = models.TextField()

에러 메시지:
AttributeError: 'NoneType' object has no attribute 'id'
File "views.py", line 4, in get_user_profile
    posts = await Post.objects.filter(author=user)

기대 동작:
- 특정 사용자의 프로필과 그 사용자의 모든 포스트를 JSON으로 반환
- 사용자가 없으면 404 반환

실제 동작:
- 사용자 ID 123으로 요청 시 AttributeError 발생
- 사용자 ID 123은 DB에 존재함 (확인함)

시도한 해결책:
- sync_to_async 래퍼 사용 → 같은 에러
- .aget()으로 변경 → 같은 에러
"""

# AI가 제공할 해결책 예시
solution = """
문제 원인:
Django ORM의 async 쿼리는 await으로 실행하면 실제 객체가 아니라
쿼리셋을 반환합니다. 그래서 user는 None이 아니지만
사용할 수 없는 상태입니다.

해결책:
from asgiref.sync import sync_to_async

async def get_user_profile(request, user_id):
    # get_object_or_404를 async로 래핑
    user = await sync_to_async(User.objects.get)(id=user_id)

    # 쿼리셋을 리스트로 변환
    posts = await sync_to_async(list)(
        Post.objects.filter(author=user)
    )

    return JsonResponse({
        'user': user.id,
        'posts': [p.id for p in posts]
    })

또는 Django 4.1+라면:
async def get_user_profile(request, user_id):
    user = await User.objects.aget(id=user_id)
    posts = [p async for p in Post.objects.filter(author=user)]

    return JsonResponse({
        'user': user.id,
        'posts': [p.id for p in posts]
    })
"""

설명

이것이 하는 일: 위 예시는 맥락 제공 기법을 사용하여 복잡한 버그를 효과적으로 해결하는 방법을 보여줍니다. 맥락이 부족한 요청과 충분한 맥락이 있는 요청의 차이를 비교할 수 있어요.

첫 번째로, bad_request는 에러 메시지만 덩그러니 제공합니다. "AttributeError: 'NoneType' object has no attribute 'id'"만 보면 AI는 수많은 가능성을 고려해야 해요.

변수가 None인지, 딕셔너리 접근 실패인지, 객체 초기화 문제인지 알 수 없죠. 결국 "코드를 보여주세요", "어떤 상황에서 발생하나요?"같은 추가 질문을 하게 됩니다.

두 번째로, good_request는 완전히 다릅니다. 먼저 "환경" 섹션에서 Python 3.11, Django 4.2, PostgreSQL 14, 비동기 뷰 사용이라는 중요한 맥락을 줬어요.

이것만으로도 AI는 "Django async ORM 문제일 수 있겠다"고 방향을 잡습니다. "관련 코드"에서는 views.py와 models.py를 모두 보여줘서 데이터 구조와 코드 흐름을 이해할 수 있게 했죠.

세 번째로, "에러 메시지"는 전체 traceback을 제공하여 정확히 어느 줄에서 문제가 발생했는지 알려줍니다. "기대 동작"과 "실제 동작"으로 무엇이 잘못됐는지 명확히 하고, "시도한 해결책"으로 이미 시도했던 방법을 알려줘서 같은 제안을 반복하지 않게 했어요.

이 모든 맥락 덕분에 AI는 "Django async ORM의 특정 버전 이슈"라고 정확히 진단하고, 두 가지 해결책(sync_to_async 래핑, async comprehension)을 제시할 수 있습니다. 여러분이 이 기법을 사용하면 디버깅 시간이 크게 줄어듭니다.

AI와 10번 왕복하는 대신 한 번에 정확한 답을 받으니까요. 또한 맥락을 정리하는 과정에서 스스로 문제를 발견하는 경우도 많아요.

"환경이 뭐지?"를 생각하다가 "아, 파이썬 버전이 달랐네!"처럼 깨닫게 되죠. 이는 러버덕 디버깅과 비슷한 효과도 있습니다.

실전 팁

💡 환경 정보는 버전까지 명시하세요. "Django"보다 "Django 4.2.7"이 훨씬 정확합니다. 버전에 따라 동작이 다른 경우가 많아요.

💡 최소 재현 코드를 만드세요. 1000줄 코드보다 문제를 재현하는 10줄 코드가 더 유용합니다. 핵심만 추출하세요.

💡 에러는 전체 traceback을 주세요. 마지막 줄만 주지 말고 전체 스택 트레이스를 보여주면 AI가 호출 경로를 파악합니다.

💡 "되어야 하는데 안 됨"을 명시하세요. 기대 동작과 실제 동작의 차이를 명확히 하면 문제 범위가 좁혀집니다.

💡 관련 설정 파일도 포함하세요. requirements.txt, package.json, .env 같은 설정이 문제의 원인일 수 있어요.


#AI#PromptEngineering#ChatGPT#LLM#OpenAI

댓글 (0)

댓글을 작성하려면 로그인이 필요합니다.