从零搭建生成式AI项目:OpenAI + Node.js 环境配置与密钥安全实践

从零搭建生成式AI项目:OpenAI + Node.js 环境配置与密钥安全实践 🚀

一份完整的学习笔记,带你绕过那些"坑"

最近我在准备英伟达生成式AI证书 ,课程中需要实际调用OpenAI API完成几个实验。本以为就是npm install openai然后写几行代码的事,结果发现:API Key管理、依赖安装方式、Git忽略规则 ......每一个环节都有讲究。踩了几个坑之后,我把整个过程整理成这篇笔记,希望能帮你少走弯路,顺便理解背后的原理


📌 目录

  1. [背景:英伟达证书与Generative AI](#背景:英伟达证书与Generative AI "#1-%E8%83%8C%E6%99%AF%E8%8B%B1%E4%BC%9F%E8%BE%BE%E8%AF%81%E4%B9%A6%E4%B8%8Egenerative-ai")
  2. [第一步:API Key 的安全存储 ------ 别把它写死在代码里](#第一步:API Key 的安全存储 —— 别把它写死在代码里 "#2-%E7%AC%AC%E4%B8%80%E6%AD%A5api-key-%E7%9A%84%E5%AE%89%E5%85%A8%E5%AD%98%E5%82%A8--%E5%88%AB%E6%8A%8A%E5%AE%83%E5%86%99%E6%AD%BB%E5%9C%A8%E4%BB%A3%E7%A0%81%E9%87%8C")
  3. [第二步:初始化Node.js项目 ------ npm init -y 背后发生了什么](#第二步:初始化Node.js项目 —— npm init -y 背后发生了什么 "#3-%E7%AC%AC%E4%BA%8C%E6%AD%A5%E5%88%9D%E5%A7%8B%E5%8C%96nodejs%E9%A1%B9%E7%9B%AE--npm-init--y-%E8%83%8C%E5%90%8E%E5%8F%91%E7%94%9F%E4%BA%86%E4%BB%80%E4%B9%88")
  4. [第三步:安装OpenAI模块 ------ 为什么它是"事实标准"?](#第三步:安装OpenAI模块 —— 为什么它是“事实标准”? "#4-%E7%AC%AC%E4%B8%89%E6%AD%A5%E5%AE%89%E8%A3%85openai%E6%A8%A1%E5%9D%97--%E4%B8%BA%E4%BB%80%E4%B9%88%E5%AE%83%E6%98%AF%E4%BA%8B%E5%AE%9E%E6%A0%87%E5%87%86")
  5. [第四步:选择包管理器 ------ npm vs pnpm 深度对比](#第四步:选择包管理器 —— npm vs pnpm 深度对比 "#5-%E7%AC%AC%E5%9B%9B%E6%AD%A5%E9%80%89%E6%8B%A9%E5%8C%85%E7%AE%A1%E7%90%86%E5%99%A8--npm-vs-pnpm-%E6%B7%B1%E5%BA%A6%E5%AF%B9%E6%AF%94")
  6. [第五步:.gitignore的最佳实践 ------ 不只是忽略.env](#第五步:.gitignore的最佳实践 —— 不只是忽略.env "#5-%E7%AC%AC%E4%BA%94%E6%AD%A5gitignore%E7%9A%84%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5--%E4%B8%8D%E5%8F%AA%E6%98%AF%E5%BF%BD%E7%95%A5env")
  7. 完整代码示例:第一个生成式AI调用
  8. 总结与扩展建议

1. 背景:英伟达证书与Generative AI

英伟达(NVIDIA)推出的 Generative AI 证书 (全称可能是 NVIDIA DLI Certificate in Generative AI )是当下热门的技能认证。课程涵盖:大语言模型原理、Prompt Engineering、RAG(检索增强生成)、以及如何通过API调用模型

实践环节通常要求你用Python或Node.js调用OpenAI、Cohere或NVIDIA NeMo服务。我选择了Node.js,因为前端/全栈开发者更熟悉,而且OpenAI官方提供了高质量的Node SDK。

📝 笔记:课程本身不限制语言,但官方示例多为Python。Node.js生态同样成熟,openai npm包月下载量超过300万,值得信赖。


2. 第一步:API Key 的安全存储 ------ 别把它写死在代码里

2.1 血的教训:Key泄露的后果

OpenAI的API Key就像你的银行卡密码。如果你把Key直接写在代码里:

javascript 复制代码
// ❌ 绝对不要这么做!
const apiKey = "sk-abc123xyz789";

然后提交到GitHub(即使是私有仓库),攻击者可以通过爬虫扫描公开仓库、甚至利用GitHub的搜索功能找到Key。一旦泄露:

  • 别人可以用你的Key调用GPT-4,花光你的额度
  • OpenAI会封禁你的账号
  • 你可能还需要承担异常账单(某些案例中高达数千美元)

2.2 正确的做法:环境变量 + .env文件

标准流程:

  1. 在项目根目录创建.env文件(不要提交到Git

  2. 内容格式:

    ini 复制代码
    OPENAI_API_KEY=sk-你的真实Key
  3. 在代码中通过process.env.OPENAI_API_KEY读取

Node.js中加载.env需要dotenv

bash 复制代码
pnpm add dotenv

然后在入口文件最顶部引入:

javascript 复制代码
import 'dotenv/config';
// 或者 require('dotenv').config();

📝 笔记:如果你使用的是ES Module("type": "module"),记得用import 'dotenv/config'这种写法。CommonJS则用require('dotenv').config()

2.3 为什么不用其他方法?

方法 安全性 便捷性 推荐度
硬编码 ❌ 极差 方便一时 🚫 禁止
系统环境变量(export ⚠️ 一般(会留在shell历史) 麻烦 ⚠️ 仅测试用
.env + .gitignore ✅ 好 ✅ 方便 强烈推荐
密钥管理服务(如AWS Secrets Manager) ✅✅ 最好 配置复杂 🔧 生产环境可选

对于本地开发和学习项目,.env方案已经足够安全。


3. 第二步:初始化Node.js项目 ------ npm init -y 背后发生了什么

3.1 快速初始化

bash 复制代码
mkdir my-ai-project
cd my-ai-project
npm init -y

-y参数表示"yes",跳过所有问答,使用默认值生成package.json

3.2 生成的package.json长什么样?

json 复制代码
{
  "name": "my-ai-project",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

3.3 需要手动调整的两个关键字段

"type": "module"

如果你打算使用import/export语法(现代Node推荐),在package.json中加入:

json 复制代码
"type": "module",

否则,默认是CommonJS(require/module.exports)。

"scripts" 添加启动命令

json 复制代码
"scripts": {
  "start": "node index.js",
  "dev": "node --watch index.js"
}

📝 笔记:node --watch是Node.js 18+的实验性功能,文件变动自动重启,类似nodemon


4. 第三步:安装OpenAI模块 ------ 为什么它是"事实标准"?

4.1 安装命令

bash 复制代码
npm install openai

或者用pnpm(下节详谈):

bash 复制代码
pnpm add openai

4.2 OpenAI npm包的演进

  • v3及以前 :基于axios,使用CommonJS,调用方式较原始。
  • v4(当前主要版本):完全重写,支持ES Module、TypeScript原生类型、流式响应、函数调用(function calling)等。

v4调用示例:

javascript 复制代码
import OpenAI from 'openai';

const openai = new OpenAI({
  apiKey: process.env.OPENAI_API_KEY,
});

const completion = await openai.chat.completions.create({
  model: 'gpt-3.5-turbo',
  messages: [{ role: 'user', content: 'Hello!' }],
});

4.3 为什么它是"事实标准"?

  • 官方维护:由OpenAI直接发布,API更新最及时。
  • 完整类型定义:如果你用TypeScript,所有请求/响应都有类型提示。
  • 支持流式输出:SSE(Server-Sent Events),实现ChatGPT式的逐字显示。
  • 自动重试与超时:内置合理的错误处理策略。

4.4 安装耗时分析

为什么npm install openai有时需要30秒甚至更久

  • 该包依赖form-datanode-fetchweb-streams-polyfill等,依赖树大小约15个包
  • 加上npm的扁平化安装算法,需要计算去重。
  • 如果是第一次安装,还要从registry下载所有文件。

解决方法:使用pnpm(见下节)或配置npm镜像源。


5. 第四步:选择包管理器 ------ npm vs pnpm 深度对比

5.1 pnpm的核心理念

节省磁盘空间,提升安装速度,严格依赖隔离

pnpm使用全局内容寻址存储 (global store) + 硬链接 (hard links) + 符号链接(symlinks)。

  • 每个依赖包只下载一次,存在~/.pnpm-store中。
  • 不同项目的node_modules通过硬链接指向store中的同一份文件。
  • 依赖的间接依赖不会"幽灵式"提升到顶层,从而避免非法访问未声明的包。

5.2 性能对比实测(模拟数据)

操作 npm pnpm
首次安装 openai 12.3s 11.8s(相差不大)
第二次安装(不同项目) 12.3s(重复下载) 0.8s(链接store)
磁盘占用(10个项目) ~1.2GB ~120MB(store)+ 少量链接
安装express(有缓存) 2.1s 0.5s

5.3 安装pnpm

bash 复制代码
npm install -g pnpm

或者用更安全的方式(Homebrew / winget):

bash 复制代码
# macOS
brew install pnpm

# Windows (winget)
winget install pnpm

5.4 常用pnpm命令对照表

功能 npm pnpm
安装所有依赖 npm install pnpm install
添加依赖 npm install <pkg> pnpm add <pkg>
全局安装 npm install -g <pkg> pnpm add -g <pkg>
运行脚本 npm run start pnpm start
移除依赖 npm uninstall <pkg> pnpm remove <pkg>

5.5 团队协作建议

如果团队使用pnpm,可以在package.json中添加:

json 复制代码
"scripts": {
  "preinstall": "npx only-allow pnpm"
}

这样使用npm install会报错,强制统一使用pnpm。

📝 笔记:npx only-allow pnpm会检测当前包管理器,不是pnpm就退出并报错。


6. 第五步:.gitignore的最佳实践 ------ 不只是忽略.env

6.1 基础.gitignore模板

创建一个.gitignore文件,内容如下:

gitignore 复制代码
# 环境变量
.env
.env.local
.env.*.local

# 依赖目录
node_modules/
.pnpm-store/

# 构建输出
dist/
build/
.vercel/

# 日志
*.log
npm-debug.log*
pnpm-debug.log*

# 操作系统
.DS_Store
Thumbs.db

# IDE
.vscode/
.idea/
*.swp

# 缓存
.cache/
.parcel-cache/

6.2 为什么node_modules/必须忽略?

  • 文件数量巨大(动辄几万个文件),提交到Git会极其臃肿。
  • 可以通过package.json + lock文件(package-lock.jsonpnpm-lock.yaml)精确复现依赖。
  • 不同操作系统可能存在原生模块的差异,提交node_modules反而不便于跨平台。

6.3 检查是否误提交了敏感文件

方法一: git status 查看暂存区

方法二: 使用git-secrets等工具 pre-commit 钩子

bash 复制代码
# 安装 git-secrets (macOS)
brew install git-secrets

# 扫描历史
git secrets --scan-history

6.4 已经提交过Key怎么办?

  1. 立即在OpenAI平台撤销该Key,生成新的Key。
  2. 使用git filter-branchBFG Repo-Cleaner清除历史。
  3. 强制推送(git push --force)------ 注意团队协作时要沟通。

7. 完整代码示例:第一个生成式AI调用

现在我们把所有知识点串联起来,写一个完整的index.js

7.1 项目结构

bash 复制代码
my-ai-project/
├── .env                 # 存放 OPENAI_API_KEY
├── .gitignore
├── package.json
├── pnpm-lock.yaml
└── index.js

7.2 代码实现

javascript 复制代码
// 加载环境变量(必须放在最顶部)
import 'dotenv/config';
import OpenAI from 'openai';

// 初始化客户端
const openai = new OpenAI({
  apiKey: process.env.OPENAI_API_KEY,
});

// 定义一个简单的对话函数
async function askGPT(prompt) {
  try {
    const completion = await openai.chat.completions.create({
      model: 'gpt-3.5-turbo', // 或者 'gpt-4'
      messages: [
        { role: 'system', content: 'You are a helpful assistant.' },
        { role: 'user', content: prompt },
      ],
      temperature: 0.7,       // 控制随机性(0~2,越高越发散)
      max_tokens: 500,
    });

    const reply = completion.choices[0].message.content;
    console.log('🤖 Assistant:', reply);
    return reply;
  } catch (error) {
    console.error('❌ Error:', error.message);
    if (error.response) {
      console.error('Status:', error.response.status);
      console.error('Details:', error.response.data);
    }
  }
}

// 执行
const userPrompt = process.argv[2] || 'Explain the concept of generative AI in one sentence.';
console.log('🧑 User:', userPrompt);
await askGPT(userPrompt);

7.3 运行

bash 复制代码
# 确保 .env 文件配置正确
pnpm start "What is the difference between npm and pnpm?"

7.4 进阶:流式输出

javascript 复制代码
async function askGPTStream(prompt) {
  const stream = await openai.chat.completions.create({
    model: 'gpt-3.5-turbo',
    messages: [{ role: 'user', content: prompt }],
    stream: true, // 开启流式
  });

  process.stdout.write('🤖 Assistant: ');
  for await (const chunk of stream) {
    const content = chunk.choices[0]?.delta?.content || '';
    process.stdout.write(content);
  }
  console.log(); // 换行
}

📝 笔记:流式输出是生成式AI体验的核心,能显著降低首字延迟。


8. 总结与扩展建议

8.1 核心知识点回顾

知识点 关键结论
API Key安全 永远使用.env + .gitignore,不要硬编码
项目初始化 npm init -y + 手动设置"type": "module"
OpenAI SDK 官方包是事实标准,v4支持ESM和TypeScript
包管理器 pnpm 节省空间且更快,推荐用于多项目环境
Git忽略 除了.env,还需忽略node_modules、日志、IDE配置

8.2 接下来你可以做什么?

  1. 部署到云函数:将上述代码包装成API端点(例如使用Vercel Functions或AWS Lambda)。
  2. 接入RAG :用langchainpinecone实现基于私有文档的问答。
  3. 添加缓存:使用Redis缓存相同的提问,节省Token费用。
  4. 申请英伟达证书:完成课程实验后,参加考试拿到认证。

8.3 最后的叮嘱

  • 不要图省事把Key写在代码里 ------ 我亲眼见过朋友因此被刷掉$200。
  • 使用pnpm时,记得提交pnpm-lock.yaml,它能锁定依赖版本,保证团队环境一致。
  • 如果遇到网络问题(比如OpenAI API被墙),考虑使用代理或国内中转服务。

希望这份笔记能帮助你顺利通过英伟达证书实验,并且在生成式AI的道路上走得更稳。如果你有任何问题,欢迎在评论区留言交流!

Happy Coding! 🎉


本文首发于稀土掘金。转载需注明出处。

相关推荐
柒和远方40 分钟前
每日一学V012: 从 Python 到 Node.js:一个 AI Native 开发者的 JavaScript 调用 LLM 实战
javascript·node.js·api
lichenyang4531 小时前
鸿蒙实战:聊天记录持久化 · 历史会话页面 · 两个真实 Bug 的定位与修复
前端
STDD1 小时前
Farming Simulator 25(模拟农场 25) Linux 专服搭建完全指南
linux·运维·javascript
天蓝色的鱼鱼1 小时前
前端也能写 AI Agent?用 Vercel AI SDK 十分钟跑通你的第一个智能助手
前端·ai编程
DevUI团队1 小时前
接口即代码:一个Skill轻松搞定类型定义、接口调用、Mock与调试
前端·agent·ai编程
DevUI团队1 小时前
从截图到企业级前端页面:2个Skill,1次对话,10X效率开发符合设计/编码规范的页面
前端·agent·ai编程
xiaofeichaichai1 小时前
网络与跨域
前端·网络
七牛云行业应用1 小时前
别每次重复配置了!CLAUDE.md + Hooks 让 Claude Code 开箱就记住你的规则
前端