Pathway RAG 评测流水线实战:基于 CUAD 数据集的检索指标与 RAGAS 自动化评估指南

Pathway RAG 评测流水线实战:基于 CUAD 数据集的检索指标与 RAGAS 自动化评估指南 Pathway RAG 评测流水线实战基于 CUAD 数据集的检索指标与 RAGAS 自动化评估指南【免费下载链接】pathwayPython ETL framework for stream processing, real-time analytics, LLM pipelines, and RAG.项目地址: https://gitcode.com/GitHub_Trending/pa/pathway本篇技术指南聚焦 Pathway 仓库中integration_tests/rag_evals/目录一个面向 RAG检索增强生成应用的自动化评测与回归测试框架。它通过app.yaml拉起一个基于 Pathway 实时数据框架的 RAG 服务以 CUAD 合同理解数据集与合成 QA 数据集为基准从文档检索质量与问答回答质量两条主线产出 MRR、Hitk、RAG Accuracy、RAGASAnswerCorrectness、Faithfulness等量化指标并把应用配置、问答响应与全部指标统一记录到 MLFlow。读完本文你将掌握如何在该框架上替换数据源、配置评测环境、读懂评测指标的计算方式以及如何定位答非所问等典型故障。评测框架概览两大评测类别 MLFlow 统一日志按 README 的说明这套自动化集成测试共覆盖两大评测类别Retrieval metrics检索指标衡量 RAG 应用的索引与召回模块是否能把包含正确答案的文档片段排到靠前位置核心实现位于 evaluator.pyRAGAS 指标借助ragas库对回答的忠实度Faithfulness与答案正确性AnswerCorrectness做 LLM-as-a-judge 打分见 ragas_utils.py。在评测运行期间App 配置app.yaml原文、每条问答的请求/响应、以及所有评测指标都会被记录到框架内部的 MLFlow server 上。实验入口 experiment.py 中固定使用实验名EXPERIMENT_NAME CI RAG Evals并为每次运行生成独立的 Run同时以 Git 分支名环境变量BRANCH缺失时从git探测打上Branch name标签——这意味着它可以同时服务本地调参实验与CI 上的每日回归方便对照不同配置、不同分支的评测分数。数据集准备CUAD 与合成数据CUAD 合同问答数据集评测主要依赖CUADContract Understanding Atticus Dataset合同理解数据集。框架按文件—问题—标准答案三元组的方式组织评测数据逐行存放在dataset/下的制表符分隔文件TSV中仓库内已有示例文件 dataset/labeled.tsv。该文件的表头结构反映了 CUAD 的问答形式每个合同条款类别都有一对列例如Parties检索用存放期望被召回的证据片段列表形如[BIRCH FIRST GLOBAL INVESTMENTS INC., MA, ...]与Parties-Answer回答用存放标准答案文本例如Birch First Global Investments Inc. (Company); Mount Kowledge Holdings Inc. (Marketing Affiliate, MA)。真正参与评测的条款类别并不是 CUAD 全量 50 余类而是从 eval_questions.py 中的EVAL_QUESTIONS选出并展开得到的 28 个问题类型14 个检索型 Answer 型组合包括Parties、Agreement Date、Effective Date、Expiration Date、Governing Law、Competitive Restriction Exception、Exclusivity、Non-Disparagement、Anti-Assignment、Minimum Commitment、License Grant、Non-Transferable License、Audit Rights、Cap On Liability。为便于把紧凑的列名转成适合大模型回答的自然语言问题同一文件还维护了question_mapper字典例如把Parties映射为 Who are the parties in the contract (licensee and licensor)?。使用自定义数据集时按以下方式接入将评测 TSV 下载/导出为Tab Separated Values (.tsv)格式电子表格工具中通常为 File - Download - Tab Separated Values放入仓库的dataset/目录对应 dataset/labeled.tsv保持列结构与本仓库的labeled.tsv一致即每行一个合同文件每列一个条款类别含-Answer后缀的列存答案。合成 QA 数据集除 CUAD 外dataset/synthetic_tests/ 下还预置了两份合成 QA 数据用于在标准答案文本上做更贴近真实问答形态的评估20230203_alphabet_10K.jsonl映射为AlphabetQA20230203_alphabet_10K_tables.jsonl映射为AlphabetTables。从 experiment.py 中的FILE_TO_DATASET_META可见二者都源自同一份公开文档20230203_alphabet_10K.pdf通过程序化方式从文档中抽取问答对user_inputreference_contexts证据片段生成细节参考了官方发布的技术博客。每条记录均符合ragas.EvaluationDataset.from_jsonl可直接读取的 JSONL 结构。安装与运行环境准备依赖安装首先确保已安装 Pathway 本体及其扩展依赖pip install pathway[all]随后安装评测侧所需的额外依赖ragas、mlflow、evaluate、bert_score、seaborn、langchain-openai等见 requirements.txtpip install -r integration_tests/rag_evals/requirements.txt环境变量.env评测运行依赖以下环境变量参考文件为 .example.envOPENAI_API_KEYsk-... RUN_MODELOCAL # RUN_MODECI MLFLOW_URIhttps://...变量含义OPENAI_API_KEYOpenAI 密钥用于 RAG 应用的回答生成、嵌入与各类 LLM 评判器RUN_MODE运行模式。设为LOCAL走本地模式注释掉/不设则走 CI 模式二者差异主要体现在日志落盘路径与部分超时/清理行为上见 test_eval.py 的LOCAL_RUN判定与 logging_utils.pyMLFLOW_URIMLFlow Tracking Server 地址评测启动时会校验该变量缺失则抛出RuntimeError见 experiment.py 的run_eval_experiment复制.example.env为.env并填入真实值即可框架侧通过load_dotenv()加载。理解 RAG 应用配置app.yaml 逐节拆解app.yaml 是本次评测所驱动的Pathway Live Data Framework RAG 应用的完整配置使用 Pathway 的 YAML 配置语法通过$前缀声明可复用组件最终导出顶层节点question_answerer。逐节说明如下。$sources数据源连接器运行前必须按需替换$sources: - !pw.io.gdrive.read object_id: 1ErwN5WajWsEdIRMBIjyBfncNUmkxRfRy # large: ... # small: ... service_user_credentials_file: /credentials/credentials.json # ./gdrive_indexer.json # /integration_tests/rag_evals/gdrive_indexer.json file_name_pattern: - *.pdf - *.docx object_size_limit: null with_metadata: true refresh_interval: 30 - !pw.io.gdrive.read object_id: 1GC0jVKLd2_GZb4pJx1umgJwmjOCxzkDW # synthetic dataset service_user_credentials_file: /credentials/credentials.json file_name_pattern: - *.pdf - *.docx object_size_limit: null with_metadata: true refresh_interval: 30默认配置通过pw.io.gdrive.read连接器指向两个 Google Drive 文件夹一个存放选定版本的 CUAD 合同 PDF/DOCX 原文另一个存放合成数据集对应的 PDF。关键参数object_id目标 Drive 文件夹 IDservice_user_credentials_file服务账号凭据 JSON 路径file_name_pattern按文件名通配符过滤要解析的文件with_metadata: true保留文件路径等元数据评测依赖路径做文件级过滤见下文globmatch过滤refresh_interval: 30以秒为单位的轮询刷新周期体现 Pathway 的实时数据特性。⚠️ 接入你自己的数据时需要修改$sources段将其替换为能访问到你的评测文件的连接器本地目录、S3、Drive 等均可。若使用本地文件连接器建议保持with_metadata并让元数据中包含可标识文件名/路径的字段否则文件级filter无法生效。$llm / $embedderLLM 与嵌入模型$llm: !pw.xpacks.llm.llms.OpenAIChat model: gpt-4o-mini retry_strategy: !pw.udfs.ExponentialBackoffRetryStrategy max_retries: 6 cache_strategy: !pw.udfs.DefaultCache {} temperature: 0 capacity: 8 $embedder: !pw.xpacks.llm.embedders.OpenAIEmbedder model: text-embedding-ada-002 retry_strategy: !pw.udfs.ExponentialBackoffRetryStrategy max_retries: 6 cache_strategy: !pw.udfs.DefaultCache {}temperature: 0保证回答输出的确定性对可复现评测至关重要ExponentialBackoffRetryStrategy(max_retries6)与DefaultCache降低 API 抖动与重复调用的成本capacity: 8控制 LLM 侧的并发吞吐上限。$parser / $splitter解析与切分$splitter: !pw.xpacks.llm.splitters.TokenCountSplitter min_tokens: 250 max_tokens: 600 $parser: !pw.xpacks.llm.parsers.DoclingParser {}解析器使用DoclingParser负责把 PDF/DOCX 等原始文档解析为可索引文本切分器使用按 Token 计数的TokenCountSplitter将文本切成 250600 token 的块兼顾召回粒度与上下文完整度。混合检索KNN 向量检索 BM25 关键词检索$knn_index: !pw.stdlib.indexing.BruteForceKnnFactory reserved_space: 1000 embedder: $embedder metric: !pw.engine.BruteForceKnnMetricKind.COS $bm25_index: !pw.stdlib.indexing.TantivyBM25Factory {} $retriever_factory: !pw.stdlib.indexing.HybridIndexFactory retriever_factories: - $knn_index - $bm25_index检索侧采用混合索引BruteForceKnnFactory基于余弦相似度做稠密向量召回TantivyBM25Factory底层为 tantivy 全文检索引擎仓库library_licenses/中可见其 license 文件提供稀疏关键词召回两者通过HybridIndexFactory融合兼顾语义匹配与字面命中。CUAD 合同场景中大量条款措辞高度专业化混合检索是保证召回质量的关键设计。DocumentStore 与问答器$document_store: !pw.xpacks.llm.document_store.DocumentStore docs: $sources parser: $parser splitter: $splitter retriever_factory: $retriever_factory # https://smith.langchain.com/hub/rlm/rag-prompt $prompt_template: | You are an assistant for question-answering tasks. Use the following pieces of retrieved context to answer the question. If you dont know the answer, just say that you dont know. Question: {query} Context: {context} Answer: question_answerer: !pw.xpacks.llm.question_answering.BaseRAGQuestionAnswerer llm: $llm indexer: $document_store prompt_template: $prompt_template search_topk: 8 with_cache: trueDocumentStore把数据源 → 解析 → 切分 → 混合索引整条链路串起来BaseRAGQuestionAnswerer在检索时取search_topk: 8个文档块拼入prompt_template交给 LLM。提示词显式要求不知道就直说不知道这一设计与评测侧无法从文档推断时应回答 I dont know的判定规则见下文回答评估是自洽配合的。配置末尾with_cache: true开启缓存实际运行时的缓存后端由应用入口test_eval.py、debug_main.py以pw.persistence.Backend.filesystem(Cache)落盘。评测执行入口与 REST 服务形态评测框架按先跑服务、再打接口的集成测试模式工作核心入口有两个应用入口test_eval.py读取app.yaml构造App内含question_answerer与host/port通过QASummaryRestServer启动 HTTP 服务随后在wait_result_with_checker的检查函数内执行评测conftest.py会自动下载nltk的punkt数据供分词使用。评测客户端connector.pyRagConnector封装了与运行中服务通信的两个 HTTP 端点——POST /v2/answer携带prompt、可选的filters元数据过滤表达式、model、return_context_docs返回生成答案与命中的上下文文档POST /v2/list_documents列出当前索引到的文档可按metadata_filter过滤、按keys裁剪字段。文件过滤表达式由 utils.py 的create_file_filter生成形式为globmatch(\file_name, path)即只允许系统回答来自指定合同文件的问题避免跨文件泄题污染评测结果。CI 语义上test_eval.py 的wait_for_start会先轮询/v2/list_documents直到索引文档数达到预期代码注释中的 CUAD 文件数 23 合成数据 1服务就绪后才开始评测随后以MIN_ACCURACYCI 下 0.5debug_main.py 中的独立冒烟为 0.6作为整体准确率下限判定通过与否。本地运行步骤本地联调时并不需要手动起服务——评测脚本本身就是起服务 打接口的合体直接按 README 与 run_locally.sh 执行即可。run_locally.sh首先做一件必要的事用sed把app.yaml中指向 CI 环境的凭据路径/integration_tests/rag_evals/gdrive_indexer.json改写为本地相对路径./gdrive_indexer.json然后运行pytest test_eval.pyfile_path./app.yaml sed -i s|service_user_credentials_file: /integration_tests/rag_evals/gdrive_indexer.json|service_user_credentials_file: ./gdrive_indexer.json| $file_path pytest test_eval.py即本地运行的最小操作序列为cd integration_tests/rag_evals pip install -r requirements.txt # 1. 复制 .example.env 为 .env 并填入 OPENAI_API_KEY、RUN_MODELOCAL、MLFLOW_URI # 2. 按需修改 app.yaml 的 $sources bash run_locally.shMLFlow评测日志中心如 README 所述评测的前提是有一个可用的 MLFlow Tracking Server来接收应用的配置、预测与指标。需按 MLFlow 官方 quickstart 启动 Tracking Server 后将地址写入.env的MLFLOW_URI。experiment.py 的run_eval_experiment展示了完整的日志契约校验MLFLOW_URImlflow.set_tracking_uri(...)Run 名默认取当前时间戳实验名为固定值CI RAG Evals记录标签Branch name并把app.yaml作为 artifact 归档保证哪个配置跑出哪个分数可追溯接着顺序执行CUAD 评测run_cuad_eval与合成数据评测run_alphabet_eval。CUAD 评测写入 MLFlow 的内容包括内容说明retrieval_metrics.json检索指标MRR、Hit3、Hit6、Mean Hit、Median Hit同时mlflow.log_metricsTotal RAG Accuracy回答正确率answer_df[sim].mean()file/question based eval scores按合同文件、按问题类型聚合的准确率 JSONfile_based_eval_scores.json、question_based_eval_scores.json以 artifact 记录confusion_matrix.png以文件为行、问题为列的准确/不准确热力图utils.py 的save_pivot_table_as_confusion用 seaborn 绘制并log_artifactRAGAS 指标以{dataset}-{metric}-Ragas命名的指标 RAGAS 明细表mlflow.log_table输入数据集mlflow.data.from_pandas注册 CUAD/合成数据集若在mlflow.log_table时遇到Request Entity Too Large for url报错说明提交的表体积超出了反向代理上限需要提高 nginx 侧的proxy-body-size见下文故障排查。评测指标是如何算出来的源码级拆解整体流程与数据集拆分CUAD 评测的核心循环在 experiment.pyrun_cuad_eval与 evaluator.pyRAGEvaluator中CuadDataset.from_tsv读入labeled.tsvprepare_dataset按 28 个问题类型把每一行展开为Data(file, question, label, reworded_question, question_category, ...)列表RAGEvaluator.apredict_dataset()用asyncio.gather对整份数据集并发调用/v2/answer每个问题都带上create_file_filter(file)把检索范围限定到对应合同文件收集response回答与context_docs命中文档写入predicted_dataset用-Answer是否出现在question_category中把预测集拆成检索子集与回答子集见CuadDatasetUtils.split_retrieval_answer_datasets非 Answer 型检索型用于文档召回评测Answer 型用于最终答案正确性评测检索子集经prepare_retrieval_dataset清洗——剔除标签为空/[]/nan的行并把形如[a, b, c]的字符串化标签解析为字符串列表额外拼接整句以便 top-k 命中随后进入检索指标计算回答子集经prepare_answer_dataset处理——空标签统一替换为CuadMissingData.ANSWER_LABEL no information foundconstants.py表示该问题从合同无法推断出答案再逐行做答案正确性判定并取均值作为总体准确率。Retrieval metrics命中判定与 MRR / Hitkevaluator.py 的_calculate_dataset_retrieval_metrics定义了如下判定对每条样本取预测返回的docs文本列表与 ground-truth 标签证据片段列表做词集合交并比len(set(label) ∩ set(pred)) / len(set(label))若某一 rank 位置的文档与标签的交并比 ≥STRDIFF_MIN_SIMILARITY0.65则记该位置为命中位次hit_kget_hit_index假定每条 ground truth 为单一短语/文本。基于命中位次列表聚合出五项指标实现见get_mrr/get_hit_k指标含义与计算mrr平均倒数排名1/(hit_index1)未命中的样本贡献 0 且参与均值分母对漏召回做惩罚hit_at_3命中位次 ≤ 3 的样本占比hit_at_6命中位次 ≤ 6 的样本占比mean_hit/median_hit命中位次的均值/中位数回答正确性判定字符串、日期、语义与 LLM Judge 的组合回答子集逐行调用BaseAnswerEvaluator.evaluate(pred, label) - bool仓库中提供了三种可插拔实现StringSimEvaluator规则型兜底。先判断若预测含no information/dont know/do not know仅当标签恰好是缺失占位no information found或[]时判对若标签是MM/DD/YY格式日期则先做日期规范化后精确比较否则对去除非字母数字字符后的字符串做SequenceMatcher相似度阈值SEQUENCE_MATCH_MIN_THRESHOLD 0.4BertScoreEvaluator用evaluate.load(bertscore)计算预测与标签的 BERTScore F1超过BERT_SIMILARITY_CUTOFF 0.6判对LLMAnswerEvaluator默认采用把pred与label交给一个结构化输出的 GPT-4o-mini 评判器structured_llm.py 中基于OpenAIChat扩展的OpenAIStructuredChat通过response_format返回 pydantic 模型AnswerCorrectness(is_correct: bool)。评判器的 system 提示词明确放行措辞、日期格式、详细程度不同但语义正确的回答例如参考值为01/01/2021、回答写成...date is 1st of January 2021.也判 True同时规定若标签为空/nan/no information而系统回复 I dont know. 也判 True。experiment.py 对 CUAD 回答子集使用的是LLMAnswerEvaluator逐行得到布尔值sim后求均值即Total RAG Accuracy。RAGAS 评测RAGAS 部分运行在合成数据集AlphabetQA/AlphabetTables 全部样本与 CUAD 的 Answer 型子集之上ragas_utils.py 把每条预测组装成SingleTurnSample(user_input问题, retrieved_contexts命中文档, response模型回答, reference标准答案, reference_contexts证据片段)构造EvaluationDataset评估器 LLM 用LangchainLLMWrapper(ChatOpenAI(modelgpt-4o-mini, temperature0.0))使用两类指标AnswerCorrectnessweights[1.0, 0.0]、beta1.5略微偏向 recall并在提示词中追加允许答案比标准答案更冗长/更简洁日期格式与详细程度不同也算对的宽容规则Faithfulness检验生成回答中的每个论断是否都能由检索到的上下文支撑。各指标按样本求平均后以{dataset}-{metric}-Ragas命名mlflow.log_metric并把逐样本 RAGAS 明细表log_table存档。典型故障排查症状App 一直回答 I dont know按 README 的说明这几乎总是某个数据摄入ingestion环节出问题的信号而不是模型本身的问题。排查顺序建议如下看日志定位失败模块没有看到任何文件被解析优先检查连接器$sources配置是否正确——凭证路径、object_id、文件通配符是否匹配文件确实进入流水线后仍然答不上来问题可能出在parser解析、splitter切分或 embedder嵌入上为隔离问题可以把 RAG 应用当作独立程序单独运行做手工排查python integration_tests/rag_evals/debug_main.py对应仓库中的 debug_main.py它会读取同一份app.yaml在 8092 端口拉起服务便于用 curl/客户端逐条验证索引与回答。另外从判定逻辑反推一个易混淆点若文档里确实找不到答案模型回答 I dont know 本身是正确行为且会被评判器判对只有文档明明已入库却仍检索不到、导致模型无上下文可用时才是需要排查的摄入问题。症状MLFlow 报 Request Entity Too Large for url当 RAGAS/预测明细表等大体积内容通过mlflow.log_table上传时若体量超过反向代理限制会出现该错误experiment.py 中在该调用旁也留有对应注释。解决方法是提高 nginx 配置中的proxy-body-size使代理允许转发更大的请求体。把评测跑成你自己的调参循环integration_tests/rag_evals/从设计上就是一个可复用的 RAG 评测基座README 亦明确指出当前app.yaml的取值是合理的默认值鼓励针对自己的场景调参寻找最优配置。建议的自定义路径为换数据把 dataset/labeled.tsv 换成你自己的文件—问题—标准答案三元组或自备合成 QA JSONL并保证待检索文档可被$sources连接器访问换配置调整 app.yaml 中的切分窗口TokenCountSplitter的 min/max tokens、search_topk、检索索引组合、提示词模板、LLM 模型与温度等每次运行都会作为独立 MLFlow Run 留下app.yamlartifact 与全套指标便于横向对比当门槛把 CI 下的MIN_ACCURACY与分支绑定让每次合入前自动回归任何让检索或回答质量回退的改动都会在指标上显形——这正是本目录作为集成测试存在的意义。通过检索指标 回答正确性 RAGAS 三类指标 × 真实合同与合成文档两类数据 × MLFlow 全量留痕的组合该框架为 Pathway 上构建的 RAG 应用提供了一条可量化、可复现、可持续迭代的质量保障闭环你可以直接复用它来验证自己的 RAG 管线与调参效果。【免费下载链接】pathwayPython ETL framework for stream processing, real-time analytics, LLM pipelines, and RAG.项目地址: https://gitcode.com/GitHub_Trending/pa/pathway创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考