2장. 개발 환경 준비
자주 나는 오류
거래처 창구에서 주문이 막히는 까닭은 몇 가지뿐입니다. 출입증이 틀렸거나, 이번 달 외상 한도를 넘었거나, 없는 물건을 주문했거나, 길이 막혀 창구에 닿지 못했거나, 아예 출입증을 집에 두고 왔거나. 창구 직원은 이 까닭을 번호로 알려 줍니다. 모델을 부를 때 나는 오류도 대부분 이 다섯 가지이고, 번호(상태 코드)만 보면 어디를 고칠지 압니다.
다섯 상자의 첫 줄이 까닭, 둘째 줄이 해결입니다. 앞의 세 상자는 서버까지 갔다가 번호를 받아 온 오류이고, 넷째는 서버에 닿지 못한 오류, 다섯째는 보내기도 전에 우리 PC 에서 멈춘 오류입니다. 여기서 틀린 출입증이 401, 외상 한도가 429, 없는 물건이 404, 막힌 길이 연결 오류, 집에 두고 온 출입증이 "키 못 읽음"입니다. 비유와 다른 점은, 창구 직원은 사정을 들어 주기도 하지만 서버는 번호만 돌려주고 끝이라는 것입니다. 번호를 읽고 고치는 일은 우리 몫입니다.
오류와 해결
| 오류 | 파이썬의 오류 이름 | 흔한 까닭 | 해결 |
|---|---|---|---|
| 401 인증 실패 | openai.AuthenticationError | 키 철자가 틀렸다, 앞뒤에 빈칸이 들어갔다, 지운 키다, 자리표시를 그대로 두었다 | .env 의 키를 다시 붙여 넣는다 |
| 429 한도 초과 | openai.RateLimitError | 짧은 시간에 너무 많이 보냈다, 계정의 사용 한도나 잔액을 넘었다 | 잠시 뒤 다시 보낸다. 계속되면 교수자에게 알린다 |
| 404 찾을 수 없음 | openai.NotFoundError | 모델 이름의 철자가 틀렸다, 이 계정에서 쓸 수 없는 모델이다 | OPENAI_MODEL 의 이름을 확인한다 |
| 연결 오류 | openai.APIConnectionError | 인터넷이 끊겼다, 회사·학교의 방화벽이나 프록시가 막는다 | 인터넷과 네트워크 설정을 확인한다 |
| 키 못 읽음 | openai.OpenAIError (Missing credentials) | .env 가 없거나 다른 폴더에 있다, 이름이 OPENAI_API_KEY 가 아니다 | .env 의 위치와 이름을 확인한다 |
LangChain 의 ChatOpenAI 로 불러도 오류 이름은 이 표의 것으로 잡힙니다. langchain-openai 가 이 오류들을 이어받은 OpenAIAuthenticationError 같은 이름으로 바꿔 내보내기 때문입니다. 그래서 except openai.AuthenticationError: 한 줄로 두 방식의 오류를 모두 잡습니다.
짧은 예시
두 가지를 키 없이 확인합니다. 오류 이름마다 붙은 상태 코드를 찍고, 일부러 닿지 않는 주소로 보내 연결 오류를 만들어 잡아 봅니다. 127.0.0.1 은 내 PC 자신을 가리키는 주소이고, 9 번 문(포트)에는 아무 프로그램도 없어서 연결이 거절됩니다. OpenAI 서버에는 아무것도 보내지 않습니다.
import openai
# 오류 이름마다 정해진 상태 코드
for error in [openai.AuthenticationError, openai.NotFoundError, openai.RateLimitError]:
print(error.__name__, error.status_code)
# base_url: 요청을 보낼 주소. 일부러 내 PC 의 빈 문으로 바꿔 연결 오류를 만든다
# max_retries=0: 실패해도 다시 보내지 않는다(기본은 2번 더 보낸다)
client = openai.OpenAI(api_key="sk-test-0000000000000000", base_url="http://127.0.0.1:9/v1", max_retries=0)
try:
client.chat.completions.create(model="gpt-4.1-mini", messages=[{"role": "user", "content": "안녕"}])
except openai.APIConnectionError as e:
print("잡은 오류:", type(e).__name__, "-", e)AuthenticationError 401
NotFoundError 404
RateLimitError 429
잡은 오류: APIConnectionError - Connection error.연결 오류는 서버에 닿지 못했으므로 상태 코드가 없습니다. 이 예시는 실행에 몇 초 걸립니다. 연결을 시도하다 거절당할 때까지 기다리기 때문입니다. 실습 5에서는 틀린 키와 틀린 모델 이름으로 401 과 404 를 받아 한국어 안내를 찍습니다.
코드가 의미하는 것
이 코드는 창구 직원이 쓰는 번호표를 미리 읽어 두고, 일부러 막힌 길로 가서 "창구에 닿지 못함"을 겪어 보는 일입니다. 상태 코드 찍기와 연결 오류 잡기, 두 가지 동작입니다.
| 코드 | 하는 일 | 챗봇에서 뜻하는 것 |
|---|---|---|
error.status_code | 오류 종류마다 정해진 번호를 읽는다 | 챗봇이 오류를 만났을 때 이 번호로 고칠 곳을 가립니다 |
base_url="http://127.0.0.1:9/v1" | 요청을 보낼 주소를 내 PC 의 빈 문으로 바꾼다 | OpenAI 서버에 아무것도 보내지 않고 연결 오류를 만듭니다 |
max_retries=0 | 실패해도 다시 보내지 않는다 | 기본은 두 번 더 보내므로, 끄지 않으면 오류를 받기까지 더 기다립니다 |
except openai.APIConnectionError as e | 연결 오류만 골라 잡는다 | 프로그램이 멈추지 않고, 챗봇이 사용자에게 네트워크를 확인하라는 안내를 할 수 있게 합니다 |
결과에서 읽을 것은 두 가지입니다.
- 세 번호가 표와 같습니다. 401, 404, 429 가 앞 표의 번호 그대로 찍혔습니다. 번호는 오류 종류에 붙어 있어 서버에 보내지 않아도 읽힙니다.
- 연결 오류에는 번호가 없습니다.
Connection error.만 찍혔습니다. 서버에 닿지 못해 받은 번호가 없기 때문입니다.
주의할 점
- 오류 글 전체를 그대로 화면에 보여 주거나 남에게 보내지 않습니다. 오류 글에 키의 일부가 섞여 나올 때가 있습니다.
- 429 가 났다고 곧바로 여러 번 다시 보내면 한도를 더 빨리 씁니다. 몇 초씩 기다렸다가 보냅니다. openai 패키지는 429 와 연결 오류에 기본으로 두 번 더 보내 봅니다(
max_retries). - 오류 번호가 표에 없으면(400, 500 등) 오류 글의
message를 읽습니다. 400 은 보낸 내용의 꼴이 틀린 것, 500 번대는 서버 쪽의 문제입니다.