DeepSeek Vision and Grok Imagine models are now live on CometAPI →
guide/งานวิจัย CometAPI

วิธีสร้างแอปแชต AI แบบหลายโมเดลด้วย Next.js และ CometAPI

สร้างแอปแชท AI แบบสตรีมมิ่งด้วย Next.js ที่สามารถสลับระหว่างโมเดล GPT, Claude และ Gemini ได้ โดยใช้คีย์ CometAPI เพียงชุดเดียวและเอ็นด์พอยต์แบ็กเอนด์เดียว

CometAPI
Annaทีมวิจัยโมเดล AI และ API
อัปเดตแล้ว Aug 25, 2026 8 นาทีในการอ่าน
วิธีสร้างแอปแชต AI แบบหลายโมเดลด้วย Next.js และ CometAPI
ใช้รูปแบบนี้

เรียกใช้ API ครั้งแรก

from openai import OpenAI

client = OpenAI(
    api_key="YOUR_COMETAPI_KEY",
    base_url="https://api.cometapi.com/v1",
)

response = client.chat.completions.create(
    model="gpt-5-mini",
    messages=[{"role": "user", "content": "Build this workflow."}],
)

print(response.choices[0].message.content)

สำหรับแชตบอท Next.js ที่ต้องใช้ผู้ให้บริการโมเดลหลายเจ้า แบ็กเอนด์ที่มีประโยชน์ที่สุดคือแบบที่รวมศูนย์การยืนยันตัวตน แต่ปล่อยให้แอปเลือกโมเดลต่อคำขอ CometAPI ให้รูปแบบดังกล่าว: เซิร์ฟเวอร์เก็บคีย์ API เดียวและ OpenAI-compatible base URL https://api.cometapi.com/v1 ขณะที่ฟิลด์ model ในคำขอจะเลือก GPT, Claude, Gemini หรือโมเดลแชตอื่นที่พร้อมใช้งานได้

บทเรียนนี้จะสร้างโปรเจ็กต์ App Router ที่ทำงานได้จริง พร้อมรายการอนุญาตโมเดลฝั่งเซิร์ฟเวอร์, Route Handler แบบสตรีมมิง, ตัวเลือกโมเดลบนเบราว์เซอร์, ตัวแปรสภาพแวดล้อมที่ได้รับการป้องกัน, อินเทอร์เฟซแชตครบถ้วน และคำแนะนำการดีพลอย คีย์ CometAPI จะไม่ไปถึงเบราว์เซอร์

Multi-Model AI Chat App คืออะไร?

สถาปัตยกรรมแชต AI แบบหลายโมเดลจะวางแบ็กเอนด์ที่ควบคุมโดยแอประหว่างส่วนติดต่อผู้ใช้และผู้ให้บริการโมเดลหลายเจ้า ในโปรเจ็กต์นี้ เบราว์เซอร์จะส่งบทสนทนาไปยัง /api/chat ขณะที่เซิร์ฟเวอร์เก็บข้อมูลยืนยันตัวตนของ CometAPI ไว้เป็นความลับ ตรวจสอบความถูกต้องของรหัสโมเดลที่ร้องขอ และส่งต่อคำขอผ่าน API ที่เข้ากันได้เพียงจุดเดียว

การสลับโมเดลใน Next.js ทำงานอย่างไร?

การเปลี่ยนโมเดลคือการตัดสินใจด้านการรูต เบราว์เซอร์ส่งรหัสโมเดลที่อนุมัติแล้วพร้อมบทสนทนาไปยัง /api/chat จากนั้น Route Handler จะใส่ข้อมูลยืนยันตัวตนของ CometAPI เรียก POST /v1/chat/completions และสตรีมคำตอบของโมเดลที่เลือกกลับไปยังเบราว์เซอร์

เอ็นด์พอยต์ร่วมไม่ได้ทำให้ทุกโมเดลเหมือนกัน สไตล์ผลลัพธ์ พฤติกรรมการใช้เครื่องมือ พารามิเตอร์ที่รองรับ ข้อจำกัดบริบท และราคาอาจต่างกัน เก็บรหัสโมเดลไว้ในรายการอนุญาตฝั่งเซิร์ฟเวอร์และทดสอบแต่ละเส้นทางด้วยพรอมต์ของแอปเดียวกัน ก่อนเปิดให้ผู้ใช้ใช้งาน

สิ่งที่จะสร้าง

แอปที่เสร็จสมบูรณ์มีแบ็กเอนด์ Next.js เดียวและมีเส้นทางแชตให้เลือกสามเส้นทาง:

Model IDบทบาทตัวอย่างราคา CometAPI
gemini-3.7-flashแชตปริมาณมากที่ใส่ใจต้นทุน$0.60 input / $3.00 output
claude-opus-5การให้เหตุผลระดับพรีเมียมแบบโฟกัส$4 input / $20 output
gpt-5.6gpt-5.6 เป็นเส้นทางทั่วไปของ CometAPI สำหรับ GPT-5.6 และขณะนี้แมปกับระดับ Sol$3.2 input / $16 output ในระดับ short-context

หมายเหตุเรื่องราคา: ราคาที่แสดงเป็น USD ต่อหนึ่งล้านโทเค็น ตรวจสอบเมื่อวันที่ 21 สิงหาคม 2026 และอาจมีการเปลี่ยนแปลง ควรตรวจสอบอัตราปัจจุบันในหน้ารายละเอียดโมเดลก่อนใช้งานจริง ตารางเป็นตัวอย่างการรูต ไม่ใช่อันดับคุณภาพ GPT-5.6 ใช้ระดับราคาที่สูงขึ้นเมื่อเกิน 272,000 โทเค็น ดูหน้าโมเดลที่ลิงก์ไว้ Gemini 3.7 Flash, Claude Opus 5, และ GPT-5.6 สำหรับอัตราที่ใช้ ณ วันที่ดังกล่าว

CometAPI คิดราคาโมเดลอย่างโปร่งใสอ้างอิงตาม API อย่างเป็นทางการของแต่ละผู้ให้บริการ โมเดลที่มีราคาอย่างเป็นทางการแบบรวม — เช่น OpenAI, Claude, Gemini และที่ใกล้เคียง — จะถูกคิดค่าบริการต่อโทเค็นที่อัตราส่วน 0.8:1 ของราคาทางการ คือส่วนลด 20% ส่วนโมเดลที่ไม่มี API อย่างเป็นทางการ (เช่น MidJourney, Kling, Luma) จะคิดค่าบริการต่อครั้งตามอัตราที่ CometAPI กำหนด ซึ่งลดราคา 20% เช่นกัน ดู CometAPI Pricing Guide สำหรับสูตรการคำนวณ อัตรารายโมเดล และหน่วยการคิดเงิน

ทั้งสามเส้นทางครอบคลุมการแลกเปลี่ยนข้อดีข้อเสียที่ต่างกัน Gemini 3.7 Flash คือเวิร์กฮอร์สแบบเอเจนติกที่มีประสิทธิภาพของ Google รองรับอินพุตมัลติโหมดและหน้าต่างบริบท 1,048,576 โทเค็น เหมาะกับแชตปริมาณมาก งานโค้ด และเวิร์กโฟลว์ความรู้ Claude Opus 5 คือโมเดลการให้เหตุผลระดับแนวหน้าของ Anthropic แข็งแกร่งในงานวิเคราะห์หลายขั้นตอน โค้ด และงานเขียนยาวที่รอบคอบในราคาพรีเมียม GPT-5.6 คือโมเดลอเนกประสงค์ของ OpenAI ที่บาลานซ์การให้เหตุผล การใช้เครื่องมือ และการร่างงาน พร้อมหน้าต่างบริบทกว้างสำหรับทราฟฟิกการผลิตในชีวิตประจำวัน

ก่อนเริ่มต้น

คุณต้องมี Node.js, npm, บัญชี CometAPI และคีย์ API ฝั่งเซิร์ฟเวอร์จาก CometAPI Quick Start โมเดลไอดีทั้งสามแบบด้านบนมีอยู่ในแคตาล็อกสดเมื่อวันที่ 21 สิงหาคม 2026 ไม่ได้ถูกทำเครื่องหมายว่า upcoming และรองรับ POST /v1/chat/completions

บทเรียนใช้การตั้งค่าเหล่านี้ร่วมกัน:

ขั้นตอนที่ 1: สร้างแอป Next.js

npx create-next-app@latest multi-model-chat --ts --app --eslintcd multi-model-chatnpm run dev

เวอร์ชันนี้ไม่ต้องใช้ SDK ของผู้ให้บริการโมเดล เซิร์ฟเวอร์จะใช้ fetch ที่มีมาในตัวและส่งต่อสตรีม Server-Sent Events ของต้นทาง

ขั้นตอนที่ 2: เก็บคีย์ CometAPI ไว้บนเซิร์ฟเวอร์

สร้างไฟล์ .env.local ที่รากโปรเจ็กต์:

COMETAPI_API_KEY=replace_with_your_cometapi_keyCOMETAPI_BASE_URL=https://api.cometapi.com/v1

อย่าใส่คำนำหน้า NEXT_PUBLIC_ ให้คีย์ Next.js จะเปิดเผยตัวแปรที่มีคำนำหน้านั้นไปยังบันเดิลฝั่งเบราว์เซอร์เท่านั้น คีย์ API ควรอยู่ใน Route Handler ฝั่งเซิร์ฟเวอร์

ขั้นตอนที่ 3: กำหนดนโยบายโมเดล

วางไอดีที่อนุญาตไว้ในแบ็กเอนด์ ไม่ใช่เฉพาะในดรอปดาวน์ ผู้ใช้สามารถข้ามการควบคุมบนเบราว์เซอร์และเรียกเส้นทางของคุณโดยตรงได้ ดังนั้นเซิร์ฟเวอร์ต้องปฏิเสธค่าโมเดลที่ไม่รู้จัก

const ALLOWED_MODELS = [  "gemini-3.7-flash",  "claude-opus-5",  "gpt-5.6",] as const;​type ModelId = (typeof ALLOWED_MODELS)[number];

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

ขั้นตอนที่ 4: สตรีม CometAPI ผ่าน Route Handler

สร้าง app/api/chat/route.ts เส้นทางนี้ตรวจสอบเพย์โหลดแชตแบบข้อความล้วน เรียก CometAPI ด้วย stream: true และส่งคืนสตรีมอีเวนต์ต้นทางโดยไม่เปิดเผยข้อมูลยืนยันตัวตน

export const runtime = "nodejs";export const dynamic = "force-dynamic";​const ALLOWED_MODELS = [  "gemini-3.7-flash",  "claude-opus-5",  "gpt-5.6",] as const;​type ModelId = (typeof ALLOWED_MODELS)[number];type ChatMessage = {  role: "system" | "user" | "assistant";  content: string;};​function isModelId(value: unknown): value is ModelId {  return (    typeof value === "string" &&    (ALLOWED_MODELS as readonly string[]).includes(value)  );}​function isChatMessage(value: unknown): value is ChatMessage {  if (typeof value !== "object" || value === null) return false;​  const message = value as Record<string, unknown>;  return (    ["system", "user", "assistant"].includes(String(message.role)) &&    typeof message.content === "string" &&    message.content.length > 0 &&    message.content.length <= 20_000  );}​export async function POST(request: Request) {  const apiKey = process.env.COMETAPI_API_KEY;  const baseUrl = (    process.env.COMETAPI_BASE_URL || "https://api.cometapi.com/v1"  ).replace(/\/$/, "");​  if (!apiKey) {    return Response.json(      { error: "COMETAPI_API_KEY is not configured." },      { status: 500 },    );  }​  let payload: { model?: unknown; messages?: unknown };​  try {    payload = await request.json();  } catch {    return Response.json({ error: "Invalid JSON body." }, { status: 400 });  }​  if (!isModelId(payload.model)) {    return Response.json({ error: "Unsupported model ID." }, { status: 400 });  }​  if (    !Array.isArray(payload.messages) ||    payload.messages.length === 0 ||    payload.messages.length > 50 ||    !payload.messages.every(isChatMessage)  ) {    return Response.json(      { error: "messages must contain 1 to 50 valid text messages." },      { status: 400 },    );  }​  const upstream = await fetch(`${baseUrl}/chat/completions`, {    method: "POST",    headers: {      Authorization: `Bearer ${apiKey}`,      "Content-Type": "application/json",    },    body: JSON.stringify({      model: payload.model,      messages: payload.messages,      stream: true,    }),    cache: "no-store",    signal: request.signal,  });​  if (!upstream.ok) {    const requestId = upstream.headers.get("x-request-id");​    console.error("CometAPI request failed", {      status: upstream.status,      requestId,    });​    return Response.json(      {        error: "The selected model request failed.",        status: upstream.status,        requestId,      },      { status: upstream.status },    );  }​  if (!upstream.body) {    return Response.json(      { error: "The model returned no response body." },      { status: 502 },    );  }​  return new Response(upstream.body, {    status: 200,    headers: {      "Content-Type": "text/event-stream; charset=utf-8",      "Cache-Control": "no-cache, no-transform",    },  });}

ตัวจัดการจะส่งสัญญาณตัดการเชื่อมต่อจากเบราว์เซอร์ขึ้นไปยังต้นทาง ดังนั้นการปิดคำขอจะหยุดการสร้างผลลัพธ์ที่ไม่จำเป็นได้ อีกทั้งยังส่งคืนข้อผิดพลาดที่ผ่านการทำให้ปลอดภัยไปยังไคลเอนต์ พร้อมเก็บรายละเอียดการวินิจฉัยไว้ในล็อกเซิร์ฟเวอร์

ขั้นตอนที่ 5: เพิ่มการเลือกโมเดลและการพาร์สสตรีม

สร้างคอมโพเนนต์ฝั่งไคลเอนต์ใน app/page.tsx โดยส่งโมเดลที่เลือกไปพร้อมบทสนทนา พาร์สแต่ละอีเวนต์ data: และนำข้อความ delta.content แบบเพิ่มทีละส่วนไปต่อท้ายข้อความของ assistant ล่าสุด

เบราว์เซอร์จะไม่เรียก CometAPI โดยตรง ปลายทางเดียวคือเส้นทาง /api/chat ของคุณเอง ซึ่งเก็บคีย์ไว้เป็นความลับและบังคับใช้รายการอนุญาต

โค้ดหลักของโปรเจ็กต์

Route Handler ด้านบนคือไฟล์ app/api/chat/route.ts ที่สมบูรณ์ เพิ่มเพจ เลย์เอาต์ และสไตล์ชีตต่อไปนี้เพื่อให้โปรเจ็กต์รันได้

app/page.tsx

"use client";​import { FormEvent, useState } from "react";​const MODEL_OPTIONS = [  { id: "gemini-3.7-flash", label: "Gemini 3.7 Flash" },  { id: "claude-opus-5", label: "Claude Opus 5" },  { id: "gpt-5.6", label: "GPT-5.6" },] as const;​type Role = "user" | "assistant";type Message = { role: Role; content: string };​function textFromSseLine(line: string): string {  const trimmed = line.trim();  if (!trimmed.startsWith("data:")) return "";​  const data = trimmed.slice(5).trim();  if (!data || data === "[DONE]") return "";​  try {    const event = JSON.parse(data);    return event.choices?.[0]?.delta?.content ?? "";  } catch {    return "";  }}​export default function Home() {  const [model, setModel] = useState("gemini-3.7-flash");  const [messages, setMessages] = useState<Message[]>([]);  const [input, setInput] = useState("");  const [loading, setLoading] = useState(false);  const [error, setError] = useState("");​  function appendAssistantText(text: string) {    if (!text) return;​    setMessages((current) => {      const next = [...current];      const lastIndex = next.length - 1;​      if (lastIndex >= 0 && next[lastIndex].role === "assistant") {        next[lastIndex] = {          ...next[lastIndex],          content: next[lastIndex].content + text,        };      }​      return next;    });  }​  async function sendMessage(event: FormEvent<HTMLFormElement>) {    event.preventDefault();​    const content = input.trim();    if (!content || loading) return;​    const outgoing: Message[] = [...messages, { role: "user", content }];    setMessages([...outgoing, { role: "assistant", content: "" }]);    setInput("");    setError("");    setLoading(true);​    try {      const response = await fetch("/api/chat", {        method: "POST",        headers: { "Content-Type": "application/json" },        body: JSON.stringify({ model, messages: outgoing }),      });​      if (!response.ok) {        const body = await response.json().catch(() => ({}));        throw new Error(body.error || `Request failed with ${response.status}`);      }​      if (!response.body) throw new Error("Streaming is not available.");​      const reader = response.body.getReader();      const decoder = new TextDecoder();      let buffer = "";​      while (true) {        const { value, done } = await reader.read();        buffer += decoder.decode(value, { stream: !done });​        const lines = buffer.split("\n");        buffer = lines.pop() ?? "";​        for (const line of lines) {          appendAssistantText(textFromSseLine(line));        }​        if (done) {          appendAssistantText(textFromSseLine(buffer));          break;        }      }    } catch (requestError) {      setError(        requestError instanceof Error ? requestError.message : "Request failed.",      );    } finally {      setLoading(false);    }  }​  return (    <main className="shell">      <section className="chat">        <header>          <p className="eyebrow">Next.js + CometAPI</p>          <h1>Multi-model chat</h1>          <label>            Model            <select              value={model}              onChange={(event) => setModel(event.target.value)}              disabled={loading}            >              {MODEL_OPTIONS.map((option) => (                <option key={option.id} value={option.id}>                  {option.label}                </option>              ))}            </select>          </label>        </header>​        <div className="messages" aria-live="polite">          {messages.length === 0 ? (            <p className="empty">Choose a model and send a message.</p>          ) : (            messages.map((message, index) => (              <article className={message.role} key={`${message.role}-${index}`}>                <b>{message.role === "user" ? "You" : "Assistant"}</b>                <p>{message.content || "…"}</p>              </article>            ))          )}        </div>​        <form onSubmit={sendMessage}>          <textarea            value={input}            onChange={(event) => setInput(event.target.value)}            placeholder="Ask something…"            rows={3}            maxLength={20_000}          />          <button disabled={loading || !input.trim()} type="submit">            {loading ? "Streaming…" : "Send"}          </button>          </form>​        {error ? <p className="error">{error}</p> : null}      </section>    </main>  );}

app/layout.tsx

import type { Metadata } from "next";import "./globals.css";​export const metadata: Metadata = {  title: "Multi-Model Chat",  description: "A streaming Next.js chat app powered by CometAPI.",};​export default function RootLayout({  children,}: Readonly<{ children: React.ReactNode }>) {  return (    <html lang="en">      <body>{children}</body>    </html>  );}

app/globals.css

:root {  color-scheme: dark;  font-family: Arial, sans-serif;  background: #07111f;  color: #eef4ff;}* { box-sizing: border-box; }body { margin: 0; }button, select, textarea { font: inherit; }​/* Layout shell and chat card */.shell { min-height: 100vh; display: grid; place-items: center; padding: 32px 16px; }.chat { width: min(820px, 100%); background: #0d1b2e; border: 1px solid #223957; border-radius: 20px; padding: 24px; }​/* Message list and bubbles */.messages { min-height: 360px; display: grid; align-content: start; gap: 12px; margin: 24px 0; }.messages article { max-width: 85%; padding: 12px 14px; border-radius: 14px; white-space: pre-wrap; }.user { justify-self: end; background: #164f8f; }.assistant { justify-self: start; background: #182a42; }​/* Form controls, buttons, and error states follow the same dark theme. */

ขั้นตอนที่ 6: รันและดีพลอยแอป

npm run dev

เปิด http://localhost:3000 เลือกโมเดล และส่งข้อความ สำหรับดีพลอยบน Node.js โปรดักชัน เพิ่ม COMETAPI_API_KEY และ COMETAPI_BASE_URL ลงในค่าตัวแปรสภาพแวดล้อมฝั่งเซิร์ฟเวอร์ของโฮสต์ แล้วรัน:

npm run buildnpm run start

ใช้แพลตฟอร์มโฮสต์ที่รองรับการตอบกลับแบบสตรีม ไซต์แบบสแตติกเอ็กซ์พอร์ตไม่สามารถรัน Route Handler ที่ /api/chat ได้

ทดสอบเส้นทางสตรีมมิง

เมื่อเซิร์ฟเวอร์พัฒนากำลังรันอยู่ ให้เรียกแบ็กเอนด์ของคุณโดยตรง:

curl -N http://localhost:3000/api/chat \  -H "Content-Type: application/json" \  -d '{    "model": "gemini-3.7-flash",    "messages": [      {"role": "user", "content": "Explain model routing in two sentences."}    ]  }'

คำขอที่สำเร็จจะส่งคืน Server-Sent Events ค่าจริงของไอดีและข้อความอาจต่างกันไป แต่รูปแบบสตรีมจะเป็นดังนี้:

data: {"choices":[{"delta":{"content":"Model"}}]}​data: {"choices":[{"delta":{"content":" routing"}}]}​data: [DONE]

พาร์เซอร์บนเบราว์เซอร์จะอ่านอีเวนต์ SSE แต่ละรายการ ดึง choices[0].delta.content และต่อเติมข้อความที่สตรีมเข้ามาไปยังข้อความของ assistant ทีละชิ้น

ข้อผิดพลาดการเชื่อมต่อทั่วไป

อาการสาเหตุวิธีแก้
401 authentication errorคีย์ฝั่งเซิร์ฟเวอร์หายหรือไม่ถูกต้องตั้งค่า COMETAPI_API_KEY; อย่าเปิดเผยด้วย NEXT_PUBLIC_.
404 หรือเส้นทางไม่ถูกต้องBase URL ขาด /v1ใช้ https://api.cometapi.com/v1.
400 unsupported modelไอดีไม่อยู่ในรายการอนุญาตฝั่งแบ็กเอนด์ใช้ไอดีโมเดลข้อความที่มีอยู่จริงแบบตรงตัว และอัปเดตทั้งตัวเลือกทั้งสองฝั่ง
คำตอบออกมาทีเดียวทั้งหมดโฮสต์หรือพร็อกซีบัฟเฟอร์สตรีมอีเวนต์ปิดการแปลงการตอบกลับ และใช้ดีพลอย Node.js ที่รองรับการสตรีม

เตรียมแบ็กเอนด์แชตสำหรับโปรดักชัน

  • ยืนยันตัวตนผู้ใช้ของคุณเอง อย่าเปิดเส้นทางสาธารณะที่ใช้เครดิตสำหรับทราฟฟิกนิรนาม
  • จำกัดอัตราตามผู้ใช้และ IP กำหนดเพดานสตรีมพร้อมกัน คำขอต่อนาที จำนวนข้อความ และความยาวข้อความ
  • เก็บรายการอนุญาตโมเดลไว้ฝั่งเซิร์ฟเวอร์ ตัวเลือกบนเบราว์เซอร์เป็นเพียงความสะดวก ไม่ใช่ขอบเขตความปลอดภัย
  • ตรวจสอบความถูกต้องของแคตาล็อกสดระหว่างดีพลอย เรียก GET https://api.cometapi.com/api/models และล้มการปล่อยหากไอดีที่ตั้งค่าไว้เป็น upcoming, ไม่พร้อมใช้งาน หรือไม่มีเอ็นด์พอยต์ chat-completions
  • ติดตามต้นทุนตามเส้นทาง ล็อกโมเดลที่เลือก ไอดีคำขอ เวลาแฝง การใช้โทเค็น และไอดีผู้ใช้ ตั้งโควตาหรือเพดานค่าใช้จ่ายในแดชบอร์ด CometAPI ตามความเหมาะสม
  • จัดการการตัดการเชื่อมต่อและการหมดเวลา คงไว้ซึ่ง request.signal ตั้งค่า timeout ของแอป และหยุดงานเมื่อไคลเอนต์ออก
  • อย่าซ่อนข้อผิดพลาดการตั้งค่าด้วยการ fallback แสดง 400 และ 401 อย่างตรงไปตรงมา ใช้โมเดลอื่นเฉพาะในชุดข้อผิดพลาดที่รีทรายได้และเมื่อสคีมาคำขอเข้ากันได้เท่านั้น ดู CometAPI Model Fallback Guide สำหรับโซ่ fallback สองชั้น (CometAPI หลัก → โมเดล fallback ของ CometAPI → ผู้ให้บริการทางการ)
  • ปกปิดข้อมูลในล็อก อย่าเก็บคีย์ API พรอมต์เต็ม หรือเอาต์พุตของโมเดลที่อ่อนไหวไว้ในล็อกข้อผิดพลาดโปรดักชัน

แบ็กเอนด์ Next.js เดียว หลายตัวเลือกโมเดล

การสลับโมเดลควรอยู่ในนโยบายฝั่งเซิร์ฟเวอร์ของคุณ ไม่ใช่ในบัญชีผู้ให้บริการแยกกัน Route Handler ของ Next.js สามารถเก็บคีย์ CometAPI เดียวไว้เป็นความลับ รับรหัสโมเดลที่อนุมัติแล้วต่อคำขอ และสตรีมโมเดลที่เลือกผ่านเอ็นด์พอยต์ที่เข้ากันได้กับ OpenAI ส่วนหน้าจะยังคงเรียบง่าย ขณะที่แบ็กเอนด์คงการควบคุมการเข้าถึง การตรวจสอบความถูกต้อง ความสามารถในการสังเกต และต้นทุน คีย์เดียวกันยังเข้าถึง API ภาพและวิดีโอเนทีฟของ CometAPI — เช่น Flux สำหรับสร้างภาพและ Kling สำหรับวิดีโอ — ทำให้แบ็กเอนด์แชตนี้ขยายสู่เวิร์กโฟลว์มัลติโหมดได้โดยไม่ต้องผสานอีกครั้ง

ใช้ ไดเรกทอรีโมเดลสาธารณะของ CometAPI สำหรับการค้นหาโมเดล และ GET https://api.cometapi.com/api/models สำหรับการตรวจสอบการรูตอัตโนมัติ

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

ฉันสามารถใช้โมเดล AI หลายตัวในแอป Next.js เดียวได้ไหม?

ได้ เก็บเส้นทางฝั่งเซิร์ฟเวอร์เดียวและส่งรหัสโมเดลที่อยู่ในรายการอนุญาตไปกับแต่ละคำขอ UI บนเบราว์เซอร์สามารถให้ผู้ใช้เลือกโมเดลได้ ขณะที่เซิร์ฟเวอร์ควบคุมว่าไอดีใดถูกยอมรับ

จะสลับระหว่าง GPT, Claude และ Gemini ได้อย่างไร?

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

ควรเก็บคีย์ CometAPI API key ไว้ที่ไหน?

เก็บไว้ในตัวแปรสภาพแวดล้อมฝั่งเซิร์ฟเวอร์ เช่น COMETAPI_API_KEY ห้ามเปิดเผยผ่านตัวแปร NEXT_PUBLIC_ หรือโค้ดฝั่งไคลเอนต์

API ที่เข้ากันได้กับ OpenAI ทำให้ทุกโมเดลแทนกันได้หรือไม่?

ไม่ โครงร่างคำขออาจพกพาได้ แต่โมเดลอาจต่างกันในพารามิเตอร์ที่รองรับ ข้อจำกัดบริบท พฤติกรรมเครื่องมือ สไตล์เอาต์พุต เวลาแฝง และราคา ทดสอบทุกโมเดลในรายการอนุญาตด้วยพรอมต์โปรดักชันของคุณ

Next.js Route Handlers สามารถสตรีมคำตอบ AI ได้ไหม?

ได้ Route Handler สามารถส่งคืนสตรีม Server-Sent Events ของต้นทางด้วย content type แบบ text/event-stream โดยแพลตฟอร์มดีพลอยและพร็อกซีที่อยู่ด้านหน้าต้องไม่บัฟเฟอร์การตอบกลับ

ฉันสามารถดีพลอยแอปนี้เป็นไซต์ Next.js แบบสแตติกได้ไหม?

ไม่ได้ การสแตติกเอ็กซ์พอร์ตไม่สามารถรัน Route Handler ฝั่งเซิร์ฟเวอร์ที่ /api/chat หรือปกป้องคีย์ API ได้ ใช้รันไทม์เซิร์ฟเวอร์ Node.js หรือแพลตฟอร์มที่รองรับการสตรีมแทน

เรียนรู้ต่อ

เชื่อมโยงบทความนี้กับการตัดสินใจถัดไป

ดูทุกหัวข้อ
เผยแพร่เมื่อ Aug 25, 2026
อัปเดตล่าสุด Aug 25, 2026
0 ครั้งที่ดู
ตรวจสอบความชัดเจน การอ้างอิงแหล่งที่มา และคำศัพท์ API ปัจจุบันแล้ว

พร้อมลดต้นทุนการพัฒนา AI ลง 20% แล้วหรือยัง?

เริ่มต้นฟรีภายในไม่กี่นาที มีเครดิตทดลองใช้ฟรี ไม่ต้องใช้บัตรเครดิต

อ่านเพิ่มเติม