📌 内容摘要
- 使用 Anthropic 官方 Node.js SDK,支持 JavaScript 和 TypeScript,5行代码完成第一次调用。
- 覆盖7个核心场景:基础调用、System Prompt、多轮对话、流式输出、并发请求、Express 集成、错误处理。
- 所有示例提供 TypeScript 和 JavaScript 双版本,附完整注释。
- 文末附 Express 流式 API 接口完整实现,可直接用于构建聊天后端。
一、环境准备
Node.js 版本要求
Anthropic Node.js SDK 要求 Node.js 18 及以上版本(推荐 20 LTS)。
node --version # 确认版本 ≥ 18
安装 SDK
# npm npm install @anthropic-ai/sdk # pnpm pnpm add @anthropic-ai/sdk # yarn yarn add @anthropic-ai/sdk
TypeScript 项目额外配置
npm install -D typescript @types/node ts-node
# tsconfig.json 关键配置
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"moduleResolution": "node",
"esModuleInterop": true,
"strict": true
}
}
配置 API Key
# .env 文件 ANTHROPIC_API_KEY=sk-ant-api03-你的key # 安装 dotenv npm install dotenv
二、基础调用
TypeScript 版本
import Anthropic from "@anthropic-ai/sdk";
import "dotenv/config";
const client = new Anthropic();
// 默认自动读取环境变量 ANTHROPIC_API_KEY
// 也可以显式传入:new Anthropic({ apiKey: "sk-ant-..." })
async function main() {
const message = await client.messages.create({
model: "claude-sonnet-4-6",
max_tokens: 1024,
messages: [
{ role: "user", content: "你好,请用一句话自我介绍" }
],
});
// 获取回复文本
const text = message.content[0];
if (text.type === "text") {
console.log(text.text);
}
}
main();
JavaScript 版本(ESM)
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();
const message = await client.messages.create({
model: "claude-sonnet-4-6",
max_tokens: 1024,
messages: [
{ role: "user", content: "你好,请用一句话自我介绍" }
],
});
console.log(message.content[0].text);
JavaScript 版本(CommonJS)
const Anthropic = require("@anthropic-ai/sdk").default;
const client = new Anthropic();
async function main() {
const message = await client.messages.create({
model: "claude-sonnet-4-6",
max_tokens: 1024,
messages: [
{ role: "user", content: "你好,请用一句话自我介绍" }
],
});
console.log(message.content[0].text);
}
main();
响应对象说明
console.log(message.id); // 请求唯一 ID console.log(message.model); // 实际使用的模型 console.log(message.role); // 始终是 "assistant" console.log(message.content[0].text); // 回复文本 console.log(message.stop_reason); // "end_turn" | "max_tokens" console.log(message.usage.input_tokens); // 输入消耗 token 数 console.log(message.usage.output_tokens); // 输出消耗 token 数
三、System Prompt 设置
const message = await client.messages.create({
model: "claude-sonnet-4-6",
max_tokens: 2048,
system: `你是一名资深 Node.js 工程师,专注于性能优化和最佳实践。
回答规则:
- 优先给出可运行的代码示例
- 代码使用 TypeScript,加上类型注解
- 指出潜在的内存泄漏或性能问题
- 回答简洁,直接切入要点`,
messages: [
{ role: "user", content: "如何正确关闭 Node.js 应用并释放资源?" }
],
});
console.log(message.content[0].text);
四、多轮对话
Claude API 是无状态的,每次请求需传入完整对话历史:
import Anthropic from "@anthropic-ai/sdk";
type Message = { role: "user" | "assistant"; content: string };
class ChatSession {
private client: Anthropic;
private history: Message[] = [];
private system: string;
constructor(system = "") {
this.client = new Anthropic();
this.system = system;
}
async chat(userInput: string): Promise {
// 追加用户消息
this.history.push({ role: "user", content: userInput });
const response = await this.client.messages.create({
model: "claude-sonnet-4-6",
max_tokens: 2048,
system: this.system,
messages: this.history,
});
const assistantReply =
response.content[0].type === "text"
? response.content[0].text
: "";
// 追加 AI 回复
this.history.push({ role: "assistant", content: assistantReply });
return assistantReply;
}
getHistory(): Message[] {
return [...this.history];
}
clear(): void {
this.history = [];
}
}
// 使用示例
const session = new ChatSession(
"你是一个友善的助手,记住用户说过的所有信息。"
);
console.log(await session.chat("我叫小明,是一名 Node.js 开发者"));
console.log(await session.chat("我主要做什么方向的开发?"));
console.log(await session.chat("给我推荐一个适合我的开源项目"));
五、流式输出(Streaming)
基础流式输出
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();
// 方式一:stream 辅助方法(推荐)
const stream = await client.messages.stream({
model: "claude-sonnet-4-6",
max_tokens: 2048,
messages: [
{ role: "user", content: "写一篇300字关于秋天的散文" }
],
});
// 实时打印每个文字片段
for await (const chunk of stream) {
if (
chunk.type === "content_block_delta" &&
chunk.delta.type === "text_delta"
) {
process.stdout.write(chunk.delta.text);
}
}
console.log(); // 换行
// 获取完整响应统计
const finalMessage = await stream.finalMessage();
console.log(`\n输入 tokens: ${finalMessage.usage.input_tokens}`);
console.log(`输出 tokens: ${finalMessage.usage.output_tokens}`);
使用事件监听器
const stream = client.messages.stream({
model: "claude-sonnet-4-6",
max_tokens: 1024,
messages: [{ role: "user", content: "写一首短诗" }],
});
stream
.on("text", (text) => {
process.stdout.write(text);
})
.on("message", (message) => {
console.log("\n[完成]", message.stop_reason);
})
.on("error", (error) => {
console.error("流式输出错误:", error);
});
await stream.finalMessage();
六、Express 集成:构建聊天 API
这是最常见的生产场景——把 Claude 包装成 HTTP 接口供前端调用:
npm install express cors npm install -D @types/express @types/cors
import express from "express";
import cors from "cors";
import Anthropic from "@anthropic-ai/sdk";
const app = express();
const client = new Anthropic();
app.use(cors());
app.use(express.json());
type ChatMessage = { role: "user" | "assistant"; content: string };
// ── 普通接口(等待完整响应)──────────────────────
app.post("/api/chat", async (req, res) => {
const { messages, system } = req.body as {
messages: ChatMessage[];
system?: string;
};
try {
const response = await client.messages.create({
model: "claude-sonnet-4-6",
max_tokens: 2048,
system: system ?? "你是一个有帮助的 AI 助手。",
messages,
});
res.json({
content: response.content[0].type === "text"
? response.content[0].text
: "",
usage: response.usage,
});
} catch (error) {
if (error instanceof Anthropic.APIError) {
res.status(error.status).json({ error: error.message });
} else {
res.status(500).json({ error: "Internal server error" });
}
}
});
// ── 流式接口(SSE,逐字返回)────────────────────
app.post("/api/chat/stream", async (req, res) => {
const { messages, system } = req.body as {
messages: ChatMessage[];
system?: string;
};
// 设置 SSE 响应头
res.setHeader("Content-Type", "text/event-stream");
res.setHeader("Cache-Control", "no-cache");
res.setHeader("Connection", "keep-alive");
try {
const stream = client.messages.stream({
model: "claude-sonnet-4-6",
max_tokens: 2048,
system: system ?? "你是一个有帮助的 AI 助手。",
messages,
});
// 逐块发送给前端
stream.on("text", (text) => {
res.write(`data: ${JSON.stringify({ text })}\n\n`);
});
const final = await stream.finalMessage();
// 发送结束信号和用量统计
res.write(
`data: ${JSON.stringify({
done: true,
usage: final.usage,
})}\n\n`
);
res.end();
} catch (error) {
res.write(`data: ${JSON.stringify({ error: "Stream failed" })}\n\n`);
res.end();
}
});
app.listen(3000, () => {
console.log("Server running on http://localhost:3000");
});
前端调用流式接口(示例)
async function streamChat(userMessage) {
const response = await fetch("/api/chat/stream", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
messages: [{ role: "user", content: userMessage }],
}),
});
const reader = response.body.getReader();
const decoder = new TextDecoder();
let buffer = "";
while (true) {
const { done, value } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
const lines = buffer.split("\n");
buffer = lines.pop() ?? "";
for (const line of lines) {
if (line.startsWith("data: ")) {
const data = JSON.parse(line.slice(6));
if (data.text) {
// 实时追加到页面
document.getElementById("output").textContent += data.text;
}
if (data.done) {
console.log("完成,用量:", data.usage);
}
}
}
}
}
七、并发请求
import Anthropic from "@anthropic-ai/sdk"; const client = new Anthropic(); // 控制并发数量,避免触发速率限制 async function batchProcess( prompts: string[], concurrency = 5 ): Promise{ const results: string[] = new Array(prompts.length); // 分批处理 for (let i = 0; i < prompts.length; i += concurrency) { const batch = prompts.slice(i, i + concurrency); const batchResults = await Promise.all( batch.map(async (prompt, idx) => { const response = await client.messages.create({ model: "claude-haiku-4-5-20251001", // 批量任务用 Haiku 省钱 max_tokens: 512, messages: [{ role: "user", content: prompt }], }); return { index: i + idx, text: response.content[0].type === "text" ? response.content[0].text : "", }; }) ); for (const { index, text } of batchResults) { results[index] = text; } // 批次间稍作延迟,避免频率限制 if (i + concurrency < prompts.length) { await new Promise((r) => setTimeout(r, 200)); } } return results; } // 使用示例 const questions = [ "Python 和 JavaScript 的主要区别是什么?", "什么是 REST API?", "解释一下 async/await", "什么是 Docker?", "Git rebase 和 merge 的区别?", ]; const answers = await batchProcess(questions, 3); answers.forEach((a, i) => { console.log(`Q${i + 1}: ${questions[i]}`); console.log(`A: ${a.slice(0, 80)}...\n`); });
八、错误处理
import Anthropic from "@anthropic-ai/sdk"; const client = new Anthropic(); async function callWithRetry( messages: Anthropic.MessageParam[], maxRetries = 3 ): Promise{ for (let attempt = 0; attempt < maxRetries; attempt++) { try { const response = await client.messages.create({ model: "claude-sonnet-4-6", max_tokens: 1024, messages, }); return response.content[0].type === "text" ? response.content[0].text : ""; } catch (error) { if (error instanceof Anthropic.AuthenticationError) { // API Key 错误,不重试 throw new Error("API Key 无效,请检查环境变量 ANTHROPIC_API_KEY"); } if (error instanceof Anthropic.RateLimitError) { // 频率限制,指数退避后重试 const waitMs = Math.pow(2, attempt) * 1000; console.warn(`频率限制,${waitMs / 1000}秒后重试(第${attempt + 1}次)`); await new Promise((r) => setTimeout(r, waitMs)); continue; } if (error instanceof Anthropic.APIStatusError) { if (error.status === 529) { // 服务器过载 const waitMs = Math.pow(2, attempt) * 1000; console.warn(`服务过载,${waitMs / 1000}秒后重试`); await new Promise((r) => setTimeout(r, waitMs)); continue; } // 其他 API 错误 throw new Error(`API 错误 ${error.status}: ${error.message}`); } if (error instanceof Anthropic.APIConnectionError) { if (attempt < maxRetries - 1) { console.warn("网络连接失败,重试中..."); await new Promise((r) => setTimeout(r, 1000)); continue; } throw new Error("网络连接持续失败,请检查网络环境"); } throw error; } } throw new Error(`重试 ${maxRetries} 次后仍然失败`); }
常见问题
Q:ES module 还是 CommonJS?
SDK 同时支持两种模式。新项目推荐使用 ESM(import 语法),在 package.json 中设置 "type": "module"。老项目使用 CommonJS 的 require 也完全兼容。
Q:Node.js 里如何使用顶层 await?
ESM 模块(.mjs 或 package.json 设置 "type": "module")原生支持顶层 await。CommonJS 需要包在 async function main() 里再调用。
Q:流式输出和普通输出的费用一样吗?
完全一样。流式输出只是改变了内容传输方式,不影响 token 计费。输入 token 数 × 输入单价 + 输出 token 数 × 输出单价,与是否流式无关。
Q:如何在 Vercel / Cloudflare Workers 等 Edge 环境使用?
SDK 支持 Edge Runtime。在 Vercel Edge Functions 中直接 import 即可;Cloudflare Workers 需要使用 fetch-based 传输,SDK 会自动检测环境并切换。注意 Edge 环境有执行时间限制,流式输出比等待完整响应更适合这类场景。
总结
Node.js 调用 Claude API 的核心是掌握三个场景:普通请求、流式输出、多轮对话——本文的代码示例都可以直接复制运行。实际项目中最常用的是 Express + 流式 SSE 接口这个组合,把它封装好之后,前端无论是 React 还是 Vue 都能很方便地接入。生产环境一定加上错误处理和重试机制,避免因临时网络问题导致服务中断。