ChatGPT API มีการเปลี่ยนแปลงอย่างรวดเร็ว มักจะยกเลิกสัญญาและเรียกเก็บเงินต่อโทเค็นแม้ว่าการทดสอบของคุณจะผิดพลาด การตอบกลับแบบสตรีมมิ่งล้มเหลวแตกต่างจากการตอบกลับแบบไม่สตรีมมิ่ง การเรียกใช้ฟังก์ชันเพิ่มเลเยอร์ JSON-schema ที่ไม่ตรงกับสิ่งที่โมเดลส่งกลับเสมอไป อัตราการจำกัดถูกเรียกใช้เงียบๆ ในการใช้งานจริงแต่ไม่แสดงในคอนโซลสำหรับนักพัฒนาของคุณ หากคุณดีบักทั้งหมดนี้ใน Python REPL หรือ `curl` loop คุณจะเสียเงินและเวลาไปเปล่าๆ
คู่มือนี้จะอธิบายขั้นตอนการทดสอบ ChatGPT API อย่างครบวงจรภายใน Apidog: การยืนยันตัวตน, การสนทนาครั้งแรก, SSE แบบสตรีมมิ่ง, การเรียกใช้ฟังก์ชัน, การจัดการข้อผิดพลาด, การตรวจสอบอัตราการจำกัด และการจำลองการตอบกลับสำหรับการทำงานร่วมกันของส่วนหน้า ในท้ายที่สุด คุณจะมีโปรเจกต์ Apidog ที่นำกลับมาใช้ใหม่ได้ ซึ่งสามารถตรวจจับความเปลี่ยนแปลงของสัญญา OpenAI ก่อนที่จะส่งผลกระทบต่อการใช้งานจริง
สรุป (TL;DR)
- เพิ่ม URL พื้นฐานของ ChatGPT
https://api.openai.com/v1เป็น Apidog environment, เก็บ API key เป็น secret variable และใช้ Bearer auth ในระดับโฟลเดอร์ - สร้างคำขอ
/chat/completionsเพียงครั้งเดียว บันทึกและนำกลับมาใช้ใหม่สำหรับทุกโมเดล (GPT-5.5, GPT-5.5 Pro, GPT-4o, o3) - Apidog จัดการ SSE streaming ได้อย่าง native ทำให้คุณเห็นผลลัพธ์ทีละโทเค็นในแผงการตอบกลับโดยไม่ต้องใช้เครื่องมือเพิ่มเติม
- การเรียกใช้ฟังก์ชันเป็นเพียงอาร์เรย์
toolsในเนื้อหาคำขอ; Apidog ตรวจสอบtool_callsJSON ที่ส่งกลับมาเทียบกับ schema ของคุณ - จำลอง ChatGPT ภายใน Apidog เมื่อส่วนหน้าของคุณพร้อม ก่อนที่งบประมาณ OpenAI key ของคุณจะหมด
- บันทึกคำขอที่ทำงานได้เป็น scenario การทดสอบพร้อมกับการยืนยัน (assertions) เกี่ยวกับรหัสสถานะ,
choices[0].message.contentและusage.total_tokensรันสิ่งนี้ใน CI ก่อนการเปลี่ยนแปลงพรอมต์ทุกครั้ง
ทำไมถึงต้องทดสอบ ChatGPT API เลย
หน้าตา API ของ OpenAI ดูเหมือนจะเสถียร แต่มันไม่เป็นเช่นนั้น ระหว่างเดือนมกราคม 2024 จนถึงตอนนี้ ทีมงานได้เปิดตัวหรือเปลี่ยนแปลงสิ่งต่อไปนี้:
function_callเป็นtool_calls(ยังมีสองรูปแบบที่แข่งขันกันอยู่ในขณะนี้)- โหมดเข้มงวดสำหรับ tool schemas
- โมเดลการให้เหตุผล (
o1,o3) ที่ตัดปุ่มtemperatureและtop_pออก response_format: { type: "json_schema" }พร้อมการกำหนดเวอร์ชัน- พฤติกรรมการสตรีมมิ่งสำหรับการเรียกใช้ tool (deltas มาเป็นชิ้นๆ คุณต้องประกอบมันเข้าด้วยกัน)
- เอนด์พอยต์ใหม่
/v1/responsesที่ทับซ้อนกับ/v1/chat/completions
หากคุณเชื่อมโยงสิ่งเหล่านี้โดยตรงเข้ากับแอปพลิเคชันของคุณและข้ามเลเยอร์การทดสอบ การแก้ไขพรอมต์ครั้งต่อไปของคุณจะทำให้เกิดข้อผิดพลาดที่คุณจะไม่เห็นจนกว่าผู้ใช้จะบ่น การรวบรวมคำขอใน Apidog จะให้สัญญาที่คุณควบคุมได้ คุณสามารถเล่นซ้ำคำขอเดิม เปรียบเทียบการตอบกลับ และแจ้งให้ทราบเมื่อรูปแบบเปลี่ยนไป
ขั้นตอนที่ 1: เพิ่ม OpenAI เป็น Environment ใน Apidog
เปิด Apidog และสร้างโปรเจกต์ใหม่ ภายในโปรเจกต์ เปิด Environment Management (เมนูดรอปดาวน์ด้านบนขวา) และเพิ่ม environment ที่ชื่อว่า OpenAI Prod:
| ตัวแปร (Variable) | ค่า (Value) |
|---|---|
baseUrl |
https://api.openai.com/v1 |
OPENAI_API_KEY |
sk-proj-... (เก็บเป็น Secret) |
defaultModel |
gpt-5.5 |
ทำเครื่องหมาย OPENAI_API_KEY เป็น secret เพื่อให้ถูกซ่อนในพื้นที่ทำงานที่แชร์และไม่เคยถูกเขียนลงในคอลเลกชันที่ส่งออก Apidog จัดเก็บ secrets แยกตามผู้ใช้ ดังนั้นเพื่อนร่วมทีมที่ดึงโปรเจกต์ไปจะเห็นชื่อตัวแปรแต่ต้องระบุคีย์ของตัวเอง
ขั้นตอนที่ 2: ตั้งค่า Bearer Auth ที่ระดับโฟลเดอร์
สร้างโฟลเดอร์ชื่อ ChatGPT ภายในโปรเจกต์ เปิดการตั้งค่าโฟลเดอร์ ไปที่ Auth เลือก Bearer Token และวาง {{OPENAI_API_KEY}} ทุกคำขอภายในโฟลเดอร์นี้จะสืบทอดเฮดเดอร์นี้ คุณจะหยุดการวาง Authorization: Bearer sk-... ลงในทุกคำขอ และการหมุนเวียนคีย์ก็จะเป็นการแก้ไขเพียงครั้งเดียว
นี่คือรายละเอียดเล็กๆ น้อยๆ ที่ทำให้ Apidog เร็วกว่าขั้นตอนการทำงานของ curl แบบดิบๆ: การยืนยันตัวตนอยู่ในที่เดียว เนื้อหาคำขอจะสะอาดตา
ขั้นตอนที่ 3: สร้างคำขอ Chat Completion ครั้งแรก
ภายในโฟลเดอร์ ChatGPT สร้างคำขอใหม่:
- Method:
POST - URL:
{{baseUrl}}/chat/completions - Body (JSON):
{
"model": "{{defaultModel}}",
"messages": [
{ "role": "system", "content": "คุณเป็นวิศวกรแบ็กเอนด์อาวุโส ตอบกลับภายใน 100 คำ" },
{ "role": "user", "content": "ความแตกต่างระหว่างเมธอด HTTP ที่ idempotent และ safe คืออะไร?" }
],
"temperature": 0.2
}
กด Send คุณควรได้รับการตอบกลับ 200 พร้อมฟิลด์ choices[0].message.content ที่มีคำตอบ และบล็อก usage พร้อมจำนวนโทเค็น บันทึกคำขอเป็น chat-completion-basic
หากคุณได้รับ 401 แสดงว่าคีย์ของคุณไม่ได้โหลด ตรวจสอบว่าเมนูดรอปดาวน์ environment ที่ด้านบนขวาตั้งค่าเป็น OpenAI Prod หากคุณได้รับ 429 แสดงว่าคุณถึงอัตราการจำกัด ซึ่งขั้นตอนถัดไปจะครอบคลุม
ขั้นตอนที่ 4: ทดสอบการตอบกลับแบบสตรีมมิ่ง (SSE)
การสตรีมมิ่งคือจุดที่การเชื่อมต่อ ChatGPT ส่วนใหญ่พัง การตอบกลับคือ text/event-stream ไม่ใช่ JSON และแต่ละส่วนคือบรรทัด data: {...} ที่มี delta บางส่วน Apidog รองรับ SSE ได้โดยตรง
ทำสำเนา chat-completion-basic เปลี่ยนชื่อเป็น chat-completion-stream และเพิ่ม "stream": true ลงใน body:
{
"model": "{{defaultModel}}",
"stream": true,
"messages": [
{ "role": "user", "content": "สตรีมจำนวนเฉพาะ 100 ตัวแรก คั่นด้วยจุลภาค" }
]
}
กด Send แผงการตอบกลับจะเปลี่ยนเป็นมุมมองสตรีมมิ่งและแสดงแต่ละส่วน data: เมื่อมาถึง คุณจะเห็นเฟรม SSE จริง ไม่ใช่แค่ข้อความที่ประกอบขึ้น นั่นคือมุมมองที่คุณต้องการเมื่อดีบัก delta ที่ผิดรูปแบบหรือ terminator [DONE] ที่หายไป
สิ่งที่ต้องระวัง:
- เฟรมสุดท้ายคือสตริงตัวอักษร
data: [DONE]หากไคลเอนต์ของคุณไม่จัดการสิ่งนี้ มันจะเกิดข้อผิดพลาด JSON parse usageจะไม่อยู่ในการตอบกลับแบบสตรีมมิ่ง เว้นแต่คุณจะส่ง"stream_options": { "include_usage": true }เพิ่มสิ่งนี้หากไปป์ไลน์การเรียกเก็บเงินของคุณขึ้นอยู่กับจำนวนโทเค็นต่อการเรียก- deltas ของการเรียกใช้ tool มาเป็นชิ้นๆ:
index, จากนั้นid, จากนั้นfunction.name, จากนั้นfunction.argumentsที่สะสมทีละตัวอักษร ทดสอบสิ่งนี้อย่างชัดเจน
ขั้นตอนที่ 5: ทดสอบการเรียกใช้ฟังก์ชันและการใช้เครื่องมือ
การเรียกใช้ฟังก์ชันเป็นจุดที่การเปลี่ยนแปลงพรอมต์มักจะทำให้โค้ดปลายทางพังอย่างเงียบๆ โมเดลจะส่งคืนอาร์เรย์ tool_calls; หน้าที่ของคุณคือตรวจสอบว่าอาร์กิวเมนต์สามารถแยกวิเคราะห์ได้ตาม JSON Schema ที่คุณลงทะเบียนไว้
สร้างคำขอ chat-completion-tools พร้อมเนื้อหานี้:
{
"model": "{{defaultModel}}",
"messages": [
{ "role": "user", "content": "สภาพอากาศในสิงคโปร์ตอนนี้เป็นอย่างไร?" }
],
"tools": [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "รับสภาพอากาศปัจจุบันสำหรับเมืองหนึ่งๆ",
"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 เป็นสตริง JSON ที่สามารถแยกวิเคราะห์เป็น { "city": "Singapore", "unit": "c" } (หรือคล้ายกัน)
ในแท็บ Tests ของคำขอ เพิ่ม:
pm.test("Tool ถูกเรียก", () => {
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("อาร์กิวเมนต์แยกวิเคราะห์เป็น 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 ในการใช้งานจริงล้มเหลวในห้าวิธีที่คาดการณ์ได้ สร้างคำขอสำหรับแต่ละกรณีและยืนยันพฤติกรรมที่คาดหวัง:
| สถานการณ์ | วิธีเรียกใช้ | ที่คาดหวัง |
|---|---|---|
| คีย์ไม่ถูกต้อง | ตั้งค่า OPENAI_API_KEY เป็น sk-bad ใน environment Sandbox |
401 พร้อม error.code = "invalid_api_key" |
| เกินอัตราการจำกัด | วนซ้ำคำขอ 200 ครั้งใน collection runner ของ Apidog | 429 พร้อม header Retry-After |
| เกินขีดจำกัดโทเค็น | ส่งพรอมต์ 200K โทเค็นไปยังโมเดลบริบท 128K | 400 พร้อม error.code = "context_length_exceeded" |
| ชื่อโมเดลไม่ถูกต้อง | "model": "gpt-99" |
404 |
| การละเมิด Schema | Tool-call ที่มี strict: true และอินพุตที่ผิดรูปแบบ |
โมเดลปฏิเสธ tool ส่งคืนข้อความธรรมดา |
เพิ่มการยืนยันในแท็บ Tests เพื่อให้ข้อผิดพลาดปรากฏเป็นการทดสอบสีแดง ไม่ใช่การลองใหม่ที่เงียบหายไป Header Retry-After เป็นสิ่งที่โค้ดการผลิตส่วนใหญ่ทำผิดพลาด มันอยู่ในหน่วยวินาที บางครั้งอาจเป็นค่าทศนิยม และคุณควรอ่านค่านี้แทนที่จะฮาร์ดโค้ดการหน่วงเวลา
ขั้นตอนที่ 7: Mock ChatGPT สำหรับการพัฒนาส่วนหน้าแบบขนาน
คีย์ OpenAI ของคุณมีขีดจำกัดรายเดือน ทีมส่วนหน้าของคุณไม่มี เมื่อ UI ต้องการแสดงโทเค็นที่สตรีมมา คำแนะนำในการติดตามผล และการ์ดการเรียกใช้ tool ก่อนที่พรอมต์แบ็กเอนด์จะเสร็จสมบูรณ์ ให้พวกเขาลองใช้ Apidog mock
ในโฟลเดอร์ ChatGPT คลิกขวาที่คำขอ chat-completion-basic เลือก Smart Mock และเปิดใช้งาน Apidog จะส่งคืนการตอบกลับสังเคราะห์ที่ตรงกับ schema ของ OpenAI: id, object, created, model, choices, usage URL ของ mock จะมีลักษณะคล้าย https://mock.apidog.com/m1/<projectId>/chat/completions และยอมรับ body เดียวกัน
สำหรับการ mock แบบสตรีมมิ่ง ให้กำหนดสคริปต์ในแท็บ Advanced Mock ที่เขียน data: { ... }\n\n chunks ในช่วงเวลา 50ms ส่วนหน้าจะได้รับ SSE stream ที่สมจริงโดยไม่มีการเรียกใช้งาน OpenAI ใดๆ
เมื่อพรอมต์จริงมาถึง ให้เปลี่ยน URL พื้นฐานของส่วนหน้ากลับเป็น https://api.openai.com/v1 ไม่มีอะไรอื่นเปลี่ยนแปลง
ขั้นตอนที่ 8: บันทึกชุดการทดสอบเป็น CI Test Scenario
Test Scenarios ของ Apidog ช่วยให้คุณสามารถเชื่อมโยงคำขอพร้อมกับการยืนยันและเรียกใช้แบบไร้หัวได้ สร้าง scenario ที่:
- เรียก
chat-completion-basic, ยืนยันstatus === 200และusage.total_tokens > 0 - เรียก
chat-completion-stream, ยืนยันว่า SSE จบด้วย[DONE] - เรียก
chat-completion-tools, ยืนยันว่า tool call schema ผ่านการตรวจสอบ - เรียกสถานการณ์ข้อผิดพลาดแต่ละรายการจากขั้นตอนที่ 6, ยืนยันรหัสสถานะที่ถูกต้อง
ส่งออก scenario และเรียกใช้ใน CI ผ่าน apidog-cli run scenario.json --env OpenAI Prod เชื่อมโยงสิ่งนี้เข้ากับ pipeline PR สำหรับไฟล์ที่มีพรอมต์ของคุณ การเปลี่ยนแปลงพรอมต์ทุกครั้งจะถูกเรียกใช้กับ OpenAI API ที่ใช้งานจริงเป็นการตรวจสอบก่อนการรวมเข้ากัน ค่าใช้จ่าย: ไม่กี่เซ็นต์ต่อการรัน CI มูลค่า: คุณจะหยุดการส่งข้อผิดพลาดเกี่ยวกับพรอมต์
คำถามที่พบบ่อย
สิ่งนี้ใช้ได้กับ Azure OpenAI หรือไม่? ได้ เปลี่ยน baseUrl เป็น URL ทรัพยากร Azure ของคุณ เพิ่มพารามิเตอร์คิวรี api-version และเปลี่ยนการยืนยันตัวตนจาก Bearer เป็นเฮดเดอร์ api-key เนื้อหาคำขอเหมือนกันทุกประการ
ฉันสามารถใช้สิ่งนี้สำหรับโมเดลการให้เหตุผล o1 และ o3 ได้หรือไม่? ได้ แต่โมเดลเหล่านั้นปฏิเสธ temperature, top_p, presence_penalty และ frequency_penalty สร้างโฟลเดอร์แยกต่างหาก Reasoning พร้อมกับเทมเพลต body ที่ลดทอนลง
ฉันจะจัดการเวอร์ชันพรอมต์ใน Apidog ได้อย่างไร? Apidog มีการรองรับ branch สร้าง branch สำหรับการทดลองพรอมต์แต่ละครั้ง รัน scenario การทดสอบกับ API ที่ใช้งานจริง เปรียบเทียบการใช้โทเค็นและคุณภาพการตอบกลับ จากนั้นจึงรวมเข้าด้วยกัน เป็นขั้นตอนการทำงานเดียวกับโค้ดที่นำมาใช้กับพรอมต์
แล้วเอนด์พอยต์ใหม่ /v1/responses ล่ะ? ตั้งค่าโฟลเดอร์แยกต่างหากสำหรับมัน การยืนยันตัวตนและ URL พื้นฐานเหมือนกัน มีเพียงรูปร่างของ body เท่านั้นที่แตกต่างกัน เก็บทั้งสองโฟลเดอร์ไว้เพื่อให้คุณสามารถ A/B ทดสอบกับพรอมต์เดียวกันได้
Apidog คิดค่าบริการต่อการเรียก API หรือไม่? ไม่ ไคลเอนต์ Apidog ฟรีสำหรับการใช้งานส่วนบุคคลและการใช้งานส่วนใหญ่ของทีม OpenAI คิดค่าบริการต่อโทเค็น Apidog ไม่ได้แทรกแซงระหว่างคุณกับ OpenAI
สรุป
ChatGPT API จะมีการเปลี่ยนแปลงอย่างต่อเนื่อง การสตรีมจะพังในรูปแบบใหม่ๆ schemas ของเครื่องมือจะเข้มงวดขึ้น และโมเดลการให้เหตุผลจะยังคงตัดพารามิเตอร์ที่คุณคิดว่าเสถียรออกไป การป้องกันคือการรวบรวมคำขอที่คุณควบคุมได้ เซิร์ฟเวอร์ mock ที่ส่วนหน้าของคุณสามารถพึ่งพาได้ และ scenario การทดสอบที่ CI ของคุณรันก่อนทุก PR พรอมต์
ดาวน์โหลด Apidog และนำเข้าการเรียก OpenAI ที่มีอยู่ของคุณ คอลเลกชัน Postman และคำสั่ง curl ทั้งสองสามารถแปลงได้ในคลิกเดียว สร้างคำขอทั้งแปดข้างต้นเพียงครั้งเดียว และการอัปเดต ChatGPT ในอนาคตทุกครั้งจะกลายเป็นการทดสอบที่ควบคุมได้ แทนที่จะเป็นเหตุการณ์ใน Production
