GuidesOneMux

การย้ายระบบ Node.js OpenAI SDK: Base URL, การสตรีม และระบบคัดกรองเคสด้วย Human-in-the-Loop

เรียนรู้วิธีย้ายระบบ Node.js ที่ใช้ OpenAI SDK เดิมไปสู่เกตเวย์ที่รองรับมาตรฐาน OpenAI เช่น OneMux พร้อมจัดการการสตรีม วินิจฉัยข้อผิดพลาด และสร้างเวิร์กโฟลว์คัดกรองเคสสนับสนุนลูกค้าที่มีขั้นตอนอนุมัติโดยมนุษย์

ในหน้านี้

การย้ายแอปพลิเคชัน Node.js ที่ใช้งานอยู่เดิมจากการเรียกใช้ OpenAI API โดยตรง ไปยังพร็อกซีหรือเกตเวย์แบบรวมศูนย์ที่รองรับมาตรฐาน OpenAI ไม่จำเป็นต้องเขียนลอจิกหลักของระบบใหม่ทั้งหมด เนื่องจากไลบรารี openai ทางการของ Node.js อนุญาตให้กำหนดค่าปลายทางเครือข่ายและ HTTP headers ในระดับไคลเอนต์ได้ คุณจึงสามารถเปลี่ยนเส้นทางทราฟฟิก ตรวจสอบการใช้งาน และใช้ประโยชน์จากการจัดเส้นทางเลือกใหม่ได้โดยไม่ต้องเปลี่ยนชุด SDK แต่อย่างใด

อย่างไรก็ตาม การส่งคำขอผ่านพร็อกซีหรือเกตเวย์ก็มีข้อควรพิจารณาในทางปฏิบัติ ได้แก่ การจัดการ authentication headers, การรับส่ง streaming events ผ่าน HTTP, การวิเคราะห์ข้อผิดพลาดที่ขอบระบบ (edge errors) รวมถึงการกำกับดูแลให้ผลลัพธ์อัตโนมัติยังอยู่ภายใต้การควบคุมของมนุษย์ โดยเฉพาะในระบบคัดกรองเคสบริการลูกค้า (customer support triage) ซึ่งโมเดล AI ทำหน้าที่จำแนกประเภทคำขอที่เข้ามา ร่างคำตอบ และเสนอแนะสิ่งที่ควรทำกับทิกเก็ต การบังคับใช้ขั้นตอนการตรวจสอบโดยมนุษย์ก่อนรันลอจิกทางธุรกิจจริงจึงเป็นเรื่องสำคัญอย่างยิ่ง

คู่มือนี้จะแสดงวิธีการกำหนดค่า Node.js OpenAI SDK ใหม่เพื่อเชื่อมต่อกับเกตเวย์ที่รองรับมาตรฐาน OpenAI เช่น OneMux, การสตรีมข้อเสนอแนะในการคัดกรองเคส และการบังคับใช้ระบบอนุมัติโดยมนุษย์ก่อนดำเนินขั้นตอนที่มีความเสี่ยงสูง


สถาปัตยกรรมระบบ: การคัดกรองเคสสนับสนุนลูกค้าพร้อมการอนุมัติโดยมนุษย์

ระบบคัดกรองเคสลูกค้าแบบอัตโนมัติจะเริ่มต้นด้วยการอ่านข้อมูลทิกเก็ตใหม่ ประเมินอารมณ์ความรู้สึกของผู้ใช้ จัดระดับความเร่งด่วน และแนะนำขั้นตอนถัดไป (เช่น ร่างข้อความตอบกลับ แปะแท็ก หรือให้เครดิตเงินคืนบางส่วน) ดังที่ระบุไว้ใน OpenAI Agents Guide สถาปัตยกรรมเอเจนต์ที่มีผลกระทบต่อระบบงานจริง (side effects) จะได้ประโยชน์สูงสุดเมื่อเก็บลูปการควบคุม (orchestration loop) ให้อยู่ในโค้ดของแอปพลิเคชัน ซึ่งเป็นจุดที่สามารถดูแลแนวทางความปลอดภัยและด่านตรวจการอนุมัติได้อย่างรัดกุม

แทนที่จะปล่อยให้โมเดลมีอำนาจสั่งการโดยตรง ไปป์ไลน์การคัดกรองเคสนี้จะแบ่งออกเป็น 2 ขั้นตอนอย่างชัดเจน:

  1. การวิเคราะห์และเสนอแนะ (AI Execution): โมเดลจะประมวลผลข้อความจากผู้ใช้ สตรีมเหตุผลประกอบภายในพร้อมร่างคำตอบ และสร้าง structured tool call เพื่อเสนอแนะการกระทำเฉพาะเจาะจง
  2. การอนุมัติและสั่งการ (Application Execution): แอปพลิเคชันจะหยุดเวิร์กโฟลว์ชั่วคราว บันทึกข้อเสนอแนะลงในคิวรอการตรวจสอบ และรอให้เจ้าหน้าที่ยืนยันก่อนที่จะแก้ไขสถานะทิกเก็ตหรือติดต่อกลับไปยังผู้ใช้
Incoming Ticket ──> Node.js Service ──> OneMux Gateway ──> Model Inference
                                                                 │
                                                                 ▼
Ticket Updated  <── Support Agent  <── Review Queue  <── Proposed Actions
   (Execution)        (Approves)       (Intercepted)       & Draft Stream

การกำหนดค่า Node.js SDK: Base URL และการยืนยันตัวตน

แพ็กเกจ npm openai ทางการเปิดโอกาสให้คุณชี้คำขอไปยังปลายทางใดก็ได้ที่ทำงานตามมาตรฐาน โดยปรับเปลี่ยนคุณสมบัติ baseURL คุณสามารถเลือกดูโมเดลที่เปิดให้บริการได้จาก OneMux model catalog เพื่อเลือกโมเดล completion ที่เหมาะสมกับงาน

ขั้นแรก ให้ติดตั้งแพ็กเกจทางการ:

npm install openai

หากต้องการชี้ไปยัง OneMux ให้ตั้งค่าอินสแตนซ์ของไคลเอนต์ด้วย OneMux API key ของคุณ และกำหนด base URL เป็น https://api.onemux.net/v1:

import OpenAI from 'openai';

// Initialize the OpenAI client pointing to the OneMux gateway
const client = new OpenAI({
  apiKey: process.env.ONEMUX_API_KEY,
  baseURL: 'https://api.onemux.net/v1',
});

การตรวจสอบการยืนยันตัวตน

เมื่อส่งคำขอผ่านเกตเวย์ รูปแบบของข้อผิดพลาดด้านการยืนยันตัวตนอาจต่างไปเล็กน้อย หาก API key ของคุณขาดหาย ไม่ถูกต้อง หรือยอดคงเหลือบนแพลตฟอร์มไม่เพียงพอ ไคลเอนต์จะดักจับข้อผิดพลาด AuthenticationError (HTTP 401) ก่อนที่จะรันงานคัดกรองเคสจริงบน production แนะนำให้ตรวจสอบความถูกต้องของข้อมูลรับรองตาม OneMux quickstart guide


การจัดการสตรีมมิงเพื่อร่างข้อเสนอการคัดกรองเคสแบบเรียลไทม์

เจ้าหน้าที่บริการลูกค้าจะทำงานได้สะดวกขึ้นหากเห็นข้อความร่างที่ระบบสร้างขึ้นทยอยแสดงผลทีละส่วน แทนที่จะต้องรอให้ผลลัพธ์ทั้งหมดถูกประมวลผลเสร็จสิ้น เมื่อเรียกใช้ฟังก์ชัน chat.completions.create โดยตั้งค่า stream: true ชุด SDK จะส่งคืน async iterable stream ในรูปแบบ Server-Sent Events (SSE)

โค้ดตัวอย่างด้านล่างนี้จะสตรีมข้อความร่างออกทาง standard output (หรือแดชบอร์ดภายในของเจ้าหน้าที่) ควบคู่ไปกับการดักจับ structured tool calls สำหรับการจำแนกหมวดหมู่ของเคส:

import OpenAI from 'openai';

const client = new OpenAI({
  apiKey: process.env.ONEMUX_API_KEY,
  baseURL: 'https://api.onemux.net/v1',
});

interface TriageProposal {
  draftResponse: string;
  category?: string;
  priority?: 'low' | 'medium' | 'high' | 'urgent';
  suggestedRefundAmount?: number;
}

export async function triageTicketStream(
  ticketId: string,
  customerMessage: string
): Promise<TriageProposal> {
  const tools: OpenAI.ChatCompletionTool[] = [
    {
      type: 'function',
      function: {
        name: 'propose_ticket_action',
        description: 'Propose triage tags, priority updates, or billing adjustments.',
        parameters: {
          type: 'object',
          properties: {
            category: {
              type: 'string',
              enum: ['billing', 'technical_bug', 'account_access', 'general'],
            },
            priority: {
              type: 'string',
              enum: ['low', 'medium', 'high', 'urgent'],
            },
            suggestedRefundAmount: {
              type: 'number',
              description: 'Refund amount in USD if the user experienced downtime.',
            },
          },
          required: ['category', 'priority'],
        },
      },
    },
  ];

  const stream = await client.chat.completions.create({
    model: 'gpt-4o',
    stream: true,
    tools,
    messages: [
      {
        role: 'system',
        content:
          'You are a support triage assistant. Analyze the ticket, stream a helpful draft reply for the customer, and call propose_ticket_action with triage metadata.',
      },
      {
        role: 'user',
        content: customerMessage,
      },
    ],
  });

  let draftResponse = '';
  let toolCallArguments = '';
  let toolName = '';

  for await (const chunk of stream) {
    const delta = chunk.choices[0]?.delta;

    // Stream conversational draft chunks
    if (delta?.content) {
      draftResponse += delta.content;
      process.stdout.write(delta.content);
    }

    // Accumulate tool call chunks
    if (delta?.tool_calls) {
      for (const toolCall of delta.tool_calls) {
        if (toolCall.function?.name) {
          toolName = toolCall.function.name;
        }
        if (toolCall.function?.arguments) {
          toolCallArguments += toolCall.function.arguments;
        }
      }
    }
  }

  let parsedAction = {};
  if (toolName === 'propose_ticket_action' && toolCallArguments) {
    try {
      parsedAction = JSON.parse(toolCallArguments);
    } catch (err) {
      console.error('Failed to parse tool call JSON payload:', err);
    }
  }

  return {
    draftResponse,
    ...parsedAction,
  };
}

ด่านการอนุมัติโดยมนุษย์ (The Human Approval Gate)

การปล่อยให้ระบบรัน tool calls อัตโนมัติทันทีอาจก่อให้เกิดปัญหา เช่น การคืนเงินโดยไม่ได้ตรวจสอบ หรือการยกระดับความเร่งด่วนผิดพลาด แอปพลิเคชันจึงจำเป็นต้องจัดเก็บออบเจกต์ TriageProposal ที่สร้างขึ้นไว้ในสถานะระหว่างกลาง เช่น บันทึกลงฐานข้อมูลด้วยสถานะ PENDING_APPROVAL แทนที่จะสั่งรันแอ็กชันเหล่านั้นทันที

interface PendingReviewTicket {
  ticketId: string;
  status: 'PENDING_APPROVAL' | 'APPROVED' | 'REJECTED';
  proposal: TriageProposal;
}

// Step 1: Queue the proposal for human verification
async function queueForHumanReview(ticketId: string, proposal: TriageProposal) {
  console.log(`[Review Queue] Storing proposal for ticket ${ticketId}:`, proposal);
  // Persistence logic: await db.triageReviews.create({ ticketId, proposal, status: 'PENDING_APPROVAL' });
}

// Step 2: Human operator action handler
async function handleHumanDecision(
  reviewId: string,
  decision: 'APPROVE' | 'REJECT',
  modifiedProposal?: Partial<TriageProposal>
) {
  if (decision === 'REJECT') {
    console.log(`Review ${reviewId} rejected by operator.`);
    return;
  }

  // Execute business logic only after approval
  console.log(`Review ${reviewId} approved. Executing refund and priority assignment...`);
  // e.g., await paymentGateway.issueRefund(modifiedProposal.suggestedRefundAmount);
}

การแยกส่วนการทำงานเช่นนี้ช่วยรับประกันได้ว่า แม้โมเดลจะจำแนกคำถามทั่วไปเป็นเรื่องด่วนผิดพลาด หรือเสนอให้เครดิตคืนเงินเกินความจำเป็น เจ้าหน้าที่ที่เป็นมนุษย์ก็สามารถตรวจสอบและยับยั้งการกระทำดังกล่าวก่อนที่จะมีผลจริง


การวินิจฉัยข้อผิดพลาด: แยกแยะปัญหาระหว่าง Client, Gateway และ Upstream

เมื่อใช้งานเกตเวย์ที่รองรับมาตรฐาน OpenAI อย่าง OneMux ข้อผิดพลาดอาจเกิดขึ้นได้จาก 3 จุด ได้แก่ โค้ดแอปพลิเคชันฝั่งคุณ พร็อกซีของเกตเวย์ หรือผู้ให้บริการโมเดลปลายทาง (upstream) การตรวจสอบอินสแตนซ์ APIError มาตรฐานจาก openai SDK จะช่วยระบุสาเหตุที่แท้จริงได้:

import OpenAI from 'openai';

try {
  await triageTicketStream('ticket-101', 'System is down since morning!');
} catch (error) {
  if (error instanceof OpenAI.APIError) {
    console.error(`Status Code: ${error.status}`);
    console.error(`Error Message: ${error.message}`);
    console.error(`Error Code: ${error.code}`);
    console.error(`Error Type: ${error.type}`);

    switch (error.status) {
      case 401:
        console.error('Check your OneMux API key in environment variables.');
        break;
      case 402:
        console.error('Account balance exhausted. Top up credits in the dashboard.');
        break;
      case 429:
        console.error('Rate limit reached or concurrent request ceiling exceeded.');
        break;
      case 502:
      case 504:
        console.error('Upstream model provider timeout or network disruption via gateway.');
        break;
      default:
        console.error('Unhandled API exception.');
    }
  } else {
    console.error('Non-API runtime error:', error);
  }
}

ตารางสรุป HTTP Status Code ที่พบบ่อย

HTTP Statusสาเหตุหลักที่เป็นไปได้แนวทางแก้ไขที่แนะนำ
401 UnauthorizedOneMux API key ขาดหายหรือไม่ถูกต้องตรวจสอบค่า ONEMUX_API_KEY และการส่งต่อ header ในระบบ
402 Payment Requiredยอดเงินคงเหลือในบัญชีหมดตรวจสอบปริมาณการใช้งานและเติมเงินผ่านหน้า OneMux pricing
429 Too Many Requestsชนขีดจำกัดอัตราการเรียกใช้ (rate limit) หรือจำนวนคำขอพร้อมกันใช้วิธี exponential backoff หรือขอปรับเพิ่มขีดจำกัดกับผู้ให้บริการ
500 Internal Errorฝั่งโมเดล upstream มีปัญหา หรือเกิด unhandled exception บนเกตเวย์ตรวจสอบสถานะการทำงานของเกตเวย์และลองส่งคำขอใหม่อีกครั้ง
502 / 504 Bad Gatewayเกตเวย์ไม่สามารถติดต่อผู้ให้บริการ upstream ได้กำหนดเส้นทางสำรอง (fallback routing) หรือตรวจดูความพร้อมของโมเดลผ่าน OneMux documentation

ข้อจำกัดและพารามิเตอร์ที่ยังไม่รองรับ

แม้ว่า OneMux จะรองรับการใช้งานแทนที่ได้ทันทีสำหรับ chat completion endpoints มาตรฐานของ OpenAI (/v1/chat/completions) แต่ยังคงมีข้อควรระวังดังนี้:

  1. Advanced Beta Endpoints: เอนด์พอยต์นอกเหนือจากงานแชตหลัก, embeddings และ completions เช่น สภาพแวดล้อม hosted sandbox หรือ runtime primitives ของผู้ช่วยตามที่ระบุในเอกสาร OpenAI จะขึ้นอยู่กับว่าเกตเวย์รองรับหรือไม่ จึงควรตรวจสอบความพร้อมใช้งานในเอกสารของเกตเวย์ก่อนขึ้นระบบจริง
  2. Custom Header Passthrough: เฮดเดอร์เฉพาะทางเกี่ยวกับองค์กรหรือโปรเจกต์ (OpenAI-Organization, OpenAI-Project) อาจถูกละเว้นหรือถูกแปลงรูปแบบในเลเยอร์ของพร็อกซี โปรดตรวจสอบให้แน่ใจว่าโทเคนยืนยันตัวตนส่งผ่านการตรวจสอบสิทธิ์แบบ Bearer มาตรฐาน
  3. State Management: หากคุณวางแผนจะย้ายจาก OpenAI Assistants API แบบโฮสต์ มาใช้ลูปเอเจนต์ที่จัดการเองในแอปพลิเคชัน ตัวแอปพลิเคชัน Node.js ของคุณจะต้องรับผิดชอบการจัดเก็บและดูแลประวัติเซสชันด้วยตนเอง

บทสรุป

การย้ายแอปพลิเคชัน Node.js ที่ใช้ OpenAI SDK ไปยังเกตเวย์ที่รองรับมาตรฐาน OpenAI ทำได้อย่างราบรื่นโดยแทบไม่ต้องแก้ไขอะไรมาก เพียงแค่อัปเดต baseURL ระบุเกตเวย์ API key ที่เกี่ยวข้อง และปรับปรุงระบบบันทึก error log ให้รองรับ status codes เฉพาะของเกตเวย์ นอกจากนี้ การแยกข้อเสนอแนะของโมเดลออกจากขั้นตอนที่มีผลต่อระบบงานจริงด้วยด่านอนุมัติ จะช่วยให้กระบวนการคัดกรองเคสสนับสนุนลูกค้ายังคงทำงานได้อย่างรวดเร็ว ในขณะเดียวกันก็ป้องกันข้อผิดพลาดที่ไม่ตั้งใจได้อย่างมีประสิทธิภาพ


แหล่งข้อมูลอ้างอิง

คำถามที่พบบ่อย

ฉันสามารถใช้ Node.js OpenAI SDK ทางการกับ OneMux โดยไม่ต้องแก้โค้ดการเรียกใช้เมธอดเดิมได้หรือไม่?

ได้ เนื่องจาก OneMux พัฒนาขึ้นมาให้เข้ากันได้กับ REST API ของ OpenAI อย่างสมบูรณ์ คุณเพียงแค่กำหนดค่า `baseURL` ให้ชี้ไปยัง `https://api.onemux.net/v1` และระบุ OneMux API key ใน client constructor เท่านั้น เมธอดเดิมอย่าง `client.chat.completions.create` จะสามารถทำงานได้เหมือนเดิมทุกประการ

ระบบสตรีมมิงจัดการส่งทั้งโทเคนข้อความและอาร์กิวเมนต์ของ tool call พร้อมกันได้อย่างไร?

ระหว่างการส่งคำขอแบบสตรีม แต่ละ chunk จะส่งข้อมูล delta ออกมา โดยหากโมเดลตอบกลับเป็นข้อความ `delta.content` จะเก็บข้อความที่สตรีมออกมา แต่หากโมเดลเรียกใช้ฟังก์ชันหรือเครื่องมือ `delta.tool_calls` จะสตรีมชื่อฟังก์ชันและชิ้นส่วนสตริง JSON ทีละส่วนใน `function.arguments` ซึ่งแอปพลิเคชันจะต้องสะสมข้อมูลไว้และนำมา parse หลังจากสตรีมสิ้นสุดลง

ทำไมขั้นตอนการอนุมัติโดยมนุษย์ (human approval gate) ถึงจำเป็นสำหรับระบบคัดกรองเคสบริการลูกค้า?

โมเดล AI อาจตีความน้ำเสียงของลูกค้าผิดพลาดหรือสร้างข้อมูลนโยบายขึ้นมาเอง (hallucinate) การวางด่านอนุมัติในระดับแอปพลิเคชันคั่นระหว่างข้อเสนอแนะของโมเดล (เช่น การคืนเงิน การปรับสถานะการเรียกเก็บเงิน หรือการปิดเคสด่วน) กับการสั่งการจริง จึงช่วยป้องกันไม่ให้ข้อผิดพลาดอัตโนมัติส่งผลกระทบไปถึงลูกค้าโดยตรง

แอปพลิเคชันควรรับมืออย่างไรหากพบข้อผิดพลาด HTTP 502 หรือ 504 จากเกตเวย์?

ข้อผิดพลาด 502 หรือ 504 มักบ่งชี้ว่าเกตเวย์เกิดปัญหาหมดเวลาการเชื่อมต่อ (timeout) หรือไม่สามารถเชื่อมต่อไปยังผู้ให้บริการโมเดลต้นทางได้ ควรใช้วิธีลองส่งคำขอใหม่ (retry) ร่วมกับ exponential backoff และ jitter หรือสลับไปใช้โมเดลสำรอง (fallback model) หากระบบต้องการเสถียรภาพความพร้อมใช้งานสูง

บทความที่เกี่ยวข้อง

Guides

การย้ายระบบแอปพลิเคชัน Node.js OpenAI SDK: การตั้งค่า Base URL, Streaming และ Structured Outputs

คู่มือเชิงเทคนิคสำหรับนักพัฒนา Node.js ในการย้ายระบบแอปพลิเคชัน OpenAI SDK: การกำหนดค่า custom base URL, การจัดการระบบยืนยันตัวตน, การจัดการ streaming structured outputs และการวินิจฉัยข้อผิดพลาดของ API

Guides

GPT-5.6 Sol สำหรับฝ่ายสนับสนุนลูกค้า: เลือกโมเดล OpenAI API ให้เหมาะสม

เรียนรู้ว่า GPT-5.6 Sol เหมาะกับงานอัตโนมัติด้านสนับสนุนลูกค้าอย่างไร ราคาเท่าไร และวิธีเข้าถึงผ่าน OneMux API ที่เข้ากันได้กับ OpenAI

Guides

ค้นหาโมเดล GPT-5.6 ที่เหมาะกับการสนับสนุนลูกค้า: ทำไม Terra ถึงลงตัวพอดี

ค้นพบว่า GPT-5.6 Terra เป็นโมเดลที่เหมาะสำหรับการสนับสนุนลูกค้า โดยสมดุลระหว่างต้นทุน ความเร็ว และความแม่นยำ เปรียบเทียบกับโมเดลอื่นๆ และเรียนรู้ว่า OneMux ช่วยให้การเข้าถึงง่ายขึ้น

Guides

สร้างเอเจนต์ Customer Support ด้วย LangGraph พร้อมการเรียกใช้เครื่องมือ การอนุมัติโดยมนุษย์ และข้อจำกัดการทำงาน

แนวทาง LangGraph เชิงปฏิบัติสำหรับคัดแยกคำขอฝ่ายสนับสนุนลูกค้า: จัดเส้นทางคำขอ เรียกใช้เครื่องมือค้นข้อมูล หยุดคำขอคืนเงินเพื่อรอการอนุมัติจากมนุษย์ และจำกัดการทำงานของกราฟ