TT Lab
开始
学习 学习路径 课程

LLM 工程

RAG 流水线与评估

在 TT Lab 中继续学习

目标

构建一套完整的 RAG pipeline:将文档切分为 chunk 并建立 index,通过 query 检索,以指标衡量检索质量,并过滤无依据的回答和无法回答的问题。

为什么重要

RAG 中最常见的错误是不区分检索失败与生成失败。回答异常时,人们往往先修改 prompt;但如果正确文档一开始就没有被检索出来,无论怎样调整 prompt 都没有用。

因此,本实验首先计算检索指标。Recall@3 检查正确文档是否进入前三,MRR 检查它排在第几位。如果这些数值较低,应当调整的是 retriever,而不是 generator。

接下来创建依据判定与拒答规则。检索分数较低时不作答,不是功能不足,而是安全机制。与其根据无关文档编造貌似可信的答案,不如明确表示不知道。

本实验不使用模型。检索和评估都可以只用 numpy 计算,而这些部分决定了 RAG 质量的大部分。

步骤

工作目录为 /root/llm,tokenization 规则与上一实验相同(转换为小写后使用 [가-힣a-z0-9]+)。

  1. 将 docs 中每个 body 按句号(.)切分,去掉首尾空白并丢弃空片段,把所得 chunk 保存到 /root/llm/chunks.tsv。格式为 docs.id<탭>청크번호<탭>본문,chunk 编号在每个文档中从 0 开始。按文档顺序写入。
  2. 将 chunk 级 TF-IDF 矩阵保存到 /root/llm/chunk_tfidf.npy。形状为(chunk 数,term 数),term 是从所有 chunk 汇总并升序排列的 vocabulary。idf 中的 N 是 chunk 数,公式与 normalization 和上一实验相同。
  3. 对以下 8 个 query,取前三个 chunk,并保存到 /root/llm/retrieved.tsv,格式为 질의번호<탭>순위<탭>docs.id<탭>청크번호<탭>점수。共 24 行,分数保留六位小数;分数相同时,文档 id 较小者优先,其次 chunk 编号较小者优先。
    1. 인덱스를 만들었는데 왜 순차 스캔인가
    2. 복합 인덱스는 컬럼 순서를 어떻게 정하나
    3. 격리 수준을 올려도 안 잡히는 이상 현상은 무엇인가
    4. 페이지 폴트가 잦으면 왜 느려지나
    5. 가상 주소를 물리 주소로 어떻게 바꾸나
    6. 연결 거부와 타임아웃은 무엇이 다른가
    7. 큰 요청만 멈추는 이유는 무엇인가
    8. GPU 에서 워프란 무엇인가
  4. 上述 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)。
  5. 将第 1 个 query 的前三个 chunk 正文按排名顺序逐行保存到 /root/llm/context.txt。
  6. 判断下面 3 个候选回答是否以第 5 步的 context 为依据,保存到 /root/llm/grounded.tsv,格式为 번호<탭>겹침비율<탭>판정。重叠比例为:对回答 token 去重后,其中属于 context token 集合的比例,保留三位小数。大于等于 0.6 时为 grounded,否则为 hallucinated。
    1. 인덱스는 값으로 정렬된 구조라 컬럼에 함수를 씌우면 그 정렬이 쓸모없어진다
    2. 옵티마이저가 인덱스를 쓰지 않는 것은 대개 옳은 판단이다
    3. 인덱스를 만들면 어떤 쿼리든 언제나 세 배 빨라진다
  7. 对语料库中不存在的 3 个 query,将最高分与判定保存到 /root/llm/refusal.tsv,格式为 번호<탭>최고점수<탭>판정。分数保留六位小数;低于 0.15 时为 refuse,否则为 answer。
    1. 김치찌개 맛있게 끓이는 법
    2. 프리미어리그 이번 주 경기 일정
    3. 제주도 항공권 최저가 예약
  8. 在 /root/llm/rag_report.tsv 中用三行总结。格式为 chunks<탭>청크수、queries<탭>질의수、recall_at_3<탭>값。

参考

将文档切分为句子级 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 三项分别以名称和值配对记录。