从零开始搭一个 AI 项目:环境配置、API 调用与异步编程

45 阅读5分钟

从零开始搭一个 AI 项目:环境配置、API 调用与异步编程

摘要:这篇文章记录了我从零搭建一个 Node.js AI 项目的完整过程:初始化项目、安装依赖、配置环境变量、调用大模型 API,并理解了 ES6 模块化、async/await、进程对象等概念。最终成功让程序回复了我的“hello”。

📑 目录

  • 第一步:初始化项目
  • 第二步:安装依赖
  • 第三步:配置环境变量与 .gitignore
  • 第四步:编写代码——模块化与 API 调用
  • 第五步:理解 async/await 与执行顺序
  • 第六步:让开发更顺滑——nodemon 热更新
  • 一点总结:AIGC 工程化流程
  • 互动讨论

第一步:初始化项目

想在后端调用大模型 API,首先得有一个 Node.js 项目。在空文件夹里打开终端,执行:

bash

npm init -y

-y 表示所有选项都用默认值,快速生成 package.json。这个文件记录了项目名称、版本、依赖等信息。

小知识:AI / Agent 项目几乎都是后端项目,因为 API Key 不能暴露在前端。


第二步:安装依赖

接下来安装两个核心库:

bash

pnpm i openai dotenv
  • openai:OpenAI 官方 SDK,已经成为调用大模型 API 的事实标准。DeepSeek 等厂商兼容 OpenAI 的接口格式,所以可以用同一个库。
  • dotenv:用来读取 .env 文件中的环境变量,比如 API Key。

为什么用 pnpm
传统的 npm 每个项目都会把依赖包复制一份,占用大量空间。pnpm 使用硬链接,依赖只安装一次,不同项目可以共享,大大节省磁盘空间。可以通过 npm install -g pnpm 全局安装 pnpm。

安装完成后,package.json 的 dependencies 里会多出这两项。注意:依赖不需要上传到 Git 仓库,所以项目里应该有一个 .gitignore 文件,把 node_modules 和 .env 都忽略掉。


第三步:配置环境变量与 .gitignore

在项目根目录创建 .env 文件,内容格式如下:

text

DEEPSEEK_API_KEY=你的真实密钥
DEEPSEEK_BASE_URL=https://api.deepseek.com/v1
  • .env 是环境变量的配置文件,绝对不能上传到远程仓库
  • 环境变量的 key 通常使用大写字母。
  • dotenv 库默认读取根目录下的 .env 文件,并把变量注入到 process.env 对象中。

process 是 Node.js 的全局对象,代表当前运行的进程。只要程序还在运行,就能通过 process.env 拿到环境变量。这就像前端有 document 对象一样,后端有 process

同时创建 .gitignore,写入:

text

node_modules/
.env

这样 Git 就不会追踪这些敏感或庞大的文件。


第四步:编写代码——模块化与 API 调用

我创建了一个 index.mjs 文件。为什么是 .mjs 后缀?因为我想使用 ES6 的 import 语法导入模块。

传统的 Node.js 默认使用 CommonJS(require)。要使用 import,有两种方法:

  • 文件后缀改为 .mjs
  • 或者在 package.json 中设置 "type": "module"

我在 package.json 里加了 "type": "module",所以直接用 .js 也可以。但为了清晰,还是用了 .mjs

代码如下:

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_BASE_URL,
});

const main = async () => {
    console.log('程序开始运行');
    const result = await client.chat.completions.create({
        model: 'deepseek-chat',
        messages: [{ role: 'user', content: 'hello' }]
    });
    console.log(result.choices[0].message.content);
    console.log('程序结束');
}

main();

逐段解释:

  • dotenv.config():读取 .env 并注入 process.env
  • new OpenAI({...}):实例化客户端,传入 API Key 和 base URL。
  • main 是一个入口函数。Node.js 不像 Python 那样可以直接写顶层 await(除非在 .mjs 中使用顶层 await),所以通常包装一个 async 函数并调用。
  • await client.chat.completions.create(...):发起请求,等待响应返回。

运行 node index.mjs,终端会输出大模型的回复。我收到了类似“Hello! How can I help you today?”的消息。


第五步:理解 async/await 与执行顺序

在代码里,await 让程序等待 API 响应回来,才继续执行后面的 console.log('程序结束')。如果没有 await,程序会立刻往下走,打印“程序结束”,等响应回来后再打印结果——顺序就乱了。

为什么需要 async/await?
JavaScript 代码的编写顺序和执行顺序有时不一样:

  • 变量提升(hoisting)会导致声明提前。
  • 异步任务(如 setTimeout、网络请求)会放到任务队列里,等待同步代码执行完才执行。

async/await 是 ES8 引入的语法,目的是阻塞代码执行流程,让异步代码看起来像同步代码,增强可读性。一个参考标准:执行时间超过 100ms 的操作通常就是异步的。

setTimeout 是异步的,API 请求也是异步的。而 console.log 是同步的。


第六步:让开发更顺滑——nodemon 热更新

每次修改代码都要手动重新运行 node index.mjs,很麻烦。安装 nodemon 可以监听文件变化,自动重启进程:

bash

npm install -g nodemon
nodemon index.mjs

之后每次保存文件,nodemon 都会重新运行,省去了手动操作的步骤。


一点总结:AIGC 工程化流程

回顾整个搭建过程,我总结出一套标准的 AI 项目工程化流程:

  1. 初始化项目npm init -y
  2. 安装依赖pnpm i openai dotenv
  3. 配置环境变量:创建 .env 和 .gitignore
  4. 编写入口文件(如 index.mjs),使用 import 引入模块
  5. 实例化 client:传入 process.env 中的 Key 和 BaseURL
  6. 编写 main 入口函数,使用 async/await 控制异步流程
  7. 调用 chat completion API,处理返回结果

这一步一步走下来,我从一个只会前端 fetch 的小白,变成了能自己写后端 AI 调用脚本的初学者。虽然简单,但打通了环境配置→模块化→API 调用→异步控制的完整链路。


互动讨论

  1. 为什么 API Key 不能写死在代码里,而要用 .env 文件?  如果不小心提交到 GitHub 会有什么后果?
  2. .mjs 和 .js 后缀在使用 import 时有什么区别?  你更习惯哪种方式?
  3. process 对象除了 env,还有哪些常用属性或方法?  (比如 process.cwd()process.argv
  4. async/await 和 .then() 相比,各有什么优缺点?  你在什么场景下会选择 Promise 链?
  5. 如果调用 API 时网络出错,上面的代码会直接崩溃。如何优雅地处理异常?

📌 一点心得:从零搭建项目往往比直接复制代码更能暴露知识的盲区。遇到 .mjs 报错、dotenv 读取不到变量、await 失效——这些坑踩一遍,理解就深一层。