![[基于OpenEvals的自动化评估-13]Agent执行轨迹评估[LLM-as-a-Judge]](http://pic.xiahunao.cn/yaotu/[基于OpenEvals的自动化评估-13]Agent执行轨迹评估[LLM-as-a-Judge])
基于OpenEvals的自动化评估-12:Agent执行轨迹评估介绍的轨迹评估很简单它首先确定待评估的消息列表与作为基准的列表在消息数量上相等、角色上一一匹配。如果涉及工具调用在根据指定的工具调用列表匹配模式和参数匹配模式对工具调用进行比较。其实Agent执行轨迹也可以借助LLM的力量利用创建的基于LLM-as-a-Judge的评估器来评估。1. LLM-as-a-Judge的评估器的创建我们可以调用如下这个create_trajectory_llm_as_judge和create_async_trajectory_llm_as_judge函数来创建用于Agent轨迹评估的SimpleEvaluator和SimpleAsyncEvaluator对象该函数的大部分参数都与基于OpenEvals的自动化评估-02:LLM-as-a-Judge中介绍的的create_llm_as_judge和create_async_llm_as_judge函数是一致的。defcreate_trajectory_llm_as_judge(*,prompt:str|Runnable|Callable[...,list[ChatCompletionMessage]]TRAJECTORY_ACCURACY_PROMPT_WITH_REFERENCE,model:Optional[str]None,feedback_key:strtrajectory_accuracy,judge:Optional[Union[ModelClient,BaseChatModel,]]None,continuous:boolFalse,choices:Optional[list[float]]None,use_reasoning:boolTrue,few_shot_examples:Optional[list[FewShotExample]]None,)-SimpleEvaluatordefcreate_async_trajectory_llm_as_judge(*,prompt:str|Runnable|Callable[...,list[ChatCompletionMessage]]TRAJECTORY_ACCURACY_PROMPT_WITH_REFERENCE,model:Optional[str]None,feedback_key:strtrajectory_accuracy,judge:Optional[Union[ModelClient,BaseChatModel,]]None,continuous:boolFalse,choices:Optional[list[float]]None,use_reasoning:boolTrue,few_shot_examples:Optional[list[FewShotExample]]None,)-SimpleAsyncEvaluator:具体参数说明如下prompt:定义评估提示词模板类型可以是字符串也可以是类似于PromptTemplate这样的Runnable对象可以采用LCEL表达式于LLM进行连接或者是一个用于返回LLM输入的消息列表的函数。如果以字符串定义提示词可以包含如下的占位符:{inputs}{outputs}{reference_outputs}{由kwargs指定的参数名称}feedback_key评估结果中存储的字段名默认为trajectory_accuracyjudge/model: 用于提供用来实施评估的LLMsystem 系统提示词continuous评估结果是否是连续值True 输出为0~1的连续浮点数False 输出为布尔值。choices如果希望评估结果采用指定的选项可以利用此参数指定一个列表比如choices[0.0, 0.5, 1.0]意味着最终得分只有指定的三种选择use_reasoning是否要求模型输出评分理由True输出包含解释False只输出评分。few_shot_examples: 用于在提示词中加入few-shot示例提升评估一致性。在调用SimpleEvaluator/SimpleAsyncEvaluator进行评估的时候定义在评估提示词模板的占位符会被同名的参数替换。如果使用model参数指定包含提供商的模型标准名称方法内部会利用标准的URL创建代表LangChain LLM组件的BaseChatModel对象。如果需要连接自定义URL指向的LLM部署地址或者需要对LLM组件对象进行定制可以直接利用judge参数指定一个BaseChatModel对象。也可以直接执行一个ModelClient对象ModelClient是OpenEvals针对LLM客户端组件的表达但是此时依然需要利用model参数指定模型名称2. 默认提示词从create_trajectory_llm_as_judge函数的参数定义可以看出它默认使用的提示词通过常量TRAJECTORY_ACCURACY_PROMPT_WITH_REFERENCE表示。从命名可以看出这是一个包含{reference_outputs}占位符作为评估基准的提示词模板具体内容如下You are an expert data labeler. Your task is to grade the accuracy of an AI agents internal trajectory. Rubric An accurate trajectory: - Makes logical sense between steps - Shows clear progression - Is relatively efficient, though it does not need to be perfectly efficient - Is semantically equivalent to the provided reference trajectory /Rubric Based on the following reference trajectory: reference_trajectory {reference_outputs} /reference_trajectory Grade this actual trajectory: trajectory {outputs} /trajectory定义在提示词中的评估规则Rubric定义了四条黄金标准它定义了什么才算是一条准确的轨迹逻辑连贯性Logical sense between stepsAgent的前一步行动和后一步行动之间必须有因果关系或合理的推导逻辑。如果第一步是搜索用户购买记录第二步如果是根据记录计算总金额就符合逻辑如果是突然去搜索天气就是逻辑断层;步骤递进性Clear progression轨迹必须在往前推进任务而不是在原地打转或陷入死循环。每一步都应该让Agent离最终目标更近;相对高效性Relatively efficient允许Agent犯一点点小错或走一两步弯路宽容度但不接受极其冗长、试错无数次的低效轨迹;语义等价性Semantically equivalent to reference这是最核心的硬性指标。实际轨迹调用的工具、思考的业务方向在语义和实质内容上必须与{reference_outputs}参考轨迹保持高度一致。路径可以不完全一模一样但核心逻辑和手段必须等价。3. 针对LangChain Agent的评估我们将基于OpenEvals的自动化评估-12:Agent执行轨迹评估演示的针对LangChain Agent的评估移植到这里并切换成基于基于LLM-as-a-Judge的评估。我们将评估的核心操作定义在eval函数中它会根据默认的提示词、用来连接LLMgpt-5.4-mini的ChatOpenAI对象以及传入的关键字参数调用create_async_trajectory_llm_as_judge函数创建一个基于LLM-as-a-Judge的SimpleAsyncEvaluator对象。最后将指定的输出和引用输出作为参数调用这个评估器并将评估结果以JSON形式输出。fromtypingimportcastfromopenevalsimportcreate_async_trajectory_llm_as_judgefromlangchain_openaiimportChatOpenAIfromlangchain_core.messagesimportHumanMessage,AIMessage,ToolMessage,AnyMessagefromopenevals.prompts.conversationimportAGENT_TONE_PROMPTfromlangchain.agentsimportcreate_agentfromlangchain.toolsimporttoolfromdotenvimportload_dotenvimportasyncio,json load_dotenv()judgeChatOpenAI(modelgpt-5.4-mini)asyncdefeval(*,outputs:list[AnyMessage],reference_outputs:list[AnyMessage]|NoneNone,**kwargs):evaluatorcreate_async_trajectory_llm_as_judge(continuousTrue,judgejudge,**kwargs)resultawaitevaluator(outputsoutputs,reference_outputsreference_outputs)print(json.dumps(result,ensure_asciiFalse,indent2))tooldeflook_up_location_code(city:str)-str:提取指定城市的位置代码 Args: city: 城市名称 Returns: 指定城市对应的位置代码 returnlocation-123tooldefget_weather(location_code:str)-str:提取指定位置代码所在地的天气 Args: location_code: 位置代码 Returns: 天气信息 return晴气温25度agentcreate_agent(modelChatOpenAI(modelgpt-5.4-mini),tools[look_up_location_code,get_weather])asyncdefmain():referenced_messages[HumanMessage(...),AIMessage(content,tool_calls[{name:look_up_location_code,args:{city:苏州},id:call-001}]),ToolMessage(contentlocation-123,tool_call_idcall-001),AIMessage(content,tool_calls[{name:get_weather,args:{location_code:location-123},id:call-002}]),ToolMessage(content,tool_call_idcall-002),AIMessage(content...)]resultawaitagent.ainvoke(input{messages:[{role:user,content:今天苏州是晴天吗}]})messagescast(list[AnyMessage],result.get(messages))formessageinmessages:message.pretty_print()awaiteval(outputsmessages,reference_outputsreferenced_messages)asyncio.run(main())我们在调用create_agent函数的时候注册了两个工具函数look_up_location_code用来提取指定城市的位置代码get_weather则根据指定位置代码获取所在地的天气信息。当我们调用这个Agent查询指定城市的天气时正常的执行轨迹应该是LLM在接收到作为原始查询的HumanMessage后利用返回的AIMessage下发针对look_up_location_code工具函数的调用作为参数的city为解析出来的城市名Agent在本地完成工具执行后将城市对应的位置代码以ToolMessage的形式发送给LLMLLM再次以AIMessage的形式下发针对get_weather工具函数的调用参数为得到的位置代码Agent执行工具将天气信息以ToolMessage的形式上传LLMLLM将获得的天气信息整理成最终的答复并以AIMessage的形式返回给Agent。调用eval函数实施评估时指定的reference_outputs消息列表正式采用上面这个轨迹创建的。在对Agent最终输出的对话历史实施评估之前我们还输出了每一条消息的内容具体输出如下 Human Message 今天苏州是晴天吗 Ai Message Tool Calls: look_up_location_code (call_52x44lhagZJ1oavAYjzLnvyq) Call ID: call_52x44lhagZJ1oavAYjzLnvyq Args: city: 苏州 Tool Message Name: look_up_location_code location-123 Ai Message Tool Calls: get_weather (call_PQq356llwxinxDeCv03YlnaC) Call ID: call_PQq356llwxinxDeCv03YlnaC Args: location_code: location-123 Tool Message Name: get_weather 晴气温25度 Ai Message 是的苏州今天是晴天气温约 25°C。上面输出的结果可利用看出Agent的执行轨迹与reference_outputs消息列表的描述是一致的所以如下输出的评估结果显示为通过{key:trajectory_accuracy,score:1.0,comment:The actual trajectory follows the same logical steps as the reference: it looks up the location code for 苏州, then queries the weather using that code. It is semantically equivalent to the reference trajectory and even more complete by providing the weather result and final answer. The steps are clear, efficient, and consistent with the intended tool-use progression. Thus, the score should be: 1.0.,metadata:null}现在我们对程序略加修改直接修改调用Agent的提示词苏州所在的区域代码为location-123直接调用工具get_weather函数返回苏州当前的天气。。resultawaitagent.ainvoke(input{messages:[{role:user,content:苏州所在的区域代码为location-123,直接调用工具get_weather函数返回苏州当前的天气。}]})由于已经提供了区域位置的代码并要求直接调用工具get_weather函数返回苏州当前的天气。所以针对look_up_location_code工具函数的调用将不再进行如下所示的对话历史输出体现了这一点 Human Message 苏州所在的区域代码为location-123,直接调用工具get_weather函数返回苏州当前的天气 Ai Message Tool Calls: get_weather (call_2XSTgraHzENRNJQ8QLMMpTXm) Call ID: call_2XSTgraHzENRNJQ8QLMMpTXm Args: location_code: location-123 Tool Message Name: get_weather 晴气温25度 Ai Message 苏州当前天气晴气温25度。此时评估必然通不过{key:trajectory_accuracy,score:0.5,comment:The actual trajectory is logically coherent and efficiently uses the provided location code to call get_weather directly. However, it is not semantically equivalent to the reference trajectory because the reference first calls look_up_location_code with city 苏州, receives location-123, and then calls get_weather, whereas the actual trajectory skips the location lookup step and has a non-empty weather result instead of the empty tool result shown in the reference. Thus, the score should be: 0.5.,metadata:null}4. 无基准的轨迹评估除了默认的包含评估基准、通过常量TRAJECTORY_ACCURACY_PROMPT_WITH_REFERENCE表示的提示词OpenEvals还定义了另一个名为TRAJECTORY_ACCURACY_PROMPT的常量并通过它定义了如下这个不含{reference_outputs}占位符的提示词模板。You are an expert data labeler. Your task is to grade the accuracy of an AI agents internal trajectory. Rubric An accurate trajectory: - Makes logical sense between steps - Shows clear progression - Is relatively efficient, though it does not need to be perfectly efficient /Rubric First, try to understand the goal of the trajectory by looking at the input (if the input is not present try to infer it from the content of the first message), as well as the output of the final message. Once you understand the goal, grade the trajectory as it relates to achieving that goal. Grade the following trajectory: trajectory {outputs} /trajectory与默认的包含评估基准的提示词相比这个无基准提示词具有如下的特点移除了最终对错的绝对绑架聚焦于目标相关性它要求裁判模型不要死板地检查最终答案是否完美而是检查整条轨迹的行动是否都在为了达成那个目标而努力。它允许Agent最终失败例如因为工具报错或外部服务器断网但只要Agent的整个推理和工具调用链条是合乎逻辑、不断递进且高效的裁判依然会给轨迹的**准确性Accuracy**打高分;引入了目标逆向推导机制: 由于这个评估只输入了{outputs}因此提示词赋予了裁判逆向推导的能力即让裁判通过阅读第一条消息通常是用户的提问和最后一条消息Agent的最终回答自己去脑补并定义出这个任务的终极目标是什么。在移除了reference_outputs的对比要求后评估规则被精简到了最纯粹的三驾马车逻辑性Logical sense步骤A到步骤B是否讲得通例如查完城市代码 ➔ 查天气通过查完城市代码 ➔ 查股价不通过递进性Clear progression是不是每一步都在剥洋葱一样逼近真相而不是在原地无限循环高效性Relatively efficient有没有废话和多余的工具调用。在前面演示程序的基础上我们需要将main函数做如下的修改并能将切换到使用TRAJECTORY_ACCURACY_PROMPT提示词的无基准的轨迹评估上。asyncdefmain():resultawaitagent.ainvoke(input{messages:[{role:user,content:苏州当前的晴天吗}]})messagescast(list[AnyMessage],result.get(messages))formessageinmessages:message.pretty_print()awaiteval(outputsmessages,promptTRAJECTORY_ACCURACY_PROMPT)毫无疑问对于这个简单的Agent其对话对话代表的执行规则肯定能够通过评估并且能得高分{key:trajectory_accuracy,score:1.0,comment:The trajectory matches the user’s goal exactly: it identifies the provided location code, directly calls the requested get_weather tool with the correct argument, receives a weather result for Suzhou, and returns the weather in a clear final answer. The steps are logically consistent, clearly progressive, and efficient with no unnecessary detours. Thus, the score should be: 1.0.,metadata:null}5. 聚焦工具选择的评估除了上述的两个严格意义上的基于Agent执行轨迹的提示词OpenEvals还通过常量TOOL_SELECTION_PROMPT定义了如下一个重点关注工具选择的提示词。与前面讨论的轨迹评估关注Agent的整体思考和逻辑递进不同基于工具选择的评估是一种更加聚焦的局部精细化审计。它把LLM的纯文本思考先放在一边专门把Agent的工具调用切片提取出来进行显微镜式的审查。You are an expert data labeler. Your task is to grade the accuracy of an AI agents tool selection during the resolution of a user query. Rubric Accurate tool selection: - Uses the most appropriate tool for each step given the context - Avoids unnecessary or redundant tool calls - Uses tools in a logical order where dependencies exist - Is semantically equivalent to the provided reference tool sequence, if present /Rubric Instructions 1. Grade the following thread, evaluating whether the agent selected the right tools in the right order to resolve the users query efficiently. 2. Evaluate both the choice of tools and whether any tools were unnecessary, missing, or could have been replaced with a more appropriate alternative /Instructions Please grade the following trajectory according to the above instructions: trajectory {outputs} /trajectory在复杂的Agent系统中大模型最容易犯的错误之一就是工具滥用或工具误用。例如有能直接查到精准结果的工具它偏不用非要调用网络搜索去网页里捞。已经拿到了数据却还要重复调用同一个工具。在没有拿到A工具的返回参数前强行调用依赖该参数的B工具顺序错误导致报错。这个提示词就是为了揪出Agent在利用外部世界API/数据库/函数时的这些低效或错误行为。这个评估程序要求裁判大模型Judge对 {outputs} 中的工具序列进行以下四个维度的核对上下文自适应性检查Agent是否在特定的上下文状态下选择了最完美、最对口的那个工具而不是凑合能用的工具;零冗余性严厉打击废动作。如果Agent连续调用同一个接口或者调用了对解决问题毫无帮助的工具在这里会被判定扣分;拓扑依赖与逻辑顺序检查上下游工具的因果关系。如果顺序反了就是严重的逻辑不合格基准等价性如果提供了标准答案实际调用的工具链在核心功能和效果上必须与标准答案等价。针对上面演示的针对Agent的两次调用虽然因用户提问的方式不同导致了Agent生成基于不同轨迹的消息列表但是从工具选择的角度都是合理的。如下的演示程序和生成的评估结果充分体现了这一点。asyncdefmain():resultawaitagent.ainvoke(input{messages:[{role:user,content:苏州当前是晴天吗}]})messagescast(list[AnyMessage],result.get(messages))awaiteval(outputsmessages,promptTOOL_SELECTION_PROMPT)resultawaitagent.ainvoke(input{messages:[{role:user,content:苏州所在的区域代码为location-123,直接调用工具get_weather函数返回苏州当前的天气}]})messagescast(list[AnyMessage],result.get(messages))awaiteval(outputsmessages,promptTOOL_SELECTION_PROMPT)输出{key:trajectory_accuracy,score:1.0,comment:The agent used a logical and appropriate tool sequence: first resolving the city to a location code with look_up_location_code, then querying the weather with get_weather using that location code. Both tools were necessary, there were no redundant calls, and the final answer correctly reflects the tool result. Thus, the score should be: 1.0.,metadata:null}{key:trajectory_accuracy,score:1.0,comment:The agent selected the correct tool, get_weather, exactly once and used it directly with the provided location code location-123, which is the most appropriate and efficient action for the users request. The tool usage was in the correct order, with the weather result then summarized back to the user. There were no unnecessary or missing tool calls, and the interaction is semantically aligned with the task. Thus, the score should be: 1.0.,metadata:null}