![[基于OpenEvals的自动化评估-01]OpenEvals的评估模型其实很简单](http://pic.xiahunao.cn/yaotu/[基于OpenEvals的自动化评估-01]OpenEvals的评估模型其实很简单)
OpenEvals是LangChain官方推出的开源自动化评估框架专注于Agent及大模型应用的链路质检。它不仅能评估大模型的最终回复更核心的价值在于多步行为与决策评估。框架支持工具调用准确性和多轮用户模拟仿真。通过将评估指标代码化OpenEvals将复杂的Agent推理轨迹、思维黑盒转化为可量化的分数提供了工业级的Agent操行评定表。它是破局Agent落地信任危机的核心度量衡。虽然OpenEvals可以帮助我们从很多的维度对Agent进行评估但是它的评估模型其实很简单。1. 从一个最简单评估操作开始顾名思义OpenEvals旨在打造一个与平台无关的开放的评估框架并作为其他绑定于具体Agent开发平台评估框架的基础框架比如LangChain自家的AgentEvals就将OpenEvals作为了底座框架。一些具体Agent平台的评估框架MAF会将Agent的执行纳入执行评估的API中但是作为与平台无关的OpenEvals显然不能这么做所以它总是对Agent执行的结果实施评估。我们可以将OpenEvals视为一个单元测试框架。几乎所有的单元测试框架都采用断言的方式通过比较真实输出与希望输出来确定编写的代码是否与设计匹配。OpenEvals本质上也一样其评估工作也是在评估真实输出和提供的希望输出之间的匹配度。以如下这个简单的演示程序为例我们假设Agent的输出为foo bar希望的输出为bar baz我们将它们作为outputs和reference_outputs参数调用exact_match函数验证两者是否相等并将函数返回的结果打印出来。很明显被评估的文本和希望的文本并不匹配所以评估结果以布尔值的形式出现在输出对象的score字段中而key则于调用方法函数相匹配。fromopenevalsimportexact_match resultexact_match(outputsfoo bar,reference_outputsbar baz)print(result)输出{key:exact_match,score:False,comment:None,metadata:None}如下所示的就是这个exact_match函数的完整定义。虽然简单它却涵盖了组成OpenEvals评估模型的两个基本元素用于实施评估工作的评估器Evaluator和作为评估结果的EvaluatorResult对象。defexact_match(*,outputs:Any,reference_outputs:Any,**kwargs:Any)-EvaluatorResult:defget_score():return_scorer(outputs,reference_outputs)res_run_evaluator(run_nameexact_match,scorerget_score,feedback_keyexact_match)ifisinstance(res,list):returnres[0]returnres2. 评估的结果作为评估的结果EvaluatorResult类型为具有如下定义的一个TypedDict。classEvaluatorResult(TypedDict):key:strscore:ScoreType comment:Optional[str]metadata:Optional[dict]source_run_id:Optional[str]ScoreTypeUnion[float,bool]组成评估结果的四个成员包括key当前评估指标或维度的名称在多维度综合评估时作为唯一标识符。方便后续在看板如LangSmith中进行分类、过滤和聚合统计。由于上面的例子调用exact_match函数进行严格的文本内容对等评估所以此字段的值为exact_matchscore: 评估的量化结果。将主观的AI表现转化为客观的数字布尔值单步测试的通过/失败如工具参数是否完全一致。由于上面的例子旨在进行文本内容对等验证所以量化结果就是二元布尔值连续值通常在0.0到1.0之间一般由LLM-as-a-Judge根据打分标准Rubric给出的多轮对话质量得分。comment: 裁判的评语/判词记录了评估器得出该分数的推理过程和定性理由。它打破评估黑盒提供可解释性。当score出现异常低分时开发者无需盲目盲测可以直接查看comment中的扣分原因metadata用于存放与本次评估相关的自定义元数据。可以利用它支撑高级分析与定制化扩展。比如你可以把评估时消耗的Token数量、评估模型的版本号、或是自定义的中间测试状态塞进这里为后续的评估系统迭代提供长效参考source_run_id: 追踪溯源的线索指针对应被评估目标在运行系统中的唯一追踪ID。在全链路血缘追踪中这是评估Agent轨迹的关键纽带。通过这个ID评估结果能够精准反向绑定到那次引发错误的Agent实际执行链路上实现发现问题 - 一键直达受损现场的自动化Debug闭环。3. 执行评估器所谓的评估本质上就是调用指定的一个或者多个评估器的过程。从exact_match的定义可以看出整个函数的核心就是调用如下这个执行评估器的_run_evaluator函数。这个函数返回的可以单个EvaluatorResult对象也可能是一组EvaluatorResult对象的列表。如果返回值是前者exact_match函数会直接返回生成的EvaluatorResult对象否则返回列表中的第一个EvaluatorResult对象。def_run_evaluator(*,run_name:str,scorer:Callable,feedback_key:str,ls_framework:stropenevals,**kwargs:Any,)-Union[EvaluatorResult,list[EvaluatorResult]]_run_evaluator函数的参数说明如下run_name: 评估任务的声明式标签用于指定本次评估行为在追踪系统中的显示名称。它不仅是一个字符串还会直接作为LangSmith的Run Name。通过清晰的命名开发者可以在成千上万条评估链路中一眼识别出当前执行的是哪一个评估器。上面演示实例指定的参数名为exact_matchscorer: 一个可执行的评分函数feedback_key: 输出结果在反馈系统中呈现的键名一般指定为评估指标的名称上面演示实例指定的参数名为exact_match。通常这个值会被传递并映射为EvaluatorResult中的key字段ls_framework显式指定当前使用的评估框架名称默认硬编码为openevals。作为_run_evaluator函数scorer参数的评分函数在针对exact_match函数的调用中对应如下这个_scorer函数。该函数并未对作为参数的outputs和reference_outputs的数据类型作过多的约束只要求它们不会None并且支持基于JSON的序列化因为返回值为序列化两个对象后生成JSON字符串比较的结果。def_scorer(outputs:Any,reference_outputs:Any)-bool:ifoutputsisNoneorreference_outputsisNone:raiseValueError(Exact match requires both outputs and reference_outputs)outputs_jsonjson.dumps(outputs,sort_keysTrue)reference_outputs_jsonjson.dumps(reference_outputs,sort_keysTrue)returnoutputs_jsonreference_outputs_json上面这个_run_evaluator函数最终会调用如下这个_run_evaluator_untyped函数真正评估工作正是实现在这个函数中。两个函数的区别体现在如下两个地方_run_evaluator_untyped函数读了一个布尔类型的参数return_raw_outputs表示是否直接返回scorer参数这个评分函数的值。当_run_evaluator函数内部调用此函数的时候该参数被设置为True_run_evaluator_untyped函数返回类型的联合成员类型多了一个字典类型。由于方法并未对作为评分函数的签名作任何约束所以具体返回那种类型取决于评分函数返回的结果。def_run_evaluator_untyped(*,run_name:str,scorer:Callable,feedback_key:str,return_raw_outputs:boolFalse,ls_framework:stropenevals,**kwargs:Any,)-Union[EvaluatorResult,list[EvaluatorResult],dict]评分函数具有如下两种典型的返回类型字典Key为评估指标的名称Value的类型可以是字典:包含如下的Keyscore评估得分必须reasoningLLM推理文本必须metadata元数据可选source_run_id实施评估运行的ID列表:具体的元素为具有上述结果的字典元组可以是(score, reasoning, metadata)三元组(score, reasoning) 二元组。上面提及的字典和元组最终会转换成一个EvaluatorResult对象字典的Key或者元组成员score、reasoning、metadata和source_run_id分别对应EvaluatorResult的score、comment、metadata和source_run_id字段。4. 异步执行评估器exact_match函数还有一个异步版本exact_match_async前面演示的例子也可以按照如下的方式异步调用这个函数来实施评估。fromopenevalsimportexact_match_asyncimportasyncioasyncdefeval():resultawaitexact_match_async(outputsfoo bar,reference_outputsbar baz)print(result)asyncio.run(eval())exact_match_async函数内部调用链会涉及针对如下所示的_arun_evaluator和_arun_evaluator_untyped函数的调用它们是_run_evaluator和_run_evaluator_untyped函数的异步版本。asyncdef_arun_evaluator(*,run_name:str,scorer:Callable,feedback_key:str,return_raw_outputs:boolFalse,ls_framework:stropenevals,**kwargs:Any,)-Union[EvaluatorResult,list[EvaluatorResult]]asyncdef_arun_evaluator_untyped(*,run_name:str,scorer:Callable,feedback_key:str,return_raw_outputs:boolFalse,ls_framework:stropenevals,**kwargs:Any,)-Union[EvaluatorResult,list[EvaluatorResult],dict]:5. SimpleEvaluator SimpleAsyncEvaluatorexact_match和exact_match_async函数直接将评估器的执行实现在函数内部但是在大部分情况下我们会根据评估场景调用相应的工厂函数来常见对应的评估器然后再执行评估器实施评估。OpenEvals定义了如下这两个协议类型来对同步和异步版本的评估器进行了抽象。classSimpleEvaluator(Protocol):def__call__(self,*,inputs:Optional[Any]None,outputs:Any,reference_outputs:Optional[Any]None,**kwargs,)-Union[EvaluatorResult,list[EvaluatorResult]]:...classSimpleAsyncEvaluator(Protocol):asyncdef__call__(self,*,inputs:Optional[Any]None,outputs:Any,reference_outputs:Optional[Any]None,**kwargs,)-Union[EvaluatorResult,list[EvaluatorResult]]:...由于协议中只定义了唯一的__call__方法所以评估评估器可以使用具有兼容签名的函数和Lambda表达式来表示具体的输入类型为inputs输入上下文可选outputs待评估的输出必需reference_outputs参考答案或者希望的结果可选kwargs: 扩展关键字