AI Prompt Engineering · 강의

프롬프트 연결에서 오류 처리

중간 출력을 검증하고 연결 과정의 실패에서 복구합니다.

레슨 4/413개 단계

프롬프트 연결에서 오류 처리은(는) CoddyKit의 무료 AI Prompt Engineering 강의입니다. 이것은 4개 중 4번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 AI Prompt Engineering 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. AI Prompt Engineering 강의에는 총 4개의 강의가 포함되어 있습니다.

체인이 실패하는 이유

프롬프트 체인에는 단일 프롬프트 시스템에는 없는 새로운 실패 방식이 발생합니다. 각 단계가 저마다의 방식으로 실패할 수 있으며, 실패가 누적됩니다. 잘못된 2단계 출력은 이후의 모든 단계를 손상시킵니다.

일반적인 실패 방식은 다음과 같습니다.

  • 모델이 구문 분석할 수 없는 잘못된 형식의 JSON을 반환합니다
  • 모델이 작업을 잘못 이해하여 의미상 잘못된 출력을 생성합니다
  • 요청 한도 또는 API 시간 초과로 단계가 실패합니다
  • 긴 체인에서 문맥 창의 한도를 초과합니다
  • 모델이 데이터를 환각하여 이후 단계가 이를 사실로 취급합니다

모든 단계 후 출력 검증

첫 번째 방어선은 각 단계가 끝난 즉시 출력을 검증한 후 다음 단계로 전달하는 것입니다. 모델이 요청한 내용을 반환했다고 절대 가정하지 마십시오.

import json

def validate_json_output(raw_text, required_fields):
    'Parse and validate that required fields are present in model output.'
    try:
        data = json.loads(raw_text.strip())
    except json.JSONDecodeError as e:
        raise ValueError(f'Invalid JSON: {e}. Raw: {raw_text[:200]}')

    missing = [f for f in required_fields if f not in data]
    if missing:
        raise ValueError(f'Missing required fields: {missing}. Got: {list(data.keys())}')

    return data

# Usage after a chain step
raw = '{"sentiment": "positive", "priority": "high"}'
validated = validate_json_output(raw, required_fields=['sentiment', 'priority'])
print('Valid:', validated)

일시적 오류를 위한 재시도 로직

API 오류(요청 한도, 시간 초과, 서버 오류)는 일시적일 수 있습니다. 네트워크 수준의 오류에는 지수적 대기 시간을 적용하는 재시도 로직을 구현하십시오.

import anthropic, time

client = anthropic.Anthropic(api_key='YOUR_API_KEY')

def call_with_retry(prompt, max_retries=3, base_delay=1.0):
    last_error = None
    for attempt in range(max_retries):
        try:
            r = client.messages.create(
                model='claude-opus-4-5', max_tokens=500,
                messages=[{'role': 'user', 'content': prompt}]
            )
            return r.content[0].text
        except anthropic.RateLimitError as e:
            wait = base_delay * (2 ** attempt)
            print(f'Rate limited. Waiting {wait}s before retry {attempt+1}/{max_retries}...')
            time.sleep(wait)
            last_error = e
        except anthropic.APIError as e:
            last_error = e
            if attempt < max_retries - 1:
                time.sleep(base_delay)
    raise RuntimeError(f'All retries exhausted: {last_error}')

의미 검증

일부 오류는 구조적으로는 유효하지만 의미상 잘못되어 있습니다. 모델이 유효한 JSON을 반환했지만 값이 잘못된 경우입니다. 의미가 올바른지 확인하려면 가벼운 검증 단계를 사용하십시오.

def semantic_validate(data, schema_rules):
    'Apply semantic validation rules to parsed output.'
    errors = []

    for field, rules in schema_rules.items():
        value = data.get(field)

        if rules.get('required') and value is None:
            errors.append(f'{field} is required but missing')
            continue

        if 'allowed_values' in rules and value not in rules['allowed_values']:
            errors.append(f'{field} must be one of {rules["allowed_values"]}, got: {value}')

        if 'min_length' in rules and isinstance(value, list) and len(value) < rules['min_length']:
            errors.append(f'{field} must have at least {rules["min_length"]} items, got {len(value)}')

    if errors:
        raise ValueError('Semantic validation failed: ' + '; '.join(errors))

    return data

rules = {'sentiment': {'allowed_values': ['positive', 'negative', 'mixed']}, 'issues': {'min_length': 1}}
data = {'sentiment': 'positive', 'issues': ['login bug']}
print(semantic_validate(data, rules))

대체 프롬프트

재시도 후에도 단계의 검증이 실패하면 대체 프롬프트를 사용하여 전체 체인을 중단하는 대신 더 단순하지만 사용할 수 있는 출력을 생성할 수 있습니다.

import json

def call_with_fallback(primary_prompt, fallback_prompt, required_fields):
    # Try primary prompt
    try:
        raw = call_with_retry(primary_prompt)
        return validate_json_output(raw, required_fields)
    except (ValueError, RuntimeError) as e:
        print(f'Primary prompt failed: {e}. Trying fallback...')

    # Try simpler fallback prompt
    try:
        raw = call_with_retry(fallback_prompt)
        return validate_json_output(raw, required_fields)
    except (ValueError, RuntimeError) as e:
        print(f'Fallback also failed: {e}. Returning safe default.')

    # Return safe default — chain continues with minimal data
    return {field: None for field in required_fields}

# Usage
primary = 'Analyze this review. Return JSON with 10 fields: {...}'
fallback = 'Classify this review. Return JSON: {"sentiment": "positive|negative|neutral"}'
result = call_with_fallback(primary, fallback, ['sentiment'])
print(result)

회로 차단기

회로 차단기는 실패하는 체인이 API 호출을 낭비하지 않도록 합니다. 연속해서 N번 실패하면 회로를 열고 추가 API 호출 없이 즉시 오류를 반환합니다.

class CircuitBreaker:
    def __init__(self, failure_threshold=3, recovery_timeout=60):
        self.failure_count = 0
        self.threshold = failure_threshold
        self.state = 'closed'  # closed = normal, open = blocking
        self.opened_at = None

    def call(self, fn, *args, **kwargs):
        import time
        if self.state == 'open':
            elapsed = time.time() - self.opened_at
            if elapsed > 60:  # recovery_timeout
                self.state = 'half-open'
            else:
                raise RuntimeError('Circuit open — skipping API call')
        try:
            result = fn(*args, **kwargs)
            self.failure_count = 0
            self.state = 'closed'
            return result
        except Exception as e:
            self.failure_count += 1
            if self.failure_count >= self.threshold:
                self.state = 'open'
                self.opened_at = time.time()
                print(f'Circuit opened after {self.failure_count} failures.')
            raise e

cb = CircuitBreaker(failure_threshold=3)
print('Circuit breaker initialized.')

긴 체인의 중간 결과 저장

단계가 많거나 비용이 많이 드는 체인에서는 중간 결과를 저장하십시오. 나중 단계가 실패하면 1단계부터 다시 시작하지 않고 저장된 지점에서 재개할 수 있습니다.

import json, os

CHECKPOINT_DIR = '/tmp/chain_checkpoints'
os.makedirs(CHECKPOINT_DIR, exist_ok=True)

def save_checkpoint(run_id, step_id, data):
    path = os.path.join(CHECKPOINT_DIR, f'{run_id}_step{step_id}.json')
    with open(path, 'w') as f:
        json.dump(data, f)
    print(f'Checkpoint saved: step {step_id}')

def load_checkpoint(run_id, step_id):
    path = os.path.join(CHECKPOINT_DIR, f'{run_id}_step{step_id}.json')
    if os.path.exists(path):
        with open(path) as f:
            return json.load(f)
    return None

def run_with_checkpoints(run_id, input_data):
    step1 = load_checkpoint(run_id, 1) or json.loads(call(f'Step 1 processing: {input_data}'))
    save_checkpoint(run_id, 1, step1)

    step2 = load_checkpoint(run_id, 2) or json.loads(call(f'Step 2 processing: {step1}'))
    save_checkpoint(run_id, 2, step2)

    return step2

print('Checkpointing system defined.')

점진적 기능 저하

체인의 한 단계가 실패하고 복구할 수 없는 경우, 점진적 기능 저하를 적용하면 전체를 중단하는 대신 부분적인 데이터로 체인을 계속 진행할 수 있습니다.

def process_with_degradation(tickets):
    results = []
    for ticket in tickets:
        try:
            # Full chain: extract -> classify -> respond
            extracted = json.loads(call(f'Extract issue from ticket. Return JSON: {{"issue": str}}\n\n{ticket}'))
            classified = json.loads(call(f'Classify priority. Return JSON: {{"priority": str}}\n\n{extracted["issue"]}'))
            response = call(f'Draft response for {classified["priority"]} priority: {extracted["issue"]}')
            results.append({'ticket': ticket, 'response': response, 'degraded': False})
        except Exception as e:
            print(f'Chain failed for ticket, using fallback: {e}')
            # Fallback: simple direct response without classification
            simple_response = call(f'Respond to this support ticket:\n{ticket}')
            results.append({'ticket': ticket, 'response': simple_response, 'degraded': True})
    return results

print('Graceful degradation pipeline defined.')

구조화된 오류 기록

어느 단계가 실패했는지, 입력이 무엇이었는지, 모델이 무엇을 반환했는지 진단할 수 있을 만큼 충분한 문맥과 함께 오류를 기록하십시오.

import logging, traceback
from datetime import datetime

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger('chain')

def logged_step(step_name, prompt, validator=None):
    start = datetime.utcnow()
    try:
        raw = call_with_retry(prompt)
        result = validator(raw) if validator else raw
        logger.info(f'[{step_name}] SUCCESS in {(datetime.utcnow()-start).total_seconds():.2f}s')
        return result
    except Exception as e:
        logger.error(f'[{step_name}] FAILED after {(datetime.utcnow()-start).total_seconds():.2f}s')
        logger.error(f'[{step_name}] PROMPT: {prompt[:200]}')
        logger.error(f'[{step_name}] ERROR: {traceback.format_exc()}')
        raise

print('Structured error logging defined.')

오류 상황 테스트

오류를 주입하여 오류 처리를 명시적으로 테스트하십시오. 모의 객체를 사용하여 API 오류와 잘못된 형식의 출력을 시뮬레이션하십시오.

from unittest.mock import patch, MagicMock

def test_fallback_on_json_error():
    with patch('__main__.call') as mock_call:
        # First call returns malformed JSON, fallback returns valid JSON
        mock_call.side_effect = [
            'This is not JSON at all',
            '{"sentiment": "positive"}'
        ]

        result = call_with_fallback(
            primary_prompt='Analyze review with 10 fields',
            fallback_prompt='Just classify sentiment as JSON',
            required_fields=['sentiment']
        )

        assert result['sentiment'] == 'positive'
        print('PASS: fallback activated correctly on JSON parse error')

def test_circuit_breaker_opens():
    cb = CircuitBreaker(failure_threshold=2)
    for i in range(2):
        try:
            cb.call(lambda: (_ for _ in ()).throw(RuntimeError('API fail')))
        except RuntimeError:
            pass
    assert cb.state == 'open'
    print('PASS: circuit breaker opened after 2 failures')

print('Error handling tests defined.')

운영 환경에서 체인 상태 모니터링

운영 환경에서는 체인 상태 지표를 추적하여 사용자가 성능 저하를 알아차리기 전에 이를 감지하십시오.

  • 단계 성공률: 각 단계가 첫 시도에 성공한 실행의 비율
  • 대체 처리 활성화율: 대체 프롬프트가 사용되는 빈도
  • 기능 저하율: 기능 저하 모드로 완료되는 체인 실행의 비율
  • 단계 지연 시간: 단계별 p50/p95 지연 시간을 추적하십시오. 느린 단계는 프롬프트 복잡성에 문제가 있음을 나타냅니다
  • 검증 실패율: 높은 실패율은 프롬프트를 개선해야 한다는 신호입니다

빠른 확인

프롬프트 체인에서 회로 차단기의 목적은 무엇입니까?

체인의 오류 처리 — 핵심 요점

견고한 오류 처리가 프로토타입 체인과 운영 환경용 시스템을 구분합니다.

  • 각 단계의 출력을 하위 단계로 전달하기 전에 검증하십시오. 모델이 올바른 데이터를 반환했다고 절대 가정하지 마십시오
  • 일시적인 API 오류는 지수적 대기를 적용하여 재시도하십시오. 요청 한도와 시간 초과는 복구할 수 있습니다
  • 기본 프롬프트의 의미 검증이 실패하면 더 단순한 출력을 생성하도록 대체 프롬프트를 사용하십시오
  • 회로 차단기는 반복되는 실패 후 API 호출 낭비를 막습니다
  • 비용이 많이 드는 단계를 중간 저장하여 긴 체인이 나중 단계의 실패 후 재개될 수 있도록 하십시오
  • 점진적 기능 저하는 중단하는 대신 부분적인 데이터로 파이프라인을 계속 실행합니다
  • 운영 환경에서 단계 성공률, 대체 처리율, 기능 저하율을 추적하십시오
무료로 시작

AI 튜터와 함께 AI Prompt Engineering을(를) 배우세요 — 무료

브라우저에서 실제 코드를 작성하고 실행하며, 24/7 AI 튜터로부터 즉각적인 도움을 받고, 웹이나 앱에서 중단한 부분부터 계속 학습하세요.

코스
53
레슨
199

자주 묻는 질문

“프롬프트 연결에서 오류 처리” 강의는 무료인가요?

네 — “프롬프트 연결에서 오류 처리” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 AI Prompt Engineering 강의 전체를 잠금 해제할 수 있습니다. AI Prompt Engineering 강의에는 총 4개의 강의가 포함되어 있습니다.

“프롬프트 연결에서 오류 처리”에서 뭘 배우나요?

중간 출력을 검증하고 연결 과정의 실패에서 복구합니다. 브라우저에서 직접 실행하는 실습 코드로 AI Prompt Engineering을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

AI Prompt Engineering을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 AI Prompt Engineering은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 4번째 강의입니다.

“프롬프트 연결에서 오류 처리” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 AI Prompt Engineering 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 AI Prompt Engineering 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. 프롬프트 연결이란 무엇인가
  2. 출력을 입력으로 연결하는 패턴
  3. 순차 변환 연결
  4. 프롬프트 연결에서 오류 처리
← AI Prompt Engineering(으)로 돌아가기