🚀 手把手教程:10分钟搭建你的专属 AI 聊天助手 (Node.js 版)

258 阅读4分钟

想拥有一个属于自己的、类似 ChatGPT 的 AI 聊天网页吗? 本教程将带你使用最基础的 Node.jsHTML,不依赖复杂的框架(如 Vue/React 或 Express),从零开始搭建一个支持打字机流式回复的聊天应用。

适合人群:具备基础编程知识,想了解 AI 应用底层原理的开发者或爱好者。

image.png

🛠️ 第一步:环境准备与初始化

首先,确保你的电脑上已经安装了 Node.js (建议 v18 或更高版本)。

  1. 创建项目文件夹 在你的电脑上新建一个文件夹,例如 my-ai-chat,然后在终端(命令行)中进入该目录:

    mkdir my-ai-chat
    cd my-ai-chat
    
  2. 初始化项目 运行以下命令生成 package.json 配置文件:

    npm init -y
    
  3. 修改项目类型 打开生成的 package.json 文件,在里面添加一行 "type": "module", 这样我们就可以使用现代的 import 语法了。

    {
      "name": "my-ai-chat",
      "version": "1.0.0",
      "type": "module",  // <--- 添加这一行
      ...
    }
    
  4. 安装必要依赖 我们需要两个库:openai (用于连接 AI 模型) 和 dotenv (用于安全管理密钥)。

    npm install openai dotenv
    

🔑 第二步:准备 API 密钥

本项目使用 DeepSeek(深度求索)的大模型能力。

👉 指引:请前往 DeepSeek 开放平台 注册账号并创建 API Key 即可。

拿到以 sk- 开头的密钥后,在项目根目录下创建一个名为 .env 的文件,内容如下:

DEEPSEEK_API_KEY=你的密钥粘贴在这里
PORT=3000

🖥️ 第三步:编写后端 (Server)

我们将创建一个简单的 HTTP 服务器,它负责接收你的问题,转发给 DeepSeek,然后把 AI 的回答一点一点“流”回给浏览器。

创建文件夹 src,并在其中新建文件 server.js,填入以下代码:

// src/server.js
import http from "node:http";
import OpenAI from "openai";
import dotenv from "dotenv";
import { readFile } from "node:fs/promises";

// 读取 .env 中的配置
dotenv.config();

// 初始化 AI 客户端
const client = new OpenAI({
  apiKey: process.env.DEEPSEEK_API_KEY,
  baseURL: "https://api.deepseek.com/v1", // DeepSeek 的 API 地址
});

// 辅助函数:发送流式数据
function sendJson(res, type, content) {
  res.write(JSON.stringify({ type, content }) + "\n");
}

const server = http.createServer(async (req, res) => {
  const url = new URL(req.url, `http://${req.headers.host}`);

  // 1. 提供前端页面
  if (req.method === "GET" && (url.pathname === "/" || url.pathname === "/chat.html")) {
    try {
      const html = await readFile(new URL("./chat.html", import.meta.url));
      res.writeHead(200, { "Content-Type": "text/html" });
      res.end(html);
    } catch {
      res.statusCode = 404;
      res.end("Not Found");
    }
    return;
  }

  // 2. 处理聊天接口
  if (req.method === "POST" && url.pathname === "/api/chat") {
    // 读取用户发送的消息
    let body = "";
    for await (const chunk of req) body += chunk;
    const { message } = JSON.parse(body || "{}");

    // 设置响应头:告诉浏览器我们要发送流式数据
    res.writeHead(200, {
      "Content-Type": "application/json",
      "Connection": "keep-alive",
      "Cache-Control": "no-cache",
    });

    try {
      // 调用 DeepSeek API
      const stream = await client.chat.completions.create({
        model: "deepseek-chat",
        messages: [
          { role: "system", content: "你是一个有用的AI助手。" },
          { role: "user", content: message },
        ],
        stream: true, // 开启流式模式
      });

      // 实时接收 AI 的回答并转发给前端
      for await (const chunk of stream) {
        const content = chunk.choices[0]?.delta?.content || "";
        if (content) sendJson(res, "message", content);
      }
    } catch (error) {
      console.error(error);
      sendJson(res, "error", "出错了,请稍后再试");
    } finally {
      sendJson(res, "done", "[DONE]");
      res.end();
    }
    return;
  }

  res.statusCode = 404;
  res.end("Not Found");
});

const PORT = process.env.PORT || 3000;
server.listen(PORT, () => {
  console.log(`Server is running at http://localhost:${PORT}`);
});

🎨 第四步:编写前端 (UI)

现在我们需要一个漂亮的界面来聊天。在 src 文件夹下新建 chat.html

这是一个包含 HTML、CSS 和 JS 的完整单文件:

<!-- src/chat.html -->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>我的 AI 助手</title>
  <style>
    /* 简单的样式美化 */
    body { margin: 0; font-family: sans-serif; background: #f0f2f5; display: flex; justify-content: center; height: 100vh; }
    .container { width: 100%; max-width: 800px; background: white; display: flex; flex-direction: column; box-shadow: 0 0 10px rgba(0,0,0,0.1); }
    .chat-box { flex: 1; padding: 20px; overflow-y: auto; display: flex; flex-direction: column; gap: 15px; }
    .msg { max-width: 80%; padding: 10px 15px; border-radius: 10px; line-height: 1.5; word-wrap: break-word; }
    .msg.user { align-self: flex-end; background: #007bff; color: white; }
    .msg.assistant { align-self: flex-start; background: #e9ecef; color: #333; }
    .input-area { padding: 20px; border-top: 1px solid #eee; display: flex; gap: 10px; }
    textarea { flex: 1; padding: 10px; border: 1px solid #ddd; border-radius: 5px; resize: none; height: 50px; }
    button { padding: 0 20px; background: #007bff; color: white; border: none; border-radius: 5px; cursor: pointer; }
    button:disabled { background: #ccc; }
  </style>
</head>
<body>
  <div class="container">
    <div class="chat-box" id="chat">
      <div class="msg assistant">你好!我是你的 AI 助手,有什么可以帮你的吗?</div>
    </div>
    <div class="input-area">
      <textarea id="input" placeholder="输入你的问题..."></textarea>
      <button id="send">发送</button>
    </div>
  </div>

  <script>
    const chatEl = document.getElementById('chat');
    const inputEl = document.getElementById('input');
    const sendBtn = document.getElementById('send');

    // 添加消息到屏幕
    function addMsg(role, text) {
      const div = document.createElement('div');
      div.className = `msg ${role}`;
      div.textContent = text;
      chatEl.appendChild(div);
      chatEl.scrollTop = chatEl.scrollHeight;
      return div;
    }

    // 发送消息的主逻辑
    async function sendMessage() {
      const text = inputEl.value.trim();
      if (!text) return;

      // 1. 显示用户消息
      addMsg('user', text);
      inputEl.value = '';
      sendBtn.disabled = true;

      // 2. 创建 AI 回复的占位气泡
      const aiMsgEl = addMsg('assistant', '');

      try {
        // 3. 发起请求
        const res = await fetch('/api/chat', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ message: text })
        });

        // 4. 读取流式响应
        const reader = res.body.getReader();
        const decoder = new TextDecoder();
        let buffer = '';

        while (true) {
          const { value, done } = 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.trim()) continue;
            try {
              const json = JSON.parse(line);
              if (json.type === 'message') {
                // 🌟 关键:将新收到的文字追加到气泡中
                aiMsgEl.textContent += json.content;
                chatEl.scrollTop = chatEl.scrollHeight;
              }
            } catch (e) { console.error(e); }
          }
        }
      } catch (err) {
        aiMsgEl.textContent += " [请求失败]";
      } finally {
        sendBtn.disabled = false;
      }
    }

    sendBtn.addEventListener('click', sendMessage);
  </script>
</body>
</html>

🚀 第五步:启动与体验

一切就绪!现在让我们把服务跑起来。

  1. 启动服务 在终端中运行:

    node src/server.js
    

    如果你看到 Server is running at http://localhost:3000,说明启动成功了!

  2. 打开浏览器 访问 http://localhost:3000

  3. 开始聊天 在输入框输入“讲个笑话”,你会看到 AI 的回复是一个字一个字蹦出来的,这就是流式响应的魅力!


🎉 总结

恭喜你!你已经成功搭建了一个现代化的 AI 聊天应用。

在这个过程中,你学会了:

  1. 使用 Node.js 原生模块 搭建 Web 服务器。
  2. 调用 OpenAI SDK (适配 DeepSeek) 进行 AI 对话。
  3. 实现后端到前端的 流式数据传输 (Streaming)
  4. 前端如何解析流数据并实时渲染。

这正是目前市面上大多数 AI 产品(如 ChatGPT)的核心实现原理。快去向大家展示你的成果吧!