ChatGPT API 파이썬으로 연동하기 — 처음부터 실제 사용까지
API 키 발급받고 나서 "이제 뭘 하지?" 하는 단계가 생각보다 헷갈린다. 문서는 영어고, 예제는 단순하고, 실제로 쓰려면 어디서부터 손대야 할지 막막한 경우가 많다.
이 글에서는 ChatGPT API를 파이썬으로 연동하는 전체 흐름을 정리한다. 단순 Hello World가 아니라, 실제로 쓸 수 있는 구조까지 다룬다.

API 키 발급과 환경 설정
먼저 platform.openai.com에서 계정을 만들고 API 키를 발급받아야 한다. 발급 후에는 키를 코드에 직접 넣지 말고 반드시 환경 변수로 관리한다.
pip install openai python-dotenv
프로젝트 루트에 .env 파일을 만들고 키를 저장한다.
OPENAI_API_KEY=sk-...
.gitignore에 .env를 추가하는 건 기본 중의 기본이다. 실수로 올라가면 키를 즉시 폐기해야 한다.
기본 호출 구조 잡기
openai 라이브러리는 1.x 버전부터 인터페이스가 바뀌었다. 구버전 코드가 많이 돌아다니니 버전 확인이 필요하다.
import os
from openai import OpenAI
from dotenv import load_dotenv
load_dotenv()
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
def ask(prompt: str) -> str:
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "user", "content": prompt}
]
)
return response.choices[0].message.content
gpt-4o-mini는 비용 대비 성능이 괜찮은 편이라 테스트나 단순 자동화에 많이 사용하는 방식이다. 응답 품질이 더 중요하면 gpt-4o로 바꾸면 된다.
호출 결과는 response.choices[0].message.content로 꺼낸다. 처음에는 구조가 낯설지만 한 번 익히면 패턴이 반복된다.
실무에서 자주 쓰는 패턴 3가지
시스템 프롬프트 분리
사용 목적에 따라 AI의 역할을 고정할 수 있다. 이 방식이 관리하기 편했다.
def ask_with_role(system: str, user: str) -> str:
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": system},
{"role": "user", "content": user}
]
)
return response.choices[0].message.content
result = ask_with_role(
system="당신은 파이썬 코드 리뷰 전문가입니다. 간결하게 핵심만 설명하세요.",
user="이 코드의 문제점이 뭔가요? ..."
)
시스템 프롬프트를 잘 잡으면 응답 일관성이 확실히 달라진다.
대화 맥락 유지
단발 질문이 아닌 대화 흐름이 필요하면 messages 배열을 직접 관리한다.
history = []
def chat(user_message: str) -> str:
history.append({"role": "user", "content": user_message})
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=history
)
reply = response.choices[0].message.content
history.append({"role": "assistant", "content": reply})
return reply
히스토리가 길어질수록 토큰 비용이 올라가니 적당히 자르거나 요약하는 로직을 붙이는 게 좋다.
스트리밍 응답
긴 답변을 기다리지 않고 실시간으로 출력하려면 stream=True를 쓴다.
def ask_stream(prompt: str) -> None:
stream = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": prompt}],
stream=True
)
for chunk in stream:
delta = chunk.choices[0].delta.content
if delta:
print(delta, end="", flush=True)
print()
CLI 도구나 터미널 앱에서 쓸 때 체감 속도가 많이 달라진다.

비용과 에러 처리
API는 토큰 단위로 과금되니 실제 서비스에 붙이기 전에 응답 길이를 제어하는 게 필요하다.
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": prompt}],
max_tokens=500, # 응답 최대 길이 제한
temperature=0.7 # 창의성 수준 (0~2, 낮을수록 일관적)
)
에러 처리도 빠뜨리기 쉬운 부분이다.
from openai import RateLimitError, APIConnectionError
try:
result = ask(prompt)
except RateLimitError:
print("요청 한도 초과. 잠시 후 재시도하세요.")
except APIConnectionError:
print("API 연결 실패. 네트워크를 확인하세요.")
처음에는 그냥 돌리다가 rate limit 에러 한 번 맞고 나면 자연스럽게 추가하게 된다.
마무리
처음에는 헷갈릴 수 있지만 구조 자체는 단순하다. client 만들고 → messages 구성하고 → create() 호출하고 → .content 꺼내는 흐름이 반복된다.
실무에서 쓰다 보면 시스템 프롬프트 관리, 토큰 비용 추적, 응답 캐싱 같은 부분이 추가로 필요해지는데, 그건 기본 연동이 익숙해진 다음 단계에서 하나씩 붙이는 게 낫다.
일단 이 구조로 작은 자동화 하나 만들어보는 게 제일 빠른 방법이다.
'개발' 카테고리의 다른 글
| Git rebase vs merge: 초보자를 위한 핵심 차이점과 선택 가이드 (0) | 2026.06.08 |
|---|---|
| Playwright 클릭이 안될 때 완벽 해결 가이드 — 원인 분석부터 실전 코드까지 (0) | 2026.05.31 |
| n8n 자동화 워크플로우 만들기 (0) | 2026.05.31 |
| SSD vs HDD 차이점 완벽 정리 — 어떤 저장장치를 선택해야 할까? (1) | 2026.05.29 |
| Vercel 배포 문제 완벽 해결 가이드: 초보자도 따라 할 수 있는 7가지 원인과 해법 (0) | 2026.05.29 |