Node.js 接入 OpenAI API 完整教程

Node.js 和 TypeScript 项目接大模型,官方 openai SDK 十几行代码就能跑通。这篇覆盖安装配置、baseURL 指向兼容网关、流式输出、超时重试和常见报错排查,附 Next.js 与 Express 两种落地写法。

Node.js 是大模型应用最常见的技术栈,官方 openai npm 包对 TypeScript 支持完整,十几行代码就能跑通一次对话。真正容易出问题的不是调用本身,而是三件事:baseURL 该不该带 /v1、流式在框架里被缓冲、以及超时和重试没配置导致线上挂起。这篇按可直接复制的最小实现讲清楚。

先说结论

  • 用官方 openai 包(v4+),不要手写 fetch,也不要用社区停更的封装库
  • 构造时传 baseURL: 'https://api.zaimod.com/v1',要带 /v1,这一点与部分框架(如 Spring AI)相反
  • API Key 一律走环境变量 OPENAI_API_KEY 或自定义变量,不要写进代码提交到仓库
  • 流式输出用 stream: true 配合 for await 消费,Web 框架里注意关闭响应缓冲

安装与最小可运行示例

Node 18 及以上自带 fetch,SDK 开箱即用:

npm install openai
// chat.mjs
import OpenAI from 'openai';

const client = new OpenAI({
  apiKey: process.env.ZAIMOD_API_KEY,
  baseURL: 'https://api.zaimod.com/v1',
});

const res = await client.chat.completions.create({
  model: 'gpt-4o-mini',
  messages: [{ role: 'user', content: '用一句话解释什么是 API 网关' }],
});

console.log(res.choices[0].message.content);

运行:

export ZAIMOD_API_KEY=sk-你的Key   # Windows PowerShell 用 $env:ZAIMOD_API_KEY="sk-..."
node chat.mjs

换模型只改 model 字符串。zaimod 这类聚合网关下,Claude、Gemini、DeepSeek 等模型走同一个 baseURL 和同一个 Key,协议原理见 OpenAI 兼容协议详解。

TypeScript 写法

SDK 自带完整类型,消息体用 ChatCompletionMessageParam 类型标注即可获得角色与内容检查:

import OpenAI from 'openai';
import type { ChatCompletionMessageParam } from 'openai/resources/chat/completions';

const client = new OpenAI({
  apiKey: process.env.ZAIMOD_API_KEY,
  baseURL: 'https://api.zaimod.com/v1',
});

const messages: ChatCompletionMessageParam[] = [
  { role: 'system', content: '你是严谨的技术助手,回答控制在 200 字内。' },
  { role: 'user', content: 'ESM 和 CJS 的区别是什么?' },
];

const res = await client.chat.completions.create({
  model: 'gpt-4o-mini',
  messages,
  max_tokens: 256,
});

const text = res.choices[0]?.message?.content ?? '';

注意 choices[0].message.content 类型是 string | null——模型只返回工具调用时内容为空,必须做空值处理,否则 TS 编译就过不了,这其实帮你挡住了线上的一类空指针。

流式输出

把 stream: true 打开后,返回值变成异步迭代器:

const stream = await client.chat.completions.create({
  model: 'gpt-4o-mini',
  messages: [{ role: 'user', content: '写一首关于数据中心的短诗' }],
  stream: true,
});

for await (const chunk of stream) {
  const delta = chunk.choices[0]?.delta?.content;
  if (delta) process.stdout.write(delta);
}

在 Web 框架里接入时有两个坑:

Express:用 res.write() 逐段写出,并设置 Content-Type: text/event-stream。如果前面挂了 Nginx,记得 proxy_buffering off;,否则用户看到的是最后一次性吐出全文。

Next.js App Router:Route Handler 直接把 SDK 流转成 ReadableStream 返回即可,不要用 await res.json() 之类把流读完的中间层。SSE 协议细节与前端 EventSource 写法参考 SSE 流式输出从 curl 到前端。

超时、重试与限流

SDK 默认会重试两次(仅对连接错误和 429/5xx),但默认超时 10 分钟对多数业务太长,建议显式设置:

const client = new OpenAI({
  apiKey: process.env.ZAIMOD_API_KEY,
  baseURL: 'https://api.zaimod.com/v1',
  timeout: 60_000,          // 单次请求超时
  maxRetries: 2,            // SDK 内置重试次数
});

捕获限流错误做退避:

import OpenAI from 'openai';

async function chatWithBackoff(params, maxAttempts = 3) {
  for (let i = 0; i < maxAttempts; i++) {
    try {
      return await client.chat.completions.create(params);
    } catch (err) {
      if (err instanceof OpenAI.APIError && err.status === 429 && i < maxAttempts - 1) {
        await new Promise(r => setTimeout(r, 2 ** i * 1000 + Math.random() * 500));
        continue;
      }
      throw err;
    }
  }
}

限流触发后的完整排查思路(按 RPM/TPM 哪个先超、如何申请提额)见 大模型 API 429 限流怎么解。

常见报错对照

报错信息原因处理
404 Not FoundbaseURL 少了或多了 /v1官方 SDK 固定写 https://api.zaimod.com/v1
401 Incorrect API keyKey 错误或环境变量没生效echo 检查变量名,注意进程需重启才会读到新变量
429 Rate limit并发或 token 速率超限指数退避 + 检查调用方并发
ESM/CJS 报错 ERR_REQUIRE_ESM老项目用 require 引 openaiopenai v4 是纯 ESM 包,改 import 或降级方案
流式一次性返回中间层缓冲了 SSE关 Nginx proxy_buffering,去掉多余中间件

常见问题

Q:Next.js 服务端组件里能直接调吗?

能,但建议放 Route Handler 或 Server Actions 里,并把 Key 只放在服务端环境变量。NEXT_PUBLIC_ 前缀的变量会打进浏览器 bundle,等于把 Key 公开,绝对不要这样放。

Q:怎么统计每个请求花了多少 token?

非流式响应里有 res.usage(prompt_tokens 与 completion_tokens),流式可请求 stream_options: { include_usage: true },最后一个 chunk 会带 usage。计费单价在 价格速查 按模型列出。

Q:一个 Node 进程该建几个 client 实例?

一个。OpenAI 实例内部维护连接池,做成模块级单例即可,高频 new 会导致连接抖动。若要按模型或按租户区分超时策略,可以建少量命名实例。

延伸阅读

#nodejs 调用 openai api#typescript 接入大模型#openai node sdk#openai npm 教程
免费创建 API Key

相关阅读

Java 项目接入 OpenAI API 完整方案

Spring Boot 项目要接大模型,Spring AI 和官方 openai-java SDK 该选哪个?这篇给出两套可直接落地的配置与代码,讲清 base-url 拼接、流式输出、超时重试和 429 处理,附常见报错对照。