实战项目三:语义搜索与问答系统
目录
项目概述
在智能客服、知识库问答等场景中,语义搜索与问答系统正在快速取代传统的关键词匹配。通过向量检索技术,系统能够理解“意思相近但用词不同”的查询,显著提升命中率和用户体验。
本教程聚焦企业FAQ问答这个轻量级落地场景,手把手带你实现一个开箱即用的语义问答系统。项目目标明确:
- ✅ 支持自然语言中文提问
- ✅ 检索准确率达到 85% 以上
- ✅ 单次查询响应时间小于 300 毫秒
- ✅ 无需 GPU,普通 CPU 服务器即可部署
核心架构与技术栈
精简架构
整个系统由四层组成,职责清晰:
- 用户交互层:Streamlit 搭建,无需前端经验就能做出美观界面。
- API 网关层:FastAPI 提供高性能、自动文档化的 RESTful 接口。
- RAG 引擎层:先检索再生成,用检索到的知识去辅助回答。
- 存储层:基于 FAISS 的向量索引,承载所有 FAQ 的语义向量。
选型标准与推荐
本项目坚持免费开源、轻量易部署的原则,组件选择如下:
选择
IndexFlatIP而非IndexFlatL2的原因:在向量归一化之后,内积等价于余弦相似度,且计算效率更高。
数据与向量化索引
1. 数据准备
FAQ 数据最简单的形式就是问题-答案对。为了提升检索效果,我们为每条 FAQ 增加一个 search_text 字段,把原始问题、常见相似问法、关键词等信息拼接在一起。
示例数据结构:
提示:
search_text的质量直接影响检索召回率,建议根据真实用户日志,定期补充高频相似问法。
2. 向量化与索引构建
下面这段代码完成了模型加载、批量编码、归一化以及 FAISS 索引的构建与持久化。
运行后,你会在本地得到两个文件:
faq_index.faiss:向量索引faq_data.pkl:原始 FAQ 数据
以后检索时,只需加载这两个文件即可。
语义检索与RAG实现
1. 语义检索模块
我们将检索逻辑封装为一个类,方便后续调用。
threshold 是相似度门槛,建议初期设为 0.3,后续可根据实际效果调整。低于该值的结果意味着语义差距过大,直接丢弃。
2. 轻量RAG引擎
检索到相关内容后,如何生成最终答案?这里提供了两种模式:
- 规则模式(默认):直接返回最相似 FAQ 的标准答案,完全离线、零成本。
- LLM 增强模式:将检索结果作为上下文,调用大语言模型生成更自然的回答,效果更好,但依赖外部 API。
生产环境中,可以将
Threshold、use_llm做成可配置项,动态切换模式。
快速部署方案
1. 后端FastAPI核心
后端只保留核心功能,省略了日志、鉴权、缓存的代码,方便快速上手。
启动命令:
访问 http://localhost:8000/docs 即可看到自动生成的 Swagger 文档,直接在线测试。
2. 前端Streamlit核心
前端代码极简,但功能完备:输入问题、切换 LLM 增强、查看参考来源。
启动前端:
3. 一键启动命令
打开浏览器,你就可以在 Streamlit 界面中用自然语言向 FAQ 知识库提问了。
优化要点总结
-
向量化优化
- 把相似问、分类、标签合并到
search_text字段,丰富语义信息。 - 优先使用批量编码,避免逐条调用。
- 如果有 GPU,初始化模型时加上
device="cuda"参数,编码速度能提升数倍。
- 把相似问、分类、标签合并到
-
检索优化
- 数据量小于 10 万条时,
IndexFlatIP既简单又精准。 - 数据量更大时,可以换成
IndexIVFFlat,牺牲少量精度换取更快速度。 - 设置合理的相似度阈值(例如 0.3)可以有效过滤无关结果。
- 必要时引入混合检索:用语义相似度加关键词简单的精确匹配,提升长尾问题的召回率。
- 数据量小于 10 万条时,
-
性能优化
- 本地 LRU 缓存高频查询的嵌入向量和最终结果,避免重复计算。
- 多实例部署时,用 Redis 作为集中式缓存。
- 生产环境建议用 Uvicorn 的多 worker 模式(例如
--workers 4)或搭配 Gunicorn 提升并发能力。
本项目从数据处理、向量化、索引构建,到检索、问答、前后端部署,完整覆盖了一个语义问答系统的最小可行产品。你可以将其作为企业 FAQ、产品咨询、在线课程问答等场景的起点,后续再根据实际需求叠加意图识别、多轮对话、知识库自动更新等功能,逐步完善。

