评测的每一个指标,都需要LLM参与,并且随着评测集越来越大,速度会越来越慢。我们前一个章节中给大家提供的脚本中,也做了些性能方面的优化。
1. 核心加速:全面采用异步并发架构
这是该脚本提速的最关键因素。我们没有使用传统的同步阻塞方式,而是全面拥抱了 Python 的 asyncio 异步编程模型: - 异步客户端:使用了 AsyncOpenAI 客户端,使得网络请求(调用大模型 API)在等待响应时不会阻塞主线程。 - 批量并发调度:在 main() 函数中,您通过列表推导式创建了所有评测任务,并使用 await asyncio.gather(*tasks) 将它们同时并发执行。这意味着成百上千条数据的评测是同时向 API 发起请求的,而不是排队等待,从而将原本线性的等待时间压缩到了极限。
2. 微观并发:单条数据内的多指标并行
在 evaluate_single_row 函数中,针对每一条数据,您并没有串行地依次计算 5 个指标(Context Precision, Context Recall 等),而是同时创建了 5 个 ascore 异步任务,并再次使用 asyncio.gather 并发等待结果。这使得单条数据的评测时间从“5个指标耗时之和”缩短为了“5个指标中最慢的那个耗时”。
3. 减少无效开销:优化 LLM 调用参数
在初始化 eval_llm 时,您通过 extra_body 传入了 {"enable_thinking": False}。这一配置直接关闭了模型的“思考模式”(如思维链推理),避免了模型在输出最终结果前生成大量中间推理 token。这不仅降低了 token 消耗,更显著减少了 API 的响应延迟。
4. 提升数据解析效率:纯内存字符串处理
在处理 retrieved_contexts 时,您使用了 Python 内置的字符串 split('\n\n') 和列表推导式进行切分与清洗。相比于引入 ast.literal_eval 或正则表达式等更重的解析方式,这种纯内存的字符串操作开销极低,避免了在循环中产生不必要的 CPU 瓶颈。
5. 全局资源复用:避免重复初始化
您将 AsyncOpenAI 客户端、eval_llm 和 embeddings 的初始化放在了全局作用域。这意味着在并发执行成百上千次评测任务时,系统底层的 HTTP 连接池、认证状态等都可以被复用,避免了为每个请求重复建立连接所带来的巨大网络开销。