全栈实战:基于Node.js与OpenAI构建智能用户查询系统

5 阅读7分钟

在当今技术快速发展的时代,全栈开发能力变得越来越重要。本文将详细介绍如何构建一个完整的全栈应用,它结合了前端展示、后端数据服务和AI大语言模型,实现了一个智能用户查询系统。通过这个项目,我们将探索从前端到后端的完整开发流程。

项目概述

这个全栈项目包含三个核心部分:

· 前端页面:使用Bootstrap框架构建响应式用户界面 · 后端数据服务:基于json-server提供RESTful API · LLM服务:集成OpenAI兼容API实现智能问答功能

系统允许用户查看用户列表,并通过自然语言向AI提问关于这些用户数据的问题。

技术栈与项目结构

项目采用经典的前后端分离架构:

全栈目录结构
- frontend/          # 前端页面
- backend/           # 后端数据服务
- llm/              # 大模型服务

前端实现

前端页面负责数据展示和用户交互,我们使用HTML、CSS和JavaScript实现。

页面布局与样式

我们使用Bootstrap框架快速构建响应式界面:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Users Chatbot</title>
  <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
  <div class="container">
    <div class="row col-md-6 col-md-offset-3">
      <table class="table table-striped" id="user_table">
        <thead>
          <tr>
            <th>ID</th>
            <th>姓名</th>
            <th>家乡</th>
          </tr>
        </thead>
        <tbody>
          <!-- 用户数据将动态填充到这里 -->
        </tbody>
      </table>
    </div>

    <div class="row">
      <form name="aiForm">
        <div class="form-group">
          <input type="text" id="questionInput" class="form-control" 
                 name="question" required placeholder="请输入问题">
        </div>
        <div class="form-group">
          <button type="submit" class="btn btn-primary">提交</button>
        </div>
      </form>
      <div class="row" id="message"></div>
    </div>
  </div>
  
  <script>
    // JavaScript代码将在这里实现
  </script>
</body>
</html>

Bootstrap的栅格系统让我们能够轻松创建自适应布局。col-md-6使表格在中等屏幕设备上占据一半宽度,col-md-offset-3实现居中效果。

数据获取与展示

前端通过JavaScript的Fetch API从后端获取用户数据:

// 声明全局变量存储用户数据
let users;

// 页面加载时获取用户数据
fetch('http://localhost:3001/users')
  .then(res => res.json())
  .then(data => {
    users = data; // 将数据保存到全局变量
    // 动态生成表格行
    oBody.innerHTML = data.map(user => `
      <tr>
        <td>${user.id}</td>
        <td>${user.username}</td>
        <td>${user.hometown}</td>
      </tr>
    `).join("")
  })

这里使用map方法遍历数据数组,为每个用户生成表格行,最后用join("")将数组转换为字符串插入到表格体中。

用户交互与AI集成

前端最重要的功能是处理用户提问并与LLM服务交互:

const oForm = document.forms["aiForm"];
const oBody = document.querySelector('#user_table tbody');
const oBtn = document.querySelector(".btn");

oForm.addEventListener("submit", (event) => {
  event.preventDefault(); // 阻止表单默认提交行为
  
  const question = oForm["question"].value;
  
  // 输入验证
  if (!question) {
    alert("请输入问题");
    return;
  }
  
  // 禁用按钮防止重复提交
  oBtn.disabled = true;
  
  // 向LLM服务发送请求
  fetch(`http://localhost:1314/?question=${question}&data=${JSON.stringify(users)}`)
    .then(res => res.json())
    .then(data => {
      oBtn.disabled = false; // 重新启用按钮
      document.getElementById('message').innerHTML = data.result;
    })
})

这个实现包含了完整的用户交互流程:表单提交处理、输入验证、防止重复提交、与LLM服务通信以及结果展示。

后端数据服务

后端使用json-server提供RESTful API,这是一个非常实用的工具,可以快速搭建模拟后端服务。

环境配置

首先初始化项目并安装依赖:

npm init -y
pnpm i json-server

数据文件

创建users.json文件存储用户数据:

{
  "users": [
    {
      "id": 1,
      "username": "曹威威",
      "hometown": "九江"
    },
    {
      "id": 2,
      "username": "宋婉琳",
      "hometown": "吉安"
    },
    {
      "id": 3,
      "username": "习皓俊",
      "hometown": "吉安"
    },
    {
      "id": 4,
      "username": "王毓宸",
      "hometown": "吉安"
    }
  ]
}

启动脚本

在package.json中添加启动脚本:

{
  "scripts": {
    "dev": "json-server --watch users.json --port 3001"
  }
}

通过npm run dev命令启动服务,json-server会自动创建基于用户数据的RESTful API,支持常见的CRUD操作。

LLM服务实现

LLM服务是整个应用的智能核心,它连接前端和AI大模型。

环境配置与初始化

首先导入必要的依赖并配置环境变量:

import http from 'http';
import OpenAI from 'openai';
import url from 'url';
import { config } from 'dotenv';

// 加载环境变量
config({ path: '.env' });

// 初始化OpenAI兼容客户端
const client = new OpenAI({
  apiKey: process.env.OPENAI_API_KEY,
  baseURL: 'https://api.agicto.cn/v1'
});

这里使用dotenv从.env文件加载环境变量,特别是API密钥。我们使用AGICTO作为OpenAI兼容服务提供商。

LLM调用函数

定义核心的AI调用函数:

const getCompletion = async (prompt, model = 'gpt-3.5-turbo') => {
  const messages = [{
    role: 'user',
    content: prompt
  }];
  
  const result = await client.chat.completions.create({
    model,
    messages,
    temperature: 0.1 // 低随机性,保证回答一致性
  });
  
  return result.choices[0].message.content;
}

这个函数封装了与AI模型的交互过程,使用异步编程处理网络请求。temperature参数设置为0.1,使模型输出更加确定,减少随机性。

HTTP服务器

创建HTTP服务器处理前端请求:

http.createServer(async (req, res) => {
  // 解决跨域问题
  res.setHeader('Access-Control-Allow-Origin', '*');
  
  // 解析URL和查询参数
  const parsedUrl = url.parse(req.url, true);
  
  // 构造提示词
  const prompt = `
    ${parsedUrl.query.data}
    请根据上面的JSON数据,回答${parsedUrl.query.question}这个问题。
  `;
  
  // 调用LLM获取回答
  const result = await getCompletion(prompt);
  
  // 构造响应
  let info = { result };
  res.status = 200;
  res.setHeader('Content-Type', 'application/json');
  res.end(JSON.stringify(info));
}).listen(1314);

服务器监听1314端口,处理CORS跨域问题,解析前端传递的问题和数据,构造合适的提示词后调用AI模型,最后将结果返回给前端。

系统集成与数据流

整个系统的数据流动如下:

  1. 初始化阶段:前端加载时从后端服务(localhost:3001)获取用户数据并渲染表格
  2. 用户交互:用户在前端表单中输入问题并提交
  3. 请求转发:前端将问题和使用数据构造的提示词发送到LLM服务(localhost:1314)
  4. AI处理:LLM服务接收请求,调用AI模型处理问题
  5. 结果返回:AI回答通过LLM服务返回给前端并展示给用户

这种架构实现了清晰的关注点分离,每个服务都有明确的职责。

开发心得与最佳实践

在开发这个全栈应用过程中,有几个关键点值得注意:

  1. 前后端分离的优势

前后端分离架构让前端专注于用户界面和交互,后端专注于数据处理和API提供,提高了开发效率和代码可维护性。

  1. 全局状态管理

在前端代码中,我们使用全局变量users存储从后端获取的数据,这样在后续与LLM服务交互时可以直接使用这些数据,避免了重复请求。

  1. 错误处理与用户体验

代码中包含了基本的错误处理,如表单验证、按钮禁用防止重复提交等,这些细节大大提升了用户体验。

  1. 异步编程处理

大量使用Promise和async/await处理异步操作,确保代码的执行顺序符合预期,避免回调地狱。

  1. 环境变量管理

敏感信息如API密钥通过环境变量管理,提高了安全性,便于在不同环境间切换配置。

扩展可能性

这个基础项目有很多扩展方向:

· 增加用户管理功能:实现用户的增删改查操作 · 添加身份验证:为API添加JWT认证 · 优化AI提示词:设计更精准的提示词提高回答质量 · 实现对话历史:保存用户与AI的对话记录 · 添加更多数据可视化:使用图表展示用户数据分布

总结

通过这个全栈项目,我们实现了从前端展示到后端API,再到AI集成的完整流程。项目展示了现代Web开发的核心概念:前后端分离、RESTful API设计、异步编程和第三方服务集成。

这个项目不仅是一个功能完整的应用,更是一个学习全栈开发的优秀范例。它涵盖了从界面设计到服务部署的各个环节,为进一步探索更复杂的全栈应用奠定了坚实基础。

在AI技术日益普及的今天,将传统Web开发与AI能力结合,能够创造出更加智能和有用的应用,这个项目正是这种趋势的一个具体体现。

在当今技术快速发展的时代,全栈开发能力变得越来越重要。本文将详细介绍如何构建一个完整的全栈应用,它结合了前端展示、后端数据服务和AI大语言模型,实现了一个智能用户查询系统。通过这个项目,我们将探索从前端到后端的完整开发流程。

项目概述

这个全栈项目包含三个核心部分:

· 前端页面:使用Bootstrap框架构建响应式用户界面 · 后端数据服务:基于json-server提供RESTful API · LLM服务:集成OpenAI兼容API实现智能问答功能

系统允许用户查看用户列表,并通过自然语言向AI提问关于这些用户数据的问题。

技术栈与项目结构

项目采用经典的前后端分离架构:

全栈目录结构
- frontend/          # 前端页面
- backend/           # 后端数据服务
- llm/              # 大模型服务

前端实现

前端页面负责数据展示和用户交互,我们使用HTML、CSS和JavaScript实现。

页面布局与样式

我们使用Bootstrap框架快速构建响应式界面:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Users Chatbot</title>
  <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
  <div class="container">
    <div class="row col-md-6 col-md-offset-3">
      <table class="table table-striped" id="user_table">
        <thead>
          <tr>
            <th>ID</th>
            <th>姓名</th>
            <th>家乡</th>
          </tr>
        </thead>
        <tbody>
          <!-- 用户数据将动态填充到这里 -->
        </tbody>
      </table>
    </div>

    <div class="row">
      <form name="aiForm">
        <div class="form-group">
          <input type="text" id="questionInput" class="form-control" 
                 name="question" required placeholder="请输入问题">
        </div>
        <div class="form-group">
          <button type="submit" class="btn btn-primary">提交</button>
        </div>
      </form>
      <div class="row" id="message"></div>
    </div>
  </div>
  
  <script>
    // JavaScript代码将在这里实现
  </script>
</body>
</html>

Bootstrap的栅格系统让我们能够轻松创建自适应布局。col-md-6使表格在中等屏幕设备上占据一半宽度,col-md-offset-3实现居中效果。

数据获取与展示

前端通过JavaScript的Fetch API从后端获取用户数据:

// 声明全局变量存储用户数据
let users;

// 页面加载时获取用户数据
fetch('http://localhost:3001/users')
  .then(res => res.json())
  .then(data => {
    users = data; // 将数据保存到全局变量
    // 动态生成表格行
    oBody.innerHTML = data.map(user => `
      <tr>
        <td>${user.id}</td>
        <td>${user.username}</td>
        <td>${user.hometown}</td>
      </tr>
    `).join("")
  })

这里使用map方法遍历数据数组,为每个用户生成表格行,最后用join("")将数组转换为字符串插入到表格体中。

用户交互与AI集成

前端最重要的功能是处理用户提问并与LLM服务交互:

const oForm = document.forms["aiForm"];
const oBody = document.querySelector('#user_table tbody');
const oBtn = document.querySelector(".btn");

oForm.addEventListener("submit", (event) => {
  event.preventDefault(); // 阻止表单默认提交行为
  
  const question = oForm["question"].value;
  
  // 输入验证
  if (!question) {
    alert("请输入问题");
    return;
  }
  
  // 禁用按钮防止重复提交
  oBtn.disabled = true;
  
  // 向LLM服务发送请求
  fetch(`http://localhost:1314/?question=${question}&data=${JSON.stringify(users)}`)
    .then(res => res.json())
    .then(data => {
      oBtn.disabled = false; // 重新启用按钮
      document.getElementById('message').innerHTML = data.result;
    })
})

这个实现包含了完整的用户交互流程:表单提交处理、输入验证、防止重复提交、与LLM服务通信以及结果展示。

后端数据服务

后端使用json-server提供RESTful API,这是一个非常实用的工具,可以快速搭建模拟后端服务。

环境配置

首先初始化项目并安装依赖:

npm init -y
pnpm i json-server

数据文件

创建users.json文件存储用户数据:

{
  "users": [
    {
      "id": 1,
      "username": "曹威威",
      "hometown": "九江"
    },
    {
      "id": 2,
      "username": "宋婉琳",
      "hometown": "吉安"
    },
    {
      "id": 3,
      "username": "习皓俊",
      "hometown": "吉安"
    },
    {
      "id": 4,
      "username": "王毓宸",
      "hometown": "吉安"
    }
  ]
}

启动脚本

在package.json中添加启动脚本:

{
  "scripts": {
    "dev": "json-server --watch users.json --port 3001"
  }
}

通过npm run dev命令启动服务,json-server会自动创建基于用户数据的RESTful API,支持常见的CRUD操作。

LLM服务实现

LLM服务是整个应用的智能核心,它连接前端和AI大模型。

环境配置与初始化

首先导入必要的依赖并配置环境变量:

import http from 'http';
import OpenAI from 'openai';
import url from 'url';
import { config } from 'dotenv';

// 加载环境变量
config({ path: '.env' });

// 初始化OpenAI兼容客户端
const client = new OpenAI({
  apiKey: process.env.OPENAI_API_KEY,
  baseURL: 'https://api.agicto.cn/v1'
});

这里使用dotenv从.env文件加载环境变量,特别是API密钥。我们使用AGICTO作为OpenAI兼容服务提供商。

LLM调用函数

定义核心的AI调用函数:

const getCompletion = async (prompt, model = 'gpt-3.5-turbo') => {
  const messages = [{
    role: 'user',
    content: prompt
  }];
  
  const result = await client.chat.completions.create({
    model,
    messages,
    temperature: 0.1 // 低随机性,保证回答一致性
  });
  
  return result.choices[0].message.content;
}

这个函数封装了与AI模型的交互过程,使用异步编程处理网络请求。temperature参数设置为0.1,使模型输出更加确定,减少随机性。

HTTP服务器

创建HTTP服务器处理前端请求:

http.createServer(async (req, res) => {
  // 解决跨域问题
  res.setHeader('Access-Control-Allow-Origin', '*');
  
  // 解析URL和查询参数
  const parsedUrl = url.parse(req.url, true);
  
  // 构造提示词
  const prompt = `
    ${parsedUrl.query.data}
    请根据上面的JSON数据,回答${parsedUrl.query.question}这个问题。
  `;
  
  // 调用LLM获取回答
  const result = await getCompletion(prompt);
  
  // 构造响应
  let info = { result };
  res.status = 200;
  res.setHeader('Content-Type', 'application/json');
  res.end(JSON.stringify(info));
}).listen(1314);

服务器监听1314端口,处理CORS跨域问题,解析前端传递的问题和数据,构造合适的提示词后调用AI模型,最后将结果返回给前端。

系统集成与数据流

整个系统的数据流动如下:

  1. 初始化阶段:前端加载时从后端服务(localhost:3001)获取用户数据并渲染表格
  2. 用户交互:用户在前端表单中输入问题并提交
  3. 请求转发:前端将问题和使用数据构造的提示词发送到LLM服务(localhost:1314)
  4. AI处理:LLM服务接收请求,调用AI模型处理问题
  5. 结果返回:AI回答通过LLM服务返回给前端并展示给用户

这种架构实现了清晰的关注点分离,每个服务都有明确的职责。

开发心得与最佳实践

在开发这个全栈应用过程中,有几个关键点值得注意:

  1. 前后端分离的优势

前后端分离架构让前端专注于用户界面和交互,后端专注于数据处理和API提供,提高了开发效率和代码可维护性。

  1. 全局状态管理

在前端代码中,我们使用全局变量users存储从后端获取的数据,这样在后续与LLM服务交互时可以直接使用这些数据,避免了重复请求。

  1. 错误处理与用户体验

代码中包含了基本的错误处理,如表单验证、按钮禁用防止重复提交等,这些细节大大提升了用户体验。

  1. 异步编程处理

大量使用Promise和async/await处理异步操作,确保代码的执行顺序符合预期,避免回调地狱。

  1. 环境变量管理

敏感信息如API密钥通过环境变量管理,提高了安全性,便于在不同环境间切换配置。

扩展可能性

这个基础项目有很多扩展方向:

· 增加用户管理功能:实现用户的增删改查操作 · 添加身份验证:为API添加JWT认证 · 优化AI提示词:设计更精准的提示词提高回答质量 · 实现对话历史:保存用户与AI的对话记录 · 添加更多数据可视化:使用图表展示用户数据分布

总结

通过这个全栈项目,我们实现了从前端展示到后端API,再到AI集成的完整流程。项目展示了现代Web开发的核心概念:前后端分离、RESTful API设计、异步编程和第三方服务集成。

这个项目不仅是一个功能完整的应用,更是一个学习全栈开发的优秀范例。它涵盖了从界面设计到服务部署的各个环节,为进一步探索更复杂的全栈应用奠定了坚实基础。

在AI技术日益普及的今天,将传统Web开发与AI能力结合,能够创造出更加智能和有用的应用,这个项目正是这种趋势的一个具体体现。