Phoenix Evals Python 常见错误避坑指南从 1.0 遗留 API 迁移到 2.0 的完整清单【免费下载链接】phoenixAI Observability Evaluation项目地址: https://gitcode.com/gh_mirrors/phoenix13/phoenix本指南基于仓库中.agents/skills/phoenix-evals/references/common-mistakes-python.md整理并扩展。它汇总了 LLM 在编写 Phoenix Evals 代码时高频生成错误的模式逐条给出 WRONG/RIGHT 对照、出错原因与源码级佐证帮助你快速识别并修正 1.0 遗留 API、错误的参数名、错误的结果列读取方式以及不恰当的 Span 过滤逻辑直接写出符合 Phoenix Evals 2.0 规范、可运行可复用的评估代码。在 Phoenix 的评估生态中phoenix-evals包经历了从 1.0 到 2.0 的大版本演进旧的OpenAIModel、run_evals、llm_classify等一批 API 被统一为以LLM类 Evaluator对象为核心的 2.0 架构。由于训练语料中大量 1.0 代码的存在LLM以及从旧教程复制代码的开发者经常生成已被弃用的调用方式。本文将 11 类最典型的高频错误逐一拆解并结合本仓库源码给出正确写法与底层原理。一、使用遗留的模型类包装器Legacy Model Classes错误写法从phoenix.evals顶层导入OpenAIModel、AnthropicModel等 1.0 包装器# WRONG from phoenix.evals import OpenAIModel, AnthropicModel model OpenAIModel(modelgpt-4)正确写法使用与供应商无关的 2.0 统一类LLM通过providermodel指定模型# RIGHT from phoenix.evals import LLM llm LLM(provideropenai, modelgpt-4o)为什么OpenAIModel、AnthropicModel等是 1.0 时代为每家供应商单独编写的模型包装类目前仅作为 legacy 代码保留在phoenix.evals.legacy命名空间下。2.0 的LLM类在 packages/phoenix-evals/src/phoenix/evals/llm/wrapper.py 中实现通过适配器注册表PROVIDER_REGISTRY按provider名动态查找可用客户端从而做到一份代码适配 OpenAI、Anthropic、Azure、LiteLLM 等多种供应商。从源码可以看到LLM.__init__的几个关键行为provider与model必须同时指定否则直接抛出ValueError(Must specify both provider and model.)支持client参数显式指定某个供应商下的具体 SDK 客户端默认取第一个可用注册项支持sync_client_kwargs/async_client_kwargs分别配置同步与异步客户端的超时等参数内置RateLimiter限流器initial_per_second_request_rate可覆盖默认速率提供generate_text、generate_object、generate_classification三组同步/异步方法且全部带有trace装饰器调用本身会被记录为 LLM Span见 wrapper.py天然与 Phoenix 追踪集成。可用show_provider_availability()查看当前环境中各供应商的可用性表格。二、用run_evals而不是evaluate_dataframe错误写法调用 1.0 的批量评估函数run_evals# WRONG — legacy 1.0 API from phoenix.evals import run_evals results run_evals(dataframedf, evaluators[eval1], provide_explanationTrue) # 返回的是 DataFrame 列表正确写法使用 2.0 的evaluate_dataframe# RIGHT — current 2.0 API from phoenix.evals import evaluate_dataframe results_df evaluate_dataframe(dataframedf, evaluators[eval1]) # 返回单个 DataFrame包含 {name}_score 字典列为什么run_evals是 1.0 时代的批量执行函数其返回值为多个 DataFrame 组成的列表每个评估器一个并依赖provide_explanation这类旧参数。2.0 的evaluate_dataframe定义在 packages/phoenix-evals/src/phoenix/evals/evaluators.py它返回单个 DataFrame并且结果列命名规则发生了根本变化见下一节。evaluate_dataframe的核心参数与行为来自 evaluators.py参数作用默认值dataframe输入数据每行转为 dict 传给各评估器必填evaluators应用于每一行的Evaluator列表必填tqdm_bar_format进度条格式字符串None用默认格式hide_tqdm_bar是否隐藏进度条Falseexit_on_error遇到首个错误是否停止执行由 SyncExecutor 决定默认Truemax_retries异常时重试次数由 SyncExecutor 决定默认10如果需要更高吞吐可以使用其异步版本async_evaluate_dataframeevaluators.py额外支持concurrency参数控制并发消费者数默认3每个任务超时默认 60 秒。三、读错评估结果列Wrong Result Column Names错误写法对evaluate_dataframe返回的结果列直接取均值# WRONG — 该列根本不存在 score results_df[relevance].mean() # WRONG — 列存在但里面是 dict不是数值 score results_df[relevance_score].mean()正确写法从 dict 中提取数值型score字段# RIGHT — 从 dict 中提取数值 score scores results_df[relevance_score].apply( lambda x: x.get(score, 0.0) if isinstance(x, dict) else 0.0 ) score scores.mean()为什么evaluate_dataframe的返回结果按{score.name}_score命名列每列存放的是 JSON 序列化后的Score对象字典形如{name: ..., score: 1.0, label: ..., explanation: ...}Score是 2.0 评估结果的核心数据结构定义在 evaluators.py字段包括字段类型说明nameOptional[str]评估器名称scoreOptional[float/int]数值分数labelOptional[str]分类标签explanationOptional[str]LLM 给出的理由metadataDict[str, Any]元信息如使用的模型kindOptional[KindType]评估类型human/llm/codedirectionDirectionType分数优化方向maximize/minimize因此对{name}_score列取.mean()是对 dict 求均值必然报错或得到无意义结果。除了{score.name}_score列evaluate_dataframe还会为每个评估器生成{evaluator.name}_execution_details列记录执行异常、耗时与状态可用于排查失败行。四、使用了被弃用的project_name参数错误写法# WRONG df client.spans.get_spans_dataframe(project_namemy-project)正确写法# RIGHT df client.spans.get_spans_dataframe(project_identifiermy-project)为什么在 packages/phoenix-client/src/phoenix/client/resources/spans/init.py 的get_spans_dataframe签名中project_name被明确标记为Deprecated取而代之的project_identifier同时接受项目名称或项目 ID源码中通过is_node_id(project_identifier, node_typeProject)判断传入的是 ID 还是名称。注意两者不可同时传入否则抛出ValueError(Provide only one of project_identifier or project_name.)。同样被弃用的还有root_spans_only参数见源码 L210-L218 的DeprecationWarning它建议改用查询表达式来限定根 Span详见第七节。五、Client 构造函数参数名写错Wrong Client Constructor错误写法# WRONG client Client(endpointhttps://app.phoenix.arize.com) client Client(urlhttps://app.phoenix.arize.com)正确写法# RIGHT — 远程/云端 Phoenix client Client(base_urlhttps://app.phoenix.arize.com, api_key...) # ALSO RIGHT — 本地 Phoenix回退到环境变量或 localhost:6006 client Client()为什么phoenix-client的Client构造函数参数名是base_url见 packages/phoenix-client/src/phoenix/client/client.py不存在endpoint或url参数。从源码看当base_url未显式传入时Client会调用get_base_url(credential_source...)回退到环境变量或本地默认地址localhost:6006因此本地实例直接Client()即可而远程实例需要同时提供base_url和api_key完成鉴权。这也是为什么错误代码在本地看起来能跑、换到远程就失败的原因——参数名根本没被识别。六、过于激进的时间过滤Too-Aggressive Time Filters错误写法用 1 小时窗口过滤 Span经常返回空结果# WRONG — 经常返回零条 Span from datetime import datetime, timedelta df client.spans.get_spans_dataframe( project_identifiermy-project, start_timedatetime.now() - timedelta(hours1), )正确写法用limit控制结果规模# RIGHT — 用 limit 控制结果数量 df client.spans.get_spans_dataframe( project_identifiermy-project, limit50, )为什么Trace 数据可能来自任意时间段写死 1 小时窗口在数据稀疏时极易返回空表。get_spans_dataframe的limit参数默认值为1000见 spans/init.py用于控制返回的最大条数start_time/end_time则用于真正需要时间范围过滤的场景。评估数据拉取通常应优先用limit控制规模而非猜测数据产生的时间窗。七、Span 过滤层级不当Not Filtering Spans Appropriately错误写法不区分层级一次性拉取所有 Span包括内部 LLM 调用、检索器等子 Spanfrom phoenix.client.types.spans import SpanQuery # WRONG — 拉取全部 Span包含内部 LLM 调用、retriever 等 df client.spans.get_spans_dataframe(project_identifiermy-project)端到端评估的正确写法——只取顶层根 Span# RIGHT for end-to-end evaluation — 过滤到顶层 Span df client.spans.get_spans_dataframe( project_identifiermy-project, querySpanQuery().where(parent_id is None), )RAG 评估的正确写法——分别拉取 retriever 与 LLM 子 Span# RIGHT for RAG evaluation — 获取子 Span 用于 retriever/LLM 指标 all_spans client.spans.get_spans_dataframe( project_identifiermy-project, ) retriever_spans all_spans[all_spans[span_kind] RETRIEVER] llm_spans all_spans[all_spans[span_kind] LLM]为什么SpanQuery定义在 packages/phoenix-client/src/phoenix/client/types/spans.py其where(condition)方法接受查询 DSL 条件字符串并构建过滤条件。选择哪个 Span 层级取决于你的评估目标端到端质量评估如整体回答质量应把查询范围限定在根 Span使用SpanQuery().where(parent_id is None)如果想同时把父 Span 缺失的孤儿 Span 也算作根改用SpanQuery().where(parent_span is None)——这正是root_spans_only弃用后官方推荐的写法见 spans/init.pyRAG 系统评估往往需要单独获取子 Span——RETRIEVER类型的 Span 用于RetrievalRelevance评估LLM类型的 Span 用于Faithfulness评估。仓库中的 RAG 辅助模块 packages/phoenix-client/src/phoenix/client/helpers/spans/rag.py 也印证了这一约定它定义了常量IS_ROOT parent_id is None并通过根 Span 查询与 retriever 文档拼接查询分别构造 DataFrame。八、假设 Span 输出是纯文本Assuming Span Output is Plain Text错误写法直接把attributes.output.value当作普通文本# WRONG — output 可能是 JSON不是纯文本 df[output] df[attributes.output.value]正确写法解析 JSON 并提取 answer 字段# RIGHT — 解析 JSON 并提取 answer 字段 import json def extract_answer(output_value): if not isinstance(output_value, str): return str(output_value) if output_value is not None else try: parsed json.loads(output_value) if isinstance(parsed, dict): for key in (answer, result, output, response): if key in parsed: return str(parsed[key]) except (json.JSONDecodeError, TypeError): pass return output_value df[output] df[attributes.output.value].apply(extract_answer)为什么LangChain 等框架的根 Span 输出常常是结构化 JSON例如{context: ..., question: ..., answer: ...}。评估器需要的是真正的答案文本而不是原始 JSON 字符串。如果不做解析RelevanceEvaluator、FaithfulnessEvaluator等会把整段 JSON 当作回答内容导致评估结果失真。处理原则先尝试json.loads解析命中常见键answer/result/output/response则取对应值解析失败或非 dict 则原样返回兼顾健壮性。九、用create_evaluator做 LLM 评估不会调用 LLM错误写法给create_evaluator传kindllm以为会自动调用 LLM# WRONG — create_evaluator 不会调用 LLM create_evaluator(namerelevance, kindllm) def relevance(input: str, output: str) - str: pass # 并没有 LLM 参与正确写法LLM 评估使用ClassificationEvaluator# RIGHT — 使用 ClassificationEvaluator 进行 LLM 评估 from phoenix.evals import ClassificationEvaluator, LLM relevance ClassificationEvaluator( namerelevance, prompt_templateIs this relevant?\n{{input}}\n{{output}}\nAnswer:, llmLLM(provideropenai, modelgpt-4o), choices{relevant: 1.0, irrelevant: 0.0}, )为什么create_evaluatorevaluators.py的本质是把一个普通 Python 函数包装成Evaluator其kind参数默认是code。即使显式传kindllm也只是给这个纯函数打上LLM 类型的标签LLM 调用仍需要你自己在函数体内实现——pass体显然不会产生任何评估结果。而ClassificationEvaluatorevaluators.py则真正替你完成了全部流程基于prompt_template自动推断输入字段、调用LLM生成结构化输出、解析label与score、默认附带explanation最佳实践默认开启include_explanationTrue。其choices参数支持三种形态List[str]——纯标签列表如[positive, negative]分数为NoneDict[str, float/int]——标签到数值分数的映射如{relevant: 1.0, irrelevant: 0.0}Dict[str, Tuple[float/int, str]]——标签到(分数, 描述)元组的映射官方注明不推荐因为 LLM 对这类 schema 的遵循度不可靠。注意ClassificationEvaluator要求 LLM 支持 tool calling 或 structured outputgenerate_classification底层通过generate_object JSON Schema 实现见 wrapper.py。十、用llm_classify而不是ClassificationEvaluatorasync_evaluate_dataframe错误写法继续调用 1.0 的llm_classify函数# WRONG — legacy 1.0 API from phoenix.evals import llm_classify results llm_classify( dataframedf, templatetemplate_str, modelmodel, rails[relevant, irrelevant], )正确写法组合ClassificationEvaluator与async_evaluate_dataframe# RIGHT — current 2.0 API from phoenix.evals import ClassificationEvaluator, async_evaluate_dataframe, LLM classifier ClassificationEvaluator( namerelevance, prompt_templatetemplate_str, llmLLM(provideropenai, modelgpt-4o), choices{relevant: 1.0, irrelevant: 0.0}, ) results_df await async_evaluate_dataframe(dataframedf, evaluators[classifier])为什么llm_classify是 1.0 时代的分类函数它的参数名template、model、rails与 2.0 的Evaluator对象模型完全不同。2.0 的推荐模式是先构造评估器对象再交给执行器运行同步批量执行evaluate_dataframe(dataframedf, evaluators[classifier])异步批量执行await async_evaluate_dataframe(dataframedf, evaluators[classifier])可额外指定concurrency提升吞吐。这种评估器 可复用配置对象的设计让同一个ClassificationEvaluator实例既能跑单条evaluate()也能跑批量 DataFrame还能在实验与数据集评估等场景中复用。十一、误用HallucinationEvaluator混淆幻觉与忠实度评估错误写法错误的导入路径、错误的构造方式、错误的输入字段# WRONG — 不是顶层导出且接收的是 LLM 而不是 model 字符串 from phoenix.evals import HallucinationEvaluator eval HallucinationEvaluator(model) # WRONG — 不存在 context 字段 eval.evaluate({input: question, output: answer, context: retrieved_docs})正确写法# RIGHT from phoenix.evals.metrics import HallucinationEvaluator from phoenix.evals import LLM eval HallucinationEvaluator(llmLLM(provideropenai, modelgpt-4o)) eval.evaluate({input: conversation_so_far, output: assistant_reply})为什么预置评估器位于phoenix.evals.metrics命名空间不是phoenix.evals顶层导出。HallucinationEvaluator的实现见 packages/phoenix-evals/src/phoenix/evals/metrics/hallucination.py它继承自ClassificationEvaluator核心语义是input助手能看到的完整对话历史之前的轮次、工具调用、工具结果其最后一条消息是被回答的用户轮次output被评判的助手最新回复没有context字段。如果你的事实来源是外部提供的上下文如 RAG 检索文档那应该用FaithfulnessEvaluator——它的输入 schema 明确包含input与context字段见 packages/phoenix-evals/src/phoenix/evals/metrics/faithfulness.py。另外还有一个极易踩坑的细节HallucinationEvaluator的标签为hallucinated/grounded且分数是最小化方向——hallucinated为1.0grounded为0.0源码中DIRECTION HALLUCINATION_CLASSIFICATION_EVALUATOR_CONFIG.optimization_direction该配置来自 prompts/classification_evaluator_configs/HALLUCINATION_CLASSIFICATION_EVALUATOR_CONFIG.yaml。不要假设 1.0 好在设定阈值前务必读取返回Score的direction字段minimize否则会把分数含义完全理解反。总结2.0 迁移速查表1.0 遗留写法2.0 正确写法核心差异OpenAIModel(model...)LLM(provideropenai, model...)供应商无关统一包装器run_evals(dataframe, evaluators)evaluate_dataframe(dataframe, evaluators)返回单个 DataFrame 而非列表results_df[relevance]/[relevance_score].mean()对{name}_score列中 dict 的score键取值结果列存的是Score字典project_nameproject_identifier同时支持项目名称与 IDClient(endpoint/url)Client(base_url, api_key)参数名以base_url为准1 小时时间窗口拉取limit控制规模Trace 可能来自任意时段不区分层级拉取全部 SpanSpanQuery().where(parent_id is None)等按评估目标选择 Span 层级直接把 output 当文本先json.loads再提取 answer 等键框架常输出结构化 JSONcreate_evaluator(kindllm)ClassificationEvaluator(llm..., choices...)前者不调用 LLMllm_classify(...)ClassificationEvaluatorasync_evaluate_dataframe评估器对象 执行器模式顶层导入HallucinationEvaluator、传context从phoenix.evals.metrics导入、按对话字段传入混淆场景应改用FaithfulnessEvaluator判断一段评估代码是否过时最直接的方法是检查是否出现了OpenAIModel、run_evals、llm_classify、project_name、endpoint这些关键词出现即意味着它来自 1.0 时代。按本文的对照表替换后你的 Phoenix Evals 代码将同时兼容远程/本地 Phoenix、支持异步高吞吐批量评估并能被 Phoenix 的追踪系统完整记录每次 LLM 判定调用。【免费下载链接】phoenixAI Observability Evaluation项目地址: https://gitcode.com/gh_mirrors/phoenix13/phoenix创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
企业数字化 ERP 产品动态
相关推荐
从RAR解压到图形识别:一份可复现的完整流程 简介:这是一份面向图形识别学习者的Visual C数字图像处理与识别练习包,以指纹识别为主线,覆盖图像预处理、特征提取、分类识别等关键环节,适合计算机视觉入门及进阶开发者对照实践。压缩包共四十八个文件,包含二十一个… · 2026/9/23 13:41:33
QEMU SPARC32 系统模拟器完全指南:Sun4m 架构机型、CPU 模型与外围设备详解 虚拟化硬件仿真 【免费下载链接】qemu Official QEMU mirror. Please see https://www.qemu.org/contribute/ for how to submit changes to QEMU. Pull Requests are disabled. Please only use release tarballs from the QEMU website. 项目地址: https://gitcod… · 2026/9/23 13:41:27
PSQ使用教程:用Python简化PostGIS拓扑分析实战指南 1. 为什么我推荐用 PSQ 处理 PostGIS 拓扑分析做空间数据的人应该都有这种体会:PostGIS 的空间查询和空间分析能力非常强,但一旦涉及拓扑,比如检查多边形是否共享边界、构建路网连通关系、判断要素之间是否重叠或存在缝隙,SQL 写起… · 2026/9/23 13:41:27
打包英语源码拆解:3步搞定版本升级API变更的保姆级教程 打包英语源码拆解:3步搞定版本升级API变更的保姆级教程 版本升级后 API 全变了,报错堆栈看得人眼晕,是不是感觉之前的经验一夜作废?别慌,今天这篇【打包英语】源码解析就是为你准备的保姆级教程。我们直接撕开底层代码,看看那些让你头秃的接口… · 2026/9/23 14:30:10
Dota2启动不了?3个底层排查法,告别性能优化焦虑 Dota2启动不了?3个底层排查法,告别性能优化焦虑 刚把同事发来的启动脚本复制到本地,双击运行,黑窗口一闪而过,游戏图标还在,但就是进不去。你盯着屏幕,心里那股无名火蹭蹭往上冒:这代码看着挺规范,怎么到我这就跑不通?更让人头疼的是,为了排… · 2026/9/23 14:30:10
ABB IRC5 M2004 控制柜电路图深度解析:从读图到故障定位 简介:ABB机器人IRC5 M2004控制器电路图是面向工业机器人电气设计、调试与维护人员的专业参考资料,适用于机器人控制系统架构学习、硬件选型与故障排查等场景。资源包内含1个PDF文件,整体约6.67MB,内容为ABB官方发布的IRC5 M2004控… · 2026/9/23 14:30:04
5分钟搞懂拯救公主:图解原理与实战避坑指南 5分钟搞懂拯救公主:图解原理与实战避坑指南 官方文档翻了三遍,核心逻辑还是没抓住重点?这种“文档太长、重点模糊”的痛点,几乎是每个开发者入行时的必经之路。别急,今天咱们不背八股文,直接上 图解原理… · 2026/9/23 14:29:51
有担保的海外广告账户资源平台 跨境出海投放过程中,不少企业在采购海外广告账户资源时,都遭遇过私域交易的各类风险:付款之后卖家失联、交付资产与描述不符、出现问题没有维权渠道。因此,是否具备正规交易担保机制,已经成为出海团队筛选资源平台的核… · 2026/9/23 14:29:51
基于CNN的大米识别实战:数据集处理、模型训练与产线部署 简介:本资源是一套基于PyTorch框架的CNN深度学习大米识别实战项目,面向具备Python基础、希望入门图像分类的开发者与在校学生,可用于课程设计、毕业项目或算法练手。压缩包共906个文件,包含900张jpg图片构成的多类别大米数据集&am… · 2026/9/23 14:29:31
3招搞定手机怎么下载微信面试难题实战项目解析 3招搞定手机怎么下载微信面试难题实战项目解析 面试被问“手机怎么下载微信”背后的原理,90%的人答不上来。别笑,这看似弱智的问题,实则是考察你对移动应用分发机制、安全校验及网络协议理解的试金石。我带过不少校招新人,他们背了八股文,却连一个A… · 2026/9/23 0:00:03
你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型 你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型 面试被问“高并发下如何保证消息不丢失”,你张口就是“用Redis”,结果面试官追问“如果Redis宕机了怎么办”,你瞬间卡壳。这种场景太常见了,很多新手在背八股文时,只记住了技术名词… · 2026/9/23 0:00:29