从零开始搭建一套大语言模型 + LangGraph 多智能体编排 + RAG 知识库检索** 的智能问答平台

智能问答系统(chat_py)技术架构与部署文档

本文档仅针对 chat_py_server(后端)与 chat_py_front(前端)两个项目。


1. 项目简述

本系统是一个基于 大语言模型 + LangGraph 多智能体编排 + RAG 知识库检索 的智能问答平台,面向企业招商/政策等业务场景。

核心能力:

  • 多轮对话:支持会话记忆与上下文指代消解(如"这个公司""再帮我查一下")。
  • 主管智能体编排:由主管(Supervisor)分析用户问题,自动选择并调度多个子智能体工具。
  • 子智能体工具:日历、天气、联网搜索、知识库检索、系统页面推荐、企业查找、企业详情、企业经营分析、报表生成等。
  • 技能(Skill)选择:前端可手动指定"企业详情 / 知识库查询 / 联网搜索"技能,强制主管走对应子智能体。
  • 登录鉴权:用户名密码 + 图形验证码登录,BCrypt 密码校验 + JWT Token,基于 MySQL 数据源连接池与 Redis 验证码缓存。
  • 报表与图表:后端生成 Excel 报表并提供下载链接,同时输出 ECharts 图表配置,前端直接渲染图表。
  • 知识库:文档上传 → 文本切割 → 向量化 → Milvus 向量检索。

2. 项目目录结构

text 复制代码
my-langchain/
├── chat_py_server/               # 后端(FastAPI + LangGraph)
│   ├── app.py                    # 服务入口(uvicorn 启动,监听 5020)
│   ├── requirements.txt          # Python 依赖清单
│   ├── .env                      # 环境配置(数据库/模型/密钥等)
│   ├── Dockerfile                # 后端应用镜像(FROM 基础镜像,只 COPY 源码)
│   ├── Dockerfile.base           # 后端基础镜像(安装 Python 依赖,可复用)
│   ├── .dockerignore             # 构建忽略项(排除 .env/数据/缓存等)
│   ├── docker-compose.yml        # 后端编排
│   ├── docker-compose-milvus.yml # Milvus 编排(etcd + minio + milvus)
│   └── app/
│       ├── config/               # 配置类 settings.py
│       ├── controller/           # 控制层(chat/doc/auth)
│       ├── graph/                # LangGraph 主管编排(supervisor_graph、agent_descriptions)
│       ├── service/              # 业务服务(model/system)
│       │   ├── model/            # RAG/网站推荐等模型服务
│       │   └── system/           # milvus/embedding/redis/db/auth/oauth/conversation
│       ├── tools/                # 各子智能体工具(web/rag/weather/company 等)
│       ├── entity/               # 请求/响应实体(vo)
│       ├── model/                # OpenAI 客户端(deepseek / llm)
│       ├── utils/                # 公共工具(验证码、加密等)
│       └── skills/               # 技能定义(company-detail / rag / web-search)
│
└── chat_py_front/                # 前端(Vue3 + Vite)
    ├── package.json
    ├── vite.config.js            # 开发代理 /chat_py_server -> 5020
    ├── .env.development          # 开发环境 VITE_API_BASE(默认空,走代理)
    └── src/
        ├── api/                  # axios 封装 + 接口(auth/chat/request)
        ├── views/                # 页面(Login.vue / Chat.vue)
        ├── components/           # 会话列表等组件
        ├── store/                # Pinia(用户 token)
        ├── router/               # 路由守卫
        └── utils/                # markdown 渲染、echarts 渲染

3. 所用技术栈

3.1 后端(chat_py_server)

类别 技术 说明
Web 框架 FastAPI / Uvicorn 提供 REST + SSE 流式接口
编排框架 LangGraph 主管智能体多轮迭代编排、checkpointer 会话记忆
LLM 接入 OpenAI SDK 接入 DeepSeek 及内部 LLM
向量数据库 Milvus + PyMilvus 知识库/网站页面向量检索
Embedding sentence-transformers + bge-base-zh-v1.5 文本向量化(本地 CPU 推理)
数据库 SQLAlchemy + PyMySQL 登录鉴权(用户表,连接池)
缓存 Redis 图形验证码缓存
鉴权 bcrypt + PyJWT 密码校验 + JWT 签发/解析
验证码 Pillow 图形验证码生成
报表 openpyxl 生成 Excel 报表
文档解析 PyPDF2 / langchain-text-splitters PDF 读取、文本切割
日志 loguru 日志输出
部署 Docker 后端容器化

3.2 前端(chat_py_front)

类别 技术
框架 Vue 3(Composition API)
构建 Vite
UI 组件 Element Plus
状态管理 Pinia
路由 Vue Router
HTTP Axios + fetch(SSE 流式)
Markdown marked + DOMPurify
图表 ECharts

3.3 中间件 / 基础设施

组件 说明
MySQL 用户登录鉴权(sys_user 表)
Redis 图形验证码缓存
Milvus 向量检索(知识库、网站页面)
Nginx 前端静态托管 + 后端反向代理(生产环境)

4. 架构设计

4.1 总体架构

#mermaid-svg-3h1oYNQLLUj7gEkV{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-3h1oYNQLLUj7gEkV .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-3h1oYNQLLUj7gEkV .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-3h1oYNQLLUj7gEkV .error-icon{fill:#552222;}#mermaid-svg-3h1oYNQLLUj7gEkV .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-3h1oYNQLLUj7gEkV .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-3h1oYNQLLUj7gEkV .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-3h1oYNQLLUj7gEkV .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-3h1oYNQLLUj7gEkV .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-3h1oYNQLLUj7gEkV .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-3h1oYNQLLUj7gEkV .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-3h1oYNQLLUj7gEkV .marker{fill:#333333;stroke:#333333;}#mermaid-svg-3h1oYNQLLUj7gEkV .marker.cross{stroke:#333333;}#mermaid-svg-3h1oYNQLLUj7gEkV svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-3h1oYNQLLUj7gEkV p{margin:0;}#mermaid-svg-3h1oYNQLLUj7gEkV .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-3h1oYNQLLUj7gEkV .cluster-label text{fill:#333;}#mermaid-svg-3h1oYNQLLUj7gEkV .cluster-label span{color:#333;}#mermaid-svg-3h1oYNQLLUj7gEkV .cluster-label span p{background-color:transparent;}#mermaid-svg-3h1oYNQLLUj7gEkV .label text,#mermaid-svg-3h1oYNQLLUj7gEkV span{fill:#333;color:#333;}#mermaid-svg-3h1oYNQLLUj7gEkV .node rect,#mermaid-svg-3h1oYNQLLUj7gEkV .node circle,#mermaid-svg-3h1oYNQLLUj7gEkV .node ellipse,#mermaid-svg-3h1oYNQLLUj7gEkV .node polygon,#mermaid-svg-3h1oYNQLLUj7gEkV .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-3h1oYNQLLUj7gEkV .rough-node .label text,#mermaid-svg-3h1oYNQLLUj7gEkV .node .label text,#mermaid-svg-3h1oYNQLLUj7gEkV .image-shape .label,#mermaid-svg-3h1oYNQLLUj7gEkV .icon-shape .label{text-anchor:middle;}#mermaid-svg-3h1oYNQLLUj7gEkV .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-3h1oYNQLLUj7gEkV .rough-node .label,#mermaid-svg-3h1oYNQLLUj7gEkV .node .label,#mermaid-svg-3h1oYNQLLUj7gEkV .image-shape .label,#mermaid-svg-3h1oYNQLLUj7gEkV .icon-shape .label{text-align:center;}#mermaid-svg-3h1oYNQLLUj7gEkV .node.clickable{cursor:pointer;}#mermaid-svg-3h1oYNQLLUj7gEkV .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-3h1oYNQLLUj7gEkV .arrowheadPath{fill:#333333;}#mermaid-svg-3h1oYNQLLUj7gEkV .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-3h1oYNQLLUj7gEkV .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-3h1oYNQLLUj7gEkV .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-3h1oYNQLLUj7gEkV .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-3h1oYNQLLUj7gEkV .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-3h1oYNQLLUj7gEkV .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-3h1oYNQLLUj7gEkV .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-3h1oYNQLLUj7gEkV .cluster text{fill:#333;}#mermaid-svg-3h1oYNQLLUj7gEkV .cluster span{color:#333;}#mermaid-svg-3h1oYNQLLUj7gEkV div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-3h1oYNQLLUj7gEkV .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-3h1oYNQLLUj7gEkV rect.text{fill:none;stroke-width:0;}#mermaid-svg-3h1oYNQLLUj7gEkV .icon-shape,#mermaid-svg-3h1oYNQLLUj7gEkV .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-3h1oYNQLLUj7gEkV .icon-shape p,#mermaid-svg-3h1oYNQLLUj7gEkV .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-3h1oYNQLLUj7gEkV .icon-shape .label rect,#mermaid-svg-3h1oYNQLLUj7gEkV .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-3h1oYNQLLUj7gEkV .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-3h1oYNQLLUj7gEkV .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-3h1oYNQLLUj7gEkV :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} http
静态资源
/chat_py_server/* 反向代理
浏览器
Nginx
chat_py_front 前端
chat_py_server 后端
DeepSeek / 内部 LLM
Milvus 向量库
本地 Embedding 模型 bge-base-zh-v1.5
MySQL: sys_user
Redis: 验证码
SQLite: 会话记忆 / 会话索引
外部业务接口: 企业信息 / 联网搜索

说明:

  • 前端为纯静态 SPA,由 Nginx 托管;接口统一走 /chat_py_server/*,由 Nginx 反向代理到后端 5020 端口,避免跨域。
  • 后端为核心,负责鉴权、多智能体编排、工具调用、RAG 检索、报表生成。
  • 大模型调用 DeepSeek(主)与内部 LLM。
  • 向量检索依赖 Milvus,Embedding 在容器内使用本地模型 CPU 推理。

4.2 后端分层

text 复制代码
controller(接口层)
    ↓
graph(主管编排层:supervisor_graph / agent_descriptions)
    ↓
tools(子智能体工具层)
    ↓
service(业务服务层:model / system)
    ↓
entity + config + model(实体 / 配置 / LLM 客户端)
  • controllerchat_controller(对话)、auth_controller(登录)、doc_controller(文档上传)。
  • graph:主管智能体迭代编排,主管分析问题 → 选择工具 → 并行调用 → 总结输出。
  • tools :每个子智能体是一个 BaseTool,统一注册到主管的可用工具列表。
  • service/system:Milvus、Embedding、Redis、DB、鉴权、会话等基础服务。

4.3 核心流程

4.3.1 对话编排流程(LangGraph)
  1. 前端把 messagesconversationIdskill 通过 SSE 请求发送到 /chat_py_server/chat/v1/chat/completions
  2. 后端鉴权(JWT)后进入 SupervisorGraph
  3. supervisor 节点根据用户问题 + 历史对话 + 已选技能,输出本轮要调用的工具列表(JSON)。
  4. tool_caller 节点并行调用选中的工具,累计结果。
  5. 若还需跨工具依赖(如先查信用代码再查详情),回到 supervisor 继续迭代。
  6. summarize 节点综合工具结果,流式生成最终回答;generate_report 的结构化结果直接透传(不交给 LLM 改写)。
4.3.2 知识库检索(RAG)
  1. 文档上传(doc_controller)→ 读取文本 → 切割 → Embedding → 写入 Milvus 集合。
  2. 提问时 search_knowledge_base 工具将问题向量化 → Milvus 检索 Top-K → 拼成上下文 → 交给大模型生成回答。
4.3.3 登录鉴权流程
  1. GET /captchaImage 生成图形验证码并缓存到 Redis。
  2. POST /login 校验验证码 → 查 MySQL sys_user → 校验 status → BCrypt 校验密码 → 签发 JWT。
  3. GET /getInfo 解析 JWT 返回当前用户信息。
  4. 后续请求通过 Authorization: Bearer <token> 鉴权。

5. 开发流程

5.1 后端本地开发

powershell 复制代码
cd e:\myProject\my-langchain\chat_py_server

# 1) 创建并激活虚拟环境(可选)
python -m venv .venv
.\.venv\Scripts\Activate.ps1

# 2) 安装依赖
pip install -r requirements.txt

# 3) 配置 .env(数据库、Redis、Milvus、模型密钥等)

# 4) 启动(监听 5020)
python app.py

注意:embedding_service 在启动时加载本地 Embedding 模型,首次启动较慢;DEVICE=cpu 需本机已存在模型路径 EMBEDDING_MODEL_PATH

5.2 前端本地开发

powershell 复制代码
cd e:\myProject\my-langchain\chat_py_front

npm install
npm run dev

开发环境通过 Vite 代理把 /chat_py_server 转发到 http://127.0.0.1:5020(见 vite.config.js),无需处理跨域。

5.3 新增一个子智能体工具

  1. app/tools/ 新建 xxx_tool.py,继承 langchain_core.tools.BaseTool,定义 namedescriptionargs_schema_run
  2. app/tools/__init__.py 导出工具类。
  3. app/graph/agent_descriptions.py 注册 ToolDescription 并加入 ALL_TOOLS
  4. app/graph/supervisor_graph.py_TOOL_INSTANCES_execute_single_tool 增加分发逻辑。

5.4 新增一个技能

  1. app/skills/<skill-name>/SKILL.md 编写技能定义(参考 company-detail/SKILL.md)。
  2. app/graph/agent_descriptions.pySKILL_TOOL_MAP 中把技能名映射到目标工具。
  3. 前端 Chat.vueskillOptions 中加入该技能选项。

6. 注意事项

  1. 端口与入口 :后端监听 5020,入口文件是 app.py(内部调用 uvicorn.run)。镜像采用「Dockerfile.base 装依赖 + Dockerfile 只 COPY 源码」两层构建,CMDpython app.py
  2. 容器内监听地址.envSERVER_HOST 若为 127.0.0.1,容器内只能本机访问,需改为 0.0.0.0
  3. SERVER_WORKERS=1 :LangGraph 使用 AsyncSqliteSaver 会话记忆,且 Embedding 模型/工具实例在进程内加载,建议保持单 worker,避免多进程资源重复与 SQLite 竞争。
  4. SSE 流式 :对话接口为 SSE 流式输出,Nginx 反向代理需关闭缓冲(proxy_buffering off)并调大 proxy_read_timeout
  5. Embedding 模型 :容器内 EMBEDDING_MODEL_PATH 需指向挂载进来的模型目录(如 /opt/embedding_model),且内存需足够(torch CPU + 模型约需数 GB)。模型目录顶层必须包含 config.jsonpytorch_model.bin/model.safetensors,否则启动报 OSError
  6. 前端子路径 :前端部署在 /chat_py_front/ 子路径时,需设置 Vite base 与 Vue Router createWebHistory('/chat_py_front/'),否则资源引用仍为根路径 /assets/... 导致 404。
  7. Nginx 502 :Nginx 反向代理 502 通常是连不到后端 127.0.0.1:5020,常见于 Nginx 跑在容器内(127.0.0.1 指向容器自身)或 RedHat SELinux 拦截出站连接,详见 7.6。
  8. 大模型密钥 :DeepSeek / 内部 LLM / 博查 / 智谱等密钥在 .env 中配置,注意保密,不要提交到仓库。
  9. sys_user :登录依赖 MySQL 中若依标准的 sys_user 表(user_iduser_namenick_namepasswordstatusdel_flag),密码需为 BCrypt 密文。
  10. 报表/会话持久化 :报表文件、checkpoints.sqlite(会话记忆)、conversations.sqlite(会话索引)默认写在项目根目录,容器部署建议挂载到宿主机目录以免重启丢失。
  11. Milvus 集合 :文档知识库集合 ai_demo_doc 会在上传文档时自动创建;网站页面集合 ai_demo_website 需按业务预先写入。

7. 部署详细步骤

前提:服务器已安装 Docker / Docker Compose,且 MySQL、Redis 已安装(本方案不再安装它们)。

部署组件清单:

组件 部署方式 端口
Milvus(etcd + minio + standalone) docker-compose-milvus.yml 19530 / 9091 / 9000 / 9001
chat_py_server(后端) Docker 构建 5020
chat_py_front(前端) 构建静态产物 + Nginx 80

7.1 部署 Milvus

服务器上使用仓库已有的 docker-compose-milvus.yml(镜像已确认可用):

bash 复制代码
cd /path/to/chat_py_server

# 启动 Milvus(etcd、minio、milvus-standalone)
docker compose -f docker-compose-milvus.yml up -d

# 查看状态
docker compose -f docker-compose-milvus.yml ps
docker logs -f milvus-standalone

默认暴露:

  • 19530:Milvus gRPC 服务端口(后端通过它连接)
  • 9091:Milvus 健康检查
  • 9000 / 9001:MinIO 存储

验证连通:

bash 复制代码
curl -f http://127.0.0.1:9091/healthz

默认账号为 root / Milvus(与 .env 一致)。若服务器网络环境不同,请把后端 .envMILVUS_URL 指向实际可访问地址。


7.2 准备后端配置(.env)

chat_py_server/.env 中调整以下项为部署环境实际值:

dotenv 复制代码
# 监听地址必须为 0.0.0.0,容器外部才能访问
SERVER_HOST="0.0.0.0"
SERVER_PORT=5020
SERVER_WORKERS=1

# Embedding 模型:指向容器内挂载路径
EMBEDDING_MODEL_PATH="/opt/embedding_model"

# Milvus:本机部署则为 http://<服务器内网IP>:19530
MILVUS_URL="http://<服务器内网IP>:19530"
MILVUS_USER="root"
MILVUS_PASSWORD="Milvus"

# MySQL(已安装,按实际填写)
MYSQL_HOST="<mysql地址>"
MYSQL_PORT=3306
MYSQL_USER="root"
MYSQL_PASSWORD="<密码>"
MYSQL_DATABASE="demo"

# Redis(已安装,按实际填写)
REDIS_HOST="<redis地址>"
REDIS_PORT=6379
REDIS_PASSWORD="<密码>"
REDIS_DB=1

7.3 部署后端 chat_py_server(Docker)

7.3.1 构建文件(基础镜像 + 应用镜像)

为避免每次改代码都重新安装依赖,采用两层镜像:

  • Dockerfile.base:安装全部依赖,构建为 chat_py_server:base(仅 requirements.txt 变化时重建)。
  • Dockerfile:基于 chat_py_server:base,只 COPY . .,构建为 chat_py_server:latest
  • .dockerignore:排除 .env、数据目录、缓存等,避免密钥打进镜像并加快 COPY。

Dockerfile.base

dockerfile 复制代码
FROM python:3.10-slim

LABEL maintainer="jxbd"

WORKDIR /app

COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt \
    -i https://pypi.tuna.tsinghua.edu.cn/simple \
    --default-timeout=600

Dockerfile

dockerfile 复制代码
FROM chat_py_server:base

LABEL maintainer="jxbd"

WORKDIR /app

COPY . .

CMD ["python", "app.py"]

.dockerignore

text 复制代码
.env
__pycache__/
*.pyc
.venv/
venv/
data/
report_files/
checkpoints.sqlite
conversations.sqlite
*.sqlite
.git/
.gitignore
*.md
docs/
docker-compose*.yml
Dockerfile*

说明:torch==2.6.0 默认安装 CPU 版,基础镜像体积较大,但只需在 requirements.txt 变化时重建一次。

7.3.2 docker-compose.yml

使用以下 chat_py_server/docker-compose.yml(挂载模型、.env、数据目录):

yaml 复制代码
version: "3.8"
services:
  chat_py_server:
    image: chat_py_server:latest
    container_name: chat_py_server
    environment:
      SERVER_HOST: "0.0.0.0"
      SERVER_PORT: "5020"
      EMBEDDING_MODEL_PATH: "/opt/embedding_model"
      LANGGRAPH_SQLITE_PATH: "/app/data/checkpoints.sqlite"
      CONVERSATION_SQLITE_PATH: "/app/data/conversations.sqlite"
      REPORT_FILE_DIR: "/app/data/report_files"
    volumes:
      - "./.env:/app/.env"
      # 宿主机 Embedding 模型目录(按实际路径修改)
      - "/opt/chat/bertmodel/BAAI/bge-base-zh-v1.5:/opt/embedding_model"
      # 数据持久化
      - "./data:/app/data"
    ports:
      - "5020:5020"
    restart: unless-stopped

environment 中的变量会覆盖 .env 中的同名配置(load_dotenv 默认不覆盖已存在的环境变量)。MILVUS_URL 建议直接在 .env 中配置。

挂载源 /opt/chat/bertmodel/BAAI/bge-base-zh-v1.5 必须是包含 config.jsonpytorch_model.bin/model.safetensors 的那一层目录,否则启动报 OSError(见 7.6)。

7.3.3 构建并启动
bash 复制代码
cd /path/to/chat_py_server

mkdir -p data

# 1) 基础镜像:仅 requirements.txt 变化时重建
docker build -f Dockerfile.base -t chat_py_server:base .

# 2) 应用镜像:每次改代码后构建(很快,不再 pip install)
docker build -t chat_py_server:latest .

# 3) 启动
docker compose up -d

# 4) 实时查看日志(Ctrl+C 退出)
docker compose logs -f chat_py_server

验证:

bash 复制代码
curl http://127.0.0.1:5020/chat_py_server/auth/v1/captchaImage
7.3.4 不使用 docker compose 的等价命令(可选)
bash 复制代码
cd /path/to/chat_py_server

docker build -f Dockerfile.base -t chat_py_server:base .
docker build -t chat_py_server:latest .

docker run -d \
  --name chat_py_server \
  -p 5020:5020 \
  -e SERVER_HOST=0.0.0.0 \
  -e EMBEDDING_MODEL_PATH=/opt/embedding_model \
  -v "$(pwd)/.env:/app/.env" \
  -v "/opt/chat/bertmodel/BAAI/bge-base-zh-v1.5:/opt/embedding_model" \
  -v "$(pwd)/data:/app/data" \
  --restart unless-stopped \
  chat_py_server:latest

7.4 部署前端 chat_py_front

前端以 /chat_py_front/ 子路径部署(与后端 /chat_py_server/ 区分)。

7.4.1 配置子路径
  1. vite.config.js 生产构建 base 设为 /chat_py_front/(开发环境保持 /):
js 复制代码
export default defineConfig(({ mode }) => ({
  base: mode === 'production' ? '/chat_py_front/' : '/',
  // ...其余配置
}))
  1. src/router/index.js 路由 base 设为 /chat_py_front/
js 复制代码
const router = createRouter({
  history: createWebHistory('/chat_py_front/'),
  routes,
})

这一步必须做,否则打包后 index.html 里的资源仍引用根路径 /assets/...,部署到子路径会 404。

7.4.2 构建静态产物
bash 复制代码
cd /path/to/chat_py_front

npm install
npm run build

构建产物在 chat_py_front/dist/,上传到服务器 /opt/project/front/chat_py_front/

前端默认 VITE_API_BASE 为空,接口走同源 /chat_py_server/*,由 Nginx 反向代理,无需修改。

7.4.3 部署到 Nginx

Nginx 配置(注意 root 写父目录 /opt/project/front/,不要重复写 chat_py_front):

nginx 复制代码
server {
    listen 80;
    server_name medaide.com.cn;

    # 前端静态资源(子路径部署)
    location /chat_py_front/ {
        root /opt/project/front/;
        index index.html;
        try_files $uri $uri/ /chat_py_front/index.html;
    }

    # 后端接口反向代理(含 SSE 流式)
    location /chat_py_server/ {
        proxy_pass http://127.0.0.1:5020;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        # SSE 流式必须关闭缓冲并调大超时
        proxy_buffering off;
        proxy_cache off;
        proxy_read_timeout 300s;
    }
}

重载 Nginx:

bash 复制代码
nginx -t
nginx -s reload

浏览器访问 https://medaide.com.cn/chat_py_front/,使用 MySQL sys_user 中的账号密码登录。

若 Nginx 跑在 Docker 容器里,proxy_pass http://127.0.0.1:5020 连的是容器自身,需改成宿主机内网 IP 或 host.docker.internal(见 7.6)。


7.5 部署后联调验证

  1. 登录验证
bash 复制代码
# 获取验证码
curl http://<服务器IP>/chat_py_server/auth/v1/captchaImage

# 登录(需先填写正确验证码 uuid/code)
curl -X POST http://<服务器IP>/chat_py_server/auth/v1/login \
  -H "Content-Type: application/json" \
  -d '{"username":"admin","password":"<密码>","code":"<验证码>","uuid":"<uuid>"}'

# 获取用户信息
curl http://<服务器IP>/chat_py_server/auth/v1/getInfo \
  -H "Authorization: Bearer <token>"
  1. 对话验证:浏览器登录后发起提问,确认 SSE 流式回答正常、图表正常渲染、报表可下载。

  2. 知识库验证:通过文档上传接口写入文档后,选择"知识库查询"技能提问,确认能检索到文档内容。


7.6 常见问题排查

后端启动报 OSError: no file named pytorch_model.bin/model.safetensors

说明挂载到 /opt/embedding_model 的目录里没有模型权重文件。模型目录顶层必须包含 config.jsonpytorch_model.bin(或 model.safetensors)。

bash 复制代码
ls -la /opt/chat/bertmodel/BAAI/bge-base-zh-v1.5
find /opt/chat/bertmodel -name "pytorch_model.bin" -o -name "model.safetensors" 2>/dev/null

把 docker-compose 的挂载源改成真正包含权重文件的那一层目录,再 docker compose up -d 重启。

访问接口 502

502 表示 Nginx 连不上后端 127.0.0.1:5020。先本地验证后端是否正常:

bash 复制代码
curl http://127.0.0.1:5020/chat_py_server/auth/v1/captchaImage
  • 本地 curl 通、Nginx 502 → 大概率是以下之一:

    1. Nginx 跑在 Docker 容器里,其 127.0.0.1 指向容器自身,需改 proxy_pass http://<宿主机内网IP>:5020(或用 host.docker.internal)。

    2. RedHat/CentOS 的 SELinux 拦截 Nginx 出站连接:

      bash 复制代码
      setsebool -P httpd_can_network_connect 1
  • 本地 curl 不通 → 后端没起来,用 docker compose logs -f chat_py_server 看崩溃原因(多为模型路径问题)。

前端资源 404 / 500
  • 资源路径仍是 /assets/...(无 /chat_py_front/ 前缀)→ 前端没按 7.4.1 设置 base 或没重新构建部署,重新 npm run build 并覆盖 dist/
  • Nginx 报 internal redirection cycleroot 写重了 chat_py_frontroot 应写父目录 /opt/project/front/
  • Nginx 报 403 → 检查文件权限(chmod -R 755)、SELinux 上下文(chcon -R -t httpd_sys_content_t)。
实时查看后端日志
bash 复制代码
cd /path/to/chat_py_server
docker compose logs -f chat_py_server
docker compose logs -f --tail=200 chat_py_server
# 或
docker logs -f --tail=200 chat_py_server

8. 附录:关键配置项速查

配置项 说明 默认值
SERVER_HOST / SERVER_PORT 后端监听地址与端口 127.0.0.1 / 5020
SERVER_PREFIX 接口前缀 chat_py_server
DEEPSEEK_API_* DeepSeek 模型接入 ---
LLM_API_* 内部大模型接入 ---
EMBEDDING_MODEL_PATH 本地 Embedding 模型路径 ---
MILVUS_URL / MILVUS_USER / MILVUS_PASSWORD 向量库连接 ---
MILVUS_COLLECTION_DOC 文档知识库集合 ai_demo_doc
MILVUS_COLLECTION_WEBSITE 网站页面集合 ai_demo_website
MYSQL_* 登录鉴权数据库 ---
REDIS_* 验证码缓存 ---
JWT_SECRET / JWT_EXPIRE_MINUTES JWT 密钥与有效期 ---
CAPTCHA_ENABLED / CAPTCHA_EXPIRE_MINUTES 验证码开关与有效期 true / 2
REPORT_FILE_DIR 报表文件目录 report_files
LANGGRAPH_SQLITE_PATH 会话记忆 SQLite checkpoints.sqlite
CONVERSATION_SQLITE_PATH 会话索引 SQLite conversations.sqlite
相关推荐
Lifangyun_WD1 小时前
RTX 5090 与 RTX PRO 6000 怎么选?32GB 和 96GB 显存分别适合哪些 AI 任务
人工智能·aigc·gpu算力·芯片·gpu租赁
hqyjzsb1 小时前
零 AI 项目经验,学 Python 转型 AI 的正确顺序是什么?
开发语言·人工智能·python·算法·职场和发展·数据挖掘·数据分析
微功夫信息技术1 小时前
分层多智能体强化学习驱动的非急救转运公平 - 效率统一调度系统研究与实践
人工智能·学习·算法·动态规划
TechEdu2026061 小时前
[人工智能]AI芯片家族与产品目录指南
人工智能·ai
不会写代码的女程序猿1 小时前
中小康养门店选型参考|明理 AI 四诊仪场景适配与投入回报分析
大数据·人工智能·科技·ai·健康医疗
机器人猎头David1 小时前
VLA、世界模型、强化学习,在机器人里分别解决什么问题?
人工智能·机器人·机器人猎头·机器人猎头公司
dianziyao_1 小时前
第 4.1 篇:让 Codex 理解你的双链——AI 辅助发现笔记间的关联
人工智能·笔记
围炉聊科技1 小时前
网站把自己变成 MCP server:OpenAI 第一个用上 WebMCP
人工智能
葡萄城技术团队2 小时前
一句话生成数据透视表?SpreadJS AI 如何把分析需求变成行、列和值
人工智能