首页 / 文章 / 《实用笔记:RAG、嵌入模型与向量数据库——从零开始讲解》

《实用笔记:RAG、嵌入模型与向量数据库——从零开始讲解》

《实用笔记:RAG、嵌入模型与向量数据库——从零开始讲解》的操作指南:适用于采用该模式的团队的合同、检查项及可直接使用的代码模板。

3817 词

可将此内容视为《从零开始讲解RAG、嵌入模型与向量数据库》中理念的面向操作员的重构版本:清晰的阶段划分、有序的代码模块,以及便于交接时参考的恢复说明。在“概览”阶段,若能将其视为可度量的基准,则效果最佳——在扩大范围之前,应先记录一份理想的处理过程、一个故障案例以及对应的回滚说明。相比冗长的脚本,更应采用小型且可测试的单元。当某一步骤出现故障时,故障原因应能明确指向某个特定责任模块,而非整个复杂的流程。

什么是RAG?

在“什么是RAG”阶段,应在修改代码之前明确输入内容、该步骤的负责人以及结束标准。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测隐藏状态。 将此阶段视为输入与经过验证的输出之间的契约。为相关成果命名,定义成功判定标准,并拒绝默许的半完成状态。 需注明实际作为答案依据的段落。没有引用的话,操作人员就无法区分幻觉内容与索引缺失的问题。

[ Documents ] --> [ Chunk ] --> [ Embed ] --> [ Store in Vector DB ]
                                                       |
User Question --> [ Embed Question ] --> [ Find Similar Chunks ] --> [ LLM ] --> Answer

什么是嵌入?

在“什么是嵌入”阶段,应在修改代码之前明确输入内容、该步骤的负责人以及结束标准。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测隐藏状态。除了功能结果外,还需记录执行时间以及令牌或查询成本。提前显示成本信息,可避免在从演示环境切换到共享环境时出现意外费用。必须注明实际作为答案依据的段落;没有引用的话,操作人员就无法区分幻觉内容与索引缺失的问题。

"king"   → [0.21, -0.05, 0.87, ..., 0.33]   (384 numbers)
"queen"  → [0.19, -0.03, 0.85, ..., 0.31]   (384 numbers)
"banana" → [-0.72, 0.44, 0.01, ..., -0.56]  (384 numbers)

文本如何转化为数字

在“文本如何转换为数字”阶段,应在修改代码之前明确输入参数、该步骤的负责人以及结束标准。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测隐藏状态。 配置信息应置于应用程序代码之外。环境文件、密钥存储和功能标志应集中存放于一个位置,以便操作人员无需查看整个系统结构即可进行审核。 需引用实际作为答案依据的段落。没有引用的话,操作人员就无法区分是幻觉内容还是索引缺失导致的错误。 在“文本如何转换为数字”阶段,应在修改代码之前明确输入参数、该步骤的负责人以及结束标准。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测隐藏状态。 相较于庞大的脚本,更应优先使用小型且可测试的单元。当某个步骤失败时,故障原因应能明确指向单一责任模块,而非复杂的整体问题。

管道。

步骤1:分词

在执行第一步“分词”阶段时,首先写下相关契约:所需的输入参数、成功信号以及部分失败时的处理方式。这样的清单能确保后续的代码修改保持一致性。 将此阶段视为输入与验证后输出之间的契约。为相关产物命名,明确成功判定标准,杜绝无声的半完成状态。 缓存稳定的系统指令和工具架构。重复发送相同的开头信息是造成资源浪费的常见原因。

"backend engineer jobs in bangalore"
Tokens: ["backend", "engineer", "jobs", "in", "bang", "##alore"]

步骤2:Transformer层

在处理第二步的Transformer层阶段时,首先列出相关规范:所需输入、成功信号以及部分失败时的处理方式。这样的检查清单能确保后续的代码修改保持一致性。 在功能结果旁记录执行时间以及token或查询成本。提前了解成本情况,可避免从演示环境过渡到共享环境时出现意外费用。 在调整提示词之前,先使用固定的问题集测试召回率。仅仅更换提示词往往无法改善较差的检索效果。

"backend"   → [0.52, -0.18, 0.83, 0.45, ...]   (384 numbers)
"engineer"  → [0.48, -0.15, 0.79, 0.41, ...]   (384 numbers)
"jobs"      → [0.31, -0.05, 0.67, 0.22, ...]   (384 numbers)
"in"        → [0.07, 0.02, 0.11, 0.04, ...]    (384 numbers)
"bang"      → [0.39, 0.27, 0.55, 0.30, ...]    (384 numbers)
"##alore"   → [0.14, 0.10, 0.21, 0.11, ...]    (384 numbers)

第三步:聚合

在处理第三步的聚合阶段时,首先需明确相关规范:所需的输入参数、成功信号以及部分失败时的处理方式。这样的清单能确保后续的代码修改保持一致性。 应将配置信息与应用程序代码分开存放。环境文件、密钥存储以及功能开关应集中管理,以便操作人员无需查看整个系统结构即可进行审计。 在调整提示词之前,先使用固定的问题集来测试召回率。仅仅更换提示词往往无法解决检索效果不佳的问题。 在处理第三步的聚合阶段时,首先需明确相关规范:所需的输入参数、成功信号以及部分失败时的处理方式。这样的清单能确保后续的代码修改保持一致性。 相比庞大的脚本,更应优先使用小型且可测试的单元。当某个步骤出现故障时,故障原因应能明确指向某个具体的功能模块,而非整个复杂的流程。

Dimension 1: (0.52 + 0.48 + 0.31 + 0.07 + 0.39 + 0.14) / 6 = 0.318
Dimension 2: (-0.18 + -0.15 + -0.05 + 0.02 + 0.27 + 0.10) / 6 = 0.002
... same for all 384 dimensions ...
Final: [0.318, 0.002, ...]  ← ONE vector for the entire sentence

简要说明:向量与维度

将“向量与维度”这一环节视为可测量的表面来处理,效果最佳。在扩大范围之前,先收集一份优秀的案例、一个失败案例以及回滚说明。 把这一环节视为输入与经过验证的输出之间的契约。为相关成果命名,明确成功标准,绝不允许默许部分完成的情况。 应将分块策略与检索策略分开。当质量指标发生变化时,修改其中一项不应强制要求重新编写另一项。

2D point (on a map):     [x, y]           → 1 vector, 2 dimensions
3D point (in a room):    [x, y, z]        → 1 vector, 3 dimensions
Embedding:               [n1, n2, ..n384] → 1 vector, 384 dimensions

什么是向量数据库?

“什么是向量”阶段若被视为可测量的表面,效果最佳。在扩大范围之前,先记录一个成功的案例、一个失败案例以及回滚说明。在功能结果旁同时记录处理时间以及令牌或查询成本。提前了解成本情况,可避免在系统从演示环境过渡到共享环境时出现意外账单。应将分块策略与检索策略分开,当质量指标发生变化时,修改其中一项不应迫使重新编写另一项。

┌──────────────────────────────────────────────────┐
│                   Vector DB                      │
│                                                  │
│  Entry 1:                                        │
│    text:   "Senior Backend Engineer Wipro..."    │
│    vector: [0.21, -0.05, 0.87, ...]              │
│                                                  │
│  Entry 2:                                        │
│    text:   "Frontend dev needed Chennai..."      │
│    vector: [0.71, 0.55, -0.30, ...]              │
│                                                  │
│  Entry 3:                                        │
│    text:   "Backend Engineer Flipkart..."        │
│    vector: [0.19, -0.03, 0.85, ...]              │
│                                                  │
└──────────────────────────────────────────────────┘

会存储多少个向量?

“有多少向量被获取”这一阶段若被视为可度量的对象,效果最佳。在扩大范围之前,应先记录一份理想案例、一个故障实例以及回滚说明。 配置应置于应用程序代码之外。环境文件、密钥存储和功能标志应集中存放于一处,以便操作人员无需查看整个系统结构即可进行审计。 分块策略与检索策略应分开处理。当质量指标发生变化时,修改其中一项不应迫使重新编写另一项。 “有多少向量被获取”这一阶段若被视为可度量的对象,效果最佳。在扩大范围之前,应先记录一份理想案例、一个故障实例以及回滚说明。 相较于庞大的脚本,宜采用小型且可测试的单元。当某个步骤出现故障时,故障应指向单一责任模块,而非复杂的流程链。

Page 1 (naukri.com)    → 3000 chars → split into 6 chunks  → 6 vectors
Page 2 (linkedin.com)  → 5000 chars → split into 10 chunks → 10 vectors
Page 3 (indeed.com)    → 2000 chars → split into 4 chunks  → 4 vectors
Page 4 (glassdoor.com) → 4500 chars → split into 9 chunks  → 9 vectors
Page 5 (some blog)     → 1500 chars → split into 3 chunks  → 3 vectors
                                       ─────────
                                       32 vectors in the database

检索机制的工作原理

在“检索原理”阶段,应在修改代码之前明确输入内容、该步骤的负责人以及结束标准。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测隐藏状态。 将此阶段视为输入与经过验证的输出之间的契约。为相关成果命名,定义成功判定标准,并拒绝默许的半完成状态。 需引用实际作为答案依据的段落。没有引用的话,操作人员就无法区分幻觉内容与索引缺失的问题。

步骤1:使用相同的模型嵌入查询

在第一步“嵌入阶段”中,应在修改代码之前明确输入参数、该步骤的负责人以及结束标准。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测隐藏状态。除了功能结果外,还需记录执行时间以及令牌或查询成本。提前了解成本情况,可避免在从演示环境切换到共享环境时出现意外费用。当下一步操作是编写代码或调用工具时,建议使用具有架构验证的结构化输出,而非自由形式的文本。

"backend engineering jobs in Bengaluru" → [0.20, -0.04, 0.86, ...]

第二步:与所有存储的向量进行比较

在“第2步:对比阶段”中,修改代码之前需明确输入参数、该步骤的负责人以及终止标准。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测隐藏状态。 配置信息应置于应用程序代码之外。环境文件、密钥存储以及功能标志应集中存放于一个位置,以便操作人员无需查看整个流程即可进行审计。 需引用实际作为答案依据的段落。没有引用的话,操作人员就无法区分是虚假信息还是索引缺失导致的错误。 在“第2步:对比阶段”中,修改代码之前需明确输入参数、该步骤的负责人以及终止标准。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测隐藏状态。 相较于庞大的脚本,应优先使用小型且可测试的单元。当某个步骤失败时,故障原因应能明确指向单一责任模块,而非复杂的处理流程。

。

Query vector vs Chunk 1 ("Senior Backend Engineer Wipro, Bengaluru...")
→ similarity: 0.95 ✅
Query vector vs Chunk 2 ("Frontend dev needed Chennai...")
→ similarity: 0.23 ❌Query vector vs Chunk 3 ("Backend Engineer Flipkart Bengaluru...")
→ similarity: 0.97 ✅

步骤3:返回前k个块

在执行“返回前k个块”这一步骤时,首先需明确合同条款:所需的输入、成功信号以及部分失败时的处理方式。这样的检查清单能确保后续的代码修改保持一致性。 将此阶段视为输入与经过验证的输出之间的契约。为相关成果命名,定义成功判定标准,并拒绝默许的部分完成。 在调整提示词之前,需先用固定的问题集来衡量召回率。仅仅更换提示词很难改善较差的检索效果。

分块问题

在处理“分块问题”阶段时,首先写下相关规范:所需的输入、成功信号以及部分失败时的处理方式。这样的清单能确保后续的代码修改保持一致性。 在功能结果旁记录执行时间以及令牌或查询成本。提前了解成本情况,可避免从演示环境过渡到共享环境时出现意外费用。 在调整提示词之前,先用固定的问题集测试召回率。仅仅更换提示词很难改善较差的检索效果。

Original text:
"...looking for a talented software engineer with 5 years of backend experience..."
Chunk 1 (chars 0-500):   "...looking for a talented software engi"
Chunk 2 (chars 500-999): "neer with 5 years of backend experience..."
"Home  About  Careers  Login  Contact Us  Senior Backend Eng"

更好的方法:

在“改进方法”阶段,首先需明确相关规范:所需的输入参数、成功标志以及部分失败时的处理方式。这份清单能确保后续的代码修改始终符合预期。 应将配置信息与应用程序代码分开存放。环境文件、密钥存储以及功能开关应集中管理,这样操作人员无需查看整个系统结构即可进行审计。 在调整提示词之前,先使用固定的问题集来测试召回率。仅仅更换提示词往往无法解决检索效果不佳的问题。 在“改进方法”阶段,首先需明确相关规范:所需的输入参数、成功标志以及部分失败时的处理方式。这份清单能确保后续的代码修改始终符合预期。 相比庞大的脚本,更应优先使用小型且可测试的单元。当某个步骤出现故障时,故障点应能明确指向某个具体的功能模块,而非整个复杂的流程。

结合实际数据的完整解析

将《A Complete Walkthrough With stage》视为可度量的工作面最为有效。在扩大范围之前,先记录一个成功的案例、一个失败案例以及回滚说明。 把这一阶段视为输入与经过验证的输出之间的契约。为相关成果命名,明确成功标准,绝不允许默默地只完成部分工作。 将分块策略与检索策略分开。当质量指标发生变化时,修改其中一项不应强制要求重新编写另一项。

"Home Jobs Companies Senior Backend Engineer Wipro, Bengaluru
 Build scalable APIs using Java Spring Boot. 5+ years experience required."

分词(29个标记):

将“分词为29个标记”这一阶段视为可测量的指标时效果最佳。在扩大范围之前,先记录一份理想的转录结果、一个失败案例以及回滚说明。在功能结果旁同时记录处理时间以及标记或查询成本。提前了解成本情况,可避免在从演示环境过渡到共享环境时出现意外账单。为每轮对话和每次会话设定标记使用预算。智能工具往往会大量消耗上下文资源,设置上限能防止演示环境变成令人意外的收费来源。

["[CLS]", "home", "jobs", "companies", "senior", "backend", "engineer",
 "wi", "##pro", ",", "bengal", "##uru", "build", "scala", "##ble",
 "api", "##s", "using", "java", "spring", "boot", ".", "5", "+",
 "years", "experience", "required", ".", "[SEP]"]

单标记向量(为便于阅读,仅显示8个维度而非384个):

将分为8个阶段的每令牌向量视为可测量的指标时效果最佳。在扩大范围之前,需记录一份理想案例、一个故障实例以及回滚说明。 配置应置于应用程序代码之外。环境文件、密钥存储和功能标志应集中存放,以便操作人员无需查看整个系统结构即可进行审计。 为每轮对话和每次会话设定令牌预算。智能工具往往会过度扩展上下文,设置上限可避免演示过程变成意外的费用账单。

"[CLS]"       → [ 0.01,  0.03, -0.02,  0.05,  0.01, -0.04,  0.02,  0.06]
"home"        → [ 0.44,  0.12, -0.33,  0.08, -0.21,  0.55,  0.09, -0.17]
"jobs"        → [ 0.31, -0.05,  0.67,  0.22,  0.14, -0.08,  0.43,  0.11]
"companies"   → [ 0.28,  0.09,  0.51,  0.18,  0.07, -0.12,  0.38,  0.05]
"senior"      → [ 0.15, -0.22,  0.71,  0.33,  0.41,  0.09,  0.55,  0.27]
"backend"     → [ 0.52, -0.18,  0.83,  0.45,  0.38,  0.21,  0.61,  0.34]
"engineer"    → [ 0.48, -0.15,  0.79,  0.41,  0.35,  0.18,  0.58,  0.31]
"wi"          → [ 0.11,  0.04,  0.22,  0.09,  0.03,  0.07,  0.14,  0.02]
"##pro"       → [ 0.08,  0.02,  0.19,  0.06,  0.01,  0.05,  0.11, -0.01]
","           → [ 0.00,  0.01,  0.00,  0.01, -0.01,  0.00,  0.01,  0.00]
"bengal"      → [ 0.39,  0.27,  0.55,  0.30,  0.22,  0.33,  0.41,  0.19]
"##uru"       → [ 0.14,  0.10,  0.21,  0.11,  0.08,  0.12,  0.15,  0.07]
"build"       → [ 0.35, -0.11,  0.62,  0.28,  0.19,  0.15,  0.47,  0.22]
"scala"       → [ 0.29, -0.09,  0.54,  0.24,  0.16,  0.11,  0.40,  0.18]
"##ble"       → [ 0.10,  0.03,  0.18,  0.07,  0.05,  0.04,  0.13,  0.06]
"api"         → [ 0.41, -0.14,  0.73,  0.37,  0.30,  0.19,  0.53,  0.28]
"##s"         → [ 0.03,  0.01,  0.05,  0.02,  0.01,  0.01,  0.04,  0.01]
"using"       → [ 0.07,  0.02,  0.11,  0.04,  0.03,  0.02,  0.08,  0.03]
"java"        → [ 0.46, -0.20,  0.77,  0.39,  0.32,  0.17,  0.56,  0.29]
"spring"      → [ 0.42, -0.16,  0.70,  0.35,  0.28,  0.14,  0.51,  0.25]
"boot"        → [ 0.38, -0.13,  0.65,  0.31,  0.25,  0.12,  0.48,  0.23]
"."           → [ 0.00,  0.01,  0.00,  0.01, -0.01,  0.00,  0.01,  0.00]
"5"           → [ 0.05,  0.01,  0.09,  0.03,  0.02,  0.01,  0.06,  0.02]
"+"           → [ 0.01,  0.00,  0.02,  0.01,  0.00,  0.00,  0.01,  0.00]
"years"       → [ 0.20, -0.07,  0.44,  0.19,  0.13,  0.08,  0.33,  0.14]
"experience"  → [ 0.33, -0.10,  0.61,  0.27,  0.20,  0.13,  0.45,  0.21]
"required"    → [ 0.18, -0.06,  0.39,  0.16,  0.11,  0.07,  0.29,  0.12]
"."           → [ 0.00,  0.01,  0.00,  0.01, -0.01,  0.00,  0.01,  0.00]
"[SEP]"       → [ 0.02,  0.01, -0.01,  0.03,  0.00, -0.02,  0.01,  0.04]

将分为8个阶段的每令牌向量视为可测量的指标时效果最佳。在扩大范围之前,需记录一份理想案例、一个故障实例以及回滚说明。 相比庞大的脚本,应优先选择小型且可测试的单元。当某个步骤出现故障时,故障原因应能明确指向某个具体责任方,而非复杂的流程链。

聚合——29个向量合并为1个:

在采用池化处理将29个向量整合为一个阶段时,应在修改代码之前明确输入内容、该步骤的负责人以及终止标准。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测隐藏状态。 应将这一阶段视为输入与经过验证的输出之间的契约。为相关成果命名,定义成功判定标准,并拒绝默许部分完成的情况。 需引用实际作为答案依据的段落。没有引用的话,操作人员就无法区分幻觉内容与索引缺失的问题。

Dim 1: (0.01 + 0.44 + 0.31 + 0.28 + 0.15 + 0.52 + 0.48 + 0.11 + 0.08 + 0.00
      + 0.39 + 0.14 + 0.35 + 0.29 + 0.10 + 0.41 + 0.03 + 0.07 + 0.46 + 0.42
      + 0.38 + 0.00 + 0.05 + 0.01 + 0.20 + 0.33 + 0.18 + 0.00 + 0.02) / 29
    = 0.231
Dim 2: (0.03 + 0.12 + -0.05 + 0.09 + -0.22 + -0.18 + -0.15 + 0.04 + 0.02 + 0.01
      + 0.27 + 0.10 + -0.11 + -0.09 + 0.03 + -0.14 + 0.01 + 0.02 + -0.20 + -0.16
      + -0.13 + 0.01 + 0.01 + 0.00 + -0.07 + -0.10 + -0.06 + 0.01 + 0.01) / 29
    = -0.030... same for all 384 dimensions ...

存储在向量数据库中:

对于存储在向量阶段的任务,在修改代码之前需明确输入参数、该步骤的负责人以及终止标准。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测隐藏状态。除了功能结果外,还需记录执行时间以及令牌或查询成本。提前了解成本情况可避免在任务从演示环境转移到共享环境时出现意外费用。必须注明实际作为答案依据的段落;没有引用的话,操作人员就无法区分是幻觉内容还是索引缺失导致的错误。

text:   "Home Jobs Companies Senior Backend Engineer Wipro, Bengaluru..."
vector: [0.231, -0.030, 0.421, 0.189, ...]

现在有用户搜索:“Wipro公司的高级后端工程师”

在 Now a user searches 阶段,修改代码之前需明确输入参数、该步骤的负责人以及终止条件。操作员应能够从已知的检查点重新运行该步骤,而无需猜测隐藏状态。 配置信息应置于应用程序代码之外。环境文件、密钥存储以及功能标志应集中存放于一个位置,以便操作员无需查看整个流程即可进行审计。 需引用实际作为答案依据的段落。没有引用的话,操作员就无法区分是幻觉内容还是索引缺失导致的错误。 在 Now a user searches 阶段,修改代码之前需明确输入参数、该步骤的负责人以及终止条件。操作员应能够从已知的检查点重新运行该步骤,而无需猜测隐藏状态。 相较于庞大的脚本,应优先使用小型且可测试的单元。当某个步骤失败时,故障原因应能指向单一责任模块,而非复杂的流程链。

Query vector: [0.228, -0.028, 0.418, 0.185, ...]
Chunk vector: [0.231, -0.030, 0.421, 0.189, ...]

两种模型,两项任务

在开展“两种模型,两项任务”阶段时,首先需列出相关契约:所需输入、成功信号以及部分失败时的处理方式。这样的清单能确保后续的代码修改保持一致性。 将此阶段视为输入与验证后输出之间的契约。为相关成果命名,明确成功判定标准,杜绝无声的半完成状态。 缓存稳定的系统指令和工具架构。重复发送相同的开头信息是导致资源浪费的常见原因。

为何RAG如此重要

在完成“为何RAG很重要”这一阶段时,首先写下相关规范:所需输入、成功标志以及部分失败时的处理方式。这样的清单能确保后续的代码修改保持一致性。 在功能结果旁记录执行时间以及令牌或查询成本。提前了解成本情况,可避免从演示环境过渡到共享环境时出现意外费用。 在调整提示词之前,先用固定的问题集测试召回率。仅仅更换提示词很难改善较差的检索效果。

什么才是优秀的嵌入模型?

在设计“什么是良好的阶段”时,首先需明确相关规范:所需的输入参数、成功标志以及部分失败时的处理方式。这样的清单能确保后续的代码修改保持一致性。 应将配置信息与应用程序代码分开存放。环境文件、密钥存储以及功能开关应集中管理,以便操作人员无需查看整个系统结构即可进行审计。 缓存系统中稳定的指令和工具架构。重复发送相同的开头信息是导致资源浪费的常见原因。 在设计“什么是良好的阶段”时,首先需明确相关规范:所需的输入参数、成功标志以及部分失败时的处理方式。这样的清单能确保后续的代码修改保持一致性。 相比庞大的脚本,更应优先使用小型且可测试的单元。当某个步骤失败时,故障应能指向具体的责任模块,而非整个复杂的流程。

A: "Senior Backend Engineer at Wipro"
B: "Software Developer role in Bengaluru"
C: "Best chocolate cake recipe"

操作检查清单

在处理操作检查清单阶段时,首先写下相关契约:所需的输入参数、成功标志以及部分失败时的处理方式。这样的检查清单能确保后续的代码修改保持一致性。

同时记录正常流程和故障恢复流程。重试机制、人工审核环节以及错误处理方式都是产品本身的一部分,而非后续的优化内容。