AI 应用工程入门(四):Node.js 如何调用大模型 API?
用普通人能听懂的方式解释一次 AI 调用的服务端链路、关键参数和接口防护。
学会 Prompt 之后,下一步就是把模型接进应用。一次 AI 调用听起来复杂,本质上仍然是 HTTP 请求:客户端把用户输入发给自己的后端,后端带着密钥调用模型服务,再把结果整理后返回。
题目 1:一次 AI 调用本质上是什么?
标准答案:一次 AI 调用本质上是一次服务端 HTTP 请求。请求体里通常包含模型名称、messages、temperature、最大输出长度等参数。
工程要点:不要把用户输入直接丢给模型,也不要把模型服务商的原始响应直接暴露给页面。服务端应该负责封装 Prompt、调用模型、整理结果、记录用量和处理错误。
题目 2:最小 AI 应用架构是什么?
标准答案:用户界面发请求到业务后端,业务后端调用大模型 API,大模型返回结果,后端整理后再给界面展示。
工程要点:第一条链路是 UI 输入、服务端接口、模型调用、结果返回、界面展示。能把这条链路跑通,就进入了 AI 应用工程的门口。
用 Node.js 写一个最小服务端接口,大概长这样:
import express from "express";
const app = express();
app.use(express.json());
app.post("/api/ai/title", async (req, res) => {
const article = String(req.body.article ?? "").slice(0, 8000);
const response = await fetch(
"https://example-model-provider.com/v1/chat/completions",
{
method: "POST",
headers: {
Authorization: "Bearer " + process.env.MODEL_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({
model: "example-chat-model",
temperature: 0.3,
messages: [
{
role: "system",
content: "你是中文公众号高级主编,只返回合法 JSON。",
},
{
role: "user",
content: article,
},
],
}),
}
);
if (!response.ok) {
return res.status(502).json({ error: "model_request_failed" });
}
const data = await response.json();
res.json({ result: data.choices?.[0]?.message?.content ?? "" });
});
这里有三个关键点:密钥只在服务端读取;输入先做长度限制;模型失败时返回可识别错误,而不是把底层异常直接暴露给用户。
题目 3:为什么不能直接在浏览器调用模型 API?
标准答案:因为 API Key 会泄露。只要代码进入浏览器,用户就可能看到密钥。
工程要点:API Key 应该放在服务端环境变量里。客户端只请求自己的后端,后端再调用模型。服务端还要做鉴权、限流、成本控制和敏感日志处理。
题目 4:重要参数有哪些?
标准答案:常见参数包括 model、messages、temperature、max tokens 和 stream。model 决定调用哪个模型,messages 是上下文,temperature 控制随机性,max tokens 控制输出长度,stream 决定是否流式返回。
工程要点:总结、分类、JSON 输出这类任务通常使用较低 temperature;创意写作和标题生成可以稍高。但参数不能替代清楚的任务说明,Prompt 模糊时,调参数只能缓解,不能根治。
题目 5:AI 接口要做哪些防护?
标准答案:至少要校验输入是否为空,限制输入长度,捕获模型 API 错误,设置超时,限制调用频率,不泄露密钥,不把敏感内容写进日志。
工程要点:AI 调用比普通接口更贵、更慢、更不可控。服务端必须比普通接口更谨慎。真实项目还应该记录 requestId、token 用量、响应时间和错误类型,方便后续排查与优化。
完整示例:Node.js 接模型 API 要像接一个高成本外部服务
这节课不能只给一段 fetch。一次 AI 调用在工程上至少包括:输入校验、Prompt 组装、模型请求、超时控制、错误处理、结果解析、用量记录和响应返回。模型服务比普通接口更慢、更贵、更不稳定,所以后端要更谨慎。
一个更接近真实项目的 Node.js 处理流程可以这样拆:
type TitleRequest = { article: string };
function normalizeInput(body: TitleRequest) {
const article = String(body.article ?? "").trim();
if (!article) throw new Error("empty_article");
if (article.length > 12000) return article.slice(0, 12000);
return article;
}
function buildMessages(article: string) {
return [
{ role: "system", content: "你是中文公众号高级主编,只返回合法 JSON。" },
{ role: "user", content: `文章:\n${article}` },
];
}
调用外部模型时,要加超时。否则模型服务排队或网络抖动时,你的接口会一直挂着,用户看不到结果,服务端资源也被占住。
async function callModel(messages: unknown[]) {
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), 30_000);
try {
const response = await fetch("https://example-model-provider.com/v1/chat/completions", {
method: "POST",
signal: controller.signal,
headers: {
Authorization: "Bearer " + process.env.MODEL_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({
model: "example-chat-model",
temperature: 0.2,
messages,
}),
});
if (!response.ok) throw new Error("model_request_failed");
return await response.json();
} finally {
clearTimeout(timer);
}
}
服务端返回给页面的内容也要做收敛,不要把模型服务商的完整响应透传出去。完整响应里可能有内部字段、错误细节、计费信息或你不想暴露的结构。更好的做法是只返回业务需要的字段,同时记录 requestId、耗时、模型名和 token 用量。
return res.json({
requestId,
titles: parsed.titles,
usage: { inputTokens, outputTokens },
});
这一课的完整答案是:模型 API 调用不是“一行 fetch”,而是一条可靠后端链路。密钥放服务端,输入要限制,调用要超时,输出要校验,错误要可追踪,成本要能统计。
这一篇最该带走的结论是:调用模型不是一行 fetch,而是一条受保护、可观测、可失败恢复的服务端链路。