본문 바로가기
IT/AI

[AI] Claude 3.5 Sonnet API로 AI API 연동하기: 나만의 AI 서비스 만들기

by 수누다 2026. 4. 13.

드디어 나만의 AI 서비스를 만들 수 있다고?

얼마 전에 팀 내에서 반복적인 문서 요약 작업이 너무 많다는 얘기가 나왔어요. 매일 수십 개의 장애 리포트를 요약해서 주간 보고서로 만드는 일이었는데, 솔직히 이거 사람이 할 일이 아니잖아요. 그래서 AI API 연동을 직접 해보기로 했습니다.

처음에는 막막했거든요. "AI API 연동"이라고 하면 뭔가 복잡한 백엔드 개발을 해야 할 것 같은 느낌? 근데 실제로 해보니까 생각보다 훨씬 쉬웠어요. 특히 Claude 3.5 Sonnet API는 문서화가 잘 되어 있어서 처음 시도하는 분들도 금방 따라할 수 있더라고요.

이 글에서는 제가 직접 경험한 과정을 바탕으로, Claude API를 활용한 AI 서비스 개발의 A to Z를 정리해드릴게요. 삽질도 꽤 했는데 그 부분도 솔직하게 공유해드리겠습니다 ㅎㅎ

Claude API 연동 전체 아키텍처 다이어그램 - 클라이언트에서 Flask 서버를 거쳐 Anthropic API까지의 흐름

▲ 이번 글에서 구성할 Claude API 기반 AI 서비스의 전체 아키텍처입니다. 클라이언트 → Python 백엔드 → Anthropic API 흐름으로 동작합니다.

AI API 연동의 기초부터 시작하기

API(Application Programming Interface)란?

쉽게 말해서, 내 서비스와 외부 서비스가 서로 대화하는 창구예요. 레스토랑으로 비유하면 주방(AI 모델)에 직접 들어가지 않고 웨이터(API)를 통해 주문하는 것과 같죠.

AI API 연동이란 OpenAI, Anthropic 같은 회사가 만들어놓은 AI 모델을 내 서비스에서 HTTP 요청으로 불러다 쓰는 걸 말해요. 직접 GPU 서버 구축하고 모델 학습시키는 게 아니라, 이미 만들어진 강력한 AI를 API로 가져다 쓰는 거거든요. 인프라 엔지니어 입장에서는 정말 혁명적인 변화더라고요.

왜 Claude 3.5 Sonnet인가?

저도 처음에 OpenAI GPT-4랑 많이 비교해봤어요. 결론부터 말씀드리면, 긴 문서 처리와 코드 분석에서는 Claude 3.5 Sonnet이 확실히 강점을 보이더라고요. 그리고 컨텍스트 윈도우(한 번에 처리할 수 있는 텍스트 양)가 200K 토큰이라는 것도 장애 로그 분석용으로는 딱이었습니다.

항목 Claude 3.5 Sonnet GPT-4o Gemini 1.5 Pro
컨텍스트 윈도우 200K 토큰 128K 토큰 1M 토큰
코드 생성 능력 ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐
한국어 처리 ⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐
입력 가격 (1M 토큰) $3.00 $5.00 $3.50
긴 문서 요약 매우 우수 우수 우수

💡 : 가격 대비 성능을 따지면 Claude 3.5 Sonnet이 현재 시점에서 가장 균형 잡힌 선택이에요. 특히 코드와 기술 문서 처리에는 정말 강합니다.

시작 전 준비사항 체크

본격적으로 들어가기 전에 필요한 것들을 먼저 정리해드릴게요. 저도 처음에 이것저것 빠뜨려서 중간에 멈추는 일이 있었거든요 😅

  • Anthropic 계정: console.anthropic.com 에서 가입
  • API 키 발급: 계정 생성 후 API Keys 메뉴에서 발급
  • Python 3.8 이상: 예제 코드는 Python 기준으로 작성
  • 크레딧 충전: 처음엔 $5~$10 정도로 충분해요
  • 기본 HTTP/REST API 개념: 없어도 되지만 있으면 이해가 빠릅니다

⚠️ 주의: API 키는 절대 GitHub 같은 공개 저장소에 올리면 안 돼요. 실제로 이걸 실수로 올렸다가 요금 폭탄 맞은 사람들 이야기를 꽤 들었습니다. 환경 변수나 `.env` 파일로 관리하세요.

Claude API 실전 연동하기

1단계: 라이브러리 설치

Anthropic에서 공식 Python SDK를 제공하고 있어요. 이걸 쓰면 HTTP 요청을 직접 만들 필요 없이 훨씬 편하게 쓸 수 있습니다.

# 가상환경 먼저 만들고 시작하는 걸 강력 추천합니다
python -m venv ai-service-env
source ai-service-env/bin/activate  # Windows: ai-service-env\Scripts\activate

# Anthropic SDK 설치
pip install anthropic

# 환경 변수 관리를 위한 python-dotenv도 함께 설치
pip install python-dotenv

2단계: API 키 환경 변수 설정

프로젝트 루트에 `.env` 파일을 만들고 API 키를 저장해요. 그리고 이 파일은 반드시 `.gitignore`에 추가하세요!

# .env 파일
ANTHROPIC_API_KEY=sk-ant-api03-여기에-발급받은-키를-입력하세요
# .gitignore 파일에 추가
.env
*.env
.env.local

3단계: 첫 번째 API 호출 테스트

자, 이제 진짜 첫 번째 AI 호출을 해봅시다. 드디어 됐다! 싶은 순간이 여기서 옵니다 🎉

import anthropic
from dotenv import load_dotenv
import os

# .env 파일 로드
load_dotenv()

# 클라이언트 초기화
client = anthropic.Anthropic(
    api_key=os.environ.get("ANTHROPIC_API_KEY")
)

# 기본 메시지 전송
def ask_claude(question: str) -> str:
    message = client.messages.create(
        model="claude-3-5-sonnet-20241022",  # 최신 버전 모델명
        max_tokens=1024,
        messages=[
            {"role": "user", "content": question}
        ]
    )
    return message.content[0].text

# 테스트
response = ask_claude("안녕하세요! 간단하게 자기소개 해주세요.")
print(response)

이게 동작하면 반은 먹고 들어간 거예요. 여기서 응답이 오는 걸 보면 진짜 뿌듯하더라고요.

4단계: 시스템 프롬프트로 AI 역할 지정하기

여기서부터가 진짜 AI 서비스 개발의 핵심이에요. 시스템 프롬프트(System Prompt)란 AI에게 "너는 이런 역할을 해"라고 미리 지시하는 내용이에요. 이걸 잘 설계하면 완전히 다른 서비스가 됩니다.

def create_infra_assistant():
    """인프라 엔지니어를 위한 AI 어시스턴트 생성"""
    
    system_prompt = """
    당신은 10년 이상 경력의 시니어 인프라 엔지니어입니다.
    주어진 서버 로그나 장애 리포트를 분석하여:
    1. 핵심 문제점을 3줄 이내로 요약
    2. 예상 원인을 우선순위 순으로 나열
    3. 즉시 취할 수 있는 조치 방안 제시
    4. 재발 방지를 위한 장기적 개선사항 제안
    
    답변은 항상 한국어로 작성하고, 기술 용어는 영어 원문과 한국어 설명을 병기하세요.
    """
    
    def analyze_incident(log_content: str) -> str:
        message = client.messages.create(
            model="claude-3-5-sonnet-20241022",
            max_tokens=2048,
            system=system_prompt,  # 시스템 프롬프트 별도 설정
            messages=[
                {
                    "role": "user",
                    "content": f"다음 로그를 분석해주세요:\n\n{log_content}"
                }
            ]
        )
        return message.content[0].text
    
    return analyze_incident

# 사용 예시
analyze = create_infra_assistant()

sample_log = """
[ERROR] 2024-01-15 03:42:11 - Connection pool exhausted: max_connections=100
[ERROR] 2024-01-15 03:42:15 - Database query timeout after 30000ms
[WARN]  2024-01-15 03:42:20 - Memory usage: 94% (15.2GB / 16GB)
[ERROR] 2024-01-15 03:42:25 - OOM Killer activated, process nginx killed
"""

result = analyze(sample_log)
print(result)

▲ 실제 장애 로그를 Claude API에 전달했을 때의 응답 결과입니다. 원인 분석과 조치 방안이 구조화되어 출력됩니다.

5단계: 스트리밍(Streaming) 응답으로 UX 개선

긴 응답을 기다리다 보면 사용자 입장에서 답답할 수 있어요. 스트리밍을 사용하면 ChatGPT처럼 글자가 하나씩 출력되는 효과를 구현할 수 있어요. 실제 서비스에서는 이게 훨씬 낫더라고요.

def analyze_with_streaming(log_content: str):
    """스트리밍 방식으로 실시간 응답 출력"""
    
    print("분석 중...", flush=True)
    
    with client.messages.stream(
        model="claude-3-5-sonnet-20241022",
        max_tokens=2048,
        messages=[
            {
                "role": "user",
                "content": f"다음 로그를 분석해주세요:\n\n{log_content}"
            }
        ]
    ) as stream:
        for text in stream.text_stream:
            print(text, end="", flush=True)
    
    print()  # 줄바꿈
    
    # 사용량 정보 확인 (토큰 비용 추적에 유용!)
    final_message = stream.get_final_message()
    print(f"\n--- 사용 토큰: 입력 {final_message.usage.input_tokens}, 출력 {final_message.usage.output_tokens} ---")

analyze_with_streaming(sample_log)

6단계: 실제 서비스화 - Flask로 REST API 만들기

이제 이걸 웹 서비스로 만들어볼게요. Flask(플라스크)를 써서 간단한 REST API 서버를 구성했어요. 팀원들이 브라우저에서 바로 쓸 수 있게 하려고요.

pip install flask flask-cors
from flask import Flask, request, jsonify, Response, stream_with_context
from flask_cors import CORS
import anthropic
from dotenv import load_dotenv
import os
import json

load_dotenv()

app = Flask(__name__)
CORS(app)  # Cross-Origin Resource Sharing 허용

client = anthropic.Anthropic(
    api_key=os.environ.get("ANTHROPIC_API_KEY")
)

SYSTEM_PROMPT = """
당신은 인프라 운영팀을 위한 AI 분석 어시스턴트입니다.
서버 로그, 장애 리포트, 성능 메트릭을 분석하여 실용적인 인사이트를 제공합니다.
답변은 항상 구조화된 형식으로 한국어로 작성하세요.
"""

@app.route('/health', methods=['GET'])
def health_check():
    """서비스 상태 확인 엔드포인트"""
    return jsonify({"status": "healthy", "model": "claude-3-5-sonnet-20241022"})

@app.route('/analyze', methods=['POST'])
def analyze_log():
    """로그 분석 엔드포인트 (일반 응답)"""
    data = request.get_json()
    
    if not data or 'content' not in data:
        return jsonify({"error": "content 필드가 필요합니다"}), 400
    
    try:
        message = client.messages.create(
            model="claude-3-5-sonnet-20241022",
            max_tokens=2048,
            system=SYSTEM_PROMPT,
            messages=[
                {"role": "user", "content": data['content']}
            ]
        )
        
        return jsonify({
            "result": message.content[0].text,
            "usage": {
                "input_tokens": message.usage.input_tokens,
                "output_tokens": message.usage.output_tokens
            }
        })
    
    except anthropic.RateLimitError:
        return jsonify({"error": "API 요청 한도 초과. 잠시 후 다시 시도하세요."}), 429
    except anthropic.APIError as e:
        return jsonify({"error": f"API 오류: {str(e)}"}), 500

@app.route('/analyze/stream', methods=['POST'])
def analyze_stream():
    """스트리밍 분석 엔드포인트"""
    data = request.get_json()
    
    if not data or 'content' not in data:
        return jsonify({"error": "content 필드가 필요합니다"}), 400
    
    def generate():
        with client.messages.stream(
            model="claude-3-5-sonnet-20241022",
            max_tokens=2048,
            system=SYSTEM_PROMPT,
            messages=[
                {"role": "user", "content": data['content']}
            ]
        ) as stream:
            for text in stream.text_stream:
                # Server-Sent Events(SSE) 형식으로 전송
                yield f"data: {json.dumps({'text': text})}\n\n"
        
        yield "data: [DONE]\n\n"
    
    return Response(
        stream_with_context(generate()),
        mimetype='text/event-stream',
        headers={
            'Cache-Control': 'no-cache',
            'X-Accel-Buffering': 'no'
        }
    )

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000, debug=False)

이 서버를 실행하면 `http://localhost:5000/analyze` 엔드포인트로 POST 요청을 보내서 AI 분석을 받을 수 있어요. 팀 내부 도구로 쓰기에 딱 좋은 구조입니다.

실제로 겪은 문제들과 해결법

여기서부터가 제가 진짜 삽질한 내용들이에요. 이 부분 꼭 읽어보세요!

문제 1: 토큰 비용 폭탄

처음에 max_tokens를 제한 없이 쓰다가 하루 만에 $20 날렸어요 😱 로그 파일을 그대로 넣으면 입력 토큰이 엄청나게 커지거든요.

해결책: 입력 텍스트를 전처리해서 불필요한 줄을 제거하고, max_tokens에 합리적인 상한선을 설정하세요.

def preprocess_log(log_content: str, max_lines: int = 100) -> str:
    """로그 전처리: 중요 라인만 추출"""
    lines = log_content.strip().split('\n')
    
    # ERROR, WARN, CRITICAL 레벨만 필터링
    important_lines = [
        line for line in lines 
        if any(level in line for level in ['ERROR', 'WARN', 'CRITICAL', 'FATAL'])
    ]
    
    # 최대 라인 수 제한
    if len(important_lines) > max_lines:
        important_lines = important_lines[-max_lines:]  # 최근 로그 우선
    
    return '\n'.join(important_lines)

문제 2: Rate Limit(요청 한도) 오류

여러 사람이 동시에 쓰다 보니 `RateLimitError`가 자꾸 터졌어요. Anthropic의 기본 한도가 생각보다 빡빡하거든요.

해결책: 지수 백오프(Exponential Backoff) 재시도 로직을 추가했어요.

import time
import random

def call_api_with_retry(messages, max_retries=3):
    """재시도 로직이 포함된 API 호출"""
    for attempt in range(max_retries):
        try:
            return client.messages.create(
                model="claude-3-5-sonnet-20241022",
                max_tokens=1024,
                messages=messages
            )
        except anthropic.RateLimitError:
            if attempt == max_retries - 1:
                raise
            # 지수 백오프: 1초, 2초, 4초... + 랜덤 지터
            wait_time = (2 ** attempt) + random.uniform(0, 1)
            print(f"Rate limit 도달. {wait_time:.1f}초 후 재시도...")
            time.sleep(wait_time)

문제 3: 긴 대화 컨텍스트 관리

대화가 길어질수록 토큰이 쌓여서 비용이 기하급수적으로 늘어나는 문제가 있었어요. 컨텍스트 윈도우를 관리해야 합니다.

class ConversationManager:
    """대화 히스토리 관리 클래스"""
    
    def __init__(self, max_history: int = 10):
        self.messages = []
        self.max_history = max_history  # 최대 대화 턴 수
    
    def add_message(self, role: str, content: str):
        self.messages.append({"role": role, "content": content})
        
        # 히스토리가 max_history를 초과하면 오래된 것부터 제거
        # 단, 첫 번째 user 메시지는 보존 (컨텍스트 유지)
        if len(self.messages) > self.max_history * 2:
            self.messages = self.messages[2:]  # 가장 오래된 user+assistant 쌍 제거
    
    def chat(self, user_input: str) -> str:
        self.add_message("user", user_input)
        
        response = client.messages.create(
            model="claude-3-5-sonnet-20241022",
            max_tokens=1024,
            messages=self.messages
        )
        
        assistant_reply = response.content[0].text
        self.add_message("assistant", assistant_reply)
        
        return assistant_reply

▲ Flask로 구성한 AI API 서버를 Postman으로 테스트하는 화면입니다. /analyze 엔드포인트가 정상 응답하는 모습을 확인할 수 있습니다.

완성된 서비스 검증하기

curl로 빠르게 테스트

# 서버 상태 확인
curl http://localhost:5000/health

# 로그 분석 요청
curl -X POST http://localhost:5000/analyze \
  -H "Content-Type: application/json" \
  -d '{
    "content": "[ERROR] 2024-01-15 03:42:11 - Connection pool exhausted\n[ERROR] 2024-01-15 03:42:15 - Database query timeout after 30000ms"
  }'

실제 운영 결과

팀에 배포하고 한 달 운영한 결과를 공유할게요. 기대 이상의 결과가 나왔습니다.

  • 🎉 장애 리포트 작성 시간: 평균 30분 → 5분으로 단축
  • 🎉 주간 보고서 요약: 2시간 작업 → 15분으로 단축
  • 🎉 온콜(On-call) 대응: 새벽 알람 받고 로그 분석하는 시간 60% 감소
  • ⚠️ 월 API 비용: 약 $45 (5명 팀 기준, 하루 평균 50~70건 요청)

비용이 걱정되실 수 있는데, 절약된 엔지니어 시간을 환산하면 충분히 합리적인 투자예요. 팀원들 반응도 굉장히 좋았고요.

API 사용량 모니터링하기

운영하다 보면 API 사용량과 비용을 추적하는 게 중요해요. 간단한 로깅을 추가했습니다.

import logging
from datetime import datetime

logging.basicConfig(
    filename='api_usage.log',
    level=logging.INFO,
    format='%(asctime)s - %(message)s'
)

def log_api_usage(input_tokens: int, output_tokens: int, endpoint: str):
    """API 사용량 로깅"""
    # Claude 3.5 Sonnet 가격 (2024년 기준)
    input_cost = (input_tokens / 1_000_000) * 3.0   # $3.00 per 1M tokens
    output_cost = (output_tokens / 1_000_000) * 15.0  # $15.00 per 1M tokens
    total_cost = input_cost + output_cost
    
    logging.info(
        f"endpoint={endpoint} "
        f"input_tokens={input_tokens} "
        f"output_tokens={output_tokens} "
        f"cost=${total_cost:.6f}"
    )

▲ 한 달간 운영한 AI 서비스의 사용량 대시보드입니다. 일별 토큰 사용량과 비용 추이를 한눈에 볼 수 있습니다.

자주 묻는 질문 (FAQ)

Q. API 키가 노출되면 어떻게 되나요?

즉시 Anthropic 콘솔에서 해당 키를 비활성화하고 새 키를 발급받으세요. 노출된 시간 동안의 사용 비용은 본인 부담이에요. 그래서 환경 변수 관리가 정말 중요합니다.

Q. 무료로 쓸 수 있는 방법이 있나요?

현재 Anthropic은 무료 티어를 제공하지 않아요. 다만 처음 가입 시 일부 크레딧을 주는 프로모션이 있을 수 있으니 확인해보세요. 테스트 목적이라면 $5 크레딧으로도 충분히 실험할 수 있습니다.

Q. 한국어 처리 품질은 어떤가요?

제가 직접 써보니까 한국어 처리도 꽤 훌륭해요. 다만 영어 대비 약간 응답 품질이 떨어질 수 있어서, 중요한 프롬프트는 영어로 작성하고 출력만 한국어로 요청하는 방식이 더 좋은 결과를 주더라고요.

Q. 프로덕션 환경에 바로 배포해도 되나요?

위에서 만든 Flask 서버는 개발용이에요. 프로덕션에는 Gunicorn + Nginx 조합으로 올리거나, FastAPI로 전환하는 걸 추천합니다. 인증(Authentication), 요청 제한(Rate Limiting), 에러 핸들링도 강화해야 해요.

정리하며: AI API 연동의 진짜 가치

13년 동안 인프라 일을 하면서 이렇게 빠르게 체감되는 생산성 향상은 오랜만이었어요. AI API 연동은 더 이상 개발자만의 영역이 아니에요. 인프라 엔지니어도 충분히 활용할 수 있고, 오히려 우리가 다루는 로그나 장애 리포트 같은 기술 데이터에서 더 빛을 발하더라고요.

Claude 3.5 Sonnet API를 선택한 건 탁월한 결정이었어요. 특히 긴 기술 문서 처리와 코드 분석 능력은 다른 모델과 비교해도 손색이 없었습니다.

이번 글에서 다룬 내용을 간단히 정리하면:

  1. ✅ Anthropic SDK 설치 및 API 키 설정
  2. ✅ 기본 API 호출 및 시스템 프롬프트 설계
  3. ✅ 스트리밍 응답으로 UX 개선
  4. ✅ Flask 기반 REST API 서버 구성
  5. ✅ 비용 관리 및 에러 핸들링
  6. ✅ API 사용량 모니터링

다음 글에서는 이 서비스에 벡터 데이터베이스(Vector Database)를 연동해서 RAG(Retrieval-Augmented Generation, 검색 증강 생성) 시스템을 구축하는 방법을 다뤄볼 예정이에요. 사내 위키나 런북(Runbook)을 AI가 참조해서 답변하게 만드는 건데, 이게 진짜 실용적이거든요. 기대해주세요!

궁금한 점이나 다른 활용 사례 있으시면 댓글로 남겨주세요. 같이 삽질하는 동료가 있으면 더 빨리 배우더라고요 😄