news 2026/8/7 10:50:45

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
[基于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_judgecreate_async_llm_as_judge两个工厂函数创建而成,可以说这是整个OpenEvals最为核心的两个方法。这两个函数最终会创建代表同步和异步评估器的SimpleEvaluator和SimpleAsyncEvaluator,我们在基于OpenEvals的自动化评估-01:通过一个例子了解评估模型已经对这两个类型进行过详细介绍。

defcreate_llm_as_judge(*,prompt:Union[str,Runnable,Callable[...,list[ChatCompletionMessage]]],feedback_key:str="score",judge:Optional[Union[ModelClient,BaseChatModel]]=None,model:Optional[str]=None,system:Optional[str]=None,continuous:bool=False,choices:Optional[list[float]]=None,use_reasoning:bool=True,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:str="score",judge:Optional[Union[ModelClient,BaseChatModel]]=None,model:Optional[str]=None,system:Optional[str]=None,continuous:bool=False,choices:Optional[list[float]]=None,use_reasoning:bool=True,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:评估结果中存储的字段名,默认为score;
  • judge/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_judgecreate_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_judgecreate_async_llm_as_judge这两个函数时指定output_schema参数;
  • 将prompt参数指定为StructuredPrompt对象,并由后者提供输出Schema;
  • 调用如下的函数使用默认的输出Schema作为兜底,三个参数对应两个工厂函数的同名参数。
def_construct_default_output_json_schema(*,continuous:bool=False,choices:Optional[list[float]]=None,use_reasoning:bool=True,)->tuple[dict,str]

在如下的演示程序中,我们以不同的参数调用了_construct_default_output_json_schema函数生成并输出相应的Schema:

fromopenevals.llmimport_construct_default_output_json_schemaimportjson schema=_construct_default_output_json_schema()print(json.dumps(schema,ensure_ascii=False,indent=2))schema=_construct_default_output_json_schema(continuous=True,choices=[0.0,0.5,1.0])print(json.dumps(schema,ensure_ascii=False,indent=2))

输出:

[{"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):evaluator=create_async_llm_as_judge(prompt=prompt,judge=ChatOpenAI(model="gpt-5.4-mini"))result=awaitevaluator(inputs="说出战国四大名将的姓名",outputs=outputs)print(json.dumps(result,ensure_ascii=False,indent=2))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,让评估结果体现为一个具体的分值:

evaluator=create_async_llm_as_judge(prompt=prompt,continuous=True,judge=ChatOpenAI(model="gpt-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):evaluator=create_async_llm_as_judge(prompt=prompt,continuous=True,choices=[0.0,0.25,0.50,0.75,1.0],judge=ChatOpenAI(model="gpt-5.4-mini"),few_shot_examples=few_shot_examples)result=awaitevaluator(inputs=inputs,outputs=outputs)print(json.dumps(result,ensure_ascii=False,indent=2))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}
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/7 10:49:59

本质安全设计中的温度控制:从点燃温度到PCB散热的工程实践

1. 项目概述:为什么温度是本质安全设计的“命门”? 在本质安全(Intrinsic Safety, IS)防爆领域,我们常常把电路设计、元件选型、结构布局挂在嘴边,但有一个参数,它无声无息,却贯穿于…

作者头像 李华
网站建设 2026/8/7 10:46:06

Python agentguard-pro 包详解:功能、安装、语法与案例

1. 引言agentguard-pro 是一个面向 Python 开发者的安全防护与智能体治理工具包,主要用于对基于大语言模型(LLM)构建的 Agent 应用进行输入校验、输出过滤、权限管控、日志审计与异常兜底。它把「提示词注入防护」「敏感信息脱敏」「工具调用…

作者头像 李华
网站建设 2026/8/7 10:45:50

揭秘Switch破解新境界:大气层整合包实战指南

揭秘Switch破解新境界:大气层整合包实战指南 【免费下载链接】Atmosphere-stable 大气层整合包系统稳定版 项目地址: https://gitcode.com/gh_mirrors/at/Atmosphere-stable 还在为Switch破解的复杂步骤而头疼吗?大气层整合包系统为你提供了一站式…

作者头像 李华
网站建设 2026/8/7 10:42:44

FPGA时序约束实战指南:从原理到Vivado工程实践

1. 项目概述:为什么时序约束是FPGA设计的“交通规则” 刚接触Vivado的FPGA工程师,尤其是从单片机或软件转过来的朋友,常常会有一个疑惑:我的RTL代码明明仿真都通过了,功能也验证了,为什么下载到板子上就是跑…

作者头像 李华
网站建设 2026/8/7 10:41:32

全方位揭秘网站建设工作进度:从需求分析到上线交付的全流程把控指南

做网站这一行,外人看着觉得挺高大上,好像就是敲敲代码,按按按钮,几天功夫一个光鲜亮丽的网页就出来了。但真正在里面摸爬滚打过的同行都知道,这背后的坑有多深,水有多混,尤其是那个让人既爱又恨的“网站建设工作进度”。今天我不讲那些虚头巴脑的理论,咱们就接地气地聊…

作者头像 李华