软件工程项目:知问(DocQA)—— RAG 私有知识库文档问答系统

作业所属课程:软件工程
班级:24级计科7班
作业要求:完成团队展示、选题报告与需求分析
团队名称:骞文(千问)队
团队成员:马文青(3124004255)、黎伟骞(3124004249)
项目 GitHub:https://github.com/MWQ111/ma-ai-chat5201314


一、作业的目标

1.1 作业目标

本课程大项目要求我们基于智能体(Agent)技术开发一款真实、可用、有价值的软件:智能体要能嵌入到我们开发的软件系统中,软件需要最终上线运行供老师与同学检查,选题必须来源于真实需求,并且要在课堂上答辩展示。

1.2 我们对作业目标的理解

我们认为这门课的核心不是"做一个聊天机器人",而是培养三条能力:

  1. 把 AI 能力变成真实可用的软件产品——智能体不是独立玩具,而是要嵌进一个完整的软件系统(前端、后端、存储、部署)里,让用户真的能用;
  2. 解决真实需求——选题要来自真实场景,而不是"为了用 AI 而用 AI";
  3. 工程化能力——不是调通一个接口就算完,而是要有错误处理、降级、测试、性能评估、部署上线这些软件工程的基本功。

围绕这三点,我们把选题定为:为个人和小组构建一个"私有知识库文档问答系统"——用户把自己的文档(PDF / TXT / Markdown)上传到系统里,AI 基于这些私有文档回答问题,而不是靠模型训练数据里泛泛而谈。


二、团队展示

2.1 队名

骞文(千问)队

队名取自两位成员名字:骞(黎伟骞)+ 文(马文青),谐音"千问"——寓意"千问千答",正呼应本项目"私有知识库文档问答"的定位:任何文档,千问皆答。

2.2 团队项目的具体规划及描述

项目定位:知问(DocQA)是一款 RAG 私有知识库文档问答系统。用户上传自己的文档(支持 PDF / TXT / Markdown),系统完成切分、向量化、入库;用户提问时,系统先从私有知识库中检索最相关的片段,再由大模型基于这些片段生成带依据的回答。整个过程"文档只进自己人的知识库",实现私有知识的高效问答。

规划阶段:

阶段 内容 状态
需求分析 调研"文档多、查找难、想直接问文档"的真实场景,确定核心功能与验收标准 ✅
核心链路 文档上传 → 切分 → 向量化 → 语义检索 → 问答(LangChain + ChromaDB + bge-m3) ✅
性能优化 两层缓存(精确 + 语义),缓存命中率 44%、P50 延迟 0.90s ✅
质量优化 Rerank 精排:召回 20 → CrossEncoder 重排 → 取回 3,评测 10/10 + trap 3/3 ✅
工程化 87 个自动化测试、优雅降级、Docker 一键部署、GitHub Actions CI ✅
上线运行 部署到公网,供老师、助教和同学检查 🚧 进行中

2.3 队员风采

马文青(3124004255)

  • 性格:踏实、目标感强,遇到问题喜欢深挖到底
  • 擅长技术:Python、LangGraph / Agent 编排、RAG 检索、自动化测试
  • 兴趣爱好:AI 应用开发、研究 Agent 可靠性
  • 希望的软工角色:后端开发 / 总体设计 / 测试

黎伟骞(3124004249)

  • 性格:动手能力强,注重界面与交互体验
  • 擅长技术:Streamlit 前端、Flask REST API、Docker 部署
  • 兴趣爱好:前端交互、部署运维
  • 希望的软工角色:前端开发 / API / 部署

2.5 团队项目的愿景

我们希望"知问"成为每个人身边的文档问答专家:不管是学生整理课程资料、小组沉淀项目文档,还是个人搭建私有知识库,都能三步完成"上传文档 → 提问 → 得到带依据的回答"。未来希望支持更多文档格式、多人协作的知识库,让"问自己的文档"像聊天一样自然,让私有知识真正被用起来。


三、需求分析文档

3.1 迭代记录表格

迭代 时间 内容 结果
V0.1 2026-09 项目起步:多模型对话核心(DeepSeek / OpenAI / Ollama 统一适配) 可用
V0.2 2026-09~10 RAG 文档检索:PDF / TXT / MD 上传、切分、向量化、语义检索 可用
V0.3 2026-10 性能优化:Redis 缓存 + 语义缓存阈值实验(bge-m3,0.95 零误判) 缓存命中率 44%,P50 0.90s
V0.9 2026-11-07 测试规模扩展(鉴权等新增用例),产品改名「知问 DocQA」 87 用例全绿
V0.4 2026-10-14 建立 RAG 评测集 v1 与评测文档 评测可复现
V0.5 2026-10-15 Rerank 精排实验(独立脚本验证) 10/10 + trap 3/3
V0.6 2026-10-16 精排工程化:配置开关、惰性加载、异常降级 83 回归全绿(后续增补至 87)
V0.7 2026-10-17 精排延迟压测(函数级 A/B) +1.1s 换正确率,数字落档
V0.8 2026-11-07 产品重新定位为「知问 DocQA」私有知识库问答系统,页面与文档改名 进行中

3.3 思维导图

知问(DocQA)RAG 私有知识库文档问答系统
├── 用户端
│   ├── 文档上传(PDF / TXT / Markdown)
│   ├── 文档管理(列表 / 删除 / 状态)
│   ├── 文档问答(提问 → 检索 → 带依据回答)
│   └── 结果展示(来源引用 / 相似度 / 复制)
├── 检索链路
│   ├── 文档切分(RecursiveCharacterTextSplitter,250 字 / 重叠 50)
│   ├── 向量化(bge-m3 多语言嵌入,1024 维)
│   ├── 向量存储(ChromaDB,cosine 距离)
│   └── 语义检索(top_k=3)
├── 性能优化
│   ├── 两层缓存(精确 key 命中 + 语义相似度 ≥0.95 命中)
│   └── Rerank 精排(召回 20 → CrossEncoder 重排 → 取回 3)
├── 智能体核心
│   ├── 对话核心(chat.py,流式 + 固定轮数工具循环)
│   ├── LangGraph Agent(规划 → 执行 → 反思 → 自主结束)
│   └── 工具层(时间 / 安全计算 / 网络搜索)
└── 工程化
    ├── 存储(MySQL + 本地 JSON 降级)
    ├── 缓存(Redis,可降级)
    ├── 测试(87 个 pytest 用例 + GitHub Actions CI)
    ├── 部署(Docker Compose:app + Redis + ChromaDB)
    └── 双入口(Streamlit 界面 + Flask REST API)

3.4 类图

classDiagram class AppUI { +title +upload_document() +ask_question() +show_sources() } class ChatCore { +chat(message, history) +stream_chat(message, history) +run_tool_loop() } class AgentGraph { +call_model_node() +tool_node() +should_continue() +finalize_node() } class RAG { +load_document(file) +add_to_vectorstore(docs) +search(query, top_k, rerank) +get_document_list() +delete_document(doc_id) } class ToolLayer { +execute_tool(name, args) } class Cache { +get_cache(key) +set_cache(key, value) +semantic_similarity() } class Storage { +save_session() +load_session() +fallback_json() } class VectorStore { +collection +query(texts, n_results) +add(ids, documents, metadatas) } AppUI --> ChatCore AppUI --> RAG ChatCore --> AgentGraph ChatCore --> ToolLayer ChatCore --> Cache ChatCore --> Storage RAG --> VectorStore RAG --> Cache

说明:core/ 目录为业务逻辑层(不依赖 Streamlit);app.py(Streamlit 界面)与 app_api.py(Flask API)双入口共用同一套业务逻辑。

3.5 功能描述

核心功能(杀手级):

  1. RAG 私有知识库文档问答:上传 PDF / TXT / Markdown 文档,自动切分、向量化、入库;提问时先检索私有知识库最相关片段,再基于片段生成带依据的回答(附来源与相似度)。
  2. 两层缓存优化:精确缓存(相同问题直接命中)+ 语义缓存(bge-m3 向量化,相似度 ≥0.95 判定同一问题)。实测缓存命中率 44%,P50 延迟从 1.66s 降到 0.90s。
  3. Rerank 精排:召回阶段扩容到 20 条(宁滥勿缺),用 CrossEncoder(bge-reranker-v2-m3)对"问题-片段"逐对打分重排,再取回 3 条(宁缺毋滥)。评测集 v1 上 10/10 全部命中、3/3 诱饵题纠偏;精排开关默认关闭、模型惰性加载、失败自动降级为纯向量检索。

基础功能:

  1. 智能体对话:支持普通模式(固定轮数工具循环)与 Agent 模式(LangGraph 规划 → 执行 → 反思 → 自主结束);内置时间、安全数学计算、网络搜索(Tavily + pixserp 双源降级)工具。
  2. 多模型切换:DeepSeek / OpenAI / Ollama 统一适配,界面一键切换,各模型独立参数。
  3. 会话管理:历史对话保存、切换、删除、重命名、搜索,支持 JSON / TXT / MD 导入导出。
  4. 双入口:Streamlit 图形界面 + Flask REST API(含可取消的 SSE 流式接口)。
  5. 存储与缓存降级:MySQL 不可用时自动降级本地 JSON;Redis 不可用时缓存自动降级,主流程不中断。
  6. Docker 一键部署:docker-compose 编排应用 + Redis + ChromaDB 三服务。

3.6 验收标准

编号 验收项 验收标准 状态
A1 文档上传 PDF / TXT / MD 均可上传,自动切分入库 ✅ 通过
A2 文档问答 提问能返回基于知识库片段的回答,附来源引用 ✅ 通过
A3 检索正确性 评测集 v1(10 题三分类 + 3 诱饵)全部命中 ✅ 10/10 + trap 3/3
A4 缓存优化 缓存命中率 ≥40%,P50 延迟相对关闭缓存有显著下降 ✅ 44%,0.90s
A5 精排降级 精排模型加载失败 / 执行失败时自动回纯向量检索,不中断问答 ✅ 通过
A6 回归测试 全量 pytest 用例通过 ✅ 87/87
A7 部署运行 可通过 Docker 一键启动;公网可访问供老师检查 🚧 进行中
A8 数据隔离 不同用户的文档互不可见(上线后验收) 🚧 进行中

四、项目核心实现说明

4.1 检索链路

用户提问
  → bge-m3 向量化
  → ChromaDB 语义检索(召回 top20,精排开启时)
  → CrossEncoder 逐对打分重排
  → 取回 top3 相关片段
  → 拼接系统提示词 + 片段 + 历史
  → 大模型生成带依据的回答(附来源)

4.2 为什么"召回 20 → 精排回 3"?

单靠向量相似度(双塔式嵌入)检索,容易把"字面相似但语义不相关"的片段排进前 3(实测 trap 题会被诱饵块压过)。CrossEncoder 对"问题 + 片段"逐对深度交互打分,语义区分能力更强。实测:trap-01 的诱饵块从 top3 出局,正确块与干扰块的分数差距从 0.015 拉到 12 倍;cross-01 从错误块(0.6213)纠偏为正确块(0.9501)。

4.3 精排的代价与取舍

函数级 A/B 压测(50 样本/版):纯向量 P50 38.1ms,精排后 P50 1232.1ms(净增 +1194ms);P95 从 50.8ms 升至 1478.2ms(净增 +1427ms)。我们用 约 +1.2s 延迟换 10/10 检索正确率,且通过"默认关闭 + 按次开关 + 失败降级"保证不影响存量部署——这是明确的 trade-off 决策,不是盲目加功能。

4.4 优雅降级是贯穿全项目的工程理念

RAG、工具、缓存、Agent、MySQL 任一模块缺失或异常,应用照常运行,仅对应功能不可用。这保证了上线后任何单点故障都不会让整个系统挂掉。

4.5 验收证据(实跑截图,2026-11-07)

回归测试:87/87 通过

b3d64cd0a4b7ee4abf5d85884f50b3b7

Rerank 检索正确率:10/10 + trap 3/3

73db4caf14cf883470836f75d816d0be

精排延迟压测(函数级 search(),50 样本/版)

5a285031541b1f08bcbf9fcf157a08d6

以上截图均为 2026-11-07 终端实跑,可复现(命令:python rerank_eval.py / python bench_rerank.py / pytest)。


五、小组成员分工与心得

5.1 分工

成员 分工内容
马文青(3124004255) 项目总体设计、RAG 检索模块与评测、两层缓存与 Rerank 精排、LangGraph Agent 编排、自动化测试与 CI
黎伟骞(3124004249) Streamlit 前端界面与会话管理、Flask REST API 设计、Docker 部署与多模型配置

5.2 心得

马文青(3124004255):这次大项目让我真正体会到"RAG 不是调一个接口就完事"。我们踩过最大的坑是:向量检索看起来"什么都能查到",但一到语义接近的干扰题就翻车——后来用评测集 v1 把问题量化出来(10 题三分类 + 3 道诱饵),再引入 CrossEncoder 精排,把正确率从"偶尔被诱饵压过"变成 10/10。这让我理解了为什么工业级 RAG 都要做 rerank:召回要全,精排要准。另一个收获是"工程化"——缓存命中率、P50/P95 延迟、降级路径,这些数字让我们的优化有依据,而不是"我觉得更快了"。

黎伟骞(3124004249):我主要负责前端和部署,最大的体会是"AI 应用的前端不是画个框就完事"。为了让用户真正用得起来,我们做了流式输出、来源引用展示、文档管理列表、深色模式这些交互细节;部署时用 Docker Compose 把应用、Redis、ChromaDB 三个服务编排起来,一条命令就能启动。这让我理解了:一个 AI 产品要上线,前端交互、部署、环境配置的工程量一点不比 AI 逻辑少。也第一次体会到"优雅降级"的价值——MySQL 没启动时应用照常能用,用户体验不中断。

 posted on 2026-11-07 20:01  mwq111  阅读(10)  评论(0)    收藏  举报