Skip to content
··5분 읽기

하나의 AI 파라미터 변경으로 월 $54의 비용이 발생했습니다

Cloud Run 마이그레이션이 완벽하다고 생각했는데, 단 하나의 AI 파라미터—temperature가 0이 아닌 0.7로 설정—가 30%의 API 호출 실패와 월 $54의 낭비된 토큰을 초래했습니다.

Claude에게 AWS Lambda에서 Google Cloud Run으로 마이그레이션을 도와달라고 맡겼습니다. 마이그레이션은 완벽했습니다 - 서비스 배포 완료, 워크플로우 실행, 사용자 만족. 그러다 API 청구서를 확인하고 의자에서 거의 떨어질 뻔했습니다.

*이 글은 DIALØGUE 엔지니어링 시리즈의 3부입니다. 놓치셨다면: [1부: DIALØGUE 소개]와 [2부: 광고에서 엔지니어링으로]가 기반을 다룹니다.*

이것은 프로덕션 제약 조건에 대해 명시적이지 않은 채 AI에게 프로덕션 코드를 작성하게 했을 때 어떤 일이 일어나는지에 대한 이야기입니다. 스포일러: "작동하게 해줘"와 "프로덕션에 적합하게 해줘"는 매우 다른 요청입니다.

너무 잘 진행된 마이그레이션

몇 달간 AWS Lambda와 씨름한 끝에(콜드 스타트, 레이어 제한 등), 모든 것을 Google Cloud Run으로 마이그레이션하기로 결정했습니다. 실용적인 개발자로서(읽기: 게으른), Claude를 페어 프로그래머로 등용했습니다.

"이 Lambda 함수들을 Cloud Run으로 마이그레이션하는 것을 도와줘," 라고 말했습니다. "여기 기존 코드가 있어."

Claude는 훌륭하게 해냈습니다. 깔끔한 Dockerfile, 적절한 서비스 구성, 작동하는 Cloud Workflows. 마이그레이션은 예상했던 몇 주 대신 단 하루만에 완료되었습니다. 매우 기뻤습니다!

모든 것이 원활하게 배포되었습니다. 서비스가 빠르게 시작되었습니다. 사용자들이 문제 없이 팟캐스트를 만들고 있었습니다. 성공이죠?

그런데 로그에서 이상한 것을 발견했습니다:

```
[ERROR] Segment generation failed: Unexpected token in JSON
[RETRY] Attempting segment generation again...
[SUCCESS] Segment generated successfully
```

AI 호출의 약 30%가 첫 번째 시도에서 실패하고 재시도에서 성공하고 있었습니다. 세상이 끝나는 것은 아닙니다 - 재시도 로직이 작동하고 있었으니까요! 사용자들은 문제를 인지하지 못했습니다. 하지만 그 추가 API 호출이 누적되고 있었습니다.

조사: 마이그레이션 탓인가?

첫 번째 생각은 마이그레이션 중에 뭔가 잘못되었다는 것이었습니다. 새로운 Cloud Run 환경이 다른 건 아닌지? 컨테이너 네트워킹 문제? AWS와 GCP 구성을 비교하며 몇 시간을 보냈습니다.

모든 것이 동일해 보였습니다. 같은 프롬프트, 같은 재시도 로직, 같은 에러 처리. 그런데 왜 갑자기 잘못된 JSON 응답이 나오는 걸까?

그래서 실제 코드를 비교하기 시작했습니다. 발견한 것은:

AWS Lambda 버전 (몇 달간 잘 작동):

```python
response = anthropic.messages.create(
      model="claude-3-7-sonnet-20250219",
      temperature=0,  # JSON을 위한 결정적 출력
      response_format={"type": "json_object"},  # JSON 모드
      system="You are a JSON generation assistant. Output only valid JSON.",
      messages=[{"role": "user", "content": prompt}]
)
```

GCP Cloud Run 버전 (Claude의 마이그레이션):

```python
response = anthropic.messages.create(
    model="claude-3-7-sonnet-20250219",
    temperature=0.7,  # <-- 잠깐, 뭐?
    messages=[{"role": "user", "content": prompt}]
)
```

거기 있었습니다. Temperature 0.7.

"하지만 합리적인 기본값이잖아!" 라고 말씀하실 수 있습니다. 맞습니다. 창작 글쓰기, 탐색, 브레인스토밍에는 0.7이 완벽히 합리적입니다. 하지만 구조화된 JSON 생성에는? 재앙입니다.

결정적 증거: 창의적인 JSON

실제 AI 응답을 캡처하기 위해 상세한 로깅을 추가한 후, 정확히 무슨 일이 일어나고 있는지 발견했습니다. Temperature 0.7에서 Claude가 반환하는 것은:

```
Here's the podcast segment you requested:

{
  "title": "The Rise of AI Podcasting",
  "content": "Welcome back, listeners! Today we're diving into something really fascinating...",
  "duration": 120
}

I hope this segment captures what you were looking for!
```

문제가 보이시나요? Claude가 응답 형식에서 창의적으로 행동하고 있었습니다. 때로는 JSON만, 때로는 도움되는 논평이 포함된 JSON, 때로는 마크다운 코드 블록으로 감싼 JSON. Temperature 0.7에서 메트로놈이 필요한데 재즈 뮤지션처럼 즉흥 연주하고 있었습니다.

AI 페어 프로그래밍의 사각지대

AI를 페어 프로그래머로 사용하는 것에 대한 핵심은: 코드를 작동하게 만드는 데는 놀라울 정도로 뛰어나지만, 특별히 요청하지 않으면 프로덕션 우려 사항에 대해 반드시 최적화하지는 않는다는 것입니다.

"이 Lambda 함수를 Cloud Run으로 마이그레이션해줘"라고 말했을 때, Claude는 마이그레이션 요구 사항에 집중했습니다:

- ✅ Cloud Run에서 실행되게 하기

- ✅ 같은 입력과 출력 처리

- ✅ 같은 기능 유지

- ❌ 프로덕션 효율성 최적화

Claude가 temperature 0.7을 선택한 것은 AI 애플리케이션에 대한 "합리적인 기본값"이기 때문입니다. 그리고 맞습니다! 대부분의 사용 사례에서 0.7은 창의성과 일관성 사이의 좋은 균형을 제공합니다.

하지만 여기서 배운 것은: **AI는 여러분이 말해주지 않으면 여러분의 특정 프로덕션 제약 조건을 알지 못합니다.**

원래 AWS 코드는 JSON 생성에 결정적 출력과 명시적 형식이 모두 필요하다는 것을 (어렵게) 배웠기 때문에 temperature 0 AND JSON 모드를 사용했습니다. 하지만 마이그레이션 중에 "이것은 구조화된 데이터 생성용"이라거나 "모든 JSON 특화 최적화를 유지해"라고 명시적으로 말하지 않았습니다.

그래서 Claude는 합리적인 기본값으로 완벽하게 기능하는 코드를 작성했습니다. 문제는 AI가 아니라 — 제 불완전한 요구 사항이었습니다.

수정: AI에게 구체적으로 요청하기

문제를 파악한 후, 더 나은 요구 사항으로 Claude에게 돌아갔습니다:

"이 코드를 수정해줘. 프로덕션에서의 JSON 생성용이야. 100% 신뢰성, 창의성 제로가 필요해. temperature 0과 구조화된 데이터에 대한 기타 최적화를 사용해."

Claude가 즉시 제안한 것은:

```python
response = anthropic.messages.create(
    model="claude-3-5-sonnet",
    temperature=0,  # 결정적 출력
    response_format={"type": "json_object"},  # JSON 모드
    system="You are a JSON generation assistant. Output only valid JSON.",
    messages=[{"role": "user", "content": prompt}]
)
```

잠깐, Claude가 우리가 가지고 있던 JSON 모드를 빼먹었습니다! (마이그레이션 중 모든 프로덕션 요구 사항을 명시적으로 언급하지 않으면 이런 일이 발생합니다!)

성공률이 70%에서 99.9%로 뛰었습니다. 나머지 0.1%는? 네트워크 타임아웃. 그건 Claude 탓이 아닙니다.

차이점? 이번에는 프로덕션 제약 조건에 대해 명시적이었습니다. 단순한 마이그레이션을 요청한 것이 아니라 프로덕션 최적화, 신뢰성 중심 코드를 요청했습니다.

"합리적인" 기본값의 실제 비용

이 "합리적인" temperature 설정이 실제로 얼마나 비용이 들었는지 분석해 보겠습니다:

- **일일 팟캐스트 생성**: ~200

- **실패율**: 30%가 재시도 필요

- **하루 추가 API 호출**: 60개의 실패한 호출이 재시도 필요

- **월간 낭비**: ~1,800개의 불필요한 API 호출

- **Claude 3.7 Sonnet 가격**: 백만 토큰당 입력 $3 + 출력 $15

- **호출당 평균 토큰**: ~2,000 입력 + 1,500 출력

- **재시도당 비용**: 실패한 시도당 ~$0.03

- **월간 초과**: 낭비된 API 호출로 ~$54

하지만 진짜 비용은 월 $54만이 아니었습니다. 각 재시도는 생성 시간에 3-5초를 추가했습니다. 사용자는 더 오래 기다렸고, Cloud Run 인스턴스는 더 자주 스핀업했으며, 할당량을 더 빠르게 소진하고 있었습니다.

결정타? 이 모든 것은 프로덕션 컨텍스트를 제공하지 않고 AI에게 프로덕션 결정을 맡겼기 때문에 발생했습니다. "작동한다" vs "효율적으로 작동한다"의 전형적인 사례.

AI 페어 프로그래밍에서 배운 것

1. 프로덕션 요구 사항에 대해 명시적이어야 합니다

"작동하게 해줘"는 기능하는 코드를 얻습니다. "이러한 제약 조건으로 프로덕션에서 효율적으로 작동하게 해줘"는 최적화된 코드를 얻습니다. AI는 여러분이 설명하는 문제를 잘 해결하지, 마음속에 있는 문제를 해결하는 것이 아닙니다.

2. AI는 "합리적인" 기본값을 사용하지, "최적" 기본값이 아닙니다

Temperature 0.7은 대부분의 AI 애플리케이션에 합리적입니다. 하지만 프로덕션 시스템은 종종 temperature 0 AND JSON 모드 같은 특정 최적화가 필요합니다. AI는 명시적으로 언급하지 않으면 이것을 보존하지 않습니다.

3. 코드 리뷰는 AI 생성 코드에도 적용됩니다

AI가 작성했다고 프로덕션 준비가 된 것은 아닙니다. 코드 리뷰에서 이것을 잡았어야 했지만, 마이그레이션이 작동하는지에 너무 집중해서 파라미터를 감사하지 않았습니다.

4. 컨텍스트가 생각보다 더 중요합니다

원래 AWS 코드에 temperature 0 AND JSON 모드가 있었던 데는 이유가 있었습니다 — 고통스러운 경험을 통해 배운 것입니다. 마이그레이션 중에 명시적으로 언급하지 않아 그 컨텍스트가 사라졌습니다. 이제 모든 파라미터와 기능 뒤의 "왜"를 문서화합니다.

새로운 AI 페어 프로그래밍 워크플로우

이제 프로덕션 코드에 대해 AI와 작업할 때, 제약 조건에 대해 훨씬 더 명시적입니다:

**이전:**

"이 Lambda 함수를 Cloud Run으로 마이그레이션해줘"

**지금:**

"이 Lambda 함수를 Cloud Run으로 마이그레이션해줘. 이것은 프로덕션 JSON 생성용이야 — 창의성보다 신뢰성을 우선시해. temperature 0, 가능하면 JSON 모드, 그리고 구조화된 데이터 출력을 위한 기타 최적화를 사용해."

Claude가 구축을 도와준 프로덕션 최적화 설정은 다음과 같습니다:

```python
def get_ai_json_response(prompt: str) -> dict:
    """프로덕션 최적화 AI JSON 생성"""
    response = anthropic.messages.create(
        model="claude-sonnet-4-20250514",
        temperature=0,  # 구조화된 데이터를 위한 창의성 제로
        response_format={"type": "json_object"},  # JSON 모드 강제
        system="You are a JSON generation assistant. Output only valid JSON.",
        messages=[{
            "role": "user",
            "content": f"{prompt}\n\nRespond with valid JSON only."
        }]
    )

    # 프로덕션을 위한 명시적 에러 처리
    try:
        return json.loads(response.content[0].text)
    except json.JSONDecodeError as e:
        logger.error(f"JSON parse failed: {e}")
        logger.error(f"Raw response: {response.content[0].text}")
        raise
```

차이점? AI에게 특정 사용 사례에 최적화하는 데 필요한 컨텍스트를 제공했습니다.

결과

30% 낮은 API 비용, 40% 빠른 생성. 모두 "프로덕션 준비"가 실제로 무엇을 의미하는지 구체적으로 말한 한 번의 대화에서 나왔습니다.

재미있는 부분? "창의적인" 대화 생성조차 temperature 0을 사용합니다. 결정적이라고 해서 지루하다는 의미가 아닙니다 — 신뢰할 수 있다는 의미입니다. 프롬프트와 콘텐츠 리서치가 다양성을 제공하지, 무작위 temperature 변동이 아닙니다.

AI 페어 프로그래밍은 그것이 여전히 프로그래밍이라는 것을 기억할 때 잘 작동합니다 — 요구 사항의 정밀도가 결과의 정밀도를 가져옵니다.

AI 어시스턴트가 여러분의 사용 사례에 완전히 맞지 않는 "합리적인" 선택을 한 적이 있나요? 여러분의 경험담을 듣고 싶습니다 — 합리적인 기본값에 당한 적이 다들 있을 것 같습니다 :)

감사합니다,

Chandler

유효한 JSON이 보장되는 AI 팟캐스트를 만들고 싶으시나요? DIALØGUE를 시도해 보세요 — 시작하기 위한 2개의 무료 크레딧! :P

DIALØGUE 엔지니어링 시리즈 3부. "작동하게 해줘"와 "효율적으로 작동하게 해줘"는 완전히 다른 요청이라는 것을 아직도 배우는 중입니다. chandlernguyen.com에서 더 많은 AI 페어 프로그래밍 모험을 따라오세요.

**시리즈 다음편**: 약 7일 후 공개 - "3분에서 500ms로: 말이 안 되는 가입 버그"

계속 읽기

나의 여정
연결
언어
환경설정