ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

[基于OpenEvals的自动化评估-02]LLM-as-a-Judge:让LLM当裁判来评估Agent的输出

2026/8/7 10:51:00 拓冰建站 浏览量
[基于OpenEvals的自动化评估-02]LLM-as-a-Judge:让LLM当裁判来评估Agent的输出 在大部分情况下我们会借助LLM的能力来评估Agent的输出我们将这种评估模式成为LLM-as-a-Judge。这是一种利用大型语言模型对生成式AI输出进行自动化评估的范式其核心思想是让模型承担裁判角色对候选答案进行打分、排序或选择能够在开放式任务中判断质量、相关性、逻辑性、事实性与有用性等更细腻的属性。由于LLM是一个概率模型所以评估的结果本质上是一个概率分布所以代表评估结果的Score一般是一个[0-1]的分数返回的二元布尔值也是基于指标的开率计算出来的比如得分是否大于0.5。1. LLM-as-a-Judge评估器的创建基于LLM-as-a-Judge的评估器通过如下所示的create_llm_as_judge和create_async_llm_as_judge两个工厂函数创建而成可以说这是整个OpenEvals最为核心的两个方法。这两个函数最终会创建代表同步和异步评估器的SimpleEvaluator和SimpleAsyncEvaluator我们在基于OpenEvals的自动化评估-01通过一个例子了解评估模型已经对这两个类型进行过详细介绍。defcreate_llm_as_judge(*,prompt:Union[str,Runnable,Callable[...,list[ChatCompletionMessage]]],feedback_key:strscore,judge:Optional[Union[ModelClient,BaseChatModel]]None,model:Optional[str]None,system:Optional[str]None,continuous:boolFalse,choices:Optional[list[float]]None,use_reasoning:boolTrue,few_shot_examples:Optional[list[FewShotExample]]None,output_schema:Optional[Union[dict,type]]None,)-Union[SimpleEvaluator,Callable[...,Any]]defcreate_async_llm_as_judge(*,prompt:Union[str,Runnable,Callable[...,list[ChatCompletionMessage]]],feedback_key:strscore,judge:Optional[Union[ModelClient,BaseChatModel]]None,model:Optional[str]None,system:Optional[str]None,continuous:boolFalse,choices:Optional[list[float]]None,use_reasoning:boolTrue,few_shot_examples:Optional[list[FewShotExample]]None,output_schema:Optional[Union[dict,type]]None,)-Union[SimpleAsyncEvaluator,Callable[...,Awaitable[Any]]]classFewShotExample(TypedDict):inputs:Any outputs:Any score:Union[float,bool]reasoning:Optional[str]这两个工厂方式具有相同过的参数说明分别如下prompt:定义评估提示词模板类型可以是字符串也可以是类似于PromptTemplate这样的Runnable对象可以采用LCEL表达式于LLM进行连接或者是一个用于返回LLM输入的消息列表的函数。如果以字符串定义提示词可以包含如下的占位符它们对应着调用SimpleEvaluator/SimpleAsyncEvaluator指定的参数{inputs}{outputs}{reference_outputs}{由kwargs指定的参数名称}feedback_key评估结果中存储的字段名默认为scorejudge/model: 用于提供用来实施评估的LLM。如果使用model参数指定包含提供商的模型标准名称方法内部会利用标准的URL创建代表LangChain LLM组件的BaseChatModel对象。如果需要连接自定义URL指向的LLM部署地址或者需要对LLM组件对象进行定制可以直接利用judge参数指定一个BaseChatModel对象。也可以直接执行一个ModelClient对象ModelClient是OpenEvals针对LLM客户端组件的表达但是此时依然需要利用model参数指定模型名称system 系统提示词continuous评估结果是否是连续值True 输出为0~1的连续浮点数False 输出为布尔值。choices如果希望评估结果采用指定的选项可以利用此参数指定一个列表比如choices[0.0, 0.5, 1.0]意味着最终得分只有指定的三种选择use_reasoning是否要求模型输出评分理由True输出包含解释False只输出评分。few_shot_examples: 用于在提示词中加入few-shot示例提升评估一致性output_schema评估结果的结构化输出格式。1.1 输入消息的生成调用LLM实施评估需要生成消息列表作为输入OpenEvals将用于LLM交互的消息定义成如下这个名为ChatCompletionMessage的TypedDict对应的成员分别用来表示消息的ID、角色、内容和工具调用。classChatCompletionMessage(TypedDict):id:NotRequired[Optional[str]]content:Union[str,list[dict]]role:strtool_calls:NotRequired[Optional[list[dict]]]create_llm_as_judge和create_async_llm_as_judge这两个函数会才采用如下的逻辑生成作为LLM输入的消息列表如果指定的prompt参数是一个Runnable对象会将它视为一个类似于PromptTemplate的提示词模板此时它会调用此对象生成完整的提示词作为参数的字典会包含如下的占位符分别对应调用评估器对应的参数{inputs}{outputs}{reference_outputs}{由kwargs指定的参数名称}最后按照OpenAI消息风格将执行的结果转化成ChatCompletionMessage列表。如果指定的prompt参数是一个字符串如果调用评估器利用kwargs指定了一个表示多媒体消息内容的attachments参数会创建对应的Conent-Block这里体现为一个dict对象并非LangChain的ConentBlock类型。此时会试图从提示词中定位对应的{attachments}占位符并使用前面和后面如果有文本创建对象的文本类型的Content-Block然后针对这些Content-Block作为内容创建角色为user的ChatCompletionMessage对象。否则根据提示词直接创建一个角色为user的ChatCompletionMessage对象;对于如上的两种情况提示词文本提供的上述四种占位符会被对应的参数替换。如果prompt是一个Callable[..., list[ChatCompletionMessage]]直接调用此对象生成ChatCompletionMessage对列表。上面生成ChatCompletionMessage列表还会根据提供的参数添加如下的消息如果指定了system参数会据此创建一个角色为system的消息置于消息列表的最前端如果指定了few_shot_examples参数会据此创建对应的消息列表追加到消息列表的尾部。1.2 结构化输出由于评估结果具有固有的结构所以在调用LLM的时候必须指定输出Schema以结构化输出的方式保证返回具有匹配结构的结果。输出Schema具有如下三种指定方式调用create_llm_as_judge和create_async_llm_as_judge这两个函数时指定output_schema参数将prompt参数指定为StructuredPrompt对象并由后者提供输出Schema调用如下的函数使用默认的输出Schema作为兜底三个参数对应两个工厂函数的同名参数。def_construct_default_output_json_schema(*,continuous:boolFalse,choices:Optional[list[float]]None,use_reasoning:boolTrue,)-tuple[dict,str]在如下的演示程序中我们以不同的参数调用了_construct_default_output_json_schema函数生成并输出相应的Schemafromopenevals.llmimport_construct_default_output_json_schemaimportjson schema_construct_default_output_json_schema()print(json.dumps(schema,ensure_asciiFalse,indent2))schema_construct_default_output_json_schema(continuousTrue,choices[0.0,0.5,1.0])print(json.dumps(schema,ensure_asciiFalse,indent2))输出:[{type:object,additionalProperties:false,properties:{reasoning:{type:string,description:A human-readable explanation of the score. You MUST end the reasoning with a sentence that says: Thus, the score should be: SCORE_YOU_ASSIGN.},score:{type:boolean,description:A score that is true if criteria in the prompt are met, and false otherwise.}},required:[reasoning,score]},A score that is true if criteria in the prompt are met, and false otherwise.][{type:object,additionalProperties:false,properties:{reasoning:{type:string,description:A human-readable explanation of the score. You MUST end the reasoning with a sentence that says: Thus, the score should be: SCORE_YOU_ASSIGN.},score:{type:number,description:A number that represents the degree to which the criteria in the prompt are met.,enum:[0.0,0.5,1.0]}},required:[reasoning,score]},A number that represents the degree to which the criteria in the prompt are met.]在上述默认Schema基础上一般还会添加额外的必要的字段成员。1.3 LLM的调用作为输入的消息列表生成之后我们来看看如何将它们作为输入调用对应的LLM来完成评估工作。create_llm_as_judge和create_async_llm_as_judge这两个函数与LLM相关的参数有如下两个model评估模型的标准名称judge评估模型对应的BaseChatModel或者ModelClient对象。我的系列文章03.LangChain语言模型组件对BaseChatModel表示的LangChian语言模型组件进行了详细介绍这里我们来看看ModelClient类型的定义。ModelClient是一个代表LLM 客户端的抽象协议要求任何实现它的对象必须提定义一个chat属性来提供ChatCompletionsClient类型并以此作为创建LLM组件。ChatCompletionsClient代表采用OpenAI风格的文本补齐模型的客户端。runtime_checkableclassModelClient(Protocol):propertydefchat(self)-type[ChatCompletionsClient]:...runtime_checkableclassChatCompletionsClient(Protocol):defcreate(self,**kwargs)-ChatCompletion:...classChatCompletion(TypedDict):choices:list[dict]create_llm_as_judge和create_async_llm_as_judge这两个函数最终会采用如下的方式来创建用来实施评估的LLM组件并将上面解析出来的消息列表作为如下调用它们实施评估如果judge是一个ModelClient对象此时必须要求同时提供model参数此时会调用judge.chat.completions.creat方法生成完成针对LLM的调用作为参数传入的字典会包含如下三个成员messages 消息列表model模型名称response_format输出Schema。如果只提供了model参数直接调用LangChain的init_chat_model函数根据此参数创建对应的BaseChatModel对象直接将消息列表作为如下调用此对象如果指定的judge参数是一个BaseChatModel直接将消息列表作为如下调用此对象。2. 利用LLM-as-a-Judge评估器实施评估接下来我们会使用一些简单的实例演示如何指定不同的参数调用create_async_llm_as_judge函数创建相应的评估器并对手工指定的输出实施评估。如下面的演示程序所示我们调用create_async_llm_as_judge函数时利用prompt参数指定了一段简短的提示词来完成正确性评估judge参数则设置为一个采用gpt-5.4-mini模型的ChatOpenAI对象。我们针对同一个问题:说出战国四大名将的姓名针对不同的两个答案实施评估。fromopenevalsimportcreate_async_llm_as_judgefromlangchain_openaiimportChatOpenAIfromdotenvimportload_dotenvimportasyncio,json load_dotenv()prompt\ 确认针对指定问题的提供的答案是否正确 **问题** {inputs} **答案** {outputs} asyncdefeval(outputs:str):evaluatorcreate_async_llm_as_judge(promptprompt,judgeChatOpenAI(modelgpt-5.4-mini))resultawaitevaluator(inputs说出战国四大名将的姓名,outputsoutputs)print(json.dumps(result,ensure_asciiFalse,indent2))asyncdefmain():awaiteval(吴起、廉颇、李牧和王翦)awaiteval(白起、廉颇、李牧和王翦)asyncio.run(main())输出结果{key:score,score:false,comment:题目问“战国四大名将”的姓名通行说法通常指吴起、白起、廉颇、李牧。给出的答案是吴起、廉颇、李牧和王翦其中“王翦”并非这一常见“四大名将”名单中的成员而是将“白起”写错/替换了。因此该答案不正确。Thus, the score should be: false.,metadata:null}{key:score,score:true,comment:题目要求说出“战国四大名将”的姓名。通常公认的战国四大名将指白起、王翦、廉颇、李牧答案中给出的四人完全一致只是顺序不同。因此该答案正确。Thus, the score should be: true.,metadata:null}从输出可看出评估结果的score模式采用二元布尔值continuous False,并且默认开启了推理use_reasoning True。顺便说一下由于战国四大名将其实并没有一个权威的说法所以第一次评估采用了吴起、白起、廉颇、李牧这种说法第二种则采用了白起、王翦、廉颇、李牧这种说法。2.2 输出连续值我们看看在调用create_async_llm_as_judge是将continuous参数成True让评估结果体现为一个具体的分值evaluatorcreate_async_llm_as_judge(promptprompt,continuousTrue,judgeChatOpenAI(modelgpt-5.4-mini))输出{key:score,score:0.75,comment:题目问“战国四大名将”的姓名。通行说法中战国四大名将通常指白起、王翦、廉颇、李牧。给出的答案里“廉颇、李牧和王翦”正确但“吴起”不属于这一通常名单应为“白起”。因此答案只部分正确。Thus, the score should be: 0.75.,metadata:null}{key:score,score:1.0,comment:题目要求说出“战国四大名将”的姓名。通常公认的战国四大名将是白起、王翦、廉颇、李牧给出的答案包含这四人且顺序不同不影响正确性。因此答案正确。Thus, the score should be: 1.0.,metadata:null}从输出可以看出第一种答案答对了三个得分0.75挺合理第二个答案完全正确得了满分。2.3 限制分值和指定少样本示例我们可以进一步利用choices参数将分支限制在[0.0,0.25,0.50,0.75,1.0]五个选项之间并提供少样本实例知道LLM严格按照说对的比例打分。fromopenevalsimportcreate_async_llm_as_judgefromopenevals.typesimportFewShotExamplefromlangchain_openaiimportChatOpenAIfromdotenvimportload_dotenvimportasyncio,json load_dotenv()prompt\ 确认针对指定问题的提供的答案是否正确 **问题** {inputs} **答案** {outputs} inputs说出战国四大名将的姓名,few_shot_examples:list[FewShotExample][{inputs:inputs,outputs:吴起、司马错、乐毅、蒙恬,score:0.0,reasoning:四个都错},{inputs:inputs,outputs:白起、司马错、乐毅、蒙恬,score:0.25,reasoning:四个错其三},{inputs:inputs,outputs:白起、李牧、乐毅、蒙恬,score:0.50,reasoning:四个错其二},{inputs:inputs,outputs:白起、李牧、王翦、蒙恬,score:0.75,reasoning:四个错其一},{inputs:inputs,outputs:白起、李牧、王翦、廉颇,score:1.0,reasoning:四个都对},]asyncdefeval(outputs:str):evaluatorcreate_async_llm_as_judge(promptprompt,continuousTrue,choices[0.0,0.25,0.50,0.75,1.0],judgeChatOpenAI(modelgpt-5.4-mini),few_shot_examplesfew_shot_examples)resultawaitevaluator(inputsinputs,outputsoutputs)print(json.dumps(result,ensure_asciiFalse,indent2))asyncdefmain():awaiteval(孙膑、李牧、王翦、廉颇)awaiteval(孙膑、‌庞涓‌、李牧和司马错‌)asyncio.run(main()){key:score,score:0.75,comment:题目问的是“战国四大名将”通常标准答案是白起、王翦、李牧、廉颇。给出的答案是孙膑、李牧、王翦、廉颇其中只有李牧、王翦、廉颇三人正确孙膑不属于这一组。Thus, the score should be: 0.75.,metadata:null}{key:score,score:0.25,comment:题目问的是“战国四大名将”。通行答案一般是白起、王翦、李牧、廉颇。给出的答案“孙膑、庞涓、李牧和司马错”中只有李牧属于常见正确答案其余三位都不属于这一组。因此四个错其三。Thus, the score should be: 0.25.,metadata:null}