AI & MACHINE LEARNING

OpenAI API Python 실전 가이드 - GPT-5.5 챗봇 개발

junetapa 2026. 2. 19 15 min read

ChatGPT 웹에서 대화하는 것과 API를 직접 다루는 것은 완전히 다른 경험이다. API를 쓰면 내가 만든 서비스에 AI를 집어넣을 수 있고, 프롬프트와 응답을 완전히 제어할 수 있다. SDK 설치부터 스트리밍, 히스토리 관리, 실전 챗봇 완성까지 -- 직접 만들어본 과정을 코드 중심으로 정리했다.

2026년 6월 업데이트 — 최신 모델·API 반영

모델: 현재 주력은 gpt-5.5(컨텍스트 1M 토큰, 멀티모달·함수호출·구조화 출력 지원)와 더 저렴한 gpt-5-mini다. 본문의 GPT-4o/GPT-4o-mini 예시는 모두 GPT-5.5 계열로 갱신했다. 레거시 openai.ChatCompletion.create()(0.x SDK) 방식은 폐기됐으며, from openai import OpenAI 기반 v1.x SDK가 표준이다.

API: OpenAI가 신규 Responses API(client.responses.create())를 권장하기 시작했다. 추론 모델에서 더 나은 성능을 내고 도구·상태 관리가 단순하다. 기존 Chat Completions(client.chat.completions.create())도 계속 지원되므로 이 글의 코드는 그대로 동작한다. 한편 Assistants API는 2026년 내 종료(sunset) 예정이라, 새 프로젝트는 Responses API로 시작하는 편이 안전하다.

왜 API를 직접 써야 하는가

ChatGPT 웹사이트에서 대화하는 것만으로도 많은 것을 할 수 있다. 그런데 왜 굳이 API를 직접 호출해야 하는가? 핵심은 제어권이다.

웹 인터페이스에서는 OpenAI가 정한 규칙 안에서만 움직인다. 하지만 API를 쓰면 System Prompt로 AI의 성격을 설계하고, 응답 형식을 JSON으로 강제하고, 내 서비스의 로직 안에 AI를 자연스럽게 녹여넣을 수 있다. 슬랙봇, 자동 이메일 분류기, 코드 리뷰 도구 -- 이런 것들은 웹 인터페이스로는 만들 수 없다.

  • 자동화 -- 반복 업무(메일 요약, 보고서 초안, 데이터 분류)를 코드로 자동화할 수 있다. 사람이 복사-붙여넣기하는 과정이 사라진다.
  • 서비스 통합 -- 내가 만든 웹앱이나 모바일앱에 AI 기능을 직접 내장할 수 있다. 사용자가 ChatGPT를 따로 열 필요 없이, 내 서비스 안에서 AI와 대화한다.
  • 비용 통제 -- ChatGPT Plus는 월 $20 고정이다. API는 사용한 만큼만 낸다. 가벼운 작업에는 저렴한 모델(gpt-5-mini)을, 복잡한 작업에만 고성능 모델(gpt-5.5)을 쓰면 비용을 크게 줄일 수 있다.
  • 프롬프트 완전 제어 -- temperature, max_tokens, response_format 같은 파라미터를 직접 조절해서 응답의 창의성, 길이, 형식을 세밀하게 통제한다.

환경 설정과 API 키 보안

SDK 설치

OpenAI는 공식 Python 라이브러리를 제공한다. 2023년 말에 나온 v1.0 이후로 API 사용법이 완전히 바뀌었기 때문에, 반드시 1.x 이상인지 확인해야 한다. 옛 자료에 자주 보이는 openai.ChatCompletion.create() 방식은 0.x SDK용 레거시 문법으로 지금은 동작하지 않는다. 현재(2026년)는 from openai import OpenAI로 클라이언트 인스턴스를 만들어 쓰는 v1.x 방식이 표준이다.

터미널 # 가상환경 생성 (권장) python -m venv .venv source .venv/bin/activate # macOS/Linux .venv\Scripts\activate # Windows # SDK 설치 pip install openai python-dotenv # 버전 확인 python -c "import openai; print(openai.__version__)"

API 키 발급과 보안

platform.openai.com에서 회원가입 후 API Keys 메뉴에서 키를 발급받는다. 키는 발급 시 한 번만 표시되므로 즉시 안전한 곳에 저장해야 한다.

Python # .env 파일 (프로젝트 루트에 생성) OPENAI_API_KEY=sk-proj-xxxxxxxxxxxxxxxxxxxx # main.py import os from dotenv import load_dotenv from openai import OpenAI load_dotenv() client = OpenAI( api_key=os.getenv("OPENAI_API_KEY") )
보안 원칙

API 키를 GitHub에 올리면 수분 내로 악용된다. .gitignore.env를 반드시 추가하고, 키가 노출됐다면 즉시 폐기 후 재발급해야 한다. 코드에 키를 하드코딩하는 것은 절대 금지다.

Chat Completions 기본 사용법

OpenAI API의 가장 보편적인 진입점은 chat.completions.create()다. 대화 형식의 메시지 배열을 보내고 응답을 받는 구조로, 가장 많은 예제와 라이브러리가 이 방식을 전제로 한다.

Python from openai import OpenAI client = OpenAI() # OPENAI_API_KEY 환경변수 자동 사용 response = client.chat.completions.create( model="gpt-5.5", messages=[ {"role": "user", "content": "파이썬으로 피보나치 수열을 구현해줘"} ], temperature=0.7, # 0(일관성) ~ 2(창의성) max_tokens=1000, # 응답 최대 토큰 수 ) # 응답 텍스트 추출 answer = response.choices[0].message.content print(answer) # 토큰 사용량 확인 print(f"사용 토큰: {response.usage.total_tokens}")

신규 Responses API -- 더 단순한 인터페이스

2026년 들어 OpenAI는 Responses API(client.responses.create())를 새로운 권장 방식으로 밀고 있다. 추론 모델에서 더 좋은 성능을 내고, 입력을 문자열 하나로 간단히 넘길 수 있으며, 도구 호출과 상태 관리가 매끄럽다. Chat Completions도 계속 지원되니 둘 중 익숙한 쪽을 쓰면 된다.

Python -- Responses API from openai import OpenAI client = OpenAI() response = client.responses.create( model="gpt-5.5", input="파이썬으로 피보나치 수열을 구현해줘", ) # 응답 텍스트는 output_text 한 줄로 바로 꺼낸다 print(response.output_text) print(f"사용 토큰: {response.usage.total_tokens}")

메시지 역할(role) 구조

OpenAI API는 세 가지 역할로 대화를 구성한다. 이 구조를 이해하는 것이 API 활용의 첫 번째 열쇠다.

role 역할 사용 예시
system AI의 역할, 성격, 제약 조건 설정 "당신은 한국어로만 답변하는 개발자 도우미다."
user 사용자의 입력 "파이썬으로 정렬 알고리즘 설명해줘"
assistant AI의 이전 응답 (히스토리 유지용) 직전 AI 응답 내용을 그대로 넣는다

System Prompt 설계

System Prompt는 AI의 행동 방식을 결정하는 가장 중요한 요소다. 같은 모델이라도 System Prompt에 따라 완전히 다른 캐릭터가 된다. 잘 짠 프롬프트 하나가 파인튜닝보다 효과적인 경우가 많다.

Python SYSTEM_PROMPT = """당신은 Python 개발 전문 어시스턴트다. 역할: - Python 코드 작성, 디버깅, 코드 리뷰를 담당한다. - 항상 실행 가능한 코드를 제공하고, 주석을 충분히 단다. - 보안이나 성능 이슈가 있으면 반드시 언급한다. 답변 규칙: - 한국어로 답변한다. - 코드는 ```python 코드블록```으로 감싼다. - 복잡한 개념은 단계별로 설명한다. - 모르는 것은 솔직하게 모른다고 한다. 금지사항: - 허위 정보 제공 금지 - 악의적인 코드 작성 금지""" response = client.chat.completions.create( model="gpt-5.5", messages=[ {"role": "system", "content": SYSTEM_PROMPT}, {"role": "user", "content": "SQL 인젝션 방어 코드 작성해줘"} ] )
프롬프트 설계 4원칙

좋은 System Prompt에는 네 가지 요소가 들어간다. (1) 역할을 명확히 정의한다 (2) 원하는 응답 형식을 명시한다 (3) 금지 사항을 열거한다 (4) 예시(few-shot)를 포함한다. 이 네 가지를 갖추면 응답 품질이 눈에 띄게 올라간다.

스트리밍 응답 구현

일반 호출은 응답 전체가 생성될 때까지 기다려야 한다. 긴 답변이면 수 초간 빈 화면을 보게 되는데, 사용자 입장에서 이 대기 시간은 상당히 불쾌하다. 스트리밍을 쓰면 ChatGPT처럼 글자가 하나씩 나타나는 경험을 구현할 수 있다.

Python stream = client.chat.completions.create( model="gpt-5.5", messages=[ {"role": "user", "content": "파이썬의 장점 5가지를 설명해줘"} ], stream=True # 핵심: 스트리밍 활성화 ) full_response = "" for chunk in stream: delta = chunk.choices[0].delta if delta.content is not None: print(delta.content, end="", flush=True) full_response += delta.content print() # 줄바꿈

stream=True를 설정하면 응답이 chunk 단위로 나눠서 도착한다. 각 chunk에서 delta.content를 꺼내 이어붙이면 된다. flush=True는 버퍼 없이 즉시 출력하겠다는 의미다. 웹 서비스에서는 이 chunk를 Server-Sent Events(SSE)로 클라이언트에 전달하는 방식이 일반적이다.

대화 히스토리 관리

OpenAI API는 stateless다. 매 요청이 독립적이라 이전 대화를 기억하지 못한다. "방금 말한 거 수정해줘"라고 해도, API는 "방금"이 뭔지 모른다. 대화 흐름을 유지하려면 이전 메시지들을 직접 messages 배열에 누적해서 보내야 한다.

Python class ChatBot: def __init__(self, system_prompt: str): self.messages = [ {"role": "system", "content": system_prompt} ] self.client = OpenAI() def chat(self, user_input: str) -> str: self.messages.append({"role": "user", "content": user_input}) response = self.client.chat.completions.create( model="gpt-5-mini", messages=self.messages, max_tokens=1500 ) assistant_msg = response.choices[0].message.content self.messages.append({"role": "assistant", "content": assistant_msg}) return assistant_msg def reset(self): """system prompt만 남기고 대화 초기화""" self.messages = [self.messages[0]] # 사용 bot = ChatBot("당신은 Python 튜터다.") print(bot.chat("리스트 컴프리헨션이 뭐야?")) print(bot.chat("방금 설명한 거 예시 코드 보여줘")) # 이전 대화를 기억한다

주의할 점은, 대화가 길어질수록 매 요청에 보내는 토큰 수가 누적된다는 것이다. 20턴 대화를 이어가면 이전 대화 전체가 매번 입력으로 들어간다. 비용이 기하급수적으로 올라가므로, 적절한 시점에 오래된 메시지를 잘라내는 로직이 필수다.

모델 선택 -- GPT-5.5 vs GPT-5-mini

2026년 6월 기준 OpenAI의 주력 모델을 비교하면 다음과 같다. 용도에 맞는 모델을 선택하는 것만으로도 비용을 90% 이상 절감할 수 있다. 가격은 100만(1M) 토큰 단위이며 변동될 수 있으니 결제 직전에는 공식 가격 페이지를 확인하는 게 좋다.

모델 특징 입력 가격 (1M 토큰) 출력 가격 (1M 토큰) 적합한 용도
gpt-5.5 최고 성능, 멀티모달(이미지 입력), 컨텍스트 1M 토큰 $5 $30 복잡한 분석, 코딩, 이미지 이해, 장문 처리
gpt-5.5-pro 최고 정확도(고난도 추론), 가장 비쌈 $30 $180 고난도 추론, 검증이 중요한 워크로드
gpt-5-mini 빠른 속도, 저비용 $0.25 $2.0 대화봇, 분류, 간단한 요약

내가 실제로 개발할 때 쓰는 전략은 이렇다. 개발과 테스트 단계에서는 gpt-5-mini로 빠르게 반복하고, 응답 품질이 부족한 특정 기능에만 gpt-5.5를 적용한다. 일반적인 대화봇, 텍스트 분류, 간단한 요약 같은 작업은 mini로 충분하다. gpt-5.5를 꺼내야 하는 경우는 복잡한 코드 생성이나 이미지 분석, 장문 컨텍스트 처리처럼 높은 추론 능력이 필요한 작업뿐이다. 최상위 정확도가 필요한 소수의 작업에만 gpt-5.5-pro를 제한적으로 쓴다.

토큰 관리와 비용 최적화

토큰은 API 요금의 기본 단위다. 영어는 단어 하나가 대략 1~1.3토큰이지만, 한국어는 글자 하나가 2~3토큰을 소비한다. 같은 내용이라도 한국어로 주고받으면 영어의 1.5~2배 비용이 든다.

Python import tiktoken # pip install tiktoken def count_tokens(text: str, model: str = "gpt-5.5") -> int: """텍스트의 토큰 수를 계산한다.""" try: encoding = tiktoken.encoding_for_model(model) except KeyError: # 최신 모델은 o200k_base 인코딩을 사용한다 encoding = tiktoken.get_encoding("o200k_base") return len(encoding.encode(text)) def estimate_cost(input_tokens: int, output_tokens: int, model: str = "gpt-5-mini") -> float: """예상 비용을 USD로 계산한다. (1M 토큰 단가 기준)""" prices = { "gpt-5.5": {"input": 5.0, "output": 30.0}, "gpt-5-mini": {"input": 0.25, "output": 2.0}, } p = prices.get(model, prices["gpt-5-mini"]) return (input_tokens * p["input"] + output_tokens * p["output"]) / 1_000_000 def trim_history(messages: list, max_tokens: int = 3000) -> list: """토큰 한도 초과 시 오래된 대화를 삭제한다.""" system = messages[0] history = messages[1:] while history: total = sum(count_tokens(m["content"]) for m in [system] + history) if total <= max_tokens: break history.pop(0) return [system] + history
비용 절감 팁

System Prompt를 간결하게 유지하는 것만으로도 비용이 줄어든다. 매 요청마다 System Prompt가 입력 토큰에 포함되기 때문이다. 500토큰짜리 프롬프트를 200토큰으로 줄이면, 1000번 호출 시 30만 토큰을 절약한다. 또한 동일한 System Prompt를 반복 사용한다면 Prompt Caching이 자동 적용돼 캐시된 입력 토큰은 크게 할인되며, 대량 비동기 작업은 Batch API로 보내면 약 50% 저렴하다.

함수 호출(Function Calling)과 임베딩

챗봇이 단순히 말만 하는 단계를 넘어서면, 외부 데이터를 조회하거나 실제 동작을 수행하게 만들고 싶어진다. 이때 쓰는 것이 함수 호출(Function Calling, tools)이다. 모델에게 "이런 함수들을 쓸 수 있다"고 알려주면, 모델은 필요할 때 어떤 함수를 어떤 인자로 부를지 JSON으로 알려준다. 실제 실행은 내 코드가 하고, 그 결과를 다시 모델에게 돌려줘 최종 답변을 만든다.

Python -- 함수 호출(tools) import json from openai import OpenAI client = OpenAI() # 1) 모델에게 알려줄 함수 정의(스키마) tools = [{ "type": "function", "function": { "name": "get_weather", "description": "특정 도시의 현재 날씨를 조회한다", "parameters": { "type": "object", "properties": { "city": {"type": "string", "description": "도시 이름"} }, "required": ["city"] } } }] # 2) 실제 함수 구현 (여기서는 더미 대신 예시 값) def get_weather(city: str) -> str: # 실제로는 기상청/외부 API를 호출한다 return f"{city}의 현재 날씨는 맑음, 기온 22도" messages = [{"role": "user", "content": "서울 날씨 어때?"}] # 3) 1차 호출 -- 모델이 함수 호출을 요청하는지 확인 response = client.chat.completions.create( model="gpt-5.5", messages=messages, tools=tools, ) msg = response.choices[0].message # 4) 모델이 함수 호출을 요청하면 실행 후 결과를 다시 전달 if msg.tool_calls: messages.append(msg) # 모델의 함수 호출 요청 기록 for call in msg.tool_calls: args = json.loads(call.function.arguments) result = get_weather(**args) messages.append({ "role": "tool", "tool_call_id": call.id, "content": result, }) # 5) 함수 결과를 반영한 최종 답변 final = client.chat.completions.create( model="gpt-5.5", messages=messages, ) print(final.choices[0].message.content)

임베딩(Embeddings) -- 의미 검색의 기초

임베딩은 텍스트를 의미를 담은 숫자 벡터로 바꾸는 기능이다. 문서 검색, FAQ 매칭, RAG(검색 증강 생성)처럼 "비슷한 의미의 글을 찾는" 작업의 핵심 재료다. 임베딩 모델은 입력 토큰 비용만 들고 출력 토큰이 없어 아주 저렴하다(예: text-embedding-3-small 약 $0.02 / 1M 토큰).

Python -- 임베딩 from openai import OpenAI client = OpenAI() resp = client.embeddings.create( model="text-embedding-3-small", input="파이썬으로 챗봇 만드는 법", ) vector = resp.data[0].embedding # 1536차원 실수 벡터 print(len(vector)) # 1536 # 여러 문장을 한 번에 임베딩할 수도 있다 resp = client.embeddings.create( model="text-embedding-3-small", input=["첫 번째 문서", "두 번째 문서", "세 번째 문서"], ) print(len(resp.data)) # 3

더 높은 정확도가 필요하면 text-embedding-3-large(약 $0.13 / 1M 토큰)를 쓴다. 임베딩 벡터끼리 코사인 유사도를 계산하면 의미적으로 가까운 문서를 찾을 수 있고, 이 결과를 프롬프트에 끼워 넣으면 모델이 모르는 사내 문서 기반 답변(RAG)을 만들 수 있다.

실전 챗봇 완성 코드

지금까지 다룬 내용을 전부 결합한 터미널 챗봇이다. 스트리밍, 히스토리 관리, 자동 정리가 포함되어 있고, 그대로 복사해서 실행할 수 있다.

Python -- chatbot.py """ 실전 터미널 챗봇 pip install openai python-dotenv """ import os from openai import OpenAI from dotenv import load_dotenv load_dotenv() SYSTEM_PROMPT = """당신은 유능한 한국어 AI 어시스턴트다. 사용자의 질문에 정확하고 간결하게 답변한다. 모르는 것은 솔직하게 모른다고 한다.""" class TerminalChatBot: def __init__(self): self.client = OpenAI() self.messages = [{"role": "system", "content": SYSTEM_PROMPT}] def chat(self, user_input: str): self.messages.append({"role": "user", "content": user_input}) print("\nAI: ", end="", flush=True) full_response = "" stream = self.client.chat.completions.create( model="gpt-5-mini", messages=self.messages, max_tokens=2000, stream=True ) for chunk in stream: delta = chunk.choices[0].delta if delta.content: print(delta.content, end="", flush=True) full_response += delta.content print("\n") self.messages.append({"role": "assistant", "content": full_response}) # 히스토리 자동 정리 (10턴 초과 시) if len(self.messages) > 21: self.messages = [self.messages[0]] + self.messages[-20:] def main(): bot = TerminalChatBot() print("AI 챗봇 시작 (종료: quit)\n") while True: user_input = input("You: ").strip() if not user_input: continue if user_input.lower() in ["quit", "exit", "종료"]: print("종료.") break bot.chat(user_input) if __name__ == "__main__": main()

에러 처리와 운영 팁

프로덕션에서 OpenAI API를 쓸 때 반드시 처리해야 하는 에러들이 있다. 특히 Rate Limit은 피할 수 없으므로 재시도 로직이 필수다.

Python from openai import OpenAI, APIError, RateLimitError, AuthenticationError import time def safe_chat(client: OpenAI, messages: list, retries: int = 3) -> str: """에러 처리 + 재시도 로직이 포함된 API 호출""" for attempt in range(retries): try: response = client.chat.completions.create( model="gpt-5-mini", messages=messages, max_tokens=1000, timeout=30 ) return response.choices[0].message.content except AuthenticationError: print("API 키가 유효하지 않다.") raise except RateLimitError: wait = 2 ** attempt # 지수 백오프: 1, 2, 4초 print(f"Rate limit. {wait}초 후 재시도...") time.sleep(wait) except APIError as e: print(f"API 오류 (시도 {attempt+1}/{retries}): {e}") if attempt == retries - 1: raise time.sleep(1) return "응답을 가져올 수 없다."

운영 체크리스트

  • API 키 -- 환경변수로 관리하고, .gitignore에 .env 등록. 키 노출 시 즉시 폐기 후 재발급.
  • Rate Limit -- 지수 백오프(exponential backoff) 재시도 구현. 동시 요청이 많은 서비스라면 요청 큐를 두는 것도 방법이다.
  • max_tokens -- 반드시 설정한다. 설정하지 않으면 모델이 가능한 한 길게 응답하려고 하므로 비용이 폭증할 수 있다.
  • 히스토리 관리 -- 대화가 길어지면 오래된 메시지를 잘라낸다. Context window를 초과하면 API 자체가 에러를 낸다.
  • 타임아웃 -- timeout 파라미터를 설정해서 무한 대기를 방지한다. 네트워크 문제로 응답이 안 올 때를 대비한다.
  • Prompt Injection 방어 -- 사용자 입력을 그대로 프롬프트에 넣으면 위험하다. 입력 길이 제한, 금지 패턴 필터링 등을 적용해야 한다.

OpenAI API의 기본기를 다뤘다. 이것만으로도 실용적인 챗봇이나 자동화 도구를 만들 수 있다. 여기서 더 나아가고 싶다면 Structured Output(JSON 응답 강제), 그리고 신규 Responses API의 내장 도구(웹 검색, 파일 검색, 코드 실행 등)를 살펴보면 된다. 기존 Assistants API는 2026년 내 종료가 예고됐으므로, 새 프로젝트에서는 Responses API를 기준으로 설계하는 것을 권한다.

참고 자료

OpenAI Platform Documentation, platform.openai.com/docs

OpenAI Python SDK GitHub, github.com/openai/openai-python

OpenAI Cookbook, cookbook.openai.com

OpenAI API Python GPT-5.5 챗봇 개발 Chat Completions Responses API 스트리밍
junetapa
junetapa
AI 도구를 직접 써보고 솔직한 경험을 공유하는 개발자.
Twitter Facebook URL 복사