1. 项目背景与挑战
去年底我们团队接手了一个金融知识问答系统的改造项目,客户要求将大语言模型(LLM)的响应时间控制在2秒以内,准确率需达到85%以上。初期测试结果令人沮丧:平均响应时间4.3秒,准确率仅62%。这个性能差距促使我们开始了长达三个月的RAG(检索增强生成)系统优化攻坚战。
金融领域的特殊性给项目带来了额外挑战:
- 文档库包含超过50万份PDF/PPT格式的招股书、年报等非结构化数据
- 用户查询包含大量专业术语和复合型问题(如"比较近三年科创板与创业板IPO企业的研发支出占比")
- 结果需要附带可追溯的原文引用
2. 性能瓶颈定位与分析
2.1 端到端链路耗时分解
通过插入监控探针,我们绘制了完整的处理流水线:
plaintext复制[用户请求]
→ 查询理解(0.8s)
→ 向量检索(2.1s)
→ 文档预处理(0.6s)
→ LLM生成(0.8s)
→ 结果校验(0.2s)
2.2 关键问题诊断
-
检索阶段
- 原始方案:直接使用OpenAI的text-embedding-ada-002模型
- 痛点:每次请求需要传输全部文档内容到云端,网络延迟占整体时间的40%
-
文档处理
- PDF解析采用PyPDF2库,对扫描件和复杂表格的处理效率低下
- 未做预处理缓存,相同文档被反复解析
-
生成阶段
- 采用GPT-4模型,虽然质量高但响应速度不稳定
- prompt设计未做优化,存在大量冗余指令
3. 优化方案设计与实施
3.1 检索系统改造
3.1.1 本地化嵌入模型
- 替换方案:部署bge-small-zh-v1.5模型到本地GPU服务器
- 效果对比:
指标 原方案 新方案 延迟(ms) 2100 480 准确率(@10) 72% 68% 硬件成本 $0.5/req 固定$200/月
注意:模型切换需要重新生成全部向量,我们开发了分布式处理脚本,利用20台EC2实例在36小时内完成了50万文档的重新嵌入
3.1.2 混合检索策略
python复制def hybrid_retrieval(query):
# 第一层:关键词检索(BM25)
keyword_results = bm25_search(query, top_k=50)
# 第二层:向量检索
embedding = local_model.encode(query)
vector_results = vector_db.search(embedding, top_k=30)
# 结果融合
combined = reciprocal_rank_fusion(keyword_results, vector_results)
return deduplicate(combined)[:10]
3.2 文档处理优化
-
预处理流水线改造
- 新增OCR预处理分支,对扫描件使用PaddleOCR
- 表格数据转为Markdown格式存储
- 实现文档指纹去重(SimHash)
-
缓存策略
mermaid复制graph LR A[原始文档] --> B{是否扫描件?} B -->|是| C[OCR处理] B -->|否| D[直接解析] C & D --> E[标准化存储] E --> F[Redis缓存]
3.3 生成阶段调优
3.3.1 模型选型
测试了7种开源和商业模型后,最终方案:
- 常规查询:使用本地部署的Qwen-14B-Chat(量化版)
- 复杂分析:降级到GPT-3.5-turbo
3.3.2 Prompt工程
优化前后的prompt对比:
markdown复制# 旧版
请根据以下文档回答问题,要求答案专业准确,包含引用来源...
# 新版
[角色]金融分析师
[任务]用中文回答用户问题
[要求]
1. 不超过3句话
2. 引用格式:[文档1, p.12]
3. 优先使用表格数据
4. 效果验证与持续改进
4.1 A/B测试结果
| 指标 | 优化前 | 优化后 |
|---|---|---|
| 响应时间(s) | 4.3 | 1.6 |
| 准确率(%) | 62 | 87 |
| 吞吐量(qps) | 3 | 15 |
| 错误率(%) | 18 | 5 |
4.2 踩坑记录
-
向量模型冷启动问题
- 现象:bge模型初期准确率比ada低4%
- 解决:添加领域适配训练(继续训练5000步)
-
缓存雪崩
- 事故:Redis集群故障导致全量回源,响应时间飙升到8s
- 改进:实现多级缓存(内存→Redis→磁盘)
-
PDF解析内存泄漏
- 发现:服务运行24小时后内存占用达32GB
- 定位:PyPDF2的PageObject未释放
- 修复:换用pdfplumber库+定期重启worker
5. 关键经验总结
-
检索系统黄金法则
- 本地化嵌入模型是降低延迟的关键
- 混合检索比纯向量检索准确率高15-20%
- 向量数据库选型建议:
- 小规模:FAISS
- 中规模:Milvus
- 超大规模:自研分片方案
-
文档处理最佳实践
- 一定要做文档指纹去重
- 表格数据单独处理能提升30%可用性
- 扫描件质量检测脚本:
python复制def check_scan_quality(image): from skimage.metrics import structural_similarity # 检测模糊、倾斜、阴影等问题 ...
-
生成阶段优化技巧
- 小模型+好的prompt > 大模型+差prompt
- 响应时间与质量平衡公式:
code复制质量得分 = (准确率*0.6 + 完整性*0.3 + 流畅度*0.1) 优化目标 = 质量得分 / (响应时间)^0.5
这套优化方案已稳定运行6个月,期间我们进一步实现了:
- 动态负载均衡:根据查询复杂度自动路由到不同模型
- 渐进式渲染:先返回已检索到的内容,再异步补充LLM分析
- 反馈闭环:将用户点击数据反哺到检索模型训练