Claude

Claude Fable 5 실전 가이드 — API 연동부터 에이전트 설계까지

cell-devlog 2026. 6. 10. 08:44
반응형

Fable 5 어제 떴고, 오늘 바로 프로덕션에 붙이려는 분들 있을 겁니다. 공식 문서 다 읽고 핵심만 정리했습니다.


핵심 요약

→ API 모델 ID: claude-fable-5 — 오늘부터 바로 사용 가능
→ Opus 4.8에서 마이그레이션 시 모델명 교체 외에 Fallback API 설정 추가 필요
→ 보안·생물학·화학·증류 감지 시 자동으로 Opus 4.8 응답 — 별도 예외 처리 필수
→ 프롬프트 캐싱 90% 할인 적용 — 에이전트 루프에서 비용 핵심
→ 장기 자율 작업 설계 시 파일 기반 외부 메모리 구조 권장
→ 30일 데이터 보존 정책 필수 — 기업 환경에서 데이터 거버넌스 사전 검토 필요
→ US 전용 추론 필요 시 1.1배 요금으로 미국 내 처리 선택 가능
→ 서브에이전트 위임 구조에서 Fable 5 성능이 가장 두드러짐
→ 단순 반복 작업은 Fable 5로 오케스트레이터, Haiku로 워커 분리 권장
→ max_tokens 설정 넉넉하게 — 자체 검증 루프 돌릴 공간 확보 필요


실전 1 — 기본 API 연동

Opus 4.8을 쓰고 있었다면 모델명 하나만 바꾸면 됩니다. 단, Fallback API 설정을 빠뜨리면 보안·생물학 관련 요청이 들어왔을 때 처리 방식이 예상과 다를 수 있습니다.

import anthropic

client = anthropic.Anthropic()

response = client.messages.create(
    model="claude-fable-5",          # 모델명 변경
    max_tokens=16000,                # 자체 검증 루프 공간 확보
    system="당신은 시니어 소프트웨어 엔지니어입니다.",
    messages=[
        {"role": "user", "content": "레거시 Python 2 코드를 Python 3으로 마이그레이션해줘."}
    ]
)

print(response.content[0].text)

# fallback 여부 확인
# Fable 5가 Opus 4.8로 넘긴 경우 응답 메타데이터에 표시됨
if hasattr(response, 'model') and 'opus' in response.model:
    print("⚠️ 이 요청은 Opus 4.8로 fallback됐습니다.")

개념 박스 — Fallback이란? Fable 5의 안전 분류기가 위험 영역으로 판단한 요청을 Opus 4.8로 자동 라우팅하는 구조입니다. 사용자에게는 응답이 어느 모델에서 왔는지 표시되고, 과금도 Opus 4.8 기준으로 적용됩니다. API 고객은 Fallback API를 별도로 설정해야 합니다.


실전 2 — Fallback API 설정

API 고객은 플랫폼 콘솔에서 Fallback API를 명시적으로 설정해야 합니다. 설정하지 않으면 fallback 발생 시 동작이 정의되지 않습니다.

# Fallback 응답 처리 패턴
import anthropic

client = anthropic.Anthropic()

def call_fable_with_fallback_handling(prompt: str, system: str = ""):
    response = client.messages.create(
        model="claude-fable-5",
        max_tokens=16000,
        system=system,
        messages=[{"role": "user", "content": prompt}]
    )
    
    # fallback 발생 여부 체크
    used_model = getattr(response, 'model', 'claude-fable-5')
    is_fallback = 'opus' in used_model.lower()
    
    return {
        "content": response.content[0].text,
        "is_fallback": is_fallback,
        "model_used": used_model,
        # fallback 시 Opus 요금으로 과금됨
        "billing_note": "Opus 4.8 요금 적용" if is_fallback else "Fable 5 요금 적용"
    }

result = call_fable_with_fallback_handling(
    prompt="이 코드에서 SQL injection 취약점 찾아줘.",
    system="보안 감사 도우미입니다."
)

if result["is_fallback"]:
    # 보안 관련 질문 → Opus로 fallback됨
    # 필요 시 다른 처리 로직 삽입
    print(f"Fallback 발생: {result['billing_note']}")

print(result["content"])

개념 박스 — fallback 발생 빈도 Anthropic 공식 발표 기준으로 전체 세션의 5% 미만에서 발생합니다. 보안·생물학 전문 서비스가 아닌 이상 대부분의 프로덕션 환경에서는 거의 신경 쓸 필요 없는 수준입니다.


실전 3 — 프롬프트 캐싱으로 비용 최적화

Fable 5는 입력 토큰에 90% 캐싱 할인이 적용됩니다. 에이전트 루프처럼 시스템 프롬프트가 반복되는 구조에서는 이게 비용의 핵심입니다.

import anthropic

client = anthropic.Anthropic()

# 긴 시스템 프롬프트를 캐싱 대상으로 지정
SYSTEM_PROMPT = """
당신은 시니어 풀스택 엔지니어입니다.
[... 길고 상세한 컨텍스트 ...]
""" * 50  # 실제 프로덕션에서는 코드베이스 컨텍스트, 아키텍처 문서 등

response = client.messages.create(
    model="claude-fable-5",
    max_tokens=16000,
    system=[
        {
            "type": "text",
            "text": SYSTEM_PROMPT,
            "cache_control": {"type": "ephemeral"}  # 캐싱 활성화
        }
    ],
    messages=[
        {"role": "user", "content": "auth 모듈 리팩토링 계획 세워줘."}
    ]
)

# 캐시 사용 현황 확인
usage = response.usage
print(f"캐시 히트: {usage.cache_read_input_tokens} 토큰")
print(f"신규 입력: {usage.input_tokens} 토큰")
비용 비교 (시스템 프롬프트 50,000 토큰, 100회 루프 기준)

캐싱 미적용:
  입력 비용 = $10 × (50,000 × 100) / 1,000,000 = $50.00

캐싱 적용 (첫 번째 이후):
  입력 비용 = $10 × 0.1 × (50,000 × 99) / 1,000,000 = $4.95
  절감액 ≈ $45

개념 박스 — ephemeral 캐시 Anthropic의 프롬프트 캐시는 세션 내에서 동일한 프리픽스가 반복될 때 자동 재활용됩니다. cache_control: ephemeral으로 명시적으로 지정하면 캐시 우선순위가 높아집니다. 출력 토큰은 캐싱 대상이 아닙니다.


실전 4 — 장기 자율 에이전트 설계

Fable 5의 핵심 강점은 며칠짜리 작업을 스스로 이어가는 능력입니다. 이를 최대한 활용하려면 파일 기반 외부 메모리 구조로 설계하는 게 중요합니다.

import anthropic
import json
from pathlib import Path

client = anthropic.Anthropic()

class Fable5LongRunningAgent:
    def __init__(self, project_id: str):
        self.project_id = project_id
        self.memory_file = Path(f"agent_memory_{project_id}.json")
        self.memory = self._load_memory()
    
    def _load_memory(self) -> dict:
        if self.memory_file.exists():
            return json.loads(self.memory_file.read_text())
        return {
            "completed_steps": [],
            "current_step": None,
            "notes": [],
            "errors": []
        }
    
    def _save_memory(self):
        self.memory_file.write_text(json.dumps(self.memory, ensure_ascii=False, indent=2))
    
    def run_step(self, task: str) -> str:
        # 이전 작업 컨텍스트를 메모리에서 복원
        context = f"""
이전 완료 단계: {json.dumps(self.memory['completed_steps'], ensure_ascii=False)}
현재 메모: {json.dumps(self.memory['notes'], ensure_ascii=False)}
이전 오류: {json.dumps(self.memory['errors'], ensure_ascii=False)}

현재 작업: {task}

작업 완료 후 다음 형식으로 응답해줘:
{{
  "result": "작업 결과 요약",
  "notes": ["다음 단계에 필요한 메모"],
  "next_step": "다음에 해야 할 작업 또는 null"
}}
"""
        response = client.messages.create(
            model="claude-fable-5",
            max_tokens=16000,
            messages=[{"role": "user", "content": context}]
        )
        
        result_text = response.content[0].text
        
        try:
            result = json.loads(result_text)
            # 메모리 업데이트
            self.memory["completed_steps"].append(task)
            self.memory["notes"].extend(result.get("notes", []))
            self.memory["current_step"] = result.get("next_step")
            self._save_memory()
            return result["result"]
        except json.JSONDecodeError:
            self.memory["errors"].append(f"파싱 실패: {task}")
            self._save_memory()
            return result_text

# 사용 예시
agent = Fable5LongRunningAgent(project_id="migration_v2")
result = agent.run_step("src/auth 모듈 의존성 분석 후 리팩토링 계획 작성")
print(result)

개념 박스 — 파일 기반 메모리가 중요한 이유 Anthropic의 Slay the Spire 실험에서 파일 기반 외부 메모리를 제공했을 때 Fable 5의 성능 향상 폭이 Opus 4.8의 세 배였습니다. 장기 작업에서 Fable 5가 진가를 발휘하려면 세션 간 컨텍스트를 유지하는 메모리 구조 설계가 필수입니다.


실전 5 — 오케스트레이터-워커 패턴

비용 효율을 최대화하는 구조입니다. Fable 5는 전체 계획과 판단만 맡기고, 반복 실행 작업은 저렴한 모델에 위임합니다.

import anthropic

client = anthropic.Anthropic()

def orchestrator_worker_pattern(big_task: str):
    # 1단계: Fable 5가 전체 계획 수립
    plan_response = client.messages.create(
        model="claude-fable-5",
        max_tokens=4000,
        messages=[{
            "role": "user",
            "content": f"""
다음 작업을 독립적으로 실행 가능한 세부 태스크로 분리해줘.
각 태스크는 컨텍스트 없이 단독 실행 가능해야 함.
JSON 배열로 반환: [{{"task": "...", "priority": 1}}]

작업: {big_task}
"""
        }]
    )
    
    tasks = json.loads(plan_response.content[0].text)
    results = []
    
    # 2단계: Haiku가 단순 반복 작업 처리
    for task_item in tasks:
        worker_response = client.messages.create(
            model="claude-haiku-4-5-20251001",   # 저렴한 워커 모델
            max_tokens=2000,
            messages=[{
                "role": "user",
                "content": task_item["task"]
            }]
        )
        results.append({
            "task": task_item["task"],
            "result": worker_response.content[0].text
        })
    
    # 3단계: Fable 5가 최종 결과 통합 및 검증
    final_response = client.messages.create(
        model="claude-fable-5",
        max_tokens=8000,
        messages=[{
            "role": "user",
            "content": f"""
다음 세부 작업 결과들을 통합하고 품질 검증해줘.
문제가 있으면 수정 사항도 포함해줘.

원래 작업: {big_task}
세부 결과: {json.dumps(results, ensure_ascii=False)}
"""
        }]
    )
    
    return final_response.content[0].text

result = orchestrator_worker_pattern(
    "전체 API 엔드포인트에 대한 통합 테스트 작성"
)
비용 구조 비교

단순 전부 Fable 5 사용:
  계획($10) + 실행 10개($10 × 10) + 검증($10) = $120 기준

오케스트레이터-워커 패턴:
  계획 Fable 5($10) + 실행 Haiku × 10($0.25 × 10) + 검증 Fable 5($10) = $22.50
  → 약 80% 비용 절감

개념 박스 — 오케스트레이터-워커 패턴 판단과 계획은 Fable 5, 반복 실행은 Haiku로 분리하는 구조입니다. Fable 5가 스스로 서브에이전트에게 위임하는 내장 기능도 있지만, 비용을 직접 제어하려면 이처럼 명시적으로 모델을 분리하는 게 더 유리합니다.


실전 6 — 데이터 보존 정책 대응

Fable 5는 30일 데이터 보존이 필수입니다. 기업 환경에서는 사전에 검토가 필요합니다.

# 민감 데이터 전처리 패턴
import re

def sanitize_for_fable(text: str) -> tuple[str, dict]:
    """
    Fable 5에 보내기 전 민감 정보 치환
    30일 보존 정책 대응
    """
    replacements = {}
    counter = 0
    
    # 이메일 치환
    emails = re.findall(r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b', text)
    for email in set(emails):
        placeholder = f"[EMAIL_{counter}]"
        replacements[placeholder] = email
        text = text.replace(email, placeholder)
        counter += 1
    
    # 전화번호 치환
    phones = re.findall(r'\b\d{2,3}-\d{3,4}-\d{4}\b', text)
    for phone in set(phones):
        placeholder = f"[PHONE_{counter}]"
        replacements[placeholder] = phone
        text = text.replace(phone, placeholder)
        counter += 1
    
    return text, replacements

def restore_sensitive_data(text: str, replacements: dict) -> str:
    for placeholder, original in replacements.items():
        text = text.replace(placeholder, original)
    return text

# 사용 예시
original_text = "홍길동(hong@company.com, 010-1234-5678) 고객 문의 처리"
sanitized, mapping = sanitize_for_fable(original_text)

response = client.messages.create(
    model="claude-fable-5",
    max_tokens=4000,
    messages=[{"role": "user", "content": sanitized}]
)

# 응답에서 플레이스홀더 복원
final_result = restore_sensitive_data(response.content[0].text, mapping)

✅ 마이그레이션 체크리스트

Opus 4.8에서 Fable 5로 전환 시 확인해야 할 항목입니다.

✅ 모델 ID를 claude-opus-4-8 → claude-fable-5로 변경
✅ Fallback API 플랫폼 콘솔에서 설정 완료
✅ fallback 발생 감지 로직 추가 (응답 메타데이터 확인)
✅ 시스템 프롬프트에 cache_control: ephemeral 적용
✅ max_tokens 여유있게 설정 (자체 검증 루프 공간)
✅ 30일 데이터 보존 정책 법무·보안팀 검토
✅ 민감 데이터 전처리 로직 추가
✅ 비용 모니터링 대시보드에 Fable vs Opus fallback 비율 추가

❌ 흔한 실수

❌ Fallback API 미설정 상태로 프로덕션 투입
❌ max_tokens 너무 작게 설정 — 자체 검증 중 강제 종료 발생
❌ 단순 작업에 Fable 5 전량 투입 — 비용 낭비
❌ 세션 간 메모리 없이 장기 작업 실행 — Fable 5 강점 반감
❌ 캐싱 미적용으로 에이전트 루프 비용 과다


관련 글

반응형