ChatGPT API는 빠르게 배송되지만, 계약을 자주 위반하며, 테스트가 틀렸을 때도 토큰당 비용을 청구합니다. 스트리밍 응답은 비스트리밍 응답과 다르게 실패합니다. 함수 호출은 모델이 반환하는 것과 항상 일치하지 않는 JSON 스키마 레이어를 추가합니다. 속도 제한은 개발 콘솔에서는 발생하지 않고 프로덕션에서 조용히 발생합니다. 이 모든 것을 Python REPL 또는 `curl` 루프에서 디버깅하면 돈과 시간을 낭비하게 됩니다.
이 가이드는 Apidog 내에서 전체 ChatGPT API 테스트 워크플로를 안내합니다: 인증, 첫 번째 채팅 완성, 스트리밍 SSE, 함수 호출, 오류 처리, 속도 제한 검사, 그리고 프론트엔드 병렬 작업을 위한 모의(Mock) 응답. 이 가이드를 마치면 OpenAI 계약 변경이 프로덕션에 영향을 미치기 전에 잡아낼 수 있는 재사용 가능한 Apidog 프로젝트를 갖게 될 것입니다.
TL;DR (요약)
- ChatGPT 기본 URL
https://api.openai.com/v1을 Apidog 환경으로 추가하고, API 키를 시크릿 변수로 저장하며, 폴더 수준에서 Bearer 인증을 적용하세요. /chat/completions요청을 한 번 만들고 저장한 다음, 모든 모델(GPT-5.5, GPT-5.5 Pro, GPT-4o, o3)에 재사용하세요.- Apidog는 SSE 스트리밍을 기본적으로 처리하므로, 추가 도구 없이 응답 패널에서 토큰별 출력을 볼 수 있습니다.
- 함수 호출은 요청 본문의
tools배열일 뿐이며, Apidog는 반환된tool_callsJSON을 스키마에 대해 검증합니다. - OpenAI 키 예산을 소모하기 전에 프론트엔드가 준비되면 Apidog 내에서 ChatGPT를 모의(Mock)하세요.
- 작동하는 요청을 상태 코드,
choices[0].message.content,usage.total_tokens에 대한 어설션과 함께 테스트 시나리오로 저장하세요. 모든 프롬프트 변경 전에 CI에서 실행하세요.
ChatGPT API를 테스트해야 하는 이유
OpenAI의 API 표면은 안정적으로 보입니다. 하지만 그렇지 않습니다. 2024년 1월부터 현재까지 팀은 다음을 출시하거나 변경했습니다:
function_call이tool_calls로 변경됨 (두 개의 경쟁적인 형태가 여전히 존재합니다)- 도구 스키마에 대한 엄격 모드
temperature및top_p조절 장치를 제거한 추론 모델 (o1,o3)- 버전 관리와 함께
response_format: { type: "json_schema" } - 도구 호출에 대한 스트리밍 동작 (델타는 조각으로 도착하므로 조립해야 합니다)
/v1/chat/completions와 중복되는 새로운/v1/responses엔드포인트
이 중 어떤 것이라도 테스트 레이어를 건너뛰고 애플리케이션에 직접 연결하면, 다음 프롬프트 변경 PR은 사용자가 불평하기 전까지는 알 수 없는 회귀를 발생시킬 것입니다. Apidog의 요청 컬렉션은 여러분이 제어하는 계약을 제공합니다. 정확한 요청을 다시 실행하고, 응답을 비교하며, 형태가 변경되면 큰 소리로 실패할 수 있습니다.
단계 1: Apidog에 OpenAI를 환경으로 추가
Apidog를 열고 새 프로젝트를 만드세요. 프로젝트 내에서 환경 관리(오른쪽 상단 드롭다운)를 열고 OpenAI Prod라는 환경을 추가하세요:
| 변수 (Variable) | 값 (Value) |
|---|---|
baseUrl |
https://api.openai.com/v1 |
OPENAI_API_KEY |
sk-proj-... (시크릿으로 저장) |
defaultModel |
gpt-5.5 |
OPENAI_API_KEY를 시크릿으로 표시하여 공유 워크스페이스에서 마스킹되고 내보낸 컬렉션에 기록되지 않도록 하세요. Apidog는 사용자별로 시크릿을 저장하므로, 프로젝트를 가져오는 팀원은 변수 이름은 보지만 자신의 키를 제공해야 합니다.
단계 2: 폴더 수준에서 Bearer 인증 설정
프로젝트 내에 ChatGPT라는 폴더를 만드세요. 폴더 설정을 열고, Auth로 이동하여 Bearer Token을 선택한 다음, {{OPENAI_API_KEY}}를 붙여넣으세요. 폴더 내의 모든 요청은 이 헤더를 상속합니다. 모든 요청에 Authorization: Bearer sk-...를 붙여넣는 것을 멈추고, 키 로테이션은 한 번의 편집으로 가능합니다.
이는 Apidog를 순수한 curl 워크플로보다 빠르게 만드는 작은 디테일입니다: 인증은 한 곳에 존재하고, 요청 본문은 깔끔하게 유지됩니다.
단계 3: 첫 번째 채팅 완성 요청 만들기
ChatGPT 폴더 내에서 새 요청을 만드세요:
- 메서드:
POST - URL:
{{baseUrl}}/chat/completions - 본문 (JSON):
{
"model": "{{defaultModel}}",
"messages": [
{ "role": "system", "content": "You are a senior backend engineer. Answer in under 100 words." },
{ "role": "user", "content": "What's the difference between idempotent and safe HTTP methods?" }
],
"temperature": 0.2
}
전송(Send)을 누르세요. 답변을 포함하는 choices[0].message.content 필드와 토큰 수를 포함하는 usage 블록이 있는 200 응답을 받아야 합니다. 요청을 chat-completion-basic으로 저장하세요.
401을 받았다면 키가 로드되지 않은 것입니다. 오른쪽 상단의 환경 드롭다운이 OpenAI Prod로 설정되어 있는지 확인하세요. 429를 받았다면 속도 제한에 도달한 것이며, 다음 단계에서 다룹니다.
단계 4: 스트리밍 응답 테스트 (SSE)
스트리밍은 대부분의 ChatGPT 통합이 실패하는 지점입니다. 응답은 JSON이 아닌 text/event-stream이며, 각 청크는 부분적인 delta를 포함하는 data: {...} 라인입니다. Apidog는 SSE를 기본적으로 지원합니다.
chat-completion-basic을 복제하고 이름을 chat-completion-stream으로 변경한 다음, 본문에 "stream": true를 추가하세요:
{
"model": "{{defaultModel}}",
"stream": true,
"messages": [
{ "role": "user", "content": "Stream the first 100 prime numbers, comma-separated." }
]
}
전송(Send)을 누르세요. 응답 패널이 스트리밍 뷰로 전환되고 각 data: 청크가 도착하는 대로 렌더링됩니다. 조립된 텍스트뿐만 아니라 실제 SSE 프레임을 볼 수 있습니다. 이는 잘못된 델타 또는 누락된 [DONE] 종료자를 디버깅할 때 필요한 뷰입니다.
주의할 점:
- 최종 프레임은 리터럴 문자열
data: [DONE]입니다. 클라이언트가 이를 처리하지 못하면 JSON 구문 분석 오류가 발생합니다. "stream_options": { "include_usage": true }를 전달하지 않으면usage는 스트리밍 응답에 포함되지 않습니다. 호출당 토큰 수에 빌링 파이프라인이 의존하는 경우 이를 추가하세요.- 도구 호출 델타는 조각으로 도착합니다:
index, 그 다음id, 그 다음function.name, 그 다음function.arguments가 문자 단위로 누적됩니다. 이를 명시적으로 테스트하세요.
단계 5: 함수 호출 및 도구 사용 테스트
함수 호출은 프롬프트 변경이 다운스트림 코드를 조용히 손상시키는 가장 일반적인 지점입니다. 모델은 tool_calls 배열을 반환합니다. 여러분의 작업은 등록한 JSON 스키마로 인수가 구문 분석되는지 검증하는 것입니다.
이 본문으로 chat-completion-tools 요청을 만드세요:
{
"model": "{{defaultModel}}",
"messages": [
{ "role": "user", "content": "What is the weather in Singapore right now?" }
],
"tools": [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get current weather for a city.",
"parameters": {
"type": "object",
"properties": {
"city": { "type": "string" },
"unit": { "type": "string", "enum": ["c", "f"] }
},
"required": ["city"]
},
"strict": true
}
}
],
"tool_choice": "auto"
}
올바른 응답은 choices[0].message.tool_calls[0].function.name === "get_weather"를 가지며, function.arguments는 { "city": "Singapore", "unit": "c" } (또는 유사한)으로 구문 분석되는 JSON 문자열입니다.
요청의 Tests 탭에서 다음을 추가하세요:
pm.test("Tool was called", () => {
const body = pm.response.json();
const call = body.choices[0].message.tool_calls?.[0];
pm.expect(call?.function?.name).to.eql("get_weather");
});
pm.test("Arguments parse as valid JSON", () => {
const body = pm.response.json();
const args = JSON.parse(body.choices[0].message.tool_calls[0].function.arguments);
pm.expect(args.city).to.be.a("string");
});
실행하세요. 녹색 테스트는 이제 여러분의 계약입니다. OpenAI가 형태를 변경하면, 프로덕션 트래픽이 발생하기 전에 테스트가 빨간색으로 변합니다.
단계 6: 오류 및 속도 제한 명시적으로 처리
프로덕션 ChatGPT 통합은 예측 가능한 다섯 가지 방식으로 실패합니다. 각 시나리오에 대한 요청을 만들고 예상되는 동작을 어설션하세요:
| 시나리오 | 트리거 방법 | 예상 결과 |
|---|---|---|
| 유효하지 않은 키 | Sandbox 환경에서 OPENAI_API_KEY를 sk-bad로 설정 |
401 및 error.code = "invalid_api_key" |
| 속도 제한 | Apidog의 컬렉션 러너에서 요청 200회 반복 | 429 및 Retry-After 헤더 |
| 토큰 한도 초과 | 128K 컨텍스트 모델에 200K 토큰 프롬프트 전송 | 400 및 error.code = "context_length_exceeded" |
| 잘못된 모델 이름 | "model": "gpt-99" |
404 |
| 스키마 위반 | strict: true 및 잘못된 입력으로 도구 호출 |
모델이 도구를 거부하고 일반 텍스트를 반환 |
Tests 탭에 어설션을 추가하여 회귀가 조용한 재시도 폭풍이 아닌 빨간색 테스트로 나타나도록 하세요. Retry-After 헤더는 대부분의 프로덕션 코드가 잘못 처리하는 것입니다. 이 값은 초 단위이며, 때로는 소수 값을 가질 수 있습니다. 하드코딩된 백오프 대신 이 값을 읽어야 합니다.
단계 7: 병렬 프론트엔드 개발을 위한 ChatGPT 모의(Mock)
OpenAI 키에는 월별 한도가 있습니다. 프론트엔드 팀은 그렇지 않습니다. UI가 스트리밍된 토큰, 제안된 후속 조치, 도구 호출 카드를 백엔드 프롬프트가 확정되기 전에 렌더링해야 할 때, Apidog 모의(Mock)를 제공하세요.
ChatGPT 폴더에서 chat-completion-basic 요청을 마우스 오른쪽 버튼으로 클릭하고 Smart Mock을 선택한 다음 활성화하세요. Apidog는 OpenAI 스키마와 일치하는 합성 응답을 반환합니다: id, object, created, model, choices, usage. 모의 URL은 https://mock.apidog.com/m1/<projectId>/chat/completions와 같으며 동일한 본문을 받습니다.
스트리밍 모의를 위해서는 Advanced Mock 탭에서 50ms 간격으로 data: { ... }\n\n 청크를 작성하는 스크립트를 정의하세요. 프론트엔드는 OpenAI 트래픽 없이 현실적인 SSE 스트림을 얻습니다.
실제 프롬프트가 적용되면 프론트엔드의 기본 URL을 https://api.openai.com/v1로 다시 전환하세요. 다른 것은 변경되지 않습니다.
단계 8: 스위트를 CI 테스트 시나리오로 저장
Apidog의 테스트 시나리오는 어설션과 함께 요청을 연결하고 헤드리스로 실행할 수 있게 합니다. 다음을 수행하는 시나리오를 만드세요:
chat-completion-basic을 호출하고,status === 200및usage.total_tokens > 0을 어설션합니다.chat-completion-stream을 호출하고, SSE가[DONE]으로 끝났음을 어설션합니다.chat-completion-tools를 호출하고, 도구 호출 스키마가 유효함을 어설션합니다.- 6단계의 각 오류 시나리오를 호출하고, 올바른 상태 코드를 어설션합니다.
시나리오를 내보내고 apidog-cli run scenario.json --env OpenAI Prod를 통해 CI에서 실행하세요. 이를 프롬프트를 포함하는 파일의 PR 파이프라인에 연결하세요. 이제 모든 프롬프트 변경은 라이브 OpenAI API에 대해 사전 병합 확인으로 실행됩니다. 비용: CI 실행당 몇 센트. 가치: 프롬프트 회귀를 배포하는 것을 멈춥니다.
자주 묻는 질문
Azure OpenAI와도 작동합니까? 예. baseUrl을 Azure 리소스 URL로 바꾸고, api-version 쿼리 매개변수를 추가하고, 인증을 Bearer에서 api-key 헤더로 변경하세요. 요청 본문은 동일합니다.
o1 및 o3 추론 모델에 사용할 수 있습니까? 예, 하지만 이 모델들은 temperature, top_p, presence_penalty, frequency_penalty를 거부합니다. 간소화된 본문 템플릿으로 별도의 Reasoning 폴더를 만드세요.
Apidog 내에서 프롬프트를 어떻게 버전 관리합니까? Apidog는 브랜치 지원을 제공합니다. 프롬프트 실험당 브랜치를 만들고, 라이브 API에 대해 테스트 시나리오를 실행하고, 토큰 사용량과 응답 품질을 비교한 다음 병합하세요. 코드와 동일한 워크플로를 프롬프트에 적용하는 것입니다.
새로운 /v1/responses 엔드포인트는 어떻습니까? 별도의 폴더를 설정하세요. 인증 및 기본 URL은 동일하며, 본문 형태만 다릅니다. 동일한 프롬프트에 대해 A/B 테스트를 할 수 있도록 두 폴더를 모두 유지하세요.
Apidog는 API 호출당 비용을 청구합니까? 아니요. Apidog 클라이언트는 개인 사용 및 대부분의 팀 사용에 무료입니다. OpenAI는 토큰당 비용을 청구합니다. Apidog는 여러분과 OpenAI 사이에 끼어들지 않습니다.
마무리
ChatGPT API는 계속 변할 것입니다. 스트리밍은 새로운 방식으로 깨지고, 도구 스키마는 더욱 엄격해지며, 추론 모델은 안정적이라고 생각했던 매개변수들을 계속해서 제거할 것입니다. 방어책은 여러분이 제어하는 요청 컬렉션, 프론트엔드가 의존할 수 있는 모의(Mock) 서버, 그리고 모든 프롬프트 PR 전에 CI가 실행하는 테스트 시나리오입니다.
Apidog를 다운로드하고 기존 OpenAI 호출을 가져오세요. Postman 컬렉션과 curl 명령은 모두 한 번의 클릭으로 변환됩니다. 위의 8가지 요청을 한 번 만들면, 향후 모든 ChatGPT 업데이트는 프로덕션 사고가 아닌 통제된 테스트 실행이 될 것입니다.
