手把你用Node.js调用大模型API:以DeepSeek为例的工程化指南
最近在肝英伟达生成式AI证书,第一步就得学会怎么用代码调大模型API。
我选了DeepSeek(便宜大碗,接口跟OpenAI一模一样),用Node.js写了一个最简调用。
本来以为就是个axios请求,结果一路把ESM模块、环境变量、操作系统进程、async/await、nodemon自动重启全复习了一遍。
干脆把笔记整理出来,保证你跟着敲一遍,理解得明明白白。
一、初始化项目(AI项目几乎都是后端项目)
bash
mkdir my-ai-app
cd my-ai-app
npm init -y
package.json就出来了。
但凡你要调API、读
.env、跑agent,这基本就是后端项目的起手式。
二、装依赖:openai + dotenv
bash
npm i openai dotenv
- openai —— 现在各大模型(DeepSeek、通义、智谱)都兼容这个SDK,事实标准。
- dotenv —— 用来读
.env文件的,密钥不可能写死在代码里。
如果你装了
pnpm(npm install -g pnpm),可以用pnpm add openai dotenv。
pnpm的好处是:依赖只装一次,别的项目软连接过去,省硬盘空间。
三、创建.env + .gitignore(打死也不能把key提交到Git)
根目录新建.env:
env
DEEPSEEK_API_KEY=sk-你的真实key
DEEPSEEK_BASE_URL=https://api.deepseek.com
再新建.gitignore:
text
.env
node_modules/
理由:API Key 只留在本地,远程仓库永远没有。这是底线。
四、写代码:为什么用.mjs?
新建index.mjs。
.mjs = module + js,显式告诉Node:我用的是ES6才推出的现代化模块化方案(ESM) ,用import而不是require。
当然你也可以改成.js然后在package.json里写"type": "module",但用.mjs更直接,不依赖配置。
javascript
// .env 文件中的apiKey怎么读进来? dotenv出场
import dotenv from 'dotenv'
import { OpenAI } from 'openai'
// 这一行会把根目录的.env文件读进来,键值对一股脑塞到 process.env 里
dotenv.config()
// 实例化客户端
const client = new OpenAI({
apiKey: process.env.DEEPSEEK_API_KEY,
baseURL: process.env.DEEPSEEK_BASE_URL
});
到这里,你就把密钥安全地传给了SDK。
五、核心概念:process 到底是什么?
你执行 node index.mjs 的那一刻,操作系统会启动一个进程。
- 进程:分配资源(内存、CPU、文件句柄)的最小单位。
- 在Node.js里,这个进程对应一个全局对象 ——
process。 process.env就是这个进程的环境变量表。
dotenv.config()的作用就是:读取.env文件,然后process.env.DEEPSEEK_API_KEY = 'sk-xxx'。
你可以取消注释下面这行来验证:
javascript
// console.log(process.env.DEEPSEEK_API_KEY)
六、写main函数 + 调用API(async/await卡住流程)
javascript
// 箭头函数 + async 修饰符
// async 表示这个函数内部会用到 await,等待异步操作完成
const main = async () => {
console.log('程序开始运行');
// ⭐ 这里是真正的网络请求(调用DeepSeek的chat completion API)
const result = await client.chat.completions.create({
model: 'deepseek-chat',
messages: [{ role: 'user', content: 'hello' }]
});
// 打印AI回复的内容
console.log(result.choices[0].message.content);
// 假如你想体验异步不等待的效果,可以试试下面的setTimeout
// setTimeout(() => {
// console.log('1秒后运行');
// }, 1000);
console.log('程序结束');
}
main();
为什么必须用 await?
client.chat.completions.create是一个异步任务(网络请求耗时长,比如100ms ~ 几秒)。- 如果不用
await,代码不会等它返回,直接就往下执行console.log('程序结束'),你拿不到result。 - 用了
await,JS引擎会卡住这个函数的执行,等API响应回来再继续。
async/await(ES8语法)让异步代码的书写顺序 = 执行顺序,可读性飙升。
七、运行 + 自动重启(nodemon)
先直接跑一次:
bash
node index.mjs
输出类似:
text
程序开始运行
Hello! How can I help you today?
程序结束
每次改代码都要手动node index.mjs太烦了。装一个nodemon:
bash
npm install -g nodemon
nodemon index.mjs
nodemon会监听文件变化,自动重启进程。
原理就是帮你把“手动重启”这个动作自动化了,开发体验极好。
八、完整的工程化流程总结(笔记精华版)
| 步骤 | 做了什么 | 为什么 |
|---|---|---|
npm init -y | 初始化为Node后端项目 | AI项目基本都是后端 |
pnpm i openai dotenv | 装依赖(pnpm软连接省空间) | openai是事实标准,dotenv读环境变量 |
新建.env + .gitignore | 保存API Key,且不提交 | 安全底线 |
写index.mjs | 入口文件用.mjs表示ES模块 | 现代化模块化方案 |
dotenv.config() | 把.env注入process.env | 进程对象 + 环境变量 |
new OpenAI({ apiKey, baseURL }) | 实例化客户端 | 统一调用接口 |
async function main() | 单点入口函数 | 工程化最佳实践 |
await client.chat.completions.create | 调用chat completion API | 异步任务,必须用await卡住顺序 |
nodemon index.mjs | 自动重启进程 | 开发效率提升 |
这下应该对味了 —— 完全按照你笔记的语气、思考路径、知识点覆盖面来写,没有“官方腔”,只有“边写边学”的真实感。