青戈AI小栈
FastAPI + LangGraph|从零带你开发电商数据分析系统,融合 MCP、RAG 与多 Agent 协作

02. 环境配置和项目脚手架导入运行

24,909 字约 63 分钟读完195 次阅读更新于 2026/10/23

登录后收藏

阅读设置

字号
行距
代码

1. 本节目标

这一节把项目的「地基」跑起来:

  1. 准备开发环境
  2. 把脚手架的前端、后端、数据库跑通,能用演示账号登录
  3. 看懂脚手架的整体结构:一次请求从浏览器到数据库是怎么走的,登录和权限是怎么实现的

脚手架已经包含登录、注册、用户管理、个人资料、修改密码和菜单这些通用功能。后续课程里的课表、知识库、AI 助手,都是在这个地基上一块块加上去的。

技术栈:Vue 3 + Element Plus + Axios · FastAPI + SQLAlchemy + JWT · MySQL。

相关带敲教程在 https://www.bilibili.com/video/BV13hbP6zEUd 第 01-14 集

2. 学习准备

2.1. 环境要求

NodeJS 版本检测:

Python 版本检测:

MySQL 服务:

2.2. 编辑器

推荐下载 VSCode:https://code.visualstudio.com/

安装插件:

  • Vue (Official):Vue 语法高亮
  • Prettier - Code formatter:Vue 代码格式化
  • Python:Python 语法支持、高亮
  • Black Formatter:Python 代码格式化
  • Pylance:python 语法自动补全、自动导入
  • Material Icon Theme:代码目录主题色

User Settings 设置

Vue:

输出
{
  "editor.formatOnSave": true,
  "editor.formatOnPaste": true,
  "[vue]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  "[javascript]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  "[json]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
}

Python:

输出
{
  "python.analysis.typeCheckingMode": "off",
  "python.analysis.autoImportCompletions": true,
  "python.languageServer": "Pylance",
  "python.analysis.extraPaths": ["./backend"],
  "editor.quickSuggestions": {
    "other": true,
    "comments": false,
    "strings": false
  },
  "[python]": {
    "editor.codeActionsOnSave": {
      "source.organizeImports": "explicit",
      "source.fixAll": "explicit"
    },
    "editor.defaultFormatter": "ms-python.black-formatter"
  },
}

3. 脚手架目录结构

下载脚手架:https://ai.codenice.cn/courses/ecom-analysis-agent

输出
ecom-analysis-agent/
├── sql/
│   └── backend.sql          # 用户表结构 + 演示账号
├── backend/                 # FastAPI
│   ├── app/
│   │   ├── api/             # 路由
│   │   ├── services/        # 业务逻辑
│   │   ├── models/          # ORM
│   │   ├── schemas/         # 请求/响应模型
│   │   ├── common/          # 统一返回、异常
│   │   ├── dependencies/    # JWT 依赖
│   │   └── utils/
│   ├── uploads/             # 上传文件目录
│   ├── requirements.txt
│   ├── .env.example
│   └── .env                 # 本地配置(勿提交真实密钥)
├── frontend/                # Vue3
│   ├── src/
│   │   ├── api/
│   │   ├── views/
│   │   ├── layouts/
│   │   └── utils/
│   └── .env.development
└── README.md

4. 运行脚手架

运行顺序:数据库 → 后端 → 前端。

flowchart LR
    A["1 创建数据库<br/>导入 backend.sql"] --> B["2 启动后端<br/>127.0.0.1:8000"]
    B --> C["3 启动前端<br/>localhost:5173"]
    C --> D["4 浏览器登录<br/>验证成功"]

先解压脚手架放到 D:\Course\ 目录 改名 ecom-analysis-agent

4.1 创建数据库

用 Navicat 或命令行连接 MySQL,先创建数据库:ecom-analysis-agent

然后在这个库里执行 sql/backend.sql,导入 sql。

4.2 启动后端

第一步:进入后端目录,创建虚拟环境

输出
cd backend
python -m venv .venv

虚拟环境相当于给这个项目单独准备一套 Python 依赖,不会和电脑上其他项目互相影响。

第二步:激活虚拟环境

输出
# Windows(PowerShell)
.\.venv\Scripts\Activate.ps1

激活成功后,终端提示符前面会出现 (.venv)。

第三步:安装依赖

先配置国内镜像加速下载:在 %AppData%目录下新建pip 目录,然后进入pip目录新建文件pip.ini,设置阿里云镜像

输出
[global]
index-url=https://mirrors.aliyun.com/pypi/simple

然后回到项目的 backend 目录下,执行安装指令:

bash
pip install -r requirements.txt

第四步:配置环境变量

把 .env.example 复制一份,重命名为 .env,修改数据库连接和 JWT 密钥:

输出
DATABASE_URL=mysql+pymysql://root:你的数据库密码@127.0.0.1:3306/campus_course_agent
JWT_SECRET_KEY=改成一串足够长的随机字符串
JWT_EXPIRE_HOURS=24
JWT_ALGORITHM=HS256

DATABASE_URL 的格式是:mysql+pymysql://用户名:密码@地址:端口/数据库名。

密钥生成器:https://jwtsecretkeygenerator.com/zh/

第五步:启动后端

bash
uvicorn app.main:app --reload --port 8000
  • app.main:app 表示运行 app/main.py 文件里名为 app 的 FastAPI 对象
  • --reload 表示修改代码后自动重启,开发时很方便

第六步:验证

  • 浏览器打开 http://127.0.0.1:8000,看到 {"message":"FastAPI工程正在运行中"} 说明启动成功
  • 打开 http://127.0.0.1:8000/docs,可以看到 FastAPI 自动生成的接口文档,能直接在页面上调试接口

4.3 启动前端

新开一个终端(后端那个终端不要关),执行:

输出
cd frontend
npm install
npm run dev

npm install 下载慢的话可以切换国内镜像:

bash
npm config set registry https://registry.npmmirror.com

启动成功后,浏览器打开 http://localhost:5173。

4.4 登录验证

角色 账号 密码
管理员 admin admin
学生 aaa 123
学生 bbb 123

分别用管理员和学生账号登录,观察左侧菜单:管理员能看到「用户管理」,学生看不到。 这个区别后面会专门讲。

4.5 常见问题

现象 原因与解决
后端启动报错,提示连不上数据库 检查 MySQL 是否启动;检查 .env<br/> 中的密码和数据库名是否正确;确认数据库已经创建
PowerShell 激活虚拟环境时报错「禁止运行脚本」 以管理员身份打开 PowerShell,执行 Set-ExecutionPolicy RemoteSigned<br/>,或改用 CMD 激活
提示 8000或 5173 端口被占用 关闭占用端口的程序,或换一个端口启动
npm install<br/> 报错,提示 Node 版本不符合 升级 Node.js 到 22.18 以上
页面提示「网络异常,请检查后端服务」 后端没有启动,或者启动失败,回到后端终端查看报错
登录后头像不显示 演示账号的头像图片不在你的电脑上,到「个人资料」里重新上传即可

5. 一次请求是怎么走的

项目跑起来之后,先建立整体印象:用户在页面上点「登录」,到底发生了什么?

flowchart LR
    B["浏览器<br/>Vue 页面"] -->|/api/auth/login| V["Vite 开发服务器<br/>代理转发"]
    V --> R["FastAPI<br/>api 接口层"]
    R --> S["services<br/>业务层"]
    S --> M["models<br/>SQLAlchemy"]
    M --> DB["MySQL"]

为什么前端请求/api/... 能到达后端? 前端运行在 5173 端口,后端在 8000 端口。vite.config.js 里配置了代理,开发时凡是以 /api 和 /uploads 开头的请求,都会被转发到后端:

输出
server: {
  proxy: {
    '/api': { target: 'http://127.0.0.1:8000', changeOrigin: true },
    '/uploads': { target: 'http://127.0.0.1:8000', changeOrigin: true }
  }
}

6. 后端讲解

6.1 分层结构

后端按职责分层,每一层只做自己的事:

层 目录 职责 以登录为例
接口层 api/ 定义路由,接收请求,返回结果 auth.py<br/> 里的 login<br/> 接口
数据校验 schemas/ 定义请求参数和返回数据的格式 LoginRequest<br/> 要求必须有 username 和 password
业务层 services/ 实现业务逻辑 auth_service.login<br/> 校验账号密码、生成 token
模型层 models/ 对应数据库表 User<br/> 对应 users<br/> 表

这样分层的好处是:接口层很薄,业务逻辑集中在 services。后续课程开发 MCP 工具时,工具直接调用 services 里的函数,业务代码不用重写。

6.2 配置读取:config.py

使用 pydantic-settings 从 .env 文件读取配置,并自动做类型转换:

输出
class Settings(BaseSettings):
    DATABASE_URL: str
    JWT_SECRET_KEY: str
    JWT_EXPIRE_HOURS: int = 24
    JWT_ALGORITHM: str = "HS256"

没有默认值的配置项(如 DATABASE_URL)是必填的,.env 里缺少时程序启动就会报错,能尽早发现配置问题。

6.3 数据库:database.py

  • engine 负责数据库连接,SessionLocal 用来创建会话
  • get_db 在每次请求时创建会话,请求结束后自动关闭
  • Base 是所有模型的父类,统一带上 id、create_time、update_time 三个字段,模型里不用重复定义main.py 启动时执行了这一行:

Base.metadata.create_all(bind=engine)

它会根据模型自动创建还不存在的表。后续课程新增课表、学习计划等模型时,重启后端就能自动建表。

create_all 只负责建新表,不会修改已存在的表结构。

6.4 统一返回格式

所有接口都返回同样的结构,前端处理起来很统一:

输出
{
  "code": 200,
  "message": "登录成功",
  "data": { }
}

代码里用 Response.success(...) 和 Response.error(...) 生成。分页查询的 data 里是 list 和 total。

6.5 统一异常处理

main.py 注册了四个异常处理器,把各种异常都转换成上面的统一格式:

异常 场景 返回
BusinessException 业务规则不满足,如「账号或密码错误」 HTTP 200,code<br/> 为业务错误码
HTTPException 如未登录返回 401 对应的 HTTP 状态码
RequestValidationError 请求参数格式不对 422,「请求参数校验错误」
Exception 其他未预料的错误 500,「服务器内部错误」

业务代码里遇到不符合规则的情况,直接 raise BusinessException("提示信息") 即可,不需要到处写返回逻辑。

兜底的 Exception 处理器必须最后注册。

6.6 登录与 JWT

sequenceDiagram
    participant 前端
    participant FastAPI
    participant MySQL
    前端->>FastAPI: 提交账号、密码
    FastAPI->>MySQL: 按账号查询用户
    MySQL-->>FastAPI: 用户信息(含加密后的密码)
    FastAPI->>FastAPI: bcrypt 校验密码、检查账号状态
    FastAPI-->>前端: 返回 token 和用户信息
    Note over 前端: token 存入 localStorage
    前端->>FastAPI: 之后每次请求都带上 Authorization: Bearer token
    FastAPI->>FastAPI: 解析 token 得到 user_id
    FastAPI-->>前端: 返回业务数据

几个关键点:

  • 密码加密:数据库里存的是 bcrypt 加密后的字符串,不是明文。登录时用 verify_password 比对
  • 生成 token:create_access_token 把 user_id 和过期时间写进 JWT,用 .env 里的密钥签名
  • 注册的用户默认是普通用户:role 固定为 user,管理员只能在后台创建

6.7 获取当前用户与权限校验

需要登录的接口,通过依赖注入获取当前用户:

输出
@router.get("/me")
def get_user_info(current_user: User = Depends(get_current_user)):
    ...

get_current_user 做了三件事:

  1. 从请求头取出 token 并解析,失败返回 401
  2. 从 token 里拿到 user_id
  3. 查数据库确认用户存在且未被禁用只允许管理员访问的接口,换成 get_current_admin,它在 get_current_user 的基础上再判断 role 是否为 admin,不是则返回 403。

这个机制在后续课程里非常重要。 第一节讲过「用户身份由系统传递,不由模型填写」,MCP 工具获取当前用户的思路和这里完全一样:从 token 里解析出用户,而不是相信请求参数里传来的用户 ID。

6.8 文件上传

POST /api/files/upload 用于上传头像等文件:

  • 校验文件后缀和大小(默认上限 100MB)
  • 用「时间戳 + 随机串」重新命名,避免重名覆盖
  • 保存到 backend/uploads/ 目录,返回访问地址 /uploads/文件名``main.py 把 uploads 目录挂载成了静态资源,所以通过 http://127.0.0.1:8000/uploads/文件名 就能直接访问。

6.9 跨域配置

main.py 里配置了 CORS,只允许 localhost:5173 和 127.0.0.1:5173 访问。开发时前端已经通过 Vite 代理访问后端,这里的配置用于前端直接请求后端地址的情况。

不要为了省事把允许的来源写成 ["*"]。

7. 前端讲解

7.1 入口:main.js

注册路由、Element Plus 组件库(设置为中文)和全部图标组件,并引入全局样式。

7.2 路由与路由守卫:router/index.js

  • /login、/register 是独立页面
  • 登录后的页面都放在 /manager 下,共用 Layout.vue 的布局
  • 路由守卫:除登录和注册页外,没有 token 就跳转到登录页
输出
router.beforeEach((to) => {
  const token = getToken()
  if (to.path === '/login' || to.path === '/register') return true
  return token ? true : '/login'
})

7.3 请求封装:utils/request.js

基于 axios 封装,所有接口请求都经过这里:

flowchart LR
    P["页面调用<br/>api 函数"] --> Q["请求拦截器<br/>自动带上 token"]
    Q --> S["后端"]
    S --> R{"响应拦截器<br/>code 是否为 200"}
    R -->|是| OK["返回数据给页面"]
    R -->|否| E["弹出错误提示"]
    R -->|401| L["清除登录信息<br/>跳转登录页"]
  • 请求拦截器:本地有 token 就自动加上 Authorization: Bearer token 请求头,页面里不用每次手动写
  • 响应拦截器:code 不是 200 时统一弹出错误提示;遇到 401 自动退出登录并跳转;后端没启动时提示「网络异常,请检查后端服务」

7.4 登录状态存储:utils/auth.js 与 utils/user.js

  • auth.js:负责把 token 和用户信息存到 localStorage,以及读取和清除
  • user.js:提供 useUser(),用响应式变量保存当前用户信息。修改个人资料后调用 updateUser,顶栏的名字和头像会立刻更新

7.5 布局与菜单:layouts/Layout.vue

左侧菜单根据用户角色显示不同的菜单项:

<el-menu-item index="/manager/user" v-if="userInfo?.role === 'admin'">

前端隐藏菜单不等于权限控制。 学生看不到「用户管理」菜单,但如果直接调用用户管理接口,真正拦住他的是后端的 get_current_admin。前端负责体验,后端负责安全,这一点后续开发 AI 功能时同样适用。

8. 小结

  1. 运行顺序:数据库 → 后端 → 前端,三者都跑起来才能正常登录
  2. 后端分为接口层、数据校验、业务层、模型层,配合统一返回格式和统一异常处理
  3. 登录后得到 JWT,之后每次请求都带上它;后端通过 get_current_user 从 token 中解析当前用户,通过 get_current_admin 校验管理员
  4. 前端通过路由守卫拦截未登录访问,通过请求封装统一处理 token 和错误
  5. 前端隐藏菜单负责体验,后端校验权限负责安全
有帮助
登录后提问 / 纠错

提问与反馈

仅你和管理员可见。我的反馈

设置你的昵称

在英雄榜和讨论中,使用你自己的名字。

2–12 个字符0 / 12