我调用 DeepSeek API 连踩 3 个坑,终于把 Node AIGC 开发的核心知识点捋顺了

昨天心血来潮想跑通 DeepSeek 的 API demo,本以为复制几行代码就能跑起来,结果从模块化报错、密钥读不到,到异步输出顺序乱套,连踩三个坑,折腾了快一小时才理顺。今天趁着热乎劲,把整个爬坑过程和吃透的知识点全记下来,纯干货无废话。

先被 ESM 模块化坑麻了

最开始我随手新建了 index.js,直接抄了官方的 import 语法引入 openai 库,信心满满敲下 node index.js,结果控制台直接甩给我一片红:

当时控制台就报不能在模块外使用 import 语法,我当场懵了。

我第一反应:代码抄错了?反复核对了好几遍,语法一点问题没有。后来翻了 Node 文档才明白,Node 默认用的是老的 CommonJS 模块化(require 语法) ,而现在的 AI SDK(比如 openai)全是基于 ES6 推出的 ESM 模块化写的,俩规范不兼容!

解决办法超简单,二选一:

  1. 文件名改成 .mjs 后缀,直接标识这是 ESM 模块
  2. package.json 里加一句 "type": "module"

我嫌改配置麻烦,直接把文件重命名为 index.mjs,一跑,报错直接消失,就这么简单。

说实话,以前总觉得模块化是个抽象概念,这次踩坑才真切感受到:ESM 就是现代 JS 的文件引入规范,是前端 / 后端一体化的标配,老的 CommonJS 慢慢要被淘汰了

密钥明文写代码?差点酿成大祸

模块化问题解决后,我图省事,直接把 API 密钥和接口地址写死在代码里:

javascript 复制代码
// 错误示范!纯纯找死行为
const client = new OpenAI({
    apiKey: "sk-5d846ef4c7de4fa089010bfd7db13852",
    baseURL: "https://api.deepseek.com/v1",
})

代码跑通的瞬间我就慌了:这要是顺手提交到 Git,密钥直接泄露,账号分分钟被盗刷!

这时候才想起 AIGC 开发的铁律:密钥绝对不能明文写在代码里,必须用环境变量管理。

于是我安装了 dotenv 库,专门读取 .env 文件里的环境变量,这里必须提一下 process 对象:我理解的 process 就是 Node 进程的专属管家 ,我们用 node index.mjs 启动程序,本质是开启了一个 Node 进程,内存、CPU、环境变量全归它管,process.env 就是存环境变量的储物柜。

dotenv 的作用就是:把 .env 文件里的键值对,一键塞进 process.env 这个储物柜里。

正确姿势(直接复制可用)

  1. 新建 .env 文件,严格按 KEY=VALUE 格式写(别加空格!)
env 复制代码
DEEPSEEK_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxxxx
DEEPSEEK_API_BASE_URL=https://api.deepseek.com/v1
  1. 安装依赖,编写代码
javascript 复制代码
// index.mjs
import dotenv from 'dotenv'
import { OpenAI } from 'openai'

// 注意这一行!坑了我10分钟,忘了写就读不到.env变量
dotenv.config() 

// 从进程的环境变量里取密钥,安全!
const client = new OpenAI({
    apiKey: process.env.DEEPSEEK_API_KEY,
    baseURL: process.env.DEEPSEEK_API_BASE_URL,
})
  1. 最后一步!新建 .gitignore 文件,把 .env 加进去,彻底杜绝密钥上传:
plaintext 复制代码
.env
node_modules/

小细节:.env 里的 key 建议全大写,这是行业约定,看着也清晰。

异步代码顺序乱套?async/await 救场

解决完密钥问题,我兴高采烈写了调用逻辑,结果输出顺序直接离谱:

plaintext 复制代码
程序开始运行
程序结束
你好!有什么可以帮你的?

先输出结束,再出 AI 回复?完全不符合预期。

原因很简单:API 请求是异步任务 ,JS 不会等它执行完,会先跑后面的同步代码。以前用回调函数嵌套能解决,但代码丑到爆炸,直到 ES8 出了 async/await

这玩意我愿称之为异步代码的救世主,说白了就是:用同步的写法,写异步的逻辑 ,加个 await 就能卡住流程,等 API 返回结果再继续执行。

最终可运行的完整 demo

javascript 复制代码
import dotenv from 'dotenv'
import { OpenAI } from 'openai'
dotenv.config()

const client = new OpenAI({
    apiKey: process.env.DEEPSEEK_API_KEY,
    baseURL: process.env.DEEPSEEK_API_BASE_URL,
})

// async 标记这是异步函数,内部可以用await
const main = async ()=> {
    console.log('程序开始运行')

    // await 等待AI接口返回结果,再执行下一行
    const response = await client.chat.completions.create({
        model: 'deepseek-chat',
        messages: [{ role: 'user', content: '你好' }]
    })

    // 输出AI的回复内容
    console.log(response.choices[0].message.content)
    console.log('程序结束')
}

// 执行入口函数
main()

运行后输出顺序完美:

plaintext 复制代码
程序开始运行
你好!有什么可以帮助你的吗?
程序结束

顺手优化了开发效率,顺便聊聊 pnpm 和 nodemon

跑通代码后,我又顺手优化了下开发流程,两个神器必须安利:

  1. pnpm 之前一直用 npm,安装依赖慢还占硬盘,pnpm 是全局缓存依赖,不同项目软链接共用,省空间还快。全局安装:npm install -g pnpm以后装依赖直接用 pnpm i,香到离谱。
  2. nodemon 改一次代码就要重启一次 node,太麻烦。全局安装 npm install -g nodemon,启动命令改成 nodemon index.mjs,文件修改自动重启进程,开发效率直接拉满。

扒了下源码,理清核心设计

其实吃透这些知识点后,我特意翻了 openai 库的源码和 Node 规范,才算彻底通透:

  1. AI 相关的 SDK 全是 ESM 规范,所以 Node 项目必须用模块化,这是硬性要求;
  2. process 是 Node 独有的全局对象,浏览器里根本没有,这也是AIGC 项目本质是后端 Node 项目的原因;
  3. async/await 不是黑魔法,就是 Promise 的语法糖,只是让异步代码可读性提升了 10 倍。

把我踩的坑,摆成错误 vs 正确对照表

表格

错误姿势 后果 正确姿势
.js 后缀 + import 语法 直接报错,无法运行 改.mjs 或 package.json 加 type:module
明文写 API 密钥 密钥泄露,账号被盗 .env + dotenv + .gitignore
不用 await 调用 AI 接口 代码执行顺序混乱 async 函数 + await 等待结果

聊到这也差不多了,其实这次折腾下来,核心就记住三件事:第一,做 AIGC/Agent 开发,全是 Node 后端项目,ESM 模块化是标配;第二,密钥安全是底线,环境变量 + 忽略文件是必须操作;第三,调用 AI 接口必用 async/await,异步逻辑别硬写回调。

这些工具和规范也不是万能的,比如写个超小的测试脚本,不用 pnpm、不用 nodemon 也完全没问题,适合自己的场景就好。

搞懂这些踩坑点的朋友,不妨留言说说你在 AI 开发中还踩过什么奇葩坑,咱们互相避坑~

相关推荐
咖啡八杯22 分钟前
GoF设计模式——策略模式
java·后端·spring·设计模式
lizhongxuan1 小时前
AI Agent 上下文压缩利器 Headroom
后端
Csvn4 小时前
SSH 远程管理与安全加固 — 运维的守门之道
后端
IT_陈寒4 小时前
Python搞不定字符串编码?这破玩意坑我两小时!
前端·人工智能·后端
菜鸟谢5 小时前
Rust 智能指针完整详解
后端
菜鸟谢5 小时前
Rust 函数完整知识点详解
后端
叁两5 小时前
前端转型AI Agent该如何学习?(前置篇)
前端·人工智能·node.js
爱勇宝5 小时前
淡泊名利之前,先承认我们都很焦虑
前端·后端·程序员
菜鸟谢6 小时前
Rust 闭包(Closure)完整详解
后端
ServBay6 小时前
如何利用本地技术栈构建 0 成本 AI SaaS 雏形
后端·aigc·ai编程