基于 Phoenix 构建 AI/LLM 应用评估器:从错误分析到 CI 门禁的完整实战指南
可观测性AI 评测LLMOpsAI 应用人工智能【免费下载链接】phoenixAI Observability Evaluation项目地址https://gitcode.com/gh_mirrors/phoenix13/phoenix点击查看免费下载Phoenix 的 evals 技能文档.agents/skills/phoenix-evals/SKILL.md系统阐述了在 AI/LLM 应用上构建评估器Evaluator的完整方法论与工程实践。本文以该文档为核心骨架结合仓库源码packages/phoenix-evals、packages/phoenix-client验证其底层实现整理出一套代码优先、LLM 处理细节、人类提供真值的评估体系你将掌握三种评估器类型的取舍、代码与 LLM 评估器的编写方式、DataFrame 批量评估、实验运行与验证校准以及如何将评估接入 pytest / Vitest / Jest 作为 CI 门禁。评估方法论三种评估器与选择决策Phoenix 将评估器划分为三种类型它们在速度、成本与适用场景上形成互补类型速度成本适用场景代码评估器Code快低正则、JSON、格式、精确匹配等确定性校验LLM 评估器LLM中中主观质量、复杂标准如是否有帮助、是否忠实人工评估Human慢高真值Ground Truth、校准参考决策顺序先代码Code→ 仅当代码无法表达标准时用 LLM → 用人工进行校准。这一代码优先原则贯穿整个技能文档的 Key Principles见.agents/skills/phoenix-evals/SKILL.md其核心思想是凡是能用确定性逻辑表达的标准就不要引入 LLM 的随机性与成本。评估结果的结构化约定无论哪种类型的评估器返回结果都遵循统一的结构属性是否必需说明name是评估器名称kind是code、llm、humanscore否*0-1 数值label否*pass/fail或其他二分类标签explanation否判断依据/理由*score与label至少提供一个。在源码中这一约定由 Score 数据类 实现批量评估时每个结果会序列化为包含name、score、label、explanation、metadata、kind、direction等字段的字典。Binary Likert用二元判断代替 1-5 量表技能文档强调优先使用 pass/fail 二元判断而不是 1-5 分制量表。二元标准的界定更清晰、更易校准。实践中应将一个复杂的 Likert 问题拆解为多个独立的二元检查# 多个二元检查代替一个 Likert 量表 evaluators [ AnswersQuestion(), # Yes/No UsesContext(), # Yes/No NoHallucination(), # Yes/No ]构建评估器的前置条件与生命周期在动手写代码之前先回答三个问题参考 evaluators-overview标准明确Clear criteria——具体可判而不是回答得好不好带人工标注的测试集Labeled test set——100 条带人类标注的样本可测量的准确率Measured accuracy——部署前必须知道 TPR/TNR。评估器的完整生命周期为Discover错误分析发现模式→ Design定义标准与测试用例→ Implement构建代码或 LLM 评估器→ Calibrate对照人工标签验证→ Deploy接入实验/CI 流水线→ Monitor持续跟踪准确率→ Maintain随产品演进更新。什么不该自动化罕见问题样本少于 5 例先放入观察清单不值得构建评估器快速修复改个 prompt 就能解决的先改 prompt标准仍在演进先稳定定义再考虑自动化。环境准备Python 与 TypeScript 双栈安装评估器技能支持 Python 与 TypeScript 两种语言详见 setup-python 与 setup-typescript。Python 安装# 核心 Phoenix 包包含 client、evals、otel pip install arize-phoenix # 或者按需安装独立包 pip install arize-phoenix-client # 仅 Phoenix 客户端 pip install arize-phoenix-evals # 评估工具 pip install arize-phoenix-otel # OpenTelemetry 集成LLM-as-judge 评估器还需要对应提供商的 SDKpip install openai # OpenAI pip install anthropic # Anthropic pip install google-genai # Google可选验证准确率时需要 scikit-learn 来计算 TPR/TNRpip install scikit-learn验证安装from phoenix.client import Client from phoenix.evals import LLM, ClassificationEvaluator from phoenix.otel import register # 所有导入都应成功 print(Phoenix Python setup complete)Evals 2.0 核心导入技能文档强调使用 2.0 新一代 API并明确不要使用1.0 遗留导入OpenAIModel、AnthropicModel、run_evals、llm_classifyfrom phoenix.client import Client from phoenix.evals import ( ClassificationEvaluator, # LLM 分类评估器推荐 LLM, # 供应商无关的 LLM 封装 async_evaluate_dataframe, # 批量评估 DataFrame推荐异步 evaluate_dataframe, # 批量评估 DataFrame同步 create_evaluator, # 代码评估器装饰器 create_classifier, # LLM 分类评估器工厂 bind_evaluator, # 列名到评估器参数的映射 Score, # Score 数据类 ) from phoenix.evals.utils import to_annotation_dataframe # 将结果格式化为 Phoenix 标注API 偏好建议ClassificationEvaluator优于create_classifier参数更多、可定制性更强async_evaluate_dataframe优于evaluate_dataframeLLM 评估吞吐更高。这些 API 在源码 evaluators.py 中均有对应实现create_evaluator、create_classifier、bind_evaluator、async_evaluate_dataframe分别位于 L828、L1133、L1222、L1559。构建代码评估器确定性优先代码评估器Code Evaluator不调用 LLM速度快、成本低、结果可复现详见 evaluators-code-python。基本模式create_evaluator装饰器import re import json from phoenix.evals import create_evaluator create_evaluator(namehas_citation, kindcode) def has_citation(output: str) - bool: return bool(re.search(r\[\d\], output)) create_evaluator(namejson_valid, kindcode) def json_valid(output: str) - bool: try: json.loads(output) return True except json.JSONDecodeError: return False参数绑定评估器可访问的字段参数说明output任务输出input示例输入expected期望输出metadata示例元数据create_evaluator(namematches_expected, kindcode) def matches_expected(output: str, expected: dict) - bool: return output.strip() expected.get(answer, ).strip()常见确定性模式正则匹配re.search(pattern, output)JSON schema 校验jsonschema.validate()关键词检查keyword in output.lower()长度检查len(output.split())相似度editdistance.eval()或 Jaccard 系数返回值类型约定create_evaluator装饰的函数返回值会被自动转换为标准评估结果返回类型结果boolTrue→ score1.0, labelTrueFalse→ score0.0, labelFalsefloat/int直接作为score值str短≤3 个词作为label值str长≥4 个词作为explanation值含score/label/explanation的dict直接映射到 Score 字段Score对象原样使用重要Code 与 LLM 评估器的区别create_evaluator装饰器只是包装一个普通 Python 函数kindcode默认用于不调用 LLM的确定性评估器kindllm标记为基于 LLM 的评估器但LLM 调用需要你自己在函数内部实现装饰器不会替你调用 LLM。因此大多数基于 LLM 的评估请优先使用ClassificationEvaluator——它会自动处理 LLM 调用、结构化输出解析与解释生成。预置代码评估器phoenix.evals.metrics模块内置了MatchesRegex等代码评估器from phoenix.client.experiments import create_evaluator from phoenix.evals.metrics import MatchesRegex date_format MatchesRegex(patternr\d{4}-\d{2}-\d{2})构建 LLM 评估器处理主观标准当标准是主观的、代码无法表达时使用 LLM 评估器详见 evaluators-llm-python。其核心组件是ClassificationEvaluatorLLM封装源码见 wrapper.py 与 evaluators.py。快速上手from phoenix.evals import ClassificationEvaluator, LLM llm LLM(provideropenai, modelgpt-4o) HELPFULNESS_TEMPLATE Rate how helpful the response is. question{{input}}/question response{{output}}/response helpful means directly addresses the question. not_helpful means does not address the question. Your answer (helpful/not_helpful): helpfulness ClassificationEvaluator( namehelpfulness, prompt_templateHELPFULNESS_TEMPLATE, llmllm, choices{not_helpful: 0, helpful: 1} )模板变量与 XML 标签约定用 XML 标签包裹变量让 LLM 清晰区分不同字段变量XML 标签{{input}}question{{input}}/question{{output}}response{{output}}/response{{reference}}reference{{reference}}/reference{{context}}context{{context}}/contextcreate_classifier工厂create_classifier是返回ClassificationEvaluator的简写工厂。直接实例化ClassificationEvaluator可获得更多参数与定制能力from phoenix.evals import create_classifier, LLM relevance create_classifier( namerelevance, prompt_templateIs this response relevant to the question? question{{input}}/question response{{output}}/response Answer (relevant/irrelevant):, llmLLM(provideropenai, modelgpt-4o), choices{relevant: 1.0, irrelevant: 0.0}, )输入列名映射数据框列名必须与模板变量一致。不一致时有两种处理方式# 方案 1重命名列以匹配模板变量 df df.rename(columns{user_query: input, ai_response: output}) # 方案 2使用 bind_evaluator from phoenix.evals import bind_evaluator bound bind_evaluator( evaluatorhelpfulness, input_mapping{input: user_query, output: ai_response}, )Prompt 编写最佳实践具体化——明确定义 pass/fail 的含义包含示例——为每个标签展示具体案例默认生成解释——ClassificationEvaluator自动附带explanation研究内置 prompt——参考 classification_evaluator_configs 中 Faithfulness、Correctness、RetrievalRelevance 等结构化良好的评估 prompt仓库中对应的 YAML 配置位于 prompts/classification_evaluator_configs。预置评估器拿来即用与使用注意phoenix.evals.metricsPython与arizeai/phoenix-evalsTypeScript提供了一系列开箱即用的 LLM 评估器。命名约定为 Python 用NameEvaluatorTypeScript 用createNameEvaluator。技能文档明确提示预置评估器仅用于探索生产环境前必须验证。预置评估器一览评估器输入字段Python 名标签1.0 / 0.0方向Concisenessinput,outputconcise/verbosemaximizeCorrectnessinput,outputcorrect/incorrectmaximizeFaithfulnessinput,output,contextfaithful/unfaithfulmaximizeHallucinationinput,outputhallucinated/groundedminimizePiiDetectionconversationpii_detected/no_pii_detectedminimizeRefusalinput,outputrefused/answeredneutralRetrievalRelevanceinput,contextrelevant/irrelevantmaximizeToolInvocationinput,available_tools,tool_selectioncorrect/incorrectmaximizeToolResponseHandlinginput,tool_call,tool_result,outputcorrect/incorrectmaximizeToolSelectioninput,available_tools,tool_selectioncorrect/incorrectmaximizeToxicitytexttoxic/non-toxicminimizeUserFrictionconversation,user_messagefriction/no_frictionminimize其中minimize方向的评估器高分代表坏结果。这些类在源码 metrics 目录中均有实现如ConcisenessEvaluator、CorrectnessEvaluator、FaithfulnessEvaluator、DocumentRelevanceEvaluator等均为ClassificationEvaluator的子类。使用示例from phoenix.evals import LLM from phoenix.evals.metrics import FaithfulnessEvaluator llm LLM(provideropenai, modelgpt-4o) faithfulness_eval FaithfulnessEvaluator(llmllm)import { createFaithfulnessEvaluator } from arizeai/phoenix-evals; import { openai } from ai-sdk/openai; const faithfulnessEval createFaithfulnessEvaluator({ model: openai(gpt-4o) });关键评估器的语义辨析Faithfulness vs. Hallucination两者都检查回答是否有事实依据支撑区别在于依据来源不同。Faithfulness 对照单独提供的context检索文档——用于 RAG 场景Hallucination 对照对话本身input存放助手所见到的完整历史包括工具调用与结果没有context字段——用于多轮 Agent 与聊天场景。PII 检测需覆盖完整记录唯一的conversation字段应包含全部内容——系统指令、工具调用与结果、检索文档——而不仅是用户看到的部分。评估器的explanation是结构化的FINDINGS:块或FINDINGS: none可解析出逐条的分类。占位符与脱敏内容[REDACTED]、555-01xx号码、example.com地址等样例标记会被刻意忽略所以不要用假的标识符构造测试用例。RetrievalRelevance 的字段约定RetrievalRelevanceEvaluator与来源无关对检索信息整体打分只要任一有意义的部分实质性帮助了请求该步骤即为relevant。标签为relevant/irrelevant方向为 maximizerelevant1.0irrelevant0.0每个结果附带 judge 的explanation。两个字段约定容易出错且会悄悄改变测量对象input应该是用户的请求如 trace 根的input.value而不是改写后的工具参数或生成的 SQL 查询context应包含你想评判的检索范围单文档评估传一个文档整体步骤评估将所有返回项拼接成一个context。Relevance 不是 Correctness过时或被后续反驳的信息只要确实与主题相关仍得relevant检索失败报错、超时、无结果得irrelevant。from phoenix.evals import LLM from phoenix.evals.metrics import RetrievalRelevanceEvaluator relevance_eval RetrievalRelevanceEvaluator(llmLLM(provideropenai, modelgpt-4o-mini)) scores relevance_eval.evaluate({ input: What is the capital of France?, context: Paris is the capital and largest city of France., }) print(scores[0].label) # relevantRetrievalRelevanceEvaluator接受llm外加任意**kwargs透传给 LLM 客户端如temperature0.0并要求模型支持工具调用或结构化输出。TypeScript 工厂在常规分类评估器参数之上还支持可选的name、choices、promptTemplate、optimizationDirection覆盖。何时使用预置评估器场景建议探索用它找需要 review 的 trace找离群值按分数排序生产先验证80% 人工一致性领域特定构建自定义评估器探索模式批量打分并筛选from phoenix.evals import evaluate_dataframe results_df evaluate_dataframe(dataframetraces, evaluators[faithfulness_eval]) # Score 列是 dict —— 提取数值分数 scores results_df[faithfulness_score].apply( lambda x: x.get(score, 0.0) if isinstance(x, dict) else 0.0 ) low_scores results_df[scores 0.5] # Review these high_scores results_df[scores 0.9] # Also sample批量评估 DataFrame核心 2.0 APIevaluate_dataframe/async_evaluate_dataframe是 Evals 2.0 的批量评估核心 API详见 evaluate-dataframe-python。推荐异步版本批量评估尤其涉及 LLM 评估器时优先使用异步版本以获得更高吞吐from phoenix.evals import async_evaluate_dataframe results_df await async_evaluate_dataframe( dataframedf, # pandas DataFrame列名与评估器参数匹配 evaluators[eval1, eval2], # 评估器列表 concurrency5, # 最大并发 LLM 调用数默认 3 exit_on_errorFalse, # 可选出错即停默认 True max_retries3, # 可选重试失败/超时的 LLM 调用默认 10 )同步版本from phoenix.evals import evaluate_dataframe results_df evaluate_dataframe( dataframedf, # pandas DataFrame列名与评估器参数匹配 evaluators[eval1, eval2], # 评估器列表 exit_on_errorFalse, # 可选出错即停默认 True max_retries3, # 可选重试失败/超时的 LLM 调用默认 10 )结果列格式字典而非数值evaluate_dataframe返回输入 DataFrame 的副本并追加新列。结果列包含的是字典不是原始数值。每个名为foo的评估器会新增两列列类型内容foo_scoredict{name: foo, score: 1.0, label: True, explanation: ..., metadata: {...}, kind: code, direction: maximize}foo_execution_detailsdict{status: success, exceptions: [], execution_seconds: 0.001}只有非 None 字段才会出现在 score 字典中。提取数值分数# 错误写法 —— 会失败或产生意外结果 score results_df[relevance].mean() # KeyError! score results_df[relevance_score].mean() # 尝试对字典求平均 # 正确写法 —— 从字典中提取数值 scores results_df[relevance_score].apply( lambda x: x.get(score, 0.0) if isinstance(x, dict) else 0.0 ) mean_score scores.mean()提取标签与解释labels results_df[relevance_score].apply( lambda x: x.get(label, ) if isinstance(x, dict) else ) explanations results_df[relevance_score].apply( lambda x: x.get(explanation, ) if isinstance(x, dict) else )查找失败样本scores results_df[relevance_score].apply( lambda x: x.get(score, 0.0) if isinstance(x, dict) else 0.0 ) failed_mask scores 0.5 failures results_df[failed_mask]输入列映射评估器将每一行作为 dict 接收列名必须与评估器期望的参数名一致。不一致时使用.bind()方法或bind_evaluator函数from phoenix.evals import bind_evaluator, create_evaluator, async_evaluate_dataframe create_evaluator(namecheck, kindcode) def check(response: str) - bool: return len(response.strip()) 0 # 方案 1使用评估器的 .bind() 方法 check.bind(input_mapping{response: answer}) results_df await async_evaluate_dataframe(dataframedf, evaluators[check]) # 方案 2使用 bind_evaluator 函数 bound bind_evaluator(evaluatorcheck, input_mapping{response: answer}) results_df await async_evaluate_dataframe(dataframedf, evaluators[bound])也可以直接重命名列名以匹配df df.rename(columns{ attributes.input.value: input, attributes.output.value: output, })不要使用遗留的 run_evals# 错误 —— 1.0 遗留 API from phoenix.evals import run_evals results run_evals(dataframedf, evaluators[eval1]) # 返回 List[DataFrame] —— 每个评估器一个 # 正确 —— 当前 2.0 API from phoenix.evals import async_evaluate_dataframe results_df await async_evaluate_dataframe(dataframedf, evaluators[eval1]) # 返回单个 DataFrame带 {name}_score 字典列关键区别run_evals返回每个评估器一个 DataFrame 的列表async_evaluate_dataframe返回合并了所有结果的单个 DataFrame使用{name}_score字典列格式并通过bind_evaluator做输入映射而非input_mapping参数。运行实验数据集、任务与评估的编排run_experiment将数据集、任务函数与评估器编排为一次可追踪的实验详见 experiments-running-pythonAPI 实现见 packages/phoenix-client/src/phoenix/client/experiments。基本用法from phoenix.client import Client from phoenix.client.experiments import run_experiment client Client() dataset client.datasets.get_dataset(nameqa-test-v1) def my_task(example): return call_llm(example.input[question]) def exact_match(output, expected): return 1.0 if output.strip().lower() expected[answer].strip().lower() else 0.0 experiment run_experiment( datasetdataset, taskmy_task, evaluators[exact_match], experiment_nameqa-experiment-v1, )任务函数# 基本任务 def task(example): return call_llm(example.input[question]) # 带上下文RAG def rag_task(example): return call_llm(fContext: {example.input[context]}\nQ: {example.input[question]})评估器参数访问参数访问方式output任务输出expected示例的期望输出input示例输入metadata示例元数据常用选项experiment run_experiment( datasetdataset, taskmy_task, evaluatorsevaluators, experiment_namemy-experiment, dry_run3, # 先用 3 个示例试运行 repetitions3, # 每个示例运行 3 次 )查看结果print(experiment.aggregate_scores) # {accuracy: 0.85, faithfulness: 0.92} for run in experiment.runs: print(run.output, run.scores)稳定性与重复运行repetitions当任务或评估器任一具有非确定性LLM 调用、工具使用、流式输出、LLM-as-judge时单次运行的分数会有噪声。在小数据集上单次运行的噪声可能淹没一次 prompt 变更带来的真实信号。对多次重复取平均能让报告的分数反映 prompt 本身而非采样噪声run_experiment( # ... repetitions3, )何时使用 repetitions 的考量任务或评估器是 LLM 调用且数据集较小时优先使用 repetitions单样本成本低、主要目的是定分数时优先 repetitions需要覆盖更多行为时优先扩充数据集任务与评估器都是确定性的如与真值的字符串比较时跳过 repetitions——单次运行就是答案。何时考虑增加稳定性同一实验的重复运行漂移幅度大于你试图测量的差异一次 prompt 变更导致的样本标签翻转与输出实际变化不符judge 对同一输出的推理在不同运行间读起来不一致。repetitions1默认值恰恰依赖单次运行——不要轻信基于单个 10 样本运行得到的调参结论。事后补充评估from phoenix.client.experiments import evaluate_experiment evaluate_experiment(experimentexperiment, evaluators[new_evaluator])验证评估器准确率用人工标签校准评估器投入生产前必须验证详见 validation 与 validation-evaluators-python。技能文档中的 Key Principles 给出了量化门槛judge 的 TPR/TNR 应 80%。from sklearn.metrics import classification_report print(classification_report(human_labels, evaluator_results[label])) # Target: 80% agreement评估器的构建决策树来自 evaluators-overviewShould I Build an Evaluator? │ ▼ Can I fix it with a prompt change? YES → Fix the prompt first NO → Is this a recurring issue? YES → Build evaluator NO → Add to watchlist不要过早自动化。很多问题只是简单的 prompt 修复。接入测试运行器把评估变成 CI 门禁技能文档提供了将评估器接入 pytest 与 Vitest/Jest 的完整方案见 integrations-pytest 与 integrations-vitest-jest。门禁设计核心原则Invariants gate, signals trend这一原则是整个 CI 门禁体系的设计哲学硬不变量Invariants用assert/expect把关——确定性断言如精确匹配、格式校验失败即 CI 变红硬失败LLM judge 质量信号记录并聚合把关——用接受标准acceptance criteria对聚合指标设门槛而不是对每个样本逐个设限软信号观察趋势。完整工作流从观测到生产技能文档给出了五条经过编排的标准工作流详见 SKILL.md新项目起步Starting Fresh先建立观测observe-tracing-setup→ 错误分析error-analysis→ 失败分类编码axial-coding→ 再决定评估器evaluators-overview。构建评估器Building Evaluator先读基础概念fundamentals→ 避开常见错误common-mistakes-python→ 编写代码/LLM 评估器 → 用人工标签验证validation-evaluators-{python|typescript}。RAG 系统RAG Systems用 evaluators-rag 起步 → 代码评估器评估检索retrieval→ LLM 评估器评估忠实度faithfulness。CI 门禁Gating CI编写代码/LLM 评估器 → 接入 pytest 或 Vitest/Jestintegrations-{pytest|vitest-jest}→ 持续生产production-continuous。生产环境Productionproduction-overview → production-guardrails → production-continuous。参考分类体系技能文档将全部参考材料按前缀分类方便按需查阅前缀描述fundamentals-*类型、分数、反模式observe-*追踪、采样error-analysis-*发现失败axial-coding-*对失败分类编码evaluators-*代码、LLM、RAG 评估器experiments-*数据集、运行实验integrations-*从测试运行器pytest、Vitest、Jest运行评估作为 CI 门禁validation-*对照人工标签验证评估器准确率production-*CI/CD、监控核心原则速览技能文档的 Key Principles 是整套评估体系的方法论内核原则行动错误分析先行Error analysis first未观测到的东西无法自动化自定义优于通用Custom generic从自己的失败案例出发构建代码优先Code first先确定性再 LLM验证 judgeValidate judgesTPR/TNR 80%二元优于量表Binary Likertpass/fail不用 1-5 分制不变量把关、信号看趋势Invariants gate, signals trendassert/expect硬不变量CI 变红记录 LLM judge 质量信号并聚合设接受标准而非逐个样本设限进一步探索评估 API 完整实现packages/phoenix-evals/src/phoenix/evals/evaluators.pyScoreL159、ClassificationEvaluatorL601、create_evaluatorL828、create_classifierL1133、bind_evaluatorL1222、async_evaluate_dataframeL1559预置评估器源码packages/phoenix-evals/src/phoenix/evals/metrics实验 APIpackages/phoenix-client/src/phoenix/client/experiments/init.pyrun_experimentL17、evaluate_experimentL684内置评估 prompt 配置prompts/classification_evaluator_configsPython 评估端到端教程tutorials/evals/evals_quickstart.ipynb 与 tutorials/evals/evals_introduction.ipynbTypeScript 评估包js/packages/phoenix-evals测试参考tests/unit/pxiPhoenix 内部评估器测试赞分享可观测性AI 评测LLMOpsAI 应用人工智能【免费下载链接】phoenixAI Observability Evaluation项目地址https://gitcode.com/gh_mirrors/phoenix13/phoenix点击查看免费下载相关推荐Phoenix TypeScript LLM 评估器Evaluators完全指南基于 AI SDK 的分类式评测实战Phoenix TypeScript LLM 评估器Evaluators完全指南基于 AI SDK 的分类式评测实战 导读 本文以 Phoenix 开源仓可观测性AI 评测LLMOpsAI 应用人工智能Phoenix LLM 评估反模式清单从错误分析到可量化改进的实战指南Phoenix LLM 评估反模式清单从错误分析到可量化改进的实战指南 导读 本指南基于 Arize Phoenix 的 LLM 评估技能文档 .agen可观测性AI 评测LLMOpsAI 应用人工智能Phoenix LLM Evaluators Python 指南用 LLM 构建分类评估器与大规模评测Phoenix LLM Evaluators Python 指南用 LLM 构建分类评估器与大规模评测 导读 本指南围绕 PhoenixAI Observa可观测性AI 评测LLMOpsAI 应用人工智能创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考