ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

LLM Zoomcamp 搜索评估实战:并行批量生成 Ground Truth 数据集与成本核算

LLM Zoomcamp 搜索评估实战:并行批量生成 Ground Truth 数据集与成本核算 LLM Zoomcamp 搜索评估实战并行批量生成 Ground Truth 数据集与成本核算【免费下载链接】llm-zoomcampLLM Zoomcamp - a free online course about real-life applications of LLMs. In 10 weeks you will learn how to build an AI system that answers questions about your knowledge base. Register here 项目地址: https://gitcode.com/GitHub_Trending/ll/llm-zoomcamp本课是 LLM Zoomcamp 2026 课程「评估Evaluation」模块的第三讲。在上一课中我们已经学会用结构化输出structured output为单个 FAQ 文档生成 5 个问题并转换为 ground truth 记录本课的目标是把这套流程扩展到知识库中的全部文档并解决随之而来的两个工程问题如何让成百上千次 LLM 调用既快又不触发限流以及如何精确核算整批生成的成本。读完本文你将掌握tqdm进度条 ThreadPoolExecutor并行批处理的标准写法、基于 token usage 的定价核算方法并得到一份可直接用于后续搜索评估的 ground truth CSV。从单文档到全量批量生成的目标回顾上一课 生成 Ground Truth 数据 的内容我们先用 Pydantic 定义了Questions(BaseModel)结构字段为questions: list[str]再通过 OpenAI 的responses.parse接口并传入text_formatQuestions让 LLM 针对单个 FAQ 文档返回固定结构的问题列表最后把每个问题与文档id拼成一条记录。本课要做的是同一件事的全量版本对 FAQ 数据集中每一个文档都执行一次「生成问题 → 转记录」的流程最终得到一份覆盖全部文档的 ground truth 数据集。每一条记录只有两个字段question由 LLM 针对该文档生成的提问document应当能回答该问题的文档 ID。正因为问题是从某个具体文档「反推」出来的我们天然知道每条问题的正确答案是哪篇文档——这正是 ground truth或称 gold standard数据的价值所在在 后续的搜索评估 中我们会把这些问题喂给搜索引擎然后检查正确文档是否出现在检索结果里。环境准备安装 tqdm 与 pandas批量处理需要两个基础库tqdm负责显示处理进度pandas负责把最终结果保存为 CSV。如果尚未安装可以直接用uv添加uv add tqdm pandas仓库中该模块的 pyproject.toml 已经声明了这些依赖tqdm4.67.3、pandas3.0.3、openai2.38.0、minsearch、python-dotenv、requests、jupyter这也印证了整套评估流程的依赖底座。核心处理函数generate_ground_truth批量流程的原子单元是一个「文档 → 多条 ground truth 记录」的处理函数。它包含三步把文档序列化为 JSON作为发送给 LLM 的 user prompt请 LLM 返回一个Questions对象结构化输出为对象中的每一个问题创建一条记录绑定生成它的文档 ID。import json from evaluation_utils import llm_structured_retry def generate_ground_truth(doc): user_prompt json.dumps(doc) out, usage llm_structured_retry( openai_client, data_gen_instructions, user_prompt, Questions ) results [] for q in out.questions: results.append({ question: q, document: doc[id] }) return results, usage这里有两个细节值得注意user_prompt json.dumps(doc)FAQ 文档本身就是一个字典包含id、course、question、answer、section等字段见 ingest.py 加载的数据结构直接序列化为 JSON 即可作为上下文发送给模型函数同时返回results和usage两部分前者是生成的记录后者是该次调用的 token 用量供后续成本核算使用。失败重试llm_structured_retry 源码解读当我们需要发送大量请求时必须接受一个现实某个请求可能会因为临时性的 API 或网络问题而失败。如果因为一次偶发错误就让整个批次崩溃代价太高。原文档给出的方案是从evaluation_utils.py导入重试助手from evaluation_utils import llm_structured_retry这两个助手的分工在 evaluation_utils.py 源码中非常清晰llm_structuredL32-L44只做一次结构化输出调用组装developeruser两条消息调用client.responses.parse(model..., inputmessages, text_formatoutput_type)并返回(response.output_parsed, response.usage)。注意其默认模型为gpt-5.4-minillm_structured_retryL47-L67则把同样的调用包进一个重试循环默认最多尝试 3 次max_retries3每次失败后time.sleep(2 ** attempt)做指数退避第 1 次失败等 1 秒、第 2 次等 2 秒最后一次仍失败才把异常抛给上层。def llm_structured_retry( client, instructions, user_prompt, output_type, modelgpt-5.4-mini, max_retries3, ): for attempt in range(max_retries): try: return llm_structured( client, instructions, user_prompt, output_type, modelmodel, ) except Exception: if attempt max_retries - 1: raise time.sleep(2 ** attempt)这种「短时失败自动重试、持续失败才报错」的语义正是批处理场景最需要的容错粒度单个文档的临时失败不会拖垮整个批次而真正的问题如配额耗尽也会在重试耗尽后如实暴露。串行试运行先处理前 5 个文档在投入全量并行之前先用小样本验证函数正确性。导入tqdm并运行循环from tqdm.auto import tqdm ground_truth [] usages [] for doc in tqdm(documents[:5]): records, usage generate_ground_truth(doc) ground_truth.extend(records) usages.append(usage)这段代码能跑通但它的模式是一次只发一个请求、等待响应后再发下一个。每次调用的绝大部分时间都耗在网络往返上请求发出后只是「干等」OpenAI 返回。如果对全部文档都这样串行执行耗时将难以接受——这就是下一步引入并行的原因。并行处理ThreadPoolExecutor map_progress并行的思路很朴素既然大部分时间在等待网络响应那就同时发出多个请求一起等它们返回。由于 LLM 调用是典型的 I/O 密集型任务线程池而不是进程池就足够了。仓库为这个场景专门封装了一个辅助函数map_progress它一次性解决三件事提交任务、更新进度条、收集结果。from concurrent.futures import ThreadPoolExecutor from evaluation_utils import map_progress然后只需把串行循环替换成两行with ThreadPoolExecutor(max_workers6) as pool: results map_progress(pool, documents, generate_ground_truth)map_progress的实现evaluation_utils.py L112-L127值得逐行理解def map_progress(pool, seq, f): results [] with tqdm(totallen(seq)) as progress: futures [] for el in seq: future pool.submit(f, el) future.add_done_callback(lambda p: progress.update()) futures.append(future) for future in futures: result future.result() results.append(result) return results先用tqdm(totallen(seq))初始化进度条总进度等于文档数量对每个文档调用pool.submit(f, el)提交一个任务并通过add_done_callback在每个任务完成时更新一次进度条——这就是「一边并行跑、一边看进度」的实现原理最后按futures的提交顺序依次future.result()收集结果。因为是按顺序遍历 future 列表返回的results与输入文档顺序保持一致这给后续的汇总与核验带来了极大便利。关于并发度原文档特别提醒不要一次性打开太多连接否则容易触发服务商的速率限制rate limit。max_workers6是一个稳妥的默认值——既有足够的并行度又给 API 留出了呼吸空间。汇总结果与 token 成本核算generate_ground_truth对每个文档返回两部分生成的记录列表与 token 用量。并行结束后把它们拆到两个列表中ground_truth [] usages [] for records, usage in results: ground_truth.extend(records) usages.append(usage) len(ground_truth)由于每个文档固定生成 5 个问题len(ground_truth)应约为文档数 × 5——这是最直观的完整性自检。接下来核算整批生成的成本。上一课已经介绍过calc_price(usage)单次计价这里可以逐条累加from evaluation_utils import calc_price total_cost 0.0 for usage in usages: cost calc_price(usage) total_cost total_cost cost[total_cost] total_cost由于本模块后面还会多次核算总成本工具文件提供了现成的汇总助手一步到位from evaluation_utils import calc_total_price calc_total_price(usages)价格计算逻辑定义在 evaluation_utils.py L7-L19按每百万 token 计价的常量输入$0.75/ 百万、输出$4.50/ 百万分别折算input_cost与output_cost二者之和即单次调用的total_costcalc_total_priceL22-L29则遍历所有 usage 对象求和。注意这套单价是针对该课程默认模型gpt-5.4-mini配置的如果更换模型需要相应调整常量。保存为数据帧与 CSV拿到全部记录后用pandas转成表格以便查看并落盘为 CSV 供后续课程复用import pandas as pd df_ground_truth pd.DataFrame(ground_truth) df_ground_truth.to_csv(data/ground_truth-new.csv, indexFalse)to_csv(..., indexFalse)表示不写入行号索引保证 CSV 只有question,document两列。仓库中本模块 data/ground_truth-new.csv 已保存了一份课程运行产物其表头与行结构与上面流程完全一致例如question,document Is it okay to join the course late if I just found it now?,74eb249bbf Can I still take this course even if I missed the start date?,74eb249bbf ...至此我们拥有了一份「问题 → 已知正确文档」的完整数据集。由于问题都从具体文档生成每条记录的document字段就是搜索评估时的「标准答案标签」——这正是评估检索质量所必需的 ground truth。参考运行结果与数据漂移说明课程材料使用的这份文件生成于2026 年 5 月 29 日当时的运行参数为使用79 个LLM Zoomcamp 文档共产生395 个问题79 × 5总成本$0.057187约合 6 美分。同时必须强调一个现实FAQ 数据本身会随时间变化。如果你在之后重新运行本 notebook加载到的文档与生成的问题可能不同token 用量、成本以及后续的搜索评估结果也都可能随之变化——这是数据驱动流程的正常现象也是评估工作必须定期重跑的原因。如果不想自己花时间生成尽管成本只有几美分可以直接使用仓库中已经备好的文件 data/ground_truth-new.csv将其复制到你的工作目录data/下即可列结构与自行生成的结果完全一致。下一步用 Ground Truth 做搜索评估现在我们有了「问题 已知正确文档」的数据集下一步就是让搜索引擎真正接受检验把每条问题送入检索检查返回结果中是否包含正确文档。下一课 搜索评估 将演示如何把这份 CSV 读回内存、构建 minsearch 索引并把「检索结果是否命中正确文档」转换为 0/1 相关性列表为 Hit Rate 与 MRR 等指标的计算做好准备——届时你会看到本课批量生成的每一行记录都将成为衡量检索质量的一块试金石。【免费下载链接】llm-zoomcampLLM Zoomcamp - a free online course about real-life applications of LLMs. In 10 weeks you will learn how to build an AI system that answers questions about your knowledge base. Register here 项目地址: https://gitcode.com/GitHub_Trending/ll/llm-zoomcamp创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表