面向企业内部知识管理场景:员工查 wiki 翻不完、新人上手慢、专家经验散落各处——传统文档站点只能关键词搜,搜不出"那个 DSW 怎么计费"这种自然语言问题。
本项目把多格式文档(Markdown/PDF/Excel)统一沉淀为可对话查询的私有知识库,基于混合检索(向量+BM25)+ 重排保证召回准确性,多用户隔离满足部门数据合规,双
LLM Provider 兼顾本地敏感场景与云端低成本调用,让"问一句机器人就能回答"在企业落地,把员工的查文档时间从分钟级压到秒级。
- 账号体系:注册 / 登录 / Token 鉴权 / 多用户私有知识库隔离
- 文档管理:Markdown/PDF/TXT/Excel 多格式上传,基于标题结构的语义分块
- 混合检索引擎:向量检索(BGE-M3)+ BM25 并行召回,BGE-Reranker 重排
- 链路 Hooks:before_retrieval / before_model / after_model 三段切片,做埋点、敏感词过滤、上下文裁剪
- 双 LLM Provider:Ollama 本地 / 硅基流动云端 一键切换
- 会话管理:Redis 上下文 + MySQL 历史持久化
- 前端 UI:Gradio 可视化 + Basic Auth 鉴权
整体架构
整个系统按用户层、前端层、网关层、业务层、存储层五层分布。
用户从浏览器发起请求,先到 Gradio 前端(端口 7860),Gradio 负责文件上传、对话 UI 渲染和 Basic Auth 鉴权。用户操作转化为 REST 请求后发到 FastAPI
网关(端口 8000),由网关层统一做路由分发、Token 鉴权和参数校验。
请求进入业务层后,按"链路 Hooks"机制分三段执行:before_retrieval 段做检索前的埋点和参数处理;中间段是文档处理、混合检索、LLM
调用三大核心服务串联;after_model 段做生成后的历史落库和性能统计。
业务层调用四个外部依赖:ChromaDB 存储文档向量、硅基流动 API 提供 Embedding 与 Rerank、Ollama 或硅基流动云端提供 LLM 推理、Redis 缓存会话上下文、MySQL
持久化用户数据和聊天历史。
---
技术栈
前端用 Gradio 4.21,因为它是 Python 原生组件库,不用写前端代码就能拿到上传、对话、流式响应这些能力。
后端用 FastAPI 0.110 加 Uvicorn,原因是异步性能好、Pydantic 自带类型校验、还能自动生成 OpenAPI 接口文档。
向量库用 ChromaDB 0.4.24,单进程嵌入式无需独立服务,正好适合中小规模部署,且原生支持按 metadata 过滤。
嵌入模型走硅基流动 API 的 BAAI/bge-m3,1024 维稠密向量,是当前中文场景检索效果最好的开源模型之一。
重排模型用 BAAI/bge-reranker-v2-m3,把召回的候选文档精排一遍,比单纯向量打分准确率高 15% 以上。
LLM 层做了双 Provider 抽象:本地开发走 Ollama 跑 Qwen 模型免费调试,生产环境切到硅基流动 API 的 Qwen 2.5 系列降低成本。
Redis 5.0 用来存 Token、会话上下文、用户元数据这种短生命周期数据。
MySQL 8.0 配合 SQLAlchemy 2.0 做用户表和聊天历史的持久化,事务保证数据一致性。
文档处理层引入 LangChain 0.1.20,主要用它的 Markdown Splitter、PDF 加载器、BM25 检索器等成熟工具链。
部署层用 systemd 守护 FastAPI 和 Gradio 进程,配合 Docker Compose 跑 Redis 和 MySQL 中间件。CI/CD 用 GitHub Actions 做自动测试和构建。
---
解决的核心难点
第一个难点是单一检索召回不全。纯向量检索碰到精确名词(比如型号、API 路径)召回率会很差;纯 BM25
又抓不住语义近似的问题,比如用户问"计费方式"和文档里写的"怎么收费",词面对不上但意思一样。解决方法是做混合检索:用户的查询同时走向量检索和
BM25,两路并行召回结果合并去重,再过一遍 BGE-Reranker 精排,把语义相关又关键词命中的文档顶到最前面。
第二个难点是 1G 内存的云服务器跑不动本地大模型。Qwen2.5-7B 至少要 8G 内存才能加载,1.5B 也撑不住。但本地开发又希望免费用 Ollama 调试。解决方法是在
LLMService 里抽象出统一的 generate 接口,根据 LLM_PROVIDER 环境变量动态分发:本地走 http://localhost:11434 调 Ollama,生产走硅基流动云端 chat completions
API。一行 .env 切换,业务代码完全不变,本地开发零成本,生产部署也跑得起来。
第三个难点是长文档塞不进 LLM 上下文。检索拼出的 prompt 经常超过模型 token 上限,原代码直接 text[:N]
硬切片,会砍在半句话甚至半个词中间,模型看到不完整的内容就容易胡说。解决方法是做段落边界回退:先按 max_tokens 8192、char_per_token 2
的阈值估算,超限则截断,再用 rfind 找最近的 \n\n 段落边界,只在边界位置 ≥ 70% max_chars 时才回退(避免丢太多内容),保证截断结果永远落在完整段落末尾。
第四个难点是多用户共用一个知识库会泄露数据。A 用户上传的私密文档不能被 B 用户检索到。解决方法是给每条入库的 chunk 打上 metadata 字段 user_id,检索时传入
where 条件做过滤,让 ChromaDB 在向量层就完成隔离,不依赖应用层 i
声明:本文仅代表作者观点,不代表本站立场。如果侵犯到您的合法权益,请联系我们删除侵权资源!如果遇到资源链接失效,请您通过评论或工单的方式通知管理员。未经允许,不得转载,本站所有资源文章禁止商业使用运营!

下载安装【程序员客栈】APP
实时对接需求、及时收发消息、丰富的开放项目需求、随时随地查看项目状态
评论