RAG 流水线与评估
目标
构建一套完整的 RAG pipeline:将文档切分为 chunk 并建立 index,通过 query 检索,以指标衡量检索质量,并过滤无依据的回答和无法回答的问题。
为什么重要
RAG 中最常见的错误是不区分检索失败与生成失败。回答异常时,人们往往先修改 prompt;但如果正确文档一开始就没有被检索出来,无论怎样调整 prompt 都没有用。
因此,本实验首先计算检索指标。Recall@3 检查正确文档是否进入前三,MRR 检查它排在第几位。如果这些数值较低,应当调整的是 retriever,而不是 generator。
接下来创建依据判定与拒答规则。检索分数较低时不作答,不是功能不足,而是安全机制。与其根据无关文档编造貌似可信的答案,不如明确表示不知道。
本实验不使用模型。检索和评估都可以只用 numpy 计算,而这些部分决定了 RAG 质量的大部分。
步骤
工作目录为 /root/llm,tokenization 规则与上一实验相同(转换为小写后使用 [가-힣a-z0-9]+)。
- 将
docs中每个body按句号(.)切分,去掉首尾空白并丢弃空片段,把所得 chunk 保存到/root/llm/chunks.tsv。格式为docs.id<탭>청크번호<탭>본문,chunk 编号在每个文档中从 0 开始。按文档顺序写入。 - 将 chunk 级 TF-IDF 矩阵保存到
/root/llm/chunk_tfidf.npy。形状为(chunk 数,term 数),term 是从所有 chunk 汇总并升序排列的 vocabulary。idf 中的 N 是 chunk 数,公式与 normalization 和上一实验相同。 - 对以下 8 个 query,取前三个 chunk,并保存到
/root/llm/retrieved.tsv,格式为질의번호<탭>순위<탭>docs.id<탭>청크번호<탭>점수。共 24 行,分数保留六位小数;分数相同时,文档 id 较小者优先,其次 chunk 编号较小者优先。인덱스를 만들었는데 왜 순차 스캔인가복합 인덱스는 컬럼 순서를 어떻게 정하나격리 수준을 올려도 안 잡히는 이상 현상은 무엇인가페이지 폴트가 잦으면 왜 느려지나가상 주소를 물리 주소로 어떻게 바꾸나연결 거부와 타임아웃은 무엇이 다른가큰 요청만 멈추는 이유는 무엇인가GPU 에서 워프란 무엇인가
- 上述 query 对应的正确文档依次为
24, 25, 27, 12, 11, 19, 17, 6。计算 Recall@3 和 MRR,以两行保存到/root/llm/metrics.tsv。第一列为recall_at_3和mrr,第二列为保留三位小数的值。Recall@3 在正确文档进入前三时记为 1,再除以 query 数;MRR 是正确文档首次出现排名的倒数的平均值(未出现时为 0)。 - 将第 1 个 query 的前三个 chunk 正文按排名顺序逐行保存到
/root/llm/context.txt。 - 判断下面 3 个候选回答是否以第 5 步的 context 为依据,保存到
/root/llm/grounded.tsv,格式为번호<탭>겹침비율<탭>판정。重叠比例为:对回答 token 去重后,其中属于 context token 集合的比例,保留三位小数。大于等于 0.6 时为grounded,否则为hallucinated。인덱스는 값으로 정렬된 구조라 컬럼에 함수를 씌우면 그 정렬이 쓸모없어진다옵티마이저가 인덱스를 쓰지 않는 것은 대개 옳은 판단이다인덱스를 만들면 어떤 쿼리든 언제나 세 배 빨라진다
- 对语料库中不存在的 3 个 query,将最高分与判定保存到
/root/llm/refusal.tsv,格式为번호<탭>최고점수<탭>판정。分数保留六位小数;低于 0.15 时为refuse,否则为answer。김치찌개 맛있게 끓이는 법프리미어리그 이번 주 경기 일정제주도 항공권 최저가 예약
- 在
/root/llm/rag_report.tsv中用三行总结。格式为chunks<탭>청크수、queries<탭>질의수、recall_at_3<탭>값。
参考
- chunk index 即使 term 数与 document index 相近,行数也会多得多。请先确认形状。
- 分数是 normalized vector 的 dot product,也就是 cosine similarity。
- 常见错误 1:如果以文档数为基准计算 idf,所有值都会错位。请使用 chunk 数。
- 常见错误 2:重叠比例的分母是回答 token 去重后的数量。
将文档切分为句子级 chunk
按句号切分后去掉首尾空白,并丢弃空片段。chunk 编号在每个文档中重新从 0 开始。
按 chunk 建立 index
计算 idf 时请注意,N 不是文档数,而是 chunk 数。
使用 8 个 query 检索前三个 chunk
query 也用相同方式生成 vector。请遵守分数相同时的排序规则。
计算 Recall@3 与 MRR
正确文档在前三时记为 1,否则为 0。MRR 是正确文档出现排名的倒数的平均值。
组装 context
将第 1 个 query 的检索结果按排名顺序逐行连接。
判断回答是否以 context 为依据
对回答 token 去重后,计算其中出现在 context 中的比例,再根据是否超过阈值进行判定。
拒绝语料库之外的问题
最高分低于阈值时,标记为不回答。还必须记录分数本身。
创建摘要报告
将 chunk 数、query 数、Recall@3 三项分别以名称和值配对记录。