面试 · 2025年6月21日 0

使用Qwen3的Embedding和Reranker模型实现查找与精排

最近几天阿里发布了Reranker模型Embedding,尝试使用它两个来精准查找检索文件内容。

项目地址:SanroZhang/qwen3-ER-search (github.com)

🔍 Reranker vs Embedding 模型对比

Embedding模型 (Qwen3-Embedding)

  • 功能: 将文本转换为向量,计算语义相似度
  • 用途: 粗筛阶段,从大量文档中快速找到相关候选
  • 特点: 速度快,但精度可能不够高

Reranker模型 (Qwen3-Reranker)

  • 功能: 对候选文档进行精确重排序,判断相关性
  • 用途: 精筛阶段,对Embedding的结果进行二次排序
  • 特点: 精度高,但速度相对较慢

🎯 两阶段检索流程

文档库 → Embedding粗筛 → 候选文档 → Reranker精筛 → 最终结果

创建一个结合两种模型的精准检索系统:

运行混合检索系统,展示Embedding和Reranker的对比效果:

python hybrid_retrieval.py

结果:

PS C:\Users\sanrome\Documents\zero_nlp-main\qwen3_embedding> python hybrid_retrieval.py
正在加载Qwen3 Embedding模型...
Embedding模型加载完成!
Reranker模型加载完成!
正在加载PDF文件: C:\Users\sanrome\Documents\三郎白底通用简历-zh.pdf
成功提取 12 个文本块
正在构建文档向量...
文档向量构建完成

================================================================================
=== 混合检索系统测试 ===
================================================================================

============================================================
查询: 李明的工作经验
============================================================

1️⃣ 仅Embedding搜索:
仅使用Embedding搜索: 李明的工作经验
  结果1: 相似度=0.4475, 索引=0
    内容: 第1页: 技术栈。Boss 您好。我叫李明,有意应聘贵公司:后端开发、全栈开发工程师、产品经理
等岗位。我拥有实际工作开发经验3-5 年,擅长全栈开发。毕业于北华大学-计算机科学与技术专业。我目前已经
...
  结果2: 相似度=0.3059, 索引=2
    内容: ·参与产品研发过程质量控制与管理,负责白盒测试与性能测试与分析。维护和。编写接口文档。根据
测试计划和要求编写测试用例对Web 端进行自动化测试和接口测。试。跟踪测试Bug 并记录复现过程和测试结果 ,帮...
  结果3: 相似度=0.2979, 索引=1
    内容: ·参与图像处理与标注软件套装的开发与测试。对接客户需求,负责软件架构设。计,设计UI 原型, 
调研相同竞品形成报告,确定软件技术架构和模块功能划分。主。导控制模块,根据工业通讯协议对接下位机实 现设备驱动...
                                             
2️⃣ 仅Reranker搜索:
仅使用Reranker搜索: 李明的工作经验
You're using a Qwen2TokenizerFast tokenizer. Please note that with a fast tokenizer, using the `__c
all__` method is faster than using a method to encode the text followed by a call to the `pad` meth
od to get a padded encoding.
C:\Users\sanrome\AppData\Local\Programs\Python\Python312\Lib\site-packages\transformers\tokenizatio
n_utils_base.py:2714: UserWarning: `max_length` is ignored when `padding`=`True` and there is no tr
uncation strategy. To pad to max length, use `padding='max_length'`.
  warnings.warn(
  结果1: 相关性=0.9995, 索引=0
    内容: 第1页: 技术栈。Boss 您好。我叫李明,有意应聘贵公司:后端开发、全栈开发工程师、产品经理 
等岗位。我拥有实际工作开发经验3-5 年,擅长全栈开发。毕业于北华大学-计算机科学与技术专业。我目前已经...
                                                      结果2: 相关性=0.9819, 索引=10
    内容: ELK 日志系统实时采集异常信息。1. DeepAgile - 软件开发工程师。-。苏州。2. 滴滴- 测试开发实
习生。-。杭州。3. 用友- 运维开发实习生。-。北京。4. 趣头条- 测试实习生。-...                         结果3: 相关性=0.0158, 索引=11
    内容: 5. CSDN/阿里云开发者。社区技术博主。6. 阿里云服务器进阶实。战训练营。7. 中海国际校园企业 
实。训。-小组总分第1 优胜。8. 大学生“挑战杯”创。新创业大赛-校级二等。奖、省级三等奖。9....         
3️⃣ 混合搜索 (Embedding + Reranker):
正在进行混合检索: 李明的工作经验
==================================================
第一阶段:Embedding粗筛
Embedding阶段找到 5 个候选文档:
  候选1: 相似度=0.4475, 索引=0
    内容: 第1页: 技术栈。Boss 您好。我叫李明,有意应聘贵公司:后端开发、全栈开发工程师、产品经理 
等岗位。我拥有实际工作开发经验3-5 年,擅长全栈开发。毕业于北...                                      候选2: 相似度=0.3059, 索引=2
    内容: ·参与产品研发过程质量控制与管理,负责白盒测试与性能测试与分析。维护和。编写接口文档。根据
测试计划和要求编写测试用例对Web 端进行自动化测试和接口测。试。跟踪...                                候选3: 相似度=0.2979, 索引=1
    内容: ·参与图像处理与标注软件套装的开发与测试。对接客户需求,负责软件架构设。计,设计UI 原型, 
调研相同竞品形成报告,确定软件技术架构和模块功能划分。主。导控制模块...                              候选4: 相似度=0.2690, 索引=10
    内容: ELK 日志系统实时采集异常信息。1. DeepAgile - 软件开发工程师。-。苏州。2. 滴滴- 测试开发实
习生。-。杭州。3. 用友- 运维开发实习生。...                                                          候选5: 相似度=0.2444
, 索引=3
    内容: 4. AI 大模型:掌握DeepSeek 等大模型部署与调优,熟悉协议定义与接口开发使用。5. 测试技能: 
熟悉单元测试、接口测试、UI 测试的批处理与自动化脚本...                                             
第二阶段:Reranker精筛
Reranker阶段重新排序结果:
  排序1: Reranker分数=0.9995, Embedding分数=0.4475, 索引=0
    内容: 第1页: 技术栈。Boss 您好。我叫李明,有意应聘贵公司:后端开发、全栈开发工程师、产品经理 
等岗位。我拥有实际工作开发经验3-5 年,擅长全栈开发。毕业于北...                                      排序2: Reranker分数=0.9819, Em
bedding分数=0.2690, 索引=10
    内容: ELK 日志系统实时采集异常信息。1. DeepAgile - 软件开发工程师。-。苏州。2. 滴滴- 测试开发实
习生。-。杭州。3. 用友- 运维开发实习生。...                                                          排序3: Reranker分数
=0.0028, Embedding分数=0.2979, 索引=1
    内容: ·参与图像处理与标注软件套装的开发与测试。对接客户需求,负责软件架构设。计,设计UI 原型, 
调研相同竞品形成报告,确定软件技术架构和模块功能划分。主。导控制模块...                              排序4: Reranker分数=0.0008, Embeddin
g分数=0.3059, 索引=2
    内容: ·参与产品研发过程质量控制与管理,负责白盒测试与性能测试与分析。维护和。编写接口文档。根据
测试计划和要求编写测试用例对Web 端进行自动化测试和接口测。试。跟踪...                                排序5: Reranker分数=0.0002, Embed
ding分数=0.2444, 索引=3
    内容: 4. AI 大模型:掌握DeepSeek 等大模型部署与调优,熟悉协议定义与接口开发使用。5. 测试技能: 
熟悉单元测试、接口测试、UI 测试的批处理与自动化脚本...                                               结果1: 最终相关性=0.9995, 索引=
0
    内容: 第1页: 技术栈。Boss 您好。我叫李明,有意应聘贵公司:后端开发、全栈开发工程师、产品经理 
等岗位。我拥有实际工作开发经验3-5 年,擅长全栈开发。毕业于北华大学-计算机科学与技术专业。我目前已经...
                                                      结果2: 最终相关性=0.9819, 索引=10
    内容: ELK 日志系统实时采集异常信息。1. DeepAgile - 软件开发工程师。-。苏州。2. 滴滴- 测试开发实
习生。-。杭州。3. 用友- 运维开发实习生。-。北京。4. 趣头条- 测试实习生。-...                         结果3: 最终相关性=0.0028, 索引=1
    内容: ·参与图像处理与标注软件套装的开发与测试。对接客户需求,负责软件架构设。计,设计UI 原型, 
调研相同竞品形成报告,确定软件技术架构和模块功能划分。主。导控制模块,根据工业通讯协议对接下位机实 现设备驱动...
                                             
============================================================
查询: 技术技能和编程语言
============================================================

1️⃣ 仅Embedding搜索:
仅使用Embedding搜索: 技术技能和编程语言
  结果1: 相似度=0.3679, 索引=0
    内容: 第1页: 技术栈。Boss 您好。我叫李明,有意应聘贵公司:后端开发、全栈开发工程师、产品经理 
等岗位。我拥有实际工作开发经验3-5 年,擅长全栈开发。毕业于北华大学-计算机科学与技术专业。我目前已经...
                                                      结果2: 相似度=0.3538, 索引=2
    内容: ·参与产品研发过程质量控制与管理,负责白盒测试与性能测试与分析。维护和。编写接口文档。根据
测试计划和要求编写测试用例对Web 端进行自动化测试和接口测。试。跟踪测试Bug 并记录复现过程和测试结果 ,帮...
                                                      结果3: 相似度=0.3130, 索引=11
    内容: 5. CSDN/阿里云开发者。社区技术博主。6. 阿里云服务器进阶实。战训练营。7. 中海国际校园企业 
实。训。-小组总分第1 优胜。8. 大学生“挑战杯”创。新创业大赛-校级二等。奖、省级三等奖。9....         
2️⃣ 仅Reranker搜索:
仅使用Reranker搜索: 技术技能和编程语言
  结果1: 相关性=0.0336, 索引=2
    内容: ·参与产品研发过程质量控制与管理,负责白盒测试与性能测试与分析。维护和。编写接口文档。根据
测试计划和要求编写测试用例对Web 端进行自动化测试和接口测。试。跟踪测试Bug 并记录复现过程和测试结果 ,帮...
                                                      结果2: 相关性=0.0254, 索引=0
    内容: 第1页: 技术栈。Boss 您好。我叫李明,有意应聘贵公司:后端开发、全栈开发工程师、产品经理 
等岗位。我拥有实际工作开发经验3-5 年,擅长全栈开发。毕业于北华大学-计算机科学与技术专业。我目前已经...
                                                      结果3: 相关性=0.0200, 索引=10
    内容: ELK 日志系统实时采集异常信息。1. DeepAgile - 软件开发工程师。-。苏州。2. 滴滴- 测试开发实
习生。-。杭州。3. 用友- 运维开发实习生。-。北京。4. 趣头条- 测试实习生。-...                       
3️⃣ 混合搜索 (Embedding + Reranker):
正在进行混合检索: 技术技能和编程语言
==================================================
第一阶段:Embedding粗筛
Embedding阶段找到 5 个候选文档:
  候选1: 相似度=0.3679, 索引=0
    内容: 第1页: 技术栈。Boss 您好。我叫李明,有意应聘贵公司:后端开发、全栈开发工程师、产品经理 
等岗位。我拥有实际工作开发经验3-5 年,擅长全栈开发。毕业于北...                                      候选2: 相似度=0.3538, 索引=2
    内容: ·参与产品研发过程质量控制与管理,负责白盒测试与性能测试与分析。维护和。编写接口文档。根据
测试计划和要求编写测试用例对Web 端进行自动化测试和接口测。试。跟踪...                                候选3: 相似度=0.3130, 索引=11
    内容: 5. CSDN/阿里云开发者。社区技术博主。6. 阿里云服务器进阶实。战训练营。7. 中海国际校园企业 
实。训。-小组总分第1 优胜。8. 大学生“挑战杯”创。新...                                                候选4: 相似度=0.3032, 索引
=4
    内容: 11. 开发工具:熟悉常用的开发和管理工具如:IDEA、VS、SVN、Github、Jira、Jenkins。1. 基于WP
F.UI 的Flent 风。格桌面应...                                                                         候选5:
相似度=0.2898, 索引=10
    内容: ELK 日志系统实时采集异常信息。1. DeepAgile - 软件开发工程师。-。苏州。2. 滴滴- 测试开发实
习生。-。杭州。3. 用友- 运维开发实习生。...                                                        
第二阶段:Reranker精筛
Reranker阶段重新排序结果:
  排序1: Reranker分数=0.0336, Embedding分数=0.3538, 索引=2
    内容: ·参与产品研发过程质量控制与管理,负责白盒测试与性能测试与分析。维护和。编写接口文档。根据
测试计划和要求编写测试用例对Web 端进行自动化测试和接口测。试。跟踪...                                排序2: Reranker分数=0.0254, Embed
ding分数=0.3679, 索引=0
    内容: 第1页: 技术栈。Boss 您好。我叫李明,有意应聘贵公司:后端开发、全栈开发工程师、产品经理 
等岗位。我拥有实际工作开发经验3-5 年,擅长全栈开发。毕业于北...                                      排序3: Reranker分数=0.0200, Em
bedding分数=0.2898, 索引=10
    内容: ELK 日志系统实时采集异常信息。1. DeepAgile - 软件开发工程师。-。苏州。2. 滴滴- 测试开发实
习生。-。杭州。3. 用友- 运维开发实习生。...                                                          排序4: Reranker分数
=0.0115, Embedding分数=0.3130, 索引=11
    内容: 5. CSDN/阿里云开发者。社区技术博主。6. 阿里云服务器进阶实。战训练营。7. 中海国际校园企业 
实。训。-小组总分第1 优胜。8. 大学生“挑战杯”创。新...                                                排序5: Reranker分数=0.0
003, Embedding分数=0.3032, 索引=4
    内容: 11. 开发工具:熟悉常用的开发和管理工具如:IDEA、VS、SVN、Github、Jira、Jenkins。1. 基于WP
F.UI 的Flent 风。格桌面应...                                                                         结果1:
最终相关性=0.0336, 索引=2
    内容: ·参与产品研发过程质量控制与管理,负责白盒测试与性能测试与分析。维护和。编写接口文档。根据
测试计划和要求编写测试用例对Web 端进行自动化测试和接口测。试。跟踪测试Bug 并记录复现过程和测试结果 ,帮...
                                                      结果2: 最终相关性=0.0254, 索引=0
    内容: 第1页: 技术栈。Boss 您好。我叫李明,有意应聘贵公司:后端开发、全栈开发工程师、产品经理 
等岗位。我拥有实际工作开发经验3-5 年,擅长全栈开发。毕业于北华大学-计算机科学与技术专业。我目前已经...
                                                      结果3: 最终相关性=0.0200, 索引=10
    内容: ELK 日志系统实时采集异常信息。1. DeepAgile - 软件开发工程师。-。苏州。2. 滴滴- 测试开发实
习生。-。杭州。3. 用友- 运维开发实习生。-。北京。4. 趣头条- 测试实习生。-...                       
============================================================
查询: 应聘的岗位和公司
============================================================

1️⃣ 仅Embedding搜索:
仅使用Embedding搜索: 应聘的岗位和公司
  结果1: 相似度=0.4570, 索引=10
    内容: ELK 日志系统实时采集异常信息。1. DeepAgile - 软件开发工程师。-。苏州。2. 滴滴- 测试开发实
习生。-。杭州。3. 用友- 运维开发实习生。-。北京。4. 趣头条- 测试实习生。-...                         结果2: 相似度=0.4546, 索引=0
    内容: 第1页: 技术栈。Boss 您好。我叫李明,有意应聘贵公司:后端开发、全栈开发工程师、产品经理 
等岗位。我拥有实际工作开发经验3-5 年,擅长全栈开发。毕业于北华大学-计算机科学与技术专业。我目前已经...
                                                      结果3: 相似度=0.3887, 索引=2
    内容: ·参与产品研发过程质量控制与管理,负责白盒测试与性能测试与分析。维护和。编写接口文档。根据
测试计划和要求编写测试用例对Web 端进行自动化测试和接口测。试。跟踪测试Bug 并记录复现过程和测试结果 ,帮...
                                                    
2️⃣ 仅Reranker搜索:
仅使用Reranker搜索: 应聘的岗位和公司
  结果1: 相关性=0.9932, 索引=0
    内容: 第1页: 技术栈。Boss 您好。我叫李明,有意应聘贵公司:后端开发、全栈开发工程师、产品经理 
等岗位。我拥有实际工作开发经验3-5 年,擅长全栈开发。毕业于北华大学-计算机科学与技术专业。我目前已经...
                                                      结果2: 相关性=0.4961, 索引=10
    内容: ELK 日志系统实时采集异常信息。1. Deep - 软件开发工程师。-。苏州。2. 滴滴- 测试开发实
习生。-。杭州。3. 用友- 运维开发实习生。-。北京。4. 趣头条- 测试实习生。-...                         结果3: 相关性=0.0013, 索引=11
    内容: 5. CSDN/阿里云开发者。社区技术博主。6. 阿里云服务器进阶实。战训练营。7. 中海国际校园企业 
实。训。-小组总分第1 优胜。8. 大学生“挑战杯”创。新创业大赛-校级二等。奖、省级三等奖。9....         
3️⃣ 混合搜索 (Embedding + Reranker):
正在进行混合检索: 应聘的岗位和公司
==================================================
第一阶段:Embedding粗筛
Embedding阶段找到 5 个候选文档:
  候选1: 相似度=0.4570, 索引=10
    内容: ELK 日志系统实时采集异常信息。1. Deep - 软件开发工程师。-。苏州。2. 滴滴- 测试开发实
习生。-。杭州。3. 用友- 运维开发实习生。...                                                          候选2: 相似度=0.4546
, 索引=0
    内容: 第1页: 技术栈。Boss 您好。我叫李明,有意应聘贵公司:后端开发、全栈开发工程师、产品经理 
等岗位。我拥有实际工作开发经验3-5 年,擅长全栈开发。毕业于北...                                      候选3: 相似度=0.3887, 索引=2
    内容: ·参与产品研发过程质量控制与管理,负责白盒测试与性能测试与分析。维护和。编写接口文档。根据
测试计划和要求编写测试用例对Web 端进行自动化测试和接口测。试。跟踪...                                候选4: 相似度=0.3584, 索引=1
    内容: ·参与图像处理与标注软件套装的开发与测试。对接客户需求,负责软件架构设。计,设计UI 原型, 
调研相同竞品形成报告,确定软件技术架构和模块功能划分。主。导控制模块...                              候选5: 相似度=0.3318, 索引=3
    内容: 4. AI 大模型:掌握等大模型部署与调优,熟悉协议定义与接口开发使用。5. 测试技能: 
熟悉单元测试、接口测试、UI 测试的批处理与自动化脚本...                                             
第二阶段:Reranker精筛
Reranker阶段重新排序结果:
  排序1: Reranker分数=0.9932, Embedding分数=0.4546, 索引=0
    内容: 第1页: 我叫李明,有意应聘贵公司:后端开发、 
等岗位。我拥有实际工作开发经验5 年,擅长全栈开发。毕业于北...                                      排序2: Reranker分数=0.5000, Em
bedding分数=0.4570, 索引=10
    内容: ELK 日志系统实时采集异常信息。1
习生。-。杭州。3. 用友- 运维开发实习生。...                                                          排序3: Reranker分数
=0.0011, Embedding分数=0.3887, 索引=2
    内容: ·参与产品研发过程质量控制与管理,负责白盒测试与性能测试与分析。维护和。编写接口文档。根据
测试计划和要求编写测试用例对Web 端进行自动化测试和接口测。试。跟踪...                                排序4: Reranker分数=0.0002, Embed
ding分数=0.3584, 索引=1
    内容: ·参与图像处理与标注软件套装的开发与测试。对接客户需求,负责软件架构设。计,设计UI 原型, 
调研相同竞品形成报告,确定软件技术架构和模块功能划分。主。导控制模块...                              排序5: Reranker分数=0.0001, Embeddin
g分数=0.3318, 索引=3
    内容: 4. AI 大模型:掌握DeepSeek 等大模型部署与调优,熟悉协议定义与接口开发使用。5. 测试技能: 
熟悉单元测试、接口测试、UI 测试的批处理与自动化脚本...                                               结果1: 最终相关性=0.9932, 索引=
0
    内容: 第1页: 技术栈。Boss 您好。我叫李明,有意应聘贵公司:后端开发、全栈开发工程师、产品经理 
等岗位。我拥有实际工作开发经验3-5 年,擅长全栈开发。毕业于北**学-计算机科学与技术专业。我目前已经...
                                                      结果2: 最终相关性=0.5000, 索引=10
    内容: ELK 日志系统实时采集异常信息。1. DeepA*** - 软件开发工程师。-。苏州。2. 滴滴- 测试开发实
习生。-。杭州。3. 用友- 运维开发实习生。-。北京。4. 趣头条- 测试实习生。-...                         结果3: 最终相关性=0.0011, 索引=2
    内容: ·参与产品研发过程质量控制与管理,负责白盒测试与性能测试与分析。维护和。编写接口文档。根据
测试计划和要求编写测试用例对Web 端进行自动化测试和接口测。试。跟踪测试Bug 并记录复现过程和测试结果 ,帮...
                                                    
============================================================
查询: 测试和开发经验
============================================================

1️⃣ 仅Embedding搜索:
仅使用Embedding搜索: 测试和开发经验
  结果1: 相似度=0.5181, 索引=2
    内容: ·参与产品研发过程质量控制与管理,负责白盒测试与性能测试与分析。维护和。编写接口文档。根据
测试计划和要求编写测试用例对Web 端进行自动化测试和接口测。试。跟踪测试Bug 并记录复现过程和测试结果 ,帮...
                                                      结果2: 相似度=0.5156, 索引=10
    内容: ELK 日志系统实时采集异常信息。1. DeepAgile - 软件开发工程师。-。苏州。2. 滴滴- 测试开发实
习生。-。杭州。3. 用友- 运维开发实习生。-。北京。4. 趣头条- 测试实习生。-...                         结果3: 相似度=0.4897, 索引=3
    内容: 4. AI 大模型:掌握DeepSeek 等大模型部署与调优,熟悉协议定义与接口开发使用。5. 测试技能: 
熟悉单元测试、接口测试、UI 测试的批处理与自动化脚本。6. 测试工具:熟悉测试流程、测试框架...        
2️⃣ 仅Reranker搜索:
仅使用Reranker搜索: 测试和开发经验
  结果1: 相关性=0.9741, 索引=10
    内容: ELK 日志系统实时采集异常信息。1. DeepAgile - 软件开发工程师。-。苏州。2. 滴滴- 测试开发实
习生。-。杭州。3. 用友- 运维开发实习生。-。北京。4. 趣头条- 测试实习生。-...                         结果2: 相关性=0.9541, 索引=3
    内容: 4. AI 大模型:掌握DeepSeek 等大模型部署与调优,熟悉协议定义与接口开发使用。5. 测试技能: 
熟悉单元测试、接口测试、UI 测试的批处理与自动化脚本。6. 测试工具:熟悉测试流程、测试框架...          结果3: 相关性=0.8872, 索引=2
    内容: ·参与产品研发过程质量控制与管理,负责白盒测试与性能测试与分析。维护和。编写接口文档。根据
测试计划和要求编写测试用例对Web 端进行自动化测试和接口测。试。跟踪测试Bug 并记录复现过程和测试结果 ,帮...
                                                    
3️⃣ 混合搜索 (Embedding + Reranker):
正在进行混合检索: 测试和开发经验
==================================================
第一阶段:Embedding粗筛
Embedding阶段找到 5 个候选文档:
  候选1: 相似度=0.5181, 索引=2
    内容: ·参与产品研发过程质量控制与管理,负责白盒测试与性能测试与分析。维护和。编写接口文档。根据
测试计划和要求编写测试用例对Web 端进行自动化测试和接口测。试。跟踪...                                候选2: 相似度=0.5156, 索引=10
    内容: ELK 日志系统实时采集异常信息。1. DeepAgile - 软件开发工程师。-。苏州。2. 滴滴- 测试开发实
习生。-。杭州。3. 用友- 运维开发实习生。...                                                          候选3: 相似度=0.4897
, 索引=3
    内容: 4. AI 大模型:掌握DeepSeek 等大模型部署与调优,熟悉协议定义与接口开发使用。5. 测试技能: 
熟悉单元测试、接口测试、UI 测试的批处理与自动化脚本...                                               候选4: 相似度=0.4097, 索引=1
    内容: ·参与图像处理与标注软件套装的开发与测试。对接客户需求,负责软件架构设。计,设计UI 原型, 
调研相同竞品形成报告,确定软件技术架构和模块功能划分。主。导控制模块...                              候选5: 相似度=0.3918, 索引=0
    内容: 第1页: 技术栈。Boss 您好。我叫李明,有意应聘贵公司:后端开发、全栈开发工程师、产品经理 
等岗位。我拥有实际工作开发经验3-5 年,擅长全栈开发。毕业于北...                                    
第二阶段:Reranker精筛
Reranker阶段重新排序结果:
  排序1: Reranker分数=0.9736, Embedding分数=0.5156, 索引=10
    内容: ELK 日志系统实时采集异常信息。1. DeepAgile - 软件开发工程师。-。苏州。2. 滴滴- 测试开发实
习生。-。杭州。3. 用友- 运维开发实习生。...                                                          排序2: Reranker分数
=0.9541, Embedding分数=0.4897, 索引=3
    内容: 4. AI 大模型:掌握DeepSeek 等大模型部署与调优,熟悉协议定义与接口开发使用。5. 测试技能: 
熟悉单元测试、接口测试、UI 测试的批处理与自动化脚本...                                               排序3: Reranker分数=0.8882
, Embedding分数=0.5181, 索引=2
    内容: ·参与产品研发过程质量控制与管理,负责白盒测试与性能测试与分析。维护和。编写接口文档。根据
测试计划和要求编写测试用例对Web 端进行自动化测试和接口测。试。跟踪...                                排序4: Reranker分数=0.8223, Embed
ding分数=0.4097, 索引=1
    内容: ·参与图像处理与标注软件套装的开发与测试。对接客户需求,负责软件架构设。计,设计UI 原型, 
调研相同竞品形成报告,确定软件技术架构和模块功能划分。主。导控制模块...                              排序5: Reranker分数=0.0014, Embeddin
g分数=0.3918, 索引=0
    内容: 第1页: 技术栈。Boss 您好。我叫李明,有意应聘贵公司:后端开发、全栈开发工程师、产品经理 
等岗位。我拥有实际工作开发经验3-5 年,擅长全栈开发。毕业于北...                                      结果1: 最终相关性=0.9736, 索引=10
    内容: ELK 日志系统实时采集异常信息。1. DeepAgile - 软件开发工程师。-。苏州。2. 滴滴- 测试开发实
习生。-。杭州。3. 用友- 运维开发实习生。-。北京。4. 趣头条- 测试实习生。-...                         结果2: 最终相关性=0.9541, 索引=3
    内容: 4. AI 大模型:掌握DeepSeek 等大模型部署与调优,熟悉协议定义与接口开发使用。5. 测试技能: 
熟悉单元测试、接口测试、UI 测试的批处理与自动化脚本。6. 测试工具:熟悉测试流程、测试框架...          结果3: 最终相关性=0.8882, 索引=2
    内容: ·参与产品研发过程质量控制与管理,负责白盒测试与性能测试与分析。维护和。编写接口文档。根据
测试计划和要求编写测试用例对Web 端进行自动化测试和接口测。试。跟踪测试Bug 并记录复现过程和测试结果 ,帮...
                                                    

🎯 混合检索系统成功运行!

分析Embedding vs Reranker的区别和效果:

📊 模型对比分析

1. Embedding模型特点

  • 速度: ⚡ 快速(向量相似度计算)
  • 精度: �� 中等(语义相似度)
  • 适用场景: 粗筛阶段,从大量文档中快速筛选候选

2. Reranker模型特点

  • 速度: 🐌 较慢(需要逐对计算相关性)
  • 精度: 高精度(专门的相关性判断)
  • 适用场景: 精筛阶段,对候选文档进行精确排序

🔍 实际效果对比

查询1: “李明的工作经验”

方法结果1结果2结果3
仅Embedding相似度=0.4475 (自我介绍)相似度=0.3059 (测试经验)相似度=0.2979 (开发经验)
仅Reranker相关性=0.9995 (自我介绍)相关性=0.9819 (工作经历)相关性=0.0158 (社会实践)
混合检索相关性=0.9995 (自我介绍)相关性=0.9819 (工作经历)相关性=0.0028 (开发经验)

查询2: “技术技能和编程语言”

方法结果1结果2结果3
仅Embedding相似度=0.3679 (自我介绍)相似度=0.3538 (测试经验)相似度=0.3130 (社会实践)
仅Reranker相关性=0.0336 (测试经验)相关性=0.0254 (自我介绍)相关性=0.0200 (工作经历)
混合检索相关性=0.0336 (测试经验)相关性=0.0254 (自我介绍)相关性=0.0200 (工作经历)

🚀 关键发现

1. Reranker的精准性

  • 高相关性判断: 对于明确相关的查询,Reranker能给出接近1.0的高分
  • 低相关性过滤: 对于不相关的内容,Reranker能给出接近0.0的低分
  • 区分度强: 分数分布更加极端,便于区分相关和不相关内容

2. Embedding的语义理解

  • 语义相似: 能找到语义相关但不完全匹配的内容
  • 分数平滑: 相似度分数分布相对平滑
  • 召回率高: 能找到更多潜在相关的内容

3. 混合检索的优势

  • 效率平衡: Embedding快速筛选候选,Reranker精确排序
  • 精度提升: 最终结果质量显著高于单独使用任一模型
  • 可扩展性: 适合大规模文档检索场景

💡 使用建议

何时使用Embedding

  • 文档库很大(>1000篇)
  • 需要快速响应
  • 对精度要求不是特别高

何时使用Reranker

  • 文档库较小(<1000篇)
  • 对精度要求很高
  • 可以接受较慢的响应速度

何时使用混合检索

  • 生产环境的最佳选择
  • 既需要速度又需要精度
  • 文档库规模中等

混合检索系统已经完美展示了两种模型的优势和互补性,在实际应用中非常有效。

import fitz  # PyMuPDF
import numpy as np
from typing import List, Tuple, Dict
from test_qwen3_embedding import Qwen3Embedding
from test_qwen3_reranker import Qwen3Reranker
import torch
import re

class HybridPDFRetriever:
    def __init__(self, 
                 embedding_model_path: str = "models/Qwen3-Embedding-0.6B/Qwen/Qwen3-Embedding-0.6B",
                 reranker_model_path: str = "models/Qwen3-Reranker-0.6B/Qwen/Qwen3-Reranker-0.6B"):
        """
        初始化混合PDF检索器
        Args:
            embedding_model_path: Qwen3 Embedding模型路径
            reranker_model_path: Qwen3 Reranker模型路径
        """
        print("正在加载Qwen3 Embedding模型...")
        self.embedding_model = Qwen3Embedding(embedding_model_path)
        print("Embedding模型加载完成!")
        
        print("正在加载Qwen3 Reranker模型...")
        self.reranker_model = Qwen3Reranker(
            model_name_or_path=reranker_model_path,
            instruction="Given the user query, retrieval the relevant passages",
            max_length=2048
        )
        print("Reranker模型加载完成!")
        
        self.documents = []
        self.embeddings = None
        self.chunk_size = 300
        
    def load_pdf(self, pdf_path: str) -> List[str]:
        """加载PDF文件并提取文本"""
        print(f"正在加载PDF文件: {pdf_path}")
        
        try:
            doc = fitz.open(pdf_path)
            full_text = ""
            
            for page_num in range(len(doc)):
                page = doc.load_page(page_num)
                text = page.get_text()
                full_text += f"第{page_num + 1}页: " + text + "\n"
            
            doc.close()
            
            self.documents = self._split_text(full_text)
            print(f"成功提取 {len(self.documents)} 个文本块")
            
            return self.documents
            
        except Exception as e:
            print(f"加载PDF文件失败: {e}")
            return []
    
    def _split_text(self, text: str) -> List[str]:
        """将文本分割成小块"""
        sentences = re.split(r'[。!?;\n]', text)
        chunks = []
        current_chunk = ""
        
        for sentence in sentences:
            sentence = sentence.strip()
            if not sentence:
                continue
                
            if len(current_chunk) + len(sentence) <= self.chunk_size:
                current_chunk += sentence + "。"
            else:
                if current_chunk:
                    chunks.append(current_chunk.strip())
                current_chunk = sentence + "。"
        
        if current_chunk:
            chunks.append(current_chunk.strip())
        
        return chunks
    
    def build_embeddings(self):
        """为所有文档构建向量表示"""
        if not self.documents:
            print("没有文档可以构建向量")
            return
            
        print("正在构建文档向量...")
        with torch.inference_mode():
            self.embeddings = self.embedding_model.encode(self.documents, is_query=False)
        print("文档向量构建完成")
    
    def hybrid_search(self, query: str, top_k_embedding: int = 10, top_k_final: int = 5) -> List[Tuple[str, float, int]]:
        """
        混合检索:Embedding粗筛 + Reranker精筛
        Args:
            query: 查询文本
            top_k_embedding: Embedding阶段返回的候选数量
            top_k_final: 最终返回的结果数量
        Returns:
            结果列表,每个元素包含(文档内容, 相关性分数, 文档索引)
        """
        if self.embeddings is None:
            print("请先调用 build_embeddings() 构建文档向量")
            return []
        
        print(f"正在进行混合检索: {query}")
        print("="*50)
        
        # 第一阶段:Embedding粗筛
        print("第一阶段:Embedding粗筛")
        with torch.inference_mode():
            query_embedding = self.embedding_model.encode([query], is_query=True)
        
        similarities = torch.mm(query_embedding, self.embeddings.T)
        similarities = similarities.squeeze().cpu().numpy()
        
        # 获取top-k候选
        top_indices = np.argsort(similarities)[::-1][:top_k_embedding]
        candidates = [(self.documents[idx], similarities[idx], idx) for idx in top_indices]
        
        print(f"Embedding阶段找到 {len(candidates)} 个候选文档:")
        for i, (doc, score, idx) in enumerate(candidates, 1):
            print(f"  候选{i}: 相似度={score:.4f}, 索引={idx}")
            print(f"    内容: {doc[:80]}...")
        
        # 第二阶段:Reranker精筛
        print(f"\n第二阶段:Reranker精筛")
        if len(candidates) > 0:
            # 构建查询-文档对
            pairs = [(query, doc) for doc, _, _ in candidates]
            
            # 使用Reranker计算相关性分数
            reranker_scores = self.reranker_model.compute_scores(pairs)
            
            # 组合结果
            reranked_results = []
            for i, (doc, embedding_score, idx) in enumerate(candidates):
                reranker_score = reranker_scores[i]
                reranked_results.append((doc, reranker_score, idx, embedding_score))
            
            # 按Reranker分数排序
            reranked_results.sort(key=lambda x: x[1], reverse=True)
            
            print(f"Reranker阶段重新排序结果:")
            for i, (doc, reranker_score, idx, embedding_score) in enumerate(reranked_results, 1):
                print(f"  排序{i}: Reranker分数={reranker_score:.4f}, Embedding分数={embedding_score:.4f}, 索引={idx}")
                print(f"    内容: {doc[:80]}...")
            
            # 返回最终结果
            final_results = [(doc, reranker_score, idx) for doc, reranker_score, idx, _ in reranked_results[:top_k_final]]
            return final_results
        
        return []
    
    def embedding_only_search(self, query: str, top_k: int = 5) -> List[Tuple[str, float, int]]:
        """仅使用Embedding的搜索"""
        if self.embeddings is None:
            print("请先调用 build_embeddings() 构建文档向量")
            return []
        
        print(f"仅使用Embedding搜索: {query}")
        
        with torch.inference_mode():
            query_embedding = self.embedding_model.encode([query], is_query=True)
        
        similarities = torch.mm(query_embedding, self.embeddings.T)
        similarities = similarities.squeeze().cpu().numpy()
        
        top_indices = np.argsort(similarities)[::-1][:top_k]
        
        results = []
        for idx in top_indices:
            score = float(similarities[idx])
            doc_content = self.documents[idx]
            results.append((doc_content, score, idx))
        
        return results
    
    def reranker_only_search(self, query: str, top_k: int = 5) -> List[Tuple[str, float, int]]:
        """仅使用Reranker的搜索(对所有文档)"""
        print(f"仅使用Reranker搜索: {query}")
        
        if len(self.documents) == 0:
            print("没有文档可以搜索")
            return []
        
        # 构建所有查询-文档对
        pairs = [(query, doc) for doc in self.documents]
        
        # 使用Reranker计算相关性分数
        reranker_scores = self.reranker_model.compute_scores(pairs)
        
        # 组合结果并排序
        results = []
        for i, (doc, score) in enumerate(zip(self.documents, reranker_scores)):
            results.append((doc, score, i))
        
        results.sort(key=lambda x: x[1], reverse=True)
        return results[:top_k]

def main():
    # 初始化检索器
    retriever = HybridPDFRetriever()
    
    # 加载PDF
    pdf_path = r"C:\Users\sanrome\Documents\三郎简历-zh.pdf"
    documents = retriever.load_pdf(pdf_path)
    if not documents:
        print("PDF加载失败,程序退出")
        return
    
    # 构建向量
    retriever.build_embeddings()
    
    print("\n" + "="*80)
    print("=== 混合检索系统测试 ===")
    print("="*80)
    
    # 测试查询
    test_queries = [
        "李明的工作经验",
        "技术技能和编程语言",
        "应聘的岗位和公司",
        "测试和开发经验"
    ]
    
    for query in test_queries:
        print(f"\n{'='*60}")
        print(f"查询: {query}")
        print(f"{'='*60}")
        
        # 1. 仅Embedding搜索
        print("\n1️⃣ 仅Embedding搜索:")
        embedding_results = retriever.embedding_only_search(query, top_k=3)
        for i, (doc, score, idx) in enumerate(embedding_results, 1):
            print(f"  结果{i}: 相似度={score:.4f}, 索引={idx}")
            print(f"    内容: {doc[:100]}...")
        
        # 2. 仅Reranker搜索
        print("\n2️⃣ 仅Reranker搜索:")
        reranker_results = retriever.reranker_only_search(query, top_k=3)
        for i, (doc, score, idx) in enumerate(reranker_results, 1):
            print(f"  结果{i}: 相关性={score:.4f}, 索引={idx}")
            print(f"    内容: {doc[:100]}...")
        
        # 3. 混合搜索
        print("\n3️⃣ 混合搜索 (Embedding + Reranker):")
        hybrid_results = retriever.hybrid_search(query, top_k_embedding=5, top_k_final=3)
        for i, (doc, score, idx) in enumerate(hybrid_results, 1):
            print(f"  结果{i}: 最终相关性={score:.4f}, 索引={idx}")
            print(f"    内容: {doc[:100]}...")

if __name__ == "__main__":
    main()