312 lines
13 KiB
Markdown
312 lines
13 KiB
Markdown
# 大模型智能问答客服系统系统设计文档
|
||
|
||
**日期:** 2026-03-31
|
||
**状态:** 已确认
|
||
**技术栈:** Python / FastAPI / Vue3 / DeepSeek / PostgreSQL / Redis
|
||
|
||
---
|
||
|
||
## 一、项目背景与目标
|
||
|
||
将企业内部的报销制度、软件操作手册、财务/科研流程、常见问题汇总等文档接入大模型,构建一套智能问答客服系统。用户可以用自然语言提问,系统给出答案并注明引用来源;支持上传截图辅助提问。
|
||
|
||
**核心目标:**
|
||
- 文档知识库化,降低重复人工咨询成本
|
||
- 答案可追溯,每条回答标注来源文档、章节、页码或段落
|
||
- 支持截图上传,辅助描述操作类问题
|
||
- 管理员可自助维护文档,无需开发介入
|
||
|
||
**本期检索策略目标:**
|
||
- 前期不引入向量数据库与 embedding
|
||
- 以“先选文档,再选章节,再定位段落”为主链路,优先保证准确率和可解释性
|
||
- 允许用大模型对候选文档和章节做重排,但不让大模型承担全库检索职责
|
||
|
||
---
|
||
|
||
## 二、用户角色
|
||
|
||
| 角色 | 权限 |
|
||
|------|------|
|
||
| `employee`(员工/外部合作方) | 对话问答、查看本人历史会话 |
|
||
| `admin`(管理员) | 文档上传/删除/管理、用户管理(创建/角色分配/禁用) |
|
||
|
||
---
|
||
|
||
## 三、整体架构
|
||
|
||
```text
|
||
用户浏览器
|
||
├─ 员工:问答 + 截图上传
|
||
└─ 管理员:文档上传 / 文档管理 / 用户管理
|
||
│
|
||
▼
|
||
FastAPI 后端
|
||
├─ 认证模块
|
||
├─ 对话问答模块
|
||
├─ 文档管理模块
|
||
└─ 检索编排模块
|
||
│
|
||
├─ PostgreSQL
|
||
│ ├─ 用户/会话/消息
|
||
│ ├─ 文档元数据
|
||
│ ├─ 文档章节索引
|
||
│ └─ 文档段落索引
|
||
│
|
||
├─ Redis
|
||
│ ├─ 验证码 / 速率限制
|
||
│ └─ Celery Broker / Cache
|
||
│
|
||
├─ 本地文件系统
|
||
│ ├─ 原始文档
|
||
│ └─ 解析后的规范化文本
|
||
│
|
||
├─ DeepSeek Chat
|
||
│ ├─ 候选文档/章节重排
|
||
│ └─ 基于引用片段生成答案
|
||
│
|
||
└─ 阿里云 OCR
|
||
└─ 截图文字识别
|
||
```
|
||
|
||
---
|
||
|
||
## 四、核心模块设计
|
||
|
||
### 4.1 认证模块
|
||
|
||
- **账号名:** 邮箱地址
|
||
- **注册管控:** 关闭完全开放的自助注册;支持两种方式创建账号:
|
||
- 管理员后台手动创建(指定角色)
|
||
- 邮箱自助注册(仅限白名单域名,如 `@company.com`,可配置),默认角色 `employee`
|
||
- **登录方式:**
|
||
- 邮箱 + 密码
|
||
- 邮箱 + 验证码(6位数字,5分钟有效,存 Redis)
|
||
- **验证码防刷:**
|
||
- 同一邮箱 60 秒内不可重复发送
|
||
- 同一 IP 每小时限制 10 次
|
||
- **Token 机制:**
|
||
- Access Token(JWT):有效期 2 小时
|
||
- Refresh Token:有效期 7 天,存 Redis,可主动吊销
|
||
- 管理员禁用账号时,将该账号现有 Token 加入 Redis 黑名单,立即失效
|
||
- **邮件服务:** QQ 邮箱 SMTP(`smtp.qq.com:465`,SSL,授权码鉴权)
|
||
|
||
### 4.2 文档管理模块
|
||
|
||
| 功能 | 说明 |
|
||
|------|------|
|
||
| 上传 | 支持 PDF、Word(.docx)、Excel(.xlsx),单文件限制 50MB;服务端验证 Magic Bytes + 扩展名双重校验 |
|
||
| 原始文件存储 | 原始文件保存到本地文件系统,按文档 ID / 版本号分目录存放 |
|
||
| 解析 | PDF 用 `pdfplumber`,Word 用 `python-docx`,Excel 按 Sheet 转为规范化文本或 Markdown 表格 |
|
||
| 结构化 | 解析后生成三级结构:`document`、`section`、`chunk`;章节标题、层级、页码范围、段落顺序均保留 |
|
||
| 规范化文本落盘 | 每份文档额外保存解析后的文本产物,便于调试、离线检查和兜底检索 |
|
||
| 索引入库 | 文档标题、文件名、标签、章节标题、段落正文、来源位置全部写入 PostgreSQL |
|
||
| 异步处理 | Celery + Redis;上传后后台解析、结构化、索引化,前端显示状态 |
|
||
| 状态机 | `pending` -> `processing` -> `active` / `failed` |
|
||
| 删除 | 先将文档标记 `deleting`,再删索引、删解析文本、删原始文件,任一步失败均可幂等重试 |
|
||
| 更新(版本切换) | 新版本先入库为 `pending`;索引就绪后原子切换为 `active`,旧版本转 `superseded` |
|
||
|
||
**结构化原则:**
|
||
- 文档级:文件名、别名、标签、摘要
|
||
- 章节级:目录项、一级/二级/三级标题、页码范围、Sheet 名称
|
||
- 段落级:正文、表格文本、所属章节、顺序号、来源位置
|
||
|
||
### 4.3 问答检索模块
|
||
|
||
本期不使用向量检索,主链路采用“规则召回 + 大模型重排 + 段落精定位”。
|
||
|
||
**问答流程(SSE 流式输出):**
|
||
|
||
```text
|
||
用户输入(文本 + 可选截图)
|
||
-> OCR 识别截图文字(阿里云 OCR)
|
||
-> 合并为最终 Query 文本
|
||
-> Query 归一化(术语、别名、关键词、数字、表单名)
|
||
-> 文档候选召回(文件名 + 标签 + 文档摘要 + FTS)
|
||
-> 章节候选召回(目录项/章节标题/小节标题 + FTS)
|
||
-> 大模型重排候选文档与章节
|
||
-> 在最终候选章节内做段落精定位
|
||
-> 取命中段落及相邻段扩展上下文
|
||
-> 组装 Prompt(系统提示 + 引用片段 + 历史 5 轮 + 用户问题)
|
||
-> 调用 DeepSeek Chat API(SSE 流式输出)
|
||
-> 返回答案 + 引用来源(文档名 + 章节标题 + 页码/段落号)
|
||
```
|
||
|
||
**设计原则:**
|
||
- 大模型只负责候选重排,不负责全库检索
|
||
- 先缩小范围,再精确定位,优先提升召回准确率
|
||
- 只在少量明确候选章节中做正文定位,避免把无关文档片段带进 Prompt
|
||
- 若未命中足够可信的文档/章节,明确回答“未在当前知识库中找到依据”
|
||
|
||
**查询归一化:**
|
||
- 术语同义词映射,如“报销/报账”“出差/差旅”“附件/上传材料”
|
||
- 抽取数字、金额、日期、制度名、表单名
|
||
- 去除无意义停用词,保留关键短语
|
||
|
||
**候选控制:**
|
||
- 文档候选最多 5 个
|
||
- 章节候选最多 8 到 12 个
|
||
- 大模型重排后仅保留 1 到 3 个章节
|
||
- 最终送入生成模型的正文片段控制在 6 到 12 段
|
||
|
||
**Prompt 设计原则:**
|
||
- 模型只能基于提供的引用片段回答
|
||
- 依据不足时必须明确说不知道或未找到
|
||
- 在答案末尾输出引用片段编号,系统映射成文档名、章节、页码或段落号
|
||
- 多轮对话只携带最近 5 轮历史
|
||
|
||
**后期扩展点:**
|
||
- 检索层抽象为 `RetrieverInterface`
|
||
- 重排层抽象为 `RerankerInterface`
|
||
- 后期可平滑增加 BM25 增强、RRF 融合、向量检索、Reranker 模型
|
||
|
||
### 4.4 数据模型(核心表)
|
||
|
||
```text
|
||
users
|
||
id, email, hashed_password, role, is_active, created_at
|
||
|
||
refresh_tokens
|
||
id, user_id, token_hash, expires_at, revoked
|
||
|
||
token_blacklist
|
||
jti, expires_at
|
||
|
||
documents
|
||
id, name, file_path, normalized_text_path, status, version_num,
|
||
supersedes_id, created_by, created_at, summary, tags_json
|
||
|
||
document_aliases
|
||
id, document_id, alias
|
||
|
||
document_sections
|
||
id, document_id, parent_section_id, title, level,
|
||
page_start, page_end, section_order, title_tokens
|
||
|
||
doc_chunks
|
||
id, document_id, section_id, chunk_index, text,
|
||
source_location, page_no, paragraph_no, tsv
|
||
|
||
conversations
|
||
id, user_id, title, created_at
|
||
|
||
messages
|
||
id, conversation_id, role, content, sources_json, created_at
|
||
```
|
||
|
||
**说明:**
|
||
- `documents.summary` 用于文档候选粗筛和大模型重排输入
|
||
- `document_sections` 是本期准确率的关键索引层
|
||
- `doc_chunks.tsv` 用于 PostgreSQL 全文检索
|
||
- `source_location` 统一映射为“页码 / 段落号 / Sheet 名称 / 章节路径”
|
||
|
||
### 4.5 前端页面
|
||
|
||
| 页面 | 访问角色 | 核心功能 |
|
||
|------|---------|---------|
|
||
| 登录/注册页 | 所有人 | 双模式登录、邮箱注册(白名单域名)、验证码发送 |
|
||
| 对话页 | employee / admin | 左侧会话列表、右侧 SSE 流式对话、截图上传、引用来源展示 |
|
||
| 文档管理页 | admin | 文档列表、上传、删除、解析状态查看、版本切换状态 |
|
||
| 用户管理页 | admin | 用户列表、创建账号、角色分配、禁用(即时生效) |
|
||
|
||
---
|
||
|
||
## 五、技术选型
|
||
|
||
| 层次 | 选型 | 说明 |
|
||
|------|------|------|
|
||
| 前端 | Vue3 + Element Plus | 成熟后台组件生态 |
|
||
| 后端 | FastAPI + Python 3.11 | 异步支持较好,适合 AI 服务编排 |
|
||
| 关系数据库 | PostgreSQL | 存用户、会话、文档元数据、章节索引、段落索引;支持 FTS |
|
||
| 缓存 / 队列 | Redis | 验证码、黑名单、限流、Celery Broker |
|
||
| 文件存储 | 本地文件系统 | 存原始文档与解析后的规范化文本,挂载独立数据盘 |
|
||
| 异步任务 | Celery + Redis | 文档解析、结构化、索引化后台执行 |
|
||
| 检索方式 | PostgreSQL FTS + 规则打分 | 前期不引入向量库,优先准确率与可解释性 |
|
||
| 重排方式 | DeepSeek Chat | 对候选文档与章节做小范围重排 |
|
||
| OCR | 阿里云 OCR | 截图文字识别 |
|
||
| 生成模型 | DeepSeek Chat | 基于引用片段生成答案 |
|
||
| 流式输出 | SSE(Server-Sent Events) | FastAPI 原生支持,前端 `EventSource` 接收 |
|
||
| 邮件 | QQ 邮箱 SMTP(465/SSL) | 发送验证码,额外成本低 |
|
||
| 进程管理 | systemd | FastAPI(uvicorn)、Celery Worker 均以 systemd service 守护 |
|
||
| Python 环境 | venv | 应用依赖与系统 Python 隔离,`requirements.txt` 固定版本 |
|
||
| 敏感配置 | `.env` 文件 | API Key、SMTP 授权码、OCR Key 等全部通过环境变量注入,文件权限 600 |
|
||
|
||
---
|
||
|
||
## 六、云端部署架构
|
||
|
||
所有服务部署在同一台物理服务器上,通过 systemd 管理各进程,无需容器化。
|
||
|
||
```text
|
||
用户浏览器
|
||
|
|
||
HTTPS
|
||
|
|
||
【同一台服务器】
|
||
|
|
||
Nginx
|
||
|
|
||
+-- Vue3 静态资源(/var/www/llm_ask)
|
||
|
|
||
+-- FastAPI(uvicorn,systemd service)
|
||
|
|
||
+-- PostgreSQL(本机,unix socket 连接)
|
||
+-- Redis(本机,127.0.0.1:6379)
|
||
+-- Celery Worker(systemd service,concurrency=2)
|
||
+-- 本地文件系统(独立数据盘挂载点,如 /data/llm_ask)
|
||
+-- DeepSeek API(外部)
|
||
+-- 阿里云 OCR API(外部)
|
||
```
|
||
|
||
**推荐初期服务器配置:**
|
||
- 单台服务器:8核16G ECS/CVM
|
||
- PostgreSQL、Redis、FastAPI、Celery、Nginx 全部同机部署
|
||
- 数据盘单独挂载(存文档文件),系统盘与数据分离
|
||
- PostgreSQL 调优:`shared_buffers = 2GB`,`effective_cache_size = 6GB`
|
||
- Redis 限制:`maxmemory 512mb`,`maxmemory-policy allkeys-lru`
|
||
- Celery:`--concurrency=2`,避免文档解析时内存峰值压垮其他服务
|
||
|
||
**进程管理(systemd):**
|
||
|
||
| 服务 | 启动命令 | 重启策略 |
|
||
|------|---------|---------|
|
||
| `llm-api` | `uvicorn app.main:app --workers 2 --port 8000` | `Restart=always` |
|
||
| `llm-celery` | `celery -A app.worker worker --concurrency=2` | `Restart=always` |
|
||
| `postgresql` | 系统包自带 | `Restart=on-failure` |
|
||
| `redis` | 系统包自带 | `Restart=on-failure` |
|
||
| `nginx` | 系统包自带 | `Restart=on-failure` |
|
||
|
||
---
|
||
|
||
## 七、人日估算
|
||
|
||
| 模块 | 工作内容 | 人日 |
|
||
|------|---------|:----:|
|
||
| 项目初始化 | 目录结构、venv、systemd service 模板、`.env` 规范 | 2 |
|
||
| 认证模块 | 邮箱注册/登录、验证码、防刷、JWT、Refresh Token、角色权限 | 6 |
|
||
| 文档管理后端 | 上传、校验、解析、结构化、章节索引、段落索引、状态机、补偿删除、版本切换 | 8 |
|
||
| 问答检索后端 | Query 归一化、文档召回、章节召回、LLM 重排、段落精定位、Prompt 组装、SSE 输出 | 7 |
|
||
| OCR 集成 | OCR 接入、与 Query 合并 | 2 |
|
||
| 前端:登录/注册 | 双模式登录、注册、验证码交互 | 2 |
|
||
| 前端:对话页 | 会话列表、SSE 流式渲染、截图上传、引用来源展示 | 7 |
|
||
| 前端:文档管理页 | 上传、列表、处理状态轮询、删除 | 3 |
|
||
| 前端:用户管理页 | 用户列表、创建、角色分配、禁用 | 2 |
|
||
| 集成测试 & 部署 | 云端部署、域名、SSL、systemd 服务配置、联调 | 5 |
|
||
| Buffer | 调试、需求微调、第三方 API 联调 | 6 |
|
||
| **合计** | | **50** |
|
||
|
||
**工期参考:**
|
||
- 1 人独立开发:约 9 到 10 周
|
||
- 前后端 2 人并行:约 5 到 6 周可上线基础版本
|
||
- 后期升级到混合检索:额外约 5 到 8 人日
|
||
|
||
---
|
||
|
||
## 八、后期演进路线
|
||
|
||
1. **检索增强:** 从 PostgreSQL FTS 升级到 BM25 / 更细粒度规则打分
|
||
2. **混合检索:** 在现有 `RetrieverInterface` 基础上增加向量检索,与词法检索融合
|
||
3. **重排增强:** 用专门的 reranker 模型替代通用聊天模型做候选重排
|
||
4. **文件存储迁移:** 本地文件系统迁移到阿里云 OSS
|
||
5. **SSO 集成:** 对接企业 LDAP / 统一认证
|
||
6. **用量统计:** 统计问答次数、热门问题、未命中问题、低置信问题
|