본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.
본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.
이미지 로딩 중...
AI Generated
2025. 12. 3. · 15 Views
LLM API 기본 사용법 완벽 가이드
대규모 언어 모델 API를 처음 접하는 개발자를 위한 실전 가이드입니다. OpenAI API의 구조부터 에러 핸들링까지, 실무에서 바로 활용할 수 있는 핵심 지식을 담았습니다.
목차
- API란_무엇인가
- OpenAI_API_구조_이해
- Chat_Completions_API_사용법
- 메시지_역할_이해하기
- API_파라미터_설정하기
- 응답_파싱하고_활용하기
- 에러_핸들링과_재시도_로직
1. API란 무엇인가
김개발 씨는 요즘 ChatGPT에 푹 빠져 있습니다. "이걸 내 서비스에도 넣을 수 있으면 얼마나 좋을까?" 문득 이런 생각이 들었습니다.
선배에게 물어보니 "API를 쓰면 돼"라는 답이 돌아왔습니다. API라...
많이 들어봤지만 정확히 뭘까요?
**API(Application Programming Interface)**는 프로그램들이 서로 대화할 수 있게 해주는 약속된 방식입니다. 마치 식당에서 웨이터가 손님과 주방 사이를 연결해주는 것처럼, API는 여러분의 프로그램과 외부 서비스 사이를 연결해줍니다.
이 개념을 이해하면 ChatGPT뿐 아니라 수많은 외부 서비스를 자유자재로 활용할 수 있게 됩니다.
다음 코드를 살펴봅시다.
import requests
# API 호출의 가장 기본적인 형태
# URL은 "어디로" 요청할지를 나타냅니다
api_url = "https://api.example.com/data"
# headers는 "누구인지" 증명하는 신분증 역할
headers = {
"Authorization": "Bearer your-api-key",
"Content-Type": "application/json"
}
# 실제 API 호출 - 요청을 보내고 응답을 받습니다
response = requests.get(api_url, headers=headers)
# 응답 데이터를 JSON 형태로 변환
data = response.json()
print(data)
김개발 씨는 입사 6개월 차 주니어 개발자입니다. 회사에서 고객 문의를 자동으로 분류하는 기능을 만들어 달라는 요청을 받았습니다.
ChatGPT처럼 똑똒한 AI를 직접 만들 수는 없으니, 어떻게 해야 할까요? 선배 개발자 박시니어 씨가 힌트를 줍니다.
"OpenAI에서 API를 제공하거든. 그걸 쓰면 돼." 그렇다면 API란 정확히 무엇일까요?
쉽게 비유하자면, API는 마치 식당의 웨이터와 같습니다. 손님인 여러분은 메뉴판을 보고 주문합니다.
웨이터는 그 주문을 주방에 전달하고, 완성된 요리를 다시 가져다줍니다. 손님은 주방에서 어떻게 요리하는지 알 필요가 없습니다.
그저 메뉴판에 있는 것을 주문하면 됩니다. API도 마찬가지입니다.
여러분의 프로그램은 정해진 형식으로 요청을 보냅니다. 그러면 외부 서비스가 그 요청을 처리하고 결과를 돌려줍니다.
내부적으로 어떻게 동작하는지는 몰라도 됩니다. API가 없던 시절에는 어땠을까요?
모든 기능을 직접 구현해야 했습니다. 지도 서비스가 필요하면 지도를 직접 만들어야 했고, 결제 기능이 필요하면 결제 시스템을 처음부터 구축해야 했습니다.
시간과 비용이 어마어마하게 들었습니다. 바로 이런 문제를 해결하기 위해 API가 등장했습니다.
API를 사용하면 다른 회사가 이미 만들어 놓은 기능을 가져다 쓸 수 있습니다. 구글 지도 API를 쓰면 지도 기능을, 카카오페이 API를 쓰면 결제 기능을 손쉽게 추가할 수 있습니다.
그리고 이제 OpenAI API를 쓰면 AI 기능까지 추가할 수 있습니다. 위의 코드를 살펴보겠습니다.
api_url은 요청을 보낼 주소입니다. 식당으로 치면 식당의 위치와 같습니다.
headers는 여러분이 누구인지 증명하는 신분증 역할을 합니다. API 키가 여기에 들어갑니다.
마지막으로 **requests.get()**이 실제로 요청을 보내는 부분입니다. 실제 현업에서는 어떻게 활용할까요?
쇼핑몰을 만든다고 가정해봅시다. 배송 조회 기능이 필요하면 택배사 API를, 리뷰 자동 요약이 필요하면 LLM API를 사용합니다.
레고 블록을 조립하듯 다양한 API를 조합해서 서비스를 만들 수 있습니다. 하지만 주의할 점도 있습니다.
API는 대부분 사용량에 따라 비용이 발생합니다. 또한 외부 서비스에 의존하므로 해당 서비스가 중단되면 내 서비스도 영향을 받습니다.
따라서 비용 관리와 장애 대응 계획을 미리 세워두어야 합니다. 다시 김개발 씨의 이야기로 돌아가 봅시다.
"아, API가 그런 거였군요! 그럼 OpenAI API를 어떻게 쓰는 건가요?" 김개발 씨의 눈이 반짝입니다.
이제 본격적으로 OpenAI API의 세계로 들어가 봅시다.
실전 팁
💡 - API 키는 절대로 코드에 직접 작성하지 마세요. 환경 변수를 사용하세요.
- API 호출에는 항상 비용이 따릅니다. 개발 중에는 테스트 계정을 활용하세요.
2. OpenAI API 구조 이해
김개발 씨가 OpenAI 사이트에 접속했습니다. API 문서를 열어보니 뭔가 잔뜩 있습니다.
Completions, Chat, Embeddings, Images... 어디서부터 시작해야 할지 막막합니다.
박시니어 씨가 어깨 너머로 보더니 말합니다. "일단 전체 구조부터 파악하자."
OpenAI API는 여러 가지 AI 기능을 제공하는 서비스 묶음입니다. 마치 백화점에 여러 매장이 있는 것처럼, OpenAI API에도 텍스트 생성, 이미지 생성, 음성 변환 등 다양한 기능이 있습니다.
우리가 주로 사용할 것은 Chat Completions API로, ChatGPT와 대화하는 것과 같은 기능을 프로그램에서 사용할 수 있게 해줍니다.
다음 코드를 살펴봅시다.
from openai import OpenAI
# OpenAI 클라이언트 초기화
# api_key는 환경변수에서 자동으로 읽어옵니다
client = OpenAI()
# Chat Completions API 호출
response = client.chat.completions.create(
model="gpt-4o-mini", # 사용할 모델 선택
messages=[
{"role": "user", "content": "안녕하세요!"}
]
)
# 응답에서 AI가 생성한 텍스트 추출
ai_message = response.choices[0].message.content
print(ai_message)
김개발 씨는 OpenAI 문서 페이지 앞에서 한숨을 쉬었습니다. 영어로 된 문서, 낯선 용어들.
어디서부터 봐야 할지 모르겠습니다. 박시니어 씨가 옆에 앉았습니다.
"OpenAI API를 백화점이라고 생각해봐. 각 층마다 다른 매장이 있잖아?" OpenAI API는 크게 몇 가지 주요 기능으로 나뉩니다.
첫째, Chat Completions입니다. 이것이 가장 핵심입니다.
ChatGPT처럼 대화하고, 질문에 답하고, 글을 작성하는 기능을 제공합니다. 우리가 주로 사용할 API입니다.
둘째, Embeddings입니다. 텍스트를 숫자 벡터로 변환합니다.
문서 검색이나 유사도 비교에 사용됩니다. 셋째, Images입니다.
DALL-E를 통해 이미지를 생성하거나 편집할 수 있습니다. 넷째, Audio입니다.
음성을 텍스트로 변환하거나, 텍스트를 음성으로 변환합니다. 김개발 씨가 물었습니다.
"그럼 저는 Chat Completions만 알면 되나요?" "대부분의 경우 그래. 텍스트 생성, 요약, 번역, 분류...
거의 다 Chat Completions로 할 수 있어." 위의 코드를 살펴보겠습니다. 먼저 OpenAI 클라이언트를 생성합니다.
이때 API 키가 필요한데, 환경 변수 OPENAI_API_KEY에 설정해두면 자동으로 읽어옵니다. **client.chat.completions.create()**가 실제 API를 호출하는 부분입니다.
model 파라미터로 어떤 모델을 사용할지 지정합니다. gpt-4o-mini는 빠르고 저렴한 모델이고, gpt-4o는 더 똑똑하지만 비용이 높습니다.
messages는 대화 내용을 담는 리스트입니다. 지금은 사용자 메시지 하나만 넣었지만, 이전 대화 기록을 함께 넣으면 맥락을 이해하는 대화가 가능합니다.
응답은 response.choices[0].message.content에서 추출합니다. choices가 리스트인 이유는 한 번에 여러 개의 응답을 생성할 수도 있기 때문입니다.
실제 현업에서는 이 기본 구조 위에 다양한 기능을 덧붙입니다. 에러 처리를 추가하고, 재시도 로직을 넣고, 응답을 가공해서 사용합니다.
김개발 씨의 얼굴이 밝아졌습니다. "생각보다 간단하네요!" 박시니어 씨가 고개를 끄덕였습니다.
"기본 구조는 간단해. 이제 세부적인 것들을 하나씩 알아가면 돼."
실전 팁
💡 - 처음에는 gpt-4o-mini로 시작하세요. 저렴하면서도 충분히 유능합니다.
- API 키는 반드시 환경 변수로 관리하세요. 코드에 직접 넣으면 보안 위험이 있습니다.
3. Chat Completions API 사용법
김개발 씨가 드디어 첫 번째 API 호출에 성공했습니다. "안녕하세요!"라고 보냈더니 AI가 친절하게 인사를 해줍니다.
그런데 문득 궁금해졌습니다. "이걸 어떻게 활용하면 되지?
그냥 인사만 주고받을 건 아닌데..."
Chat Completions API는 단순한 질문-답변을 넘어 다양한 작업을 수행할 수 있습니다. 마치 만능 비서를 고용한 것과 같습니다.
글을 요약해달라고 하면 요약하고, 번역해달라고 하면 번역하고, 코드를 작성해달라고 하면 코드를 작성합니다. 핵심은 프롬프트를 어떻게 작성하느냐에 달려 있습니다.
다음 코드를 살펴봅시다.
from openai import OpenAI
client = OpenAI()
# 고객 리뷰를 분석하는 실용적인 예제
review = "배송이 정말 빨랐어요! 다만 포장이 좀 아쉬웠습니다."
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{
"role": "user",
"content": f"""다음 고객 리뷰를 분석해주세요.
리뷰: {review}
다음 형식으로 답변해주세요:
- 감정: (긍정/부정/중립)
- 장점:
- 개선점: """
}
]
)
print(response.choices[0].message.content)
김개발 씨에게 새로운 업무가 떨어졌습니다. 하루에 수백 개씩 쌓이는 고객 리뷰를 분석해서 긍정적인 것과 부정적인 것을 분류해달라는 요청입니다.
"이걸 일일이 읽어보라고?" 김개발 씨는 막막했습니다. 그때 박시니어 씨가 말했습니다.
"Chat API한테 시키면 되지." Chat Completions API의 진정한 힘은 프롬프트 엔지니어링에 있습니다. 프롬프트란 AI에게 보내는 지시문입니다.
같은 API라도 프롬프트를 어떻게 작성하느냐에 따라 완전히 다른 결과가 나옵니다. 마치 같은 요리사에게 "맛있는 거 해줘"라고 말하는 것과 "토마토 파스타를 만들어 줘.
면은 알덴테로, 바질을 올려서"라고 말하는 것의 차이입니다. 위의 코드를 살펴보겠습니다.
프롬프트에서 세 가지 핵심 요소가 보입니다. 첫째, 명확한 작업 지시입니다.
"다음 고객 리뷰를 분석해주세요"라고 무엇을 해야 하는지 분명히 말합니다. 둘째, 입력 데이터입니다.
분석할 리뷰 텍스트를 제공합니다. 셋째, 출력 형식 지정입니다.
어떤 형태로 답변해야 하는지 구체적으로 명시합니다. 이 부분이 특히 중요합니다.
형식을 지정하지 않으면 AI가 자유롭게 답변하기 때문에 일관성이 떨어집니다. 실제 현업에서는 더 다양한 작업을 수행합니다.
텍스트 요약이 필요하면 "다음 글을 3문장으로 요약해주세요"라고 요청합니다. 번역이 필요하면 "다음 문장을 영어로 번역해주세요"라고 합니다.
코드 리뷰가 필요하면 "다음 코드의 문제점을 찾아주세요"라고 합니다. 한 가지 팁을 드리자면, 예시를 함께 제공하면 더 정확한 결과를 얻을 수 있습니다.
"긍정적 리뷰 예시: '너무 좋아요!' → 긍정"처럼 원하는 결과물의 예시를 보여주면 AI가 패턴을 학습합니다. 김개발 씨는 고객 리뷰 분석 기능을 완성했습니다.
수백 개의 리뷰를 몇 분 만에 분류할 수 있게 되었습니다. "이거 진짜 신세계네요!" 박시니어 씨가 웃으며 말했습니다.
"이제 시작이야. 더 잘 활용하려면 메시지 역할을 알아야 해."
실전 팁
💡 - 프롬프트에 출력 형식을 명확히 지정하세요. JSON 형태로 요청하면 파싱하기 편합니다.
- 복잡한 작업은 단계별로 나눠서 요청하면 더 좋은 결과를 얻을 수 있습니다.
4. 메시지 역할 이해하기
김개발 씨가 만든 리뷰 분석 기능이 잘 작동합니다. 그런데 가끔 AI가 엉뚱한 답변을 합니다.
"분석해줘"라고 했는데 "저는 AI라서 실제 리뷰를 볼 수 없습니다"라고 답하기도 합니다. 박시니어 씨가 코드를 보더니 말했습니다.
"system 메시지를 안 넣었구나."
Chat Completions API의 메시지에는 세 가지 **역할(role)**이 있습니다. system은 AI의 성격과 행동 규칙을 정의하고, user는 사용자의 입력이며, assistant는 AI의 응답입니다.
마치 연극에서 배우에게 배역을 주고, 대본을 건네주는 것과 같습니다. system 메시지로 배역을 정해주면 AI가 그 역할에 맞게 일관되게 행동합니다.
다음 코드를 살펴봅시다.
from openai import OpenAI
client = OpenAI()
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
# system: AI의 역할과 규칙을 정의
{
"role": "system",
"content": "당신은 전문 고객 리뷰 분석가입니다. 리뷰를 분석하여 감정, 주요 키워드, 개선점을 JSON 형식으로 반환합니다."
},
# user: 사용자의 요청
{
"role": "user",
"content": "리뷰: 가격 대비 품질이 훌륭합니다. 배송도 빨랐어요!"
},
# assistant: 이전 AI 응답 (대화 기록용)
{
"role": "assistant",
"content": '{"감정": "긍정", "키워드": ["가성비", "배송"], "개선점": "없음"}'
},
# user: 새로운 요청
{
"role": "user",
"content": "리뷰: 디자인은 예쁜데 내구성이 약해요."
}
]
)
print(response.choices[0].message.content)
김개발 씨는 고개를 갸웃거렸습니다. "system 메시지요?
그게 뭔데요?" 박시니어 씨가 설명을 시작했습니다. "연극을 생각해봐.
배우한테 배역을 안 주면 어떻게 되겠어?" system 메시지는 AI에게 역할을 부여합니다. "당신은 친절한 고객 상담원입니다"라고 하면 AI는 친절하게 응답합니다.
"당신은 엄격한 코드 리뷰어입니다"라고 하면 AI는 코드의 문제점을 날카롭게 지적합니다. system 메시지 없이 요청하면 AI는 범용적인 어시스턴트처럼 행동합니다.
user 메시지는 사용자의 입력입니다. 실제 사용자가 보내는 질문이나 요청이 여기에 들어갑니다.
이 부분은 직관적이라 따로 설명이 필요 없을 것입니다. assistant 메시지는 AI의 이전 응답입니다.
이 부분이 흥미롭습니다. 왜 AI의 응답을 다시 넣어줄까요?
바로 대화 맥락을 유지하기 위해서입니다. OpenAI API는 상태를 저장하지 않습니다.
매번 새로운 요청으로 취급됩니다. 따라서 대화를 이어가려면 이전 대화 내용을 함께 보내야 합니다.
user와 assistant 메시지를 번갈아 넣어주면 AI가 이전 대화를 기억하는 것처럼 동작합니다. 위의 코드를 살펴보면 이 구조가 잘 드러납니다.
먼저 system 메시지로 "전문 고객 리뷰 분석가"라는 역할을 부여합니다. 그 다음 이전 대화 기록(user-assistant 쌍)을 넣어줍니다.
마지막으로 새로운 user 메시지를 추가합니다. AI는 이 모든 맥락을 이해하고 일관된 형식으로 응답합니다.
실무에서 흔히 하는 실수가 있습니다. system 메시지를 너무 길게 작성하는 것입니다.
system 메시지도 토큰을 소비합니다. 핵심적인 역할과 규칙만 간결하게 작성하는 것이 좋습니다.
또 다른 실수는 대화 기록을 무한정 쌓는 것입니다. 대화가 길어지면 토큰 사용량이 급증합니다.
적절히 오래된 대화를 잘라내거나 요약하는 전략이 필요합니다. 김개발 씨가 system 메시지를 추가하자 AI의 응답이 훨씬 일관되어졌습니다.
"오, 이제 항상 JSON으로 답변하네요!" 박시니어 씨가 웃었습니다. "그게 system 메시지의 힘이야.
이제 파라미터도 조절해볼까?"
실전 팁
💡 - system 메시지는 간결하되 명확하게 작성하세요. 역할, 제약 사항, 출력 형식을 포함하면 좋습니다.
- 대화 기록은 최근 5-10개 정도만 유지하세요. 오래된 대화는 요약해서 system 메시지에 넣는 방법도 있습니다.
5. API 파라미터 설정하기
김개발 씨가 챗봇을 만들었습니다. 그런데 매번 같은 질문에 똑같은 답변만 합니다.
좀 더 창의적인 답변을 원하는데 어떻게 해야 할까요? 반대로 고객 문의 분류 기능에서는 너무 창의적인 답변이 나와서 문제입니다.
박시니어 씨가 힌트를 줍니다. "temperature를 조절해봐."
Chat Completions API에는 AI의 행동을 세밀하게 조절하는 파라미터들이 있습니다. temperature는 창의성을 조절하고, max_tokens는 응답 길이를 제한하며, top_p는 단어 선택 범위를 조절합니다.
마치 오디오 믹서의 슬라이더처럼, 이 파라미터들을 조절해서 원하는 결과물을 만들어낼 수 있습니다.
다음 코드를 살펴봅시다.
from openai import OpenAI
client = OpenAI()
# 창의적인 글쓰기용 설정
creative_response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": "봄을 주제로 시를 써주세요."}],
temperature=0.9, # 높을수록 창의적 (0~2)
max_tokens=500, # 최대 응답 길이
top_p=0.95 # 단어 선택 다양성
)
# 정확한 분류 작업용 설정
precise_response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": "이 문장의 감정을 분류하세요: 정말 실망스럽네요"}],
temperature=0.1, # 낮을수록 일관적
max_tokens=50 # 짧은 응답으로 제한
)
김개발 씨는 두 가지 기능을 만들고 있습니다. 하나는 마케팅 문구를 생성하는 기능이고, 다른 하나는 고객 문의를 분류하는 기능입니다.
문제는 두 기능이 전혀 다른 성격이라는 점입니다. 마케팅 문구는 매번 새롭고 창의적이어야 합니다.
같은 제품이라도 다양한 표현으로 소개해야 합니다. 반면 고객 문의 분류는 정확하고 일관되어야 합니다.
"환불 요청"은 항상 "환불 요청"으로 분류되어야 합니다. temperature 파라미터가 이 문제를 해결합니다.
temperature는 0에서 2 사이의 값을 가집니다. 0에 가까울수록 AI는 가장 확률 높은 답변만 선택합니다.
따라서 일관되고 예측 가능한 응답이 나옵니다. 반대로 값이 높을수록 AI는 다양한 가능성을 탐색합니다.
창의적이고 예상치 못한 응답이 나올 수 있습니다. 비유하자면 이렇습니다.
temperature가 낮으면 AI는 "모범생"처럼 행동합니다. 정답만 말하고 튀는 행동을 하지 않습니다.
temperature가 높으면 AI는 "예술가"처럼 행동합니다. 때로는 기발한 아이디어를, 때로는 엉뚱한 답변을 내놓습니다.
max_tokens 파라미터도 중요합니다. 토큰은 대략 한글 기준 한 글자 정도입니다.
max_tokens를 100으로 설정하면 대략 100자 정도의 응답을 받습니다. 이 파라미터는 비용 관리에도 중요합니다.
API 비용은 토큰 수에 비례하기 때문입니다. top_p 파라미터는 temperature와 비슷한 역할을 합니다.
다만 작동 방식이 다릅니다. top_p는 확률 상위 몇 퍼센트의 단어만 고려할지 결정합니다.
0.1로 설정하면 상위 10%의 가능성 있는 단어만 사용합니다. 일반적으로 temperature와 top_p 중 하나만 조절하는 것이 좋습니다.
실무에서의 권장 설정을 알려드리겠습니다. 데이터 추출, 분류, 변환 같은 정확성이 중요한 작업은 temperature를 0에서 0.3 사이로 설정하세요.
글쓰기, 아이디어 생성, 대화 같은 창의성이 필요한 작업은 0.7에서 1.0 사이가 적당합니다. 김개발 씨는 분류 기능에는 temperature 0.1을, 마케팅 문구 생성에는 temperature 0.8을 설정했습니다.
"오, 분류가 훨씬 정확해졌어요!" 박시니어 씨가 고개를 끄덕였습니다. "이제 응답을 잘 처리하는 법을 알아보자."
실전 팁
💡 - 분류, 추출 작업은 temperature 0.1 이하로 설정하세요.
- max_tokens를 적절히 제한하면 비용을 절약할 수 있습니다.
- temperature와 top_p를 동시에 크게 조절하지 마세요. 결과가 불안정해집니다.
6. 응답 파싱하고 활용하기
김개발 씨의 API 호출은 성공적입니다. 그런데 새로운 고민이 생겼습니다.
AI가 보내주는 응답을 어떻게 프로그램에서 활용해야 할까요? 문자열 그대로 쓸 수는 없으니 적절히 가공해야 합니다.
특히 JSON 형태로 받은 응답은 파싱해서 사용해야 합니다.
API 응답은 구조화된 객체로 돌아옵니다. 우리가 필요한 텍스트는 깊숙이 들어있어서 올바른 경로로 접근해야 합니다.
또한 AI에게 JSON 형식으로 응답하라고 요청하면 response_format 파라미터를 사용해서 더 안정적으로 JSON을 받을 수 있습니다. 마치 택배 상자를 열고 완충재를 걷어내야 실제 상품이 나오는 것처럼, 응답 객체에서 필요한 데이터를 추출하는 방법을 알아야 합니다.
다음 코드를 살펴봅시다.
from openai import OpenAI
import json
client = OpenAI()
# JSON 형식 응답 요청
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": "JSON 형식으로만 응답하세요."},
{"role": "user", "content": "서울의 유명 관광지 3곳을 추천해주세요."}
],
response_format={"type": "json_object"} # JSON 모드 활성화
)
# 응답 구조 이해하기
content = response.choices[0].message.content # 문자열
data = json.loads(content) # 딕셔너리로 변환
# 메타데이터 활용
print(f"사용 토큰: {response.usage.total_tokens}")
print(f"모델: {response.model}")
print(f"결과: {data}")
김개발 씨가 API 응답을 받아서 화면에 출력했습니다. 그런데 뭔가 이상합니다.
"이 response 객체가 뭐예요? 제가 원하는 텍스트는 어디 있는 거죠?" 박시니어 씨가 응답 구조를 설명해주었습니다.
API 응답은 여러 정보를 담고 있는 객체입니다. response.choices는 생성된 응답들의 리스트입니다.
보통 한 개의 응답만 요청하므로 **choices[0]**을 사용합니다. choices[0].message는 메시지 객체입니다.
여기에 역할(role)과 내용(content)이 있습니다. choices[0].message.content가 우리가 원하는 실제 텍스트입니다.
여기서 중요한 점이 있습니다. content는 항상 문자열입니다.
AI에게 JSON으로 답해달라고 해도 받는 것은 JSON 형태의 문자열입니다. 이것을 프로그램에서 사용하려면 **json.loads()**로 파싱해야 합니다.
response_format 파라미터는 JSON 응답을 더 안정적으로 받게 해줍니다. 이 옵션을 사용하면 AI가 반드시 유효한 JSON 형식으로 응답합니다.
사용하지 않으면 가끔 JSON 앞뒤에 설명 문구가 붙어서 파싱 에러가 날 수 있습니다. response.usage도 유용한 정보를 제공합니다.
prompt_tokens는 요청에 사용된 토큰 수, completion_tokens는 응답에 사용된 토큰 수, total_tokens는 합계입니다. 이 정보로 API 사용 비용을 추적할 수 있습니다.
실무에서 흔히 하는 실수가 있습니다. JSON 파싱 시 예외 처리를 하지 않는 것입니다.
아무리 response_format을 설정해도 네트워크 문제 등으로 이상한 응답이 올 수 있습니다. 반드시 try-except로 감싸세요.
또 다른 실수는 응답이 비어있는 경우를 고려하지 않는 것입니다. API 제한에 걸리거나 콘텐츠 필터에 걸리면 빈 응답이 올 수 있습니다.
김개발 씨가 코드를 수정했습니다. "이제 응답을 깔끔하게 딕셔너리로 받아서 쓸 수 있네요!" 박시니어 씨가 말했습니다.
"좋아, 그런데 아직 중요한 게 남았어. 에러 처리를 안 하면 서비스가 터질 수 있어."
실전 팁
💡 - JSON 응답이 필요하면 response_format과 system 메시지를 함께 사용하세요.
- json.loads()는 반드시 try-except로 감싸세요. 예상치 못한 응답에 대비해야 합니다.
- usage 정보를 로깅해서 비용을 모니터링하세요.
7. 에러 핸들링과 재시도 로직
김개발 씨가 만든 서비스가 드디어 배포되었습니다. 그런데 다음 날 아침, 알람이 울립니다.
"API 호출 실패!" 원인을 찾아보니 OpenAI 서버가 일시적으로 불안정했던 것 같습니다. 이런 상황에서도 서비스가 안정적으로 동작하려면 어떻게 해야 할까요?
외부 API를 사용할 때는 반드시 에러 핸들링이 필요합니다. 네트워크 문제, 서버 과부하, 요청 한도 초과 등 다양한 이유로 실패할 수 있기 때문입니다.
재시도 로직을 구현하면 일시적인 오류에서 자동으로 복구할 수 있습니다. 마치 전화가 안 될 때 몇 번 더 시도해보는 것처럼, 프로그램도 실패했을 때 다시 시도하도록 만들어야 합니다.
다음 코드를 살펴봅시다.
from openai import OpenAI, APIError, RateLimitError, APIConnectionError
import time
client = OpenAI()
def call_api_with_retry(messages, max_retries=3):
"""재시도 로직이 포함된 API 호출 함수"""
for attempt in range(max_retries):
try:
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=messages,
timeout=30 # 30초 타임아웃
)
return response.choices[0].message.content
except RateLimitError:
# 요청 한도 초과 - 대기 후 재시도
wait_time = (attempt + 1) * 5
print(f"한도 초과. {wait_time}초 대기 중...")
time.sleep(wait_time)
except APIConnectionError:
# 연결 실패 - 짧게 대기 후 재시도
time.sleep(2)
except APIError as e:
# 기타 API 에러 - 로깅 후 재시도
print(f"API 에러: {e}")
time.sleep(1)
raise Exception("최대 재시도 횟수 초과")
김개발 씨는 배포 첫날 밤을 뜬눈으로 보냈습니다. 새벽 3시에 알람이 울렸기 때문입니다.
"Rate limit exceeded"라는 에러 메시지가 화면을 가득 채웠습니다. 박시니어 씨가 출근하자마자 말했습니다.
"외부 API는 믿으면 안 돼. 항상 실패할 수 있다고 가정해야 해." API 호출이 실패하는 이유는 다양합니다.
첫째, RateLimitError입니다. 짧은 시간에 너무 많은 요청을 보내면 발생합니다.
OpenAI는 분당, 일당 요청 한도를 설정해두고 있습니다. 둘째, APIConnectionError입니다.
네트워크 문제로 서버에 연결하지 못할 때 발생합니다. 인터넷이 불안정하거나 OpenAI 서버가 다운되었을 수 있습니다.
셋째, APIError입니다. 서버 내부 오류나 잘못된 요청 등 다양한 원인으로 발생합니다.
재시도 로직은 이런 일시적인 오류를 극복하게 해줍니다. 핵심은 **지수 백오프(exponential backoff)**입니다.
첫 번째 실패 후에는 짧게 기다리고, 두 번째 실패 후에는 더 길게 기다립니다. 이렇게 하면 서버가 회복될 시간을 주면서도 불필요한 대기를 줄일 수 있습니다.
위의 코드를 살펴보겠습니다. max_retries로 최대 재시도 횟수를 설정합니다.
무한히 재시도하면 안 됩니다. RateLimitError의 경우 대기 시간을 점점 늘립니다.
(attempt + 1) * 5로 5초, 10초, 15초 순으로 대기합니다. timeout 파라미터도 중요합니다.
응답이 너무 오래 걸리면 자동으로 실패 처리합니다. 그렇지 않으면 요청 하나가 전체 시스템을 멈추게 할 수 있습니다.
실무에서는 더 정교한 처리가 필요합니다. 로깅을 추가해서 어떤 에러가 얼마나 자주 발생하는지 모니터링해야 합니다.
에러가 지속되면 알림을 보내는 기능도 필요합니다. 또한 fallback 응답을 준비해두는 것도 좋습니다.
API가 완전히 실패해도 서비스가 최소한의 동작은 하도록 만드는 것입니다. 김개발 씨는 재시도 로직을 적용했습니다.
그날 밤부터 알람이 훨씬 줄었습니다. "이제 좀 잘 수 있겠네요." 박시니어 씨가 웃으며 말했습니다.
"축하해. 이제 LLM API 기본은 다 익혔어.
다음은 더 고급 기술을 배워볼까?" 김개발 씨는 뿌듯한 표정으로 고개를 끄덕였습니다. API라는 것이 처음에는 막막했는데, 하나씩 배워가니 어느새 실무에서 활용할 수 있는 수준이 되었습니다.
여러분도 오늘 배운 내용을 실제 프로젝트에 적용해보세요. 처음에는 간단한 기능부터 시작해서 점점 복잡한 기능으로 확장해 나가면 됩니다.
실전 팁
💡 - 재시도 횟수는 3-5회가 적당합니다. 너무 많이 재시도하면 비용이 늘어납니다.
- RateLimitError는 대기 시간을 충분히 주세요. 급하게 재시도하면 계속 실패합니다.
- 프로덕션에서는 tenacity 같은 라이브러리를 사용하면 더 편리합니다.
이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!
댓글 (0)
함께 보면 좋은 카드 뉴스
Helm 마이크로서비스 패키징 완벽 가이드
Kubernetes 환경에서 마이크로서비스를 효율적으로 패키징하고 배포하는 Helm의 핵심 기능을 실무 중심으로 학습합니다. Chart 생성부터 릴리스 관리까지 체계적으로 다룹니다.
보안 아키텍처 구성 완벽 가이드
프로젝트의 보안을 처음부터 설계하는 방법을 배웁니다. AWS 환경에서 VPC부터 WAF, 암호화, 접근 제어까지 실무에서 바로 적용할 수 있는 보안 아키텍처를 단계별로 구성해봅니다.
AWS Organizations 완벽 가이드
여러 AWS 계정을 체계적으로 관리하고 통합 결제와 보안 정책을 적용하는 방법을 실무 스토리로 쉽게 배워봅니다. 초보 개발자도 바로 이해할 수 있는 친절한 설명과 실전 예제를 제공합니다.
AWS KMS 암호화 완벽 가이드
AWS KMS(Key Management Service)를 활용한 클라우드 데이터 암호화 방법을 초급 개발자를 위해 쉽게 설명합니다. CMK 생성부터 S3, EBS 암호화, 봉투 암호화까지 실무에 필요한 모든 내용을 담았습니다.
AWS Secrets Manager 완벽 가이드
AWS에서 데이터베이스 비밀번호, API 키 등 민감한 정보를 안전하게 관리하는 Secrets Manager의 핵심 개념과 실무 활용법을 배워봅니다. 초급 개발자도 쉽게 따라할 수 있도록 실전 예제와 함께 설명합니다.