实用笔记:分块是RAG中隐藏的设计决策
实用笔记操作指南:分块是RAG中隐藏的设计决策——为采用该模式的团队提供契约、校验机制以及可直接插入的代码模块。
本指南将逐步展示如何从原始材料构建出一个可运行的系统:分块处理是RAG中隐含的设计决策。重点在于具体的操作步骤、明确的检查点,以及可以直接放入代码库中的代码,无需猜测其用途。 在概览阶段,应在修改代码之前明确输入参数、各步骤的负责人以及终止标准。操作人员应能够从已知的检查点重新运行相应步骤,而无需猜测系统的隐藏状态。 需同时记录正常流程和异常恢复流程。重试机制、人工审核环节以及错误处理都是产品不可或缺的部分,而非后续需要补充的功能。
RAG流程
在处理RAG流程阶段时,首先写下相关规范:所需的输入参数、成功信号以及部分失败时的处理方式。这样的检查清单能确保后续的代码修改保持一致性。 建议采用小型、可测试的单元而非庞大的脚本。当某个步骤出现故障时,故障应指向单一的责任模块,而非复杂的流程链。 在调整提示词之前,先使用固定的问题集来测试召回率。仅仅更换提示词很难解决检索效果不佳的问题。
从文本到向量
在“从文本到向量”阶段工作时,首先写下相关契约:所需的输入、成功信号以及部分失败时的处理方式。这样的检查清单能确保后续的代码修改保持一致性。 将这一阶段视为输入与经过验证的输出之间的契约。为相关成果命名,明确成功判定标准,杜绝无声的半完成状态。 在调整提示词之前,先使用固定的问题集来衡量召回率。仅仅更换提示词很难改善较差的检索效果。
分块大小与重叠度
在处理分块大小与重叠度阶段时,首先需明确相关约定:所需输入、成功信号以及部分失败时的处理方式。这样的清单能确保后续的代码修改始终符合初始设计。
在功能结果旁记录处理时间以及令牌或查询成本。提前了解成本情况,可避免在系统从演示环境过渡到共享环境时出现意外费用。
在调整提示词之前,先使用固定的问题集测试系统的召回率。仅仅更换提示词往往无法改善较差的检索效果。
在处理分块大小与重叠度阶段时,首先需明确相关约定:所需输入、成功信号以及部分失败时的处理方式。这样的清单能确保后续的代码修改始终符合初始设计。
需同时记录正常流程与异常恢复流程。重试机制、人工干预措施以及错误处理方式都是产品不可或缺的部分,而非后续需要补充的功能。
DEFAULT_CHUNK_SIZE = 800 # characters
DEFAULT_CHUNK_OVERLAP = 150 # characters
stride = chunk_size − chunk_overlap
= 800 − 150
= 650 characters
"…but left school at the age of ten."
向量存储记录包含的内容
将“向量存储记录”这一环节视为可度量的对象来处理,其效果最佳。在扩大范围之前,先记录一份理想的处理结果、一个故障案例以及回滚说明。 相比复杂的脚本,应优先使用小型且可测试的单元。当某个步骤出现故障时,故障点应指向单一责任主体,而非错综复杂的处理流程。 应将分块策略与检索策略分开。当质量指标发生变化时,修改其中一项不应迫使重新编写另一项。
id
document
embedding
metadata
id 7c2a1e90-4b11-4d3e-9f08-12a6c0e84b21
document "His boyhood in Boston was a stern beginning of the habit
of hard work and rigid economy which marked the man. For
a year he went to the Latin Grammar School on School
Street, but left off at the age of ten to help his father
in making soap and candles."
embedding 384 floats — [-0.0412, 0.0187, 0.0621, -0.0094, 0.0330, …]
norm = 1.0
metadata {
book: "Franklin's Autobiography",
source: "https://www.gutenberg.org/cache/epub/36151/pg36151-images.html",
gutenberg_id: 36151,
page_label: "5",
chunk_index: 2
}
为什么规范化很重要
将“为何标准化很重要”这一阶段视为可测量的对象来处理效果最佳。在扩大范围之前,先记录一份完美的示例文本、一个失败案例以及回滚说明。 把这一阶段视为输入与经过验证的输出之间的契约。为相关成果命名,明确成功标准,绝不允许默默地只完成部分工作。 将分块策略与检索策略分开。当质量指标发生变化时,修改其中一项不应迫使重新编写另一项。
‖v‖ = √(v₁² + v₂² + … + vₙ²)
cos θ = (a · b) / (‖a‖ ‖b‖)
If ‖a‖ = ‖b‖ = 1:
cos θ = a · b
你看不见的令牌限制
将你所设定的令牌限制视为一个可测量的指标,这样效果最佳。在扩大应用范围之前,先记录一份理想的操作流程、一个故障案例以及回滚说明。 在功能测试结果旁同时记录执行时间以及令牌或查询成本。提前了解成本情况,就能避免在从演示环境过渡到共享环境时出现意外账单。 为每轮操作和每次会话设定令牌预算。智能工具往往会大量消耗上下文资源,设置上限可防止演示环境变成令人意外的费用来源。 将你所设定的令牌限制视为一个可测量的指标,这样效果最佳。在扩大应用范围之前,先记录一份理想的操作流程、一个故障案例以及回滚说明。 同时记录正常运行路径和故障恢复路径。重试机制、人工审核环节以及错误处理流程都是产品本身的一部分,而非后续需要补充的内容。
maximum safe chunk size in characters
≈ model token limit × 4
代码片段
在代码片段阶段,应在修改代码之前明确输入内容、该步骤的负责人以及结束标准。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测隐藏状态。 优先选择小型、可测试的单元,而非冗长的脚本。当某个步骤失败时,故障应指向单一责任点,而非复杂的流程链。 需引用实际作为答案依据的段落。没有引用的话,操作人员就无法区分是幻觉内容还是索引缺失所致。
from rag_qa.gutenberg import load_pages
from rag_qa.chunk import chunk_documents
from rag_qa.config import load_settings
s = load_settings()
print(s.summary())
# {
# 'chunk_size_chars': 800,
# 'chunk_overlap_chars': 150,
# 'stride_chars': 650, # size − overlap; this sets chunk count
# 'model': 'all-MiniLM-L6-v2',
# 'model_max_tokens': 256, # hard cap; overflow is silent
# 'embedding_dims': 384,
# 'max_safe_chunk_chars': 1024, # 256 × 4
# 'book': "Franklin's Autobiography",
# 'gutenberg_id': 36151,
# }
pages = load_pages()
chunks = chunk_documents(pages, s.chunk_size, s.chunk_overlap)
print(len(pages), len(chunks), s.stride)
from sentence_transformers import SentenceTransformer
from rag_qa.tokens import check_chunk
m = SentenceTransformer("all-MiniLM-L6-v2")
print(m.max_seq_length) # 256
for c in chunks:
r = check_chunk(c)
if r.truncated:
print("silent truncate:", r.n_chars, "chars /", r.n_tokens, "tokens")
256
256
silent truncate: 1820 chars / 412 tokens
silent truncate: 960 chars / 301 tokens
from rag_qa.store import ingest, open_store
store = open_store()
ingest(chunks, store)
row = store.get(limit=1)
print(row["ids"][0])
print(row["documents"][0][:200])
print(len(row["embeddings"][0]), row["metadatas"][0])
# 384 floats, norm 1.0, metadata.page_label == printed [Pg N]
doc-12-p3-c0
She left school at the age of ten. The next sentence continues on the same page…
384 {'page_label': '3', 'source': 'notes.pdf'}
from rag_qa.retrieve import search, search_mmr
q = "why did Franklin want Britain to keep Canada"
for hit in search(q, k=5):
print(f"{hit['score']:.3f} p.{hit['metadata']['page_label']} {hit['document'][:120]}")
# overlap makes near-duplicate hits; MMR trades a little score for diversity
for hit in search_mmr(q, k=5):
print(hit["metadata"]["page_label"], hit["score"])
0.812 p.7 I have long been of opinion that the foundations of the future grandeur and stability of the British empire lie in America
0.781 p.7 they are, nevertheless, broad and strong enough to support the greatest political structure that human wisdom ever yet
0.744 p.7 I am, therefore, by no means for restoring Canada. If we keep it all the country from the St. Lawrence to the Mississippi
0.691 p.8 I left England about the end of August, 1762, in company with ten sail of merchant ships
0.640 p.6 In this Autobiography Franklin tells of his own life to the year 1757, when he went to England
附录
在补充阶段,应在修改代码之前明确输入内容、该步骤的负责人以及结束标准。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测隐藏状态。 将此阶段视为输入与经过验证的输出之间的契约。为相关成果命名,定义成功判定标准,并拒绝默许的半完成状态。 需引用实际作为答案依据的段落。没有引用的话,操作人员就无法区分是幻觉还是索引缺失所致。
A. 同一段落,部分内容重复出现
在“相同段落重叠”阶段,修改代码之前需明确输入参数、该步骤的负责人以及终止标准。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测隐藏状态。 在功能结果旁记录执行时间以及令牌或查询成本。提前显示成本可避免在流程从演示环境转向共享环境时出现意外费用。 需注明实际用于生成答案的段落。没有引用的话,操作人员就无法区分是幻觉内容还是索引缺失导致的错误。 在“相同段落重叠”阶段,修改代码之前需明确输入参数、该步骤的负责人以及终止标准。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测隐藏状态。 需同时记录正常流程和异常恢复流程。重试机制、人工审核环节以及错误处理方式都是产品本身的组成部分,而非后续需要补充的内容。
[0] 59 His boyhood in Boston was a stern beginning of the habit of
[1] 55 hard work and rigid economy which marked the man. For a
[2] 58 year he went to the Latin Grammar School on School Street,
[3] 31 but left off at the age of ten.
[0] 59 His boyhood in Boston was a stern beginning of the habit of
[1] 57 ⟦the habit of⟧ hard work and rigid economy which marked the
[2] 55 ⟦marked the⟧ man. For a year he went to the Latin Grammar
[3] 58 ⟦Latin Grammar⟧ School on School Street, but left off at the
[4] 22 ⟦off at the⟧ age of ten.
⟦…⟧ = text repeated from the previous chunk
B. 用于构建RAG的库以及向量的存储位置
在处理构建阶段的B类库时,首先明确相关规范:所需的输入参数、成功信号,以及部分失败时的处理方式。这样的检查清单能确保后续的代码修改保持一致性。 建议使用小型、可测试的单元而非庞大的脚本。当某个步骤出现故障时,故障应指向单一的责任模块,而非复杂的流程链。 在调整提示词之前,先使用固定的问题集来评估召回率。仅仅更换提示词往往无法解决检索效果不佳的问题。
操作检查清单
将操作检查清单阶段视为可衡量的指标,效果会更好。在扩大范围之前,先记录一份理想的处理结果、一个故障案例以及回滚说明。
将配置信息置于应用程序代码之外。环境文件、密钥存储以及功能开关应集中存放于一处,以便操作人员无需查看全部架构即可进行审计。
将分块策略与检索策略分开。当质量指标发生变化时,修改其中一项不应迫使重新编写另一项。
在预算允许的情况下,利用测试数据而非真实的付费 API,在持续集成过程中添加用于检测关键路径的冒烟测试。
同时记录正常流程与故障恢复流程。重试机制、人工审核环节以及死信处理都是产品不可或缺的部分,而非后续需要补充的功能。
将分块策略与检索策略分开。当质量指标发生变化时,修改其中一项不应迫使重新编写另一项。
在推广该技术栈之前,应先冻结版本,为关键流程记录标准输出日志,并明确回滚步骤。共享环境需要设置速率限制、租户验证机制,以及负责密钥轮换的明确责任人。与其展示花哨的一次性演示,不如注重扎实的可靠性。
关于62ec22cbf28d的批注:请将提供商密钥移出代码仓库,设定单会话令牌上限,并将日志存储在评估用示例文件旁,以便后续模型更换时仍能保持对比性。