新手友好!50 行代码封装 DeepSeek API,快速搭建 AI 对话网页

本文适合:刚接触 AI API、想做一个自己的 AI 聊天网页、但又不想一上来就被框架和工程配置劝退的新手。

最近很多同学都想给自己的个人网站、课程作业或者小工具接入 AI 对话功能。其实最小闭环并不复杂:前端输入一句话,后端转发给 DeepSeek API,拿到回复后再返回给前端展示。

我做了一个开源项目 JXL-AI,用原生 Node.js + 原生 HTML/CSS/JS 搭了一个 AI 对话网页,同时保留了图鉴上传、排行榜、小游戏等扩展功能。

项目地址:

https://github.com/Tuoxie423/jxl-ai

在线体验:

https://tuoxie.asia/

如果你觉得项目对新手有帮助,欢迎点一个 Star 支持一下。


一、最终效果

项目里有几个页面:

  • 首页:角色展示、小游戏、排行榜、证书生成
  • 聊天页:调用 DeepSeek API 和角色对话
  • 图鉴页:上传图片并展示
  • 开场动画页:角色入场动画

README 里放了截图和 GIF,clone 后可以直接运行:

npm install
npm start

浏览器访问:

http://127.0.0.1:5177

二、为什么不用复杂框架?

很多 AI Web 教程一上来就是:

  • Next.js
  • LangChain
  • 向量数据库
  • 登录系统
  • 云函数部署

这些当然都很强,但对新手来说有点重。

这篇文章只讲最小闭环:

浏览器输入消息
    ↓
fetch 请求自己的 Node 后端
    ↓
Node 后端调用 DeepSeek API
    ↓
DeepSeek 返回 AI 回复
    ↓
后端把 reply 返回给浏览器
    ↓
页面展示回复

只要理解这个流程,你再去学复杂框架就会轻松很多。


三、准备工作

你需要:

  • Node.js 22.5+,推荐 Node.js 24+
  • 一个 DeepSeek API Key
  • 一个普通编辑器

安装依赖:

npm install openai

配置环境变量,不要把 Key 写死到代码里:

export DEEPSEEK_API_KEY="你的 DeepSeek API Key"

Windows PowerShell:

$env:DEEPSEEK_API_KEY="你的 DeepSeek API Key"

四、50 行核心代码:封装 DeepSeek 聊天接口

下面是最小可运行版本,保存为 server.mjs

import { createServer } from "node:http";
import { readFileSync, existsSync, createReadStream } from "node:fs";
import path from "node:path";
import OpenAI from "openai";

const port = 5177;
const publicDir = path.resolve("public");

const client = new OpenAI({
  baseURL: "https://api.deepseek.com",
  apiKey: process.env.DEEPSEEK_API_KEY
});

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

  if (req.method === "POST" && url.pathname === "/api/chat") {
    const body = await readBody(req);
    const input = JSON.parse(body || "{}");
    const message = String(input.message || "").trim();

    if (!message) {
      sendJson(res, 400, { error: "message_required" });
      return;
    }

    const completion = await client.chat.completions.create({
      model: "deepseek-chat",
      messages: [
        { role: "system", content: "你是一个友好的中文 AI 助手。" },
        { role: "user", content: message }
      ]
    });

    const reply = completion.choices?.[0]?.message?.content || "我刚刚走神了。";
    sendJson(res, 200, { reply });
    return;
  }

  const file = url.pathname === "/" ? "index.html" : url.pathname.slice(1);
  const filePath = path.join(publicDir, file);
  if (!existsSync(filePath)) {
    res.writeHead(404);
    res.end("Not found");
    return;
  }
  createReadStream(filePath).pipe(res);
});

server.listen(port, () => {
  console.log(`http://127.0.0.1:${port}`);
});

function readBody(req) {
  return new Promise(resolve => {
    const chunks = [];
    req.on("data", chunk => chunks.push(chunk));
    req.on("end", () => resolve(Buffer.concat(chunks).toString("utf8")));
  });
}

function sendJson(res, status, data) {
  const body = JSON.stringify(data);
  res.writeHead(status, { "Content-Type": "application/json; charset=utf-8" });
  res.end(body);
}

上面代码做了三件事:

  1. 创建一个 Node HTTP 服务
  2. 暴露 /api/chat 接口
  3. 收到用户消息后调用 DeepSeek API,再把回复返回给前端

五、前端页面:输入消息并展示回复

新建 public/index.html

<!doctype html>
<html lang="zh-CN">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>DeepSeek AI 聊天 Demo</title>
  <style>
    body {
      margin: 0;
      min-height: 100vh;
      display: grid;
      place-items: center;
      font-family: system-ui, "Microsoft YaHei", sans-serif;
      background: #f6efe1;
    }
    main {
      width: min(720px, calc(100vw - 32px));
      padding: 24px;
      border: 2px solid #222;
      border-radius: 12px;
      background: #fffaf0;
      box-shadow: 10px 10px 0 rgba(0,0,0,.12);
    }
    #messages {
      min-height: 320px;
      display: grid;
      gap: 12px;
      align-content: start;
      margin-bottom: 16px;
    }
    .msg {
      padding: 12px 14px;
      border: 2px solid #222;
      border-radius: 10px;
      background: white;
    }
    .user { background: #f3d886; justify-self: end; }
    form { display: flex; gap: 10px; }
    input { flex: 1; padding: 12px; border: 2px solid #222; border-radius: 8px; }
    button { padding: 0 18px; border: 2px solid #222; border-radius: 8px; background: #222; color: white; }
  </style>
</head>
<body>
  <main>
    <h1>DeepSeek AI 聊天 Demo</h1>
    <div id="messages"></div>
    <form id="form">
      <input id="input" placeholder="输入一句话试试">
      <button>发送</button>
    </form>
  </main>

  <script>
    const form = document.getElementById("form");
    const input = document.getElementById("input");
    const messages = document.getElementById("messages");

    function addMessage(text, type) {
      const div = document.createElement("div");
      div.className = `msg ${type}`;
      div.textContent = text;
      messages.appendChild(div);
    }

    form.addEventListener("submit", async event => {
      event.preventDefault();
      const text = input.value.trim();
      if (!text) return;

      addMessage(text, "user");
      input.value = "";
      addMessage("思考中...", "bot");

      const last = messages.lastElementChild;
      try {
        const res = await fetch("/api/chat", {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ message: text })
        });
        const data = await res.json();
        last.textContent = data.reply || "没有拿到回复";
      } catch {
        last.textContent = "请求失败,请检查后端服务。";
      }
    });
  </script>
</body>
</html>

运行:

node server.mjs

打开:

http://127.0.0.1:5177

到这里,一个最小 AI 对话网页就跑起来了。


六、调用原理讲清楚

很多新手会卡在“API 到底是怎么调的”。其实可以把它理解成一次普通的 HTTP 请求。

1. 前端不能直接放 API Key

错误做法:

fetch("https://api.deepseek.com/...", {
  headers: {
    Authorization: "Bearer 你的 Key"
  }
});

这样 Key 会暴露在浏览器里,任何人打开开发者工具都能看到。

正确做法:

浏览器 → 你的 Node 后端 → DeepSeek API

API Key 只放在后端环境变量中。

2. messages 是什么?

DeepSeek/OpenAI 兼容接口使用 messages 数组表示对话上下文:

messages: [
  { role: "system", content: "你是一个友好的中文 AI 助手。" },
  { role: "user", content: "你好" }
]

常见 role:

role 作用
system 设定 AI 的身份、语气、规则
user 用户说的话
assistant AI 之前回复过的话

如果你想让 AI 记住上下文,就把最近几轮 userassistant 一起发给模型。

3. 为什么项目里要保留 history?

单轮对话:

用户:你好
AI:你好呀

多轮对话:

用户:我叫小明
AI:你好小明
用户:我叫什么?
AI:你叫小明

模型本身不会自动记住上一次请求,所以需要前端或后端保存历史,再传给 API。

项目里的聊天页就是把最近几轮 history 发给后端,后端再拼进 messages

const messages = [
  { role: "system", content: "你是佳小乐,一个温暖、机灵、会鼓励用户的中文互动角色。" },
  ...history.slice(-10),
  { role: "user", content: userMessage }
];

4. DeepSeek 为什么能用 OpenAI SDK?

DeepSeek 提供了 OpenAI 兼容接口,所以可以这样写:

const client = new OpenAI({
  baseURL: "https://api.deepseek.com",
  apiKey: process.env.DEEPSEEK_API_KEY
});

关键点是:

  • SDK 还是 openai
  • baseURL 换成 DeepSeek
  • apiKey 换成 DeepSeek 的 Key
  • model 使用 DeepSeek 支持的模型名

七、开源项目 JXL-AI 做了哪些增强?

上面的 Demo 是最小版,而我的开源项目 JXL-AI 在它基础上做了完整网页:

  • AI 角色聊天页
  • 聊天失败时本地回复兜底
  • 开场动画
  • 图片投稿图鉴
  • SQLite 排行榜
  • 同名用户确认
  • 整活证书生成
  • Nginx/PM2 部署友好

项目结构:

.
├── server.mjs
├── package.json
├── data/app.db
├── public/
│   ├── index.html
│   ├── chat.html
│   ├── intro.html
│   ├── bestiary.html
│   ├── uploads/
│   └── assets/
└── scripts/check.mjs

八、总结

AI 对话网页的核心并不神秘,本质就是:

前端收集输入
后端保护 API Key
后端请求 DeepSeek
前端展示回复

先跑通这个最小闭环,再去加角色设定、历史上下文、上传、数据库、部署,就会顺很多。

我把完整项目开源了:

https://github.com/Tuoxie423/jxl-ai

如果这篇文章或项目帮你跑通了第一个 AI 网页,欢迎给项目点一个 Star。后续我也会继续更新更多适合新手的 AI Web 实战内容。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐