用大模型做全栈应用?一个超简单的 AI 全栈 Demo 实战(前端 + 后端 + LLM)

109 阅读5分钟

引言


💡 一句话总结本项目
👉 用 HTML + Node.js + OpenAI 搭建一个能“看懂用户数据”的智能问答系统——输入问题,直接返回答案,像聊天一样查数据!

这不是玩具,而是现代 AI 全栈架构的核心缩影:前端交互 + 数据服务 + 智能推理三层解耦,未来所有“AI 原生应用”的雏形就在这里。


🚀 为什么要做这个项目?

2024 年了,只会写 CRUD 的开发者正在被淘汰。真正值钱的能力是:把大模型(LLM)融入业务场景中

但很多同学卡在第一步:不知道怎么把“调 API”变成“做一个完整应用”。

今天我们就来手把手实现一个极简但完整的 AI 全栈查询系统

  • ✅ 前端展示用户列表
  • ✅ 用户输入自然语言问题(如:“谁来自南昌?”)
  • ✅ 系统自动分析并返回答案(“万明翰来自南昌”)

整个项目不到 200 行代码,却完整展示了 “数据 → 接口 → 模型 → 回答” 的闭环流程。

⚠️ 注意:本项目仅为演示思想,生产环境需加强安全与性能设计。


🧱 架构设计:三层分离,职责清晰

我们采用经典的三明治架构:

[前端页面] ←HTTP→ [LLM服务] ←HTTP→ [数据API]
     ↓                  ↓               ↓
  UI交互        智能问答引擎       用户数据管理
层级技术栈功能说明
前端HTML + JS + Bootstrap展示数据 & 提交问题
数据层json-server提供 RESTful 用户数据接口
AI层OpenAI API解析问题 + 结合数据生成回答

优势

  • 各模块独立运行,便于调试和扩展
  • 可轻松替换为真实数据库或私有化模型
  • 完美体现“AI 即服务”的设计理念

🔧 第一步:搭建数据服务(json-server 快速起飞)

不想写后端?用 json-server 一行命令搞定假 API!

1. 创建 backend/uses.json

{
  "users": [
    { "id": 1, "username": "欧阳政", "hometown": "宜春" },
    { "id": 2, "username": "万明翰", "hometown": "南昌" },
    { "id": 3, "username": "王宏财", "hometown": "吉安" },
    { "id": 4, "username": "江北", "hometown": "九江" }
  ]
}

2. 初始化项目并启动服务

cd backend
npm init -y
npm install json-server --save

添加脚本到 package.json

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

启动服务:

npm run dev

🎉 访问 http://localhost:3001/users 即可看到所有用户数据!

image.png


💻 第二步:前端页面开发(简洁美观就够了)

使用 Bootstrap 快速构建响应式界面,核心功能只有两个:展示用户表 + 输入问题查询

页面结构 (frontend/index.html)

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
  <title>AI 用户查询系统</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">
    <div class="col-md-6 col-md-offset-3">
      <h3>👥 用户信息</h3>
      <table class="table table-striped" id="user_table">
        <thead>
          <tr>
            <th>ID</th>
            <th>姓名</th>
            <th>家乡</th>
          </tr>
        </thead>
        <tbody></tbody>
      </table>
    </div>
  </div>

  <!-- 查询表单 -->
  <div class="row">
    <form name="aiForm" class="col-md-6 col-md-offset-3">
      <div class="form-group">
        <label for="questionInput">💬 请输入你的问题:</label>
        <input type="text" class="form-control" id="questionInput" name="question" placeholder="例如:谁来自南昌?" required>
      </div>
      <button type="submit" class="btn btn-success">🚀 提交查询</button>
    </form>
  </div>

  <!-- 结果展示 -->
  <div class="row" style="margin-top: 20px;">
    <div class="col-md-6 col-md-offset-3" id="message"></div>
  </div>
</div>

JavaScript 数据加载与提交逻辑

<script>
const oForm = document.forms["aiForm"];
const oBody = document.querySelector('#user_table tbody');
let users;

// 页面加载时获取用户数据
fetch('http://localhost:3001/users')
  .then(res => res.json())
  .then(userData => {
    users = userData;
    // 渲染表格
    oBody.innerHTML = userData.map(user => `
      <tr>
        <td>${user.id}</td>
        <td>${user.username}</td>
        <td>${user.hometown}</td>
      </tr>
    `).join('');
  });

// 表单提交处理
oForm.addEventListener("submit", async (e) => {
  e.preventDefault();
  const question = oForm["question"].value.trim();
  const btn = e.target.querySelector('.btn');

  if (!question) return alert("请先输入问题哦~");

  btn.disabled = true;
  btn.textContent = "思考中...";

  try {
    const response = await fetch(
      `http://localhost:1314/?question=${encodeURIComponent(question)}&data=${encodeURIComponent(JSON.stringify({ users }))}`
    );
    const result = await response.json();

    document.getElementById("message").innerHTML = `
      <div class="alert alert-info">
        <strong>🤖 AI 回答:</strong> ${result.result}
      </div>`;
  } catch (err) {
    document.getElementById("message").innerHTML = `
      <div class="alert alert-danger">请求失败,请检查 LLM 服务是否启动</div>`;
  } finally {
    btn.disabled = false;
    btn.textContent = "🚀 提交查询";
  }
});
</script>

📌 小技巧:用了 encodeURIComponent 防止中文乱码问题! 界面如下:

image.png


🤖 第三步:LLM 服务开发(灵魂所在!)

这是整个系统的“大脑”,负责理解问题并结合数据给出答案。

项目结构

llm/
├── main.mjs
├── package.json
└── .env

安装依赖

npm init -y
npm install openai dotenv

.env 文件(记得 gitignore!)

OPENAI_API_KEY=sk-your-real-apikey-here

核心服务代码 main.mjs

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

config({ path: '.env' });

const client = new OpenAI({
  apiKey: process.env.OPENAI_API_KEY,
  baseURL: 'https://api.302.ai/v1', // 支持兼容 OpenAI 的代理接口
});

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,  // 更确定的回答
    max_tokens: 200,
  });
  return result.choices[0].message.content;
};

http.createServer(async (req, res) => {
  res.setHeader('Access-Control-Allow-Origin', '*');
  res.setHeader('Content-Type', 'application/json');

  const parsedUrl = url.parse(req.url, true);
  const { question, data } = parsedUrl.query;

  if (!question || !data) {
    res.statusCode = 400;
    return res.end(JSON.stringify({ error: '缺少参数' }));
  }

  try {
    const prompt = `${data}\n\n请根据以上 JSON 数据,回答这个问题:${question}`;
    const result = await getCompletion(prompt);

    res.statusCode = 200;
    res.end(JSON.stringify({ result }));
  } catch (err) {
    console.error(err);
    res.statusCode = 500;
    res.end(JSON.stringify({ error: 'AI 调用失败' }));
  }
}).listen(1314);

console.log('✅ LLM 服务已启动,监听端口 1314');

🧠 关键点解析:

特性说明
baseURL可换为国内可用的 OpenAI 兼容接口
temperature: 0.1让回答更稳定,避免胡说八道
CORS 支持前端跨域访问必备
错误捕获生产级服务必须有的兜底机制

▶️ 启动全流程(三步走)

  1. 启动数据服务

    cd backend && npm run dev
    
  2. 启动 LLM 服务

    cd llm && node main.mjs
    
  3. 打开前端页面

    打开 frontend/index.html(建议用 live-server)
    

🎯 效果演示:

输入问题输出结果
谁来自南昌?万明翰来自南昌
宜春的人是谁?欧阳政来自宜春
最大的 ID 是多少?最大 ID 是 4,对应用户是江北

✅ 成功让 AI “读懂”了我们的数据库!


🛠️ 可拓展方向(进阶思路)

虽然这是一个 demo,但它具备极强的延展性:

方向实现建议
🔐 安全增强使用 JWT 认证、限制 Origin、过滤恶意输入
📦 缓存优化Redis 缓存常见问题的回答
🧩 多轮对话维护 session 上下文,支持追问
🗃️ 数据库对接替换 json-server 为 MySQL + Express
🌐 私有模型部署接入本地 Llama3 / Qwen 等开源模型
📊 日志监控记录用户提问行为,用于后续分析

📣 总结:这不仅仅是一个 Demo

通过这个小小的项目,我们完成了:

✅ 前后端通信
✅ 数据建模与暴露
✅ LLM 提示工程实践
✅ 全链路 HTTP 调用打通

更重要的是——我们验证了一个理念:

未来的软件 = 数据 + 接口 + 自然语言入口

你可以把这个模式套用到任何场景:

  • 内部知识库问答机器人
  • 客服工单智能检索
  • CRM 客户信息语音查询
  • 数据报表口语化解读