当前位置: 首页 > news >正文

[Loop Engineering在MAF中的实现-04]利用AIJudgeLoopEvaluator让LLM当评委

本系列的首篇文章基于评估结果针对Agent的循环调用演示了一个利用LoopAgent构建了一个用来进行诗词创作的Agent,具体的做法是:通过封装AIAgent自定义一个LoopAEvaluator,借助LLM的能力对创作的作品进行评估并打分。如果分数达到要求,循环终止,否则让循环继续并提供反馈。我们也可以利用预定义的AIJudgeLoopEvaluator评估器来达到相同的目的。

1. 利用AIJudgeLoopEvaluator来评估传作的作品

在如下所示的演示程序中,我们将创作的任务和要求都塞进提示词。我们定义了辅助方法CreateChatClient帮助我们创建一个基于OpenAI的IChatClient对象。我们两次调用此方法,分别利用返回的IChatClient构建了LoopAgentinnerAgentevaluator,后者的类型为AIJudgeLoopEvaluator

usingAzure.AI.Projects;usingMicrosoft.Agents.AI;usingMicrosoft.Extensions.AI;usingOpenAI;usingSystem.ClientModel;conststringprompt=""" 基于如下这首《卫风·氓》的背景和情感基调,创作一首宋词。 氓之蚩蚩,抱布贸丝。匪来贸丝,来即我谋。 送子涉淇,至于顿丘。匪我愆期,子无良媒。 将子无怒,秋以为期。 乘彼垝垣,以望复关。不见复关,泣涕涟涟。 既见复关,载笑载言。尔卜尔筮,体无咎言。 以尔车来,以我贿迁。 桑之未落,其叶沃若。于嗟鸠兮,无食桑葚! 于嗟女兮,无与士耽!士之耽兮,犹可说也; 女之耽兮,不可说也。 桑之落矣,其黄而陨。自我徂尔,三岁食贫。 淇水汤汤,渐车帷裳。女也不爽,士贰其行。 士也罔极,二三其德。 三岁为妇,靡室劳矣;夙兴夜寐,靡有朝矣。 言既遂矣,至于暴怒。兄弟不知,咥其笑矣。 静言思之,躬自悼矣。 及尔偕老,老使我怨。淇则有岸,隰则有泮。 总角之宴,言笑晏晏。信誓旦旦,不思其反。 反是不思,亦已焉哉! 如果按照如下的标准打分,要求创作的宋词必需在80分(满分100)以上才算合格:1.格律规范(MetricalAccuracy)——30分 检测AI生成的词是否真正符合该词牌的“说明书”。-词牌结构(20分):总字数、分片、每句的字数长短必须与词牌名保持一致。-平仄规范(5分):关键位置的平仄(平声、仄声)必须严格符合词牌要求。-押韵规则(5分):检查是否在规定位置押韵,是否混淆了平仄韵,有无出韵。2.意境创设(Imagery&Conception)——30分 评估词作是否具备古典美感,是否能画出**画面感**-意象选用(15分):是否恰当使用了符合古典美学的意象。意象之间是否逻辑自洽,没有现代感违和物。-流派风格(15分):整体意境的深远程度。3.语言艺术(LinguisticArtistry)——20分 评估遣词造句的功底和文字的流畅度。-用词典雅(10分):遣词造句需有**词味**,杜绝使用现代大白话或过于生硬的拼凑词。-对仗与过片(10分):若词牌要求对仗,需检查是否工整;重点评估**过片**(上下片过渡)是否自然流转,有无断层。4.情感寄托与创新(Emotional Depth&Innovation)——20分 评估诗词的灵魂,拒绝纯粹的字词堆砌。-情感共鸣(10分):词中所表达的悲欢离合、家国情怀或羁旅之思是否真挚饱满。-陈词翻新(10分):是否只会堆砌********等陈词滥调。优秀的词作应当在传统框架下有独特的视角或新颖的构思。""";DotNetEnv.Env.Load();varloopAgent=newLoopAgent(innerAgent:CreateChatClient().AsAIAgent(),evaluator:newAIJudgeLoopEvaluator(CreateChatClient()));varresponse=awaitloopAgent.RunAsync(prompt);varindex=1;foreach(varmessageinresponse.Messages){Console.WriteLine($"""{newstring('-',20)}Message{index++}{newstring('-',20)}{message}""");}staticIChatClientCreateChatClient(){varapiKey=Environment.GetEnvironmentVariable("OPENAI_API_KEY")!;varendpoint=Environment.GetEnvironmentVariable("OPENAI_BASE_URL")!;returnnewOpenAIClient(newApiKeyCredential(apiKey),newOpenAIClientOptions{Endpoint=newUri(endpoint)}).GetChatClient(model:"gpt-5.2-chat").AsIChatClient();}

输出:

--------------------Message1-------------------- 钗头凤·淇上怨 淇波阔,桑阴薄,抱布当年眉语诺。 秋期近,归车迅。 笑倚颓垣,共卜嘉卺。 信、信、信。 桑华尽,鸠声哽,十年辛苦孤灯冷。 晨炊惯,霜衾短。 淇岸虽宽,不容愁眼。 恨、恨、恨。 --------------------Message2-------------------- Your previous response did not fully address the original request. The following is still missing or incomplete: 虽然已经创作了一首仿宋词作品,但距离用户要求的“按严格标准至少达到80分以上”还有明显缺口。 主要问题: 1. 词牌格律不够严谨。 《钗头凤》属于定格较严格的词牌,当前作品在句式、字数与常见正格之间存在偏差,例如“笑倚颓垣,共卜嘉卺”“淇岸虽宽,不容愁眼”等句的节奏与标准谱式不完全贴合,且未体现对平仄与用韵的严格控制。用户明确把“格律规范”列为30分的大项,因此这一部分难以达到高分。 2. 情节承接略显压缩。 原作《氓》包含“初恋—婚嫁—操劳—背弃—决绝”的完整情感弧线,而当前词作篇幅虽短,但后半段转折较快,“士贰其行”“誓言反覆”等核心情节没有充分展开,情感厚度不足。 3. 语言尚有现代化、概括化倾向。 如“十年辛苦孤灯冷”“不容愁眼”等表达较泛,缺少更具宋词气息的细节锤炼。用户要求“词味”与“陈词翻新”,当前版本意象较集中但新意不够突出。 4. 未体现对评分标准的自检。 用户特别给出了详细评分维度,理想回应应尽量确保词牌合规,并最好附简要说明其格律与构思如何对应《氓》的情感基调,以证明其目标确实是“80分以上”的完成度。 因此,这首词属于“完成了创作”,但尚不足以认定为完全满足原请求。 Please continue and fully address the original request. --------------------Message3-------------------- 蝶恋花·淇水辞盟 抱布当年曾问字。淇水西风,送我过烟渚。 一诺秋期人不寤。谁教轻信章台语。 桑叶初肥鸠莫顾。灯火寒机,三岁愁中度。 淇岸有涯情已暮。回身不共斜阳去。 此调依《蝶恋花》正格双调六十字:上下片各四仄韵到底。全词用“字、渚、寤、语、顾、度、暮、去”同部近韵,句式依“七七四五”层递展开,尽量贴合常见词谱。 构思上保留《氓》的核心情感线: - 上片写“抱布贸丝”至“秋以为期”的初遇与轻信,以“淇水西风”“烟渚”营造送别与期待。 - 下片转入“桑之未落”到“士贰其行”的婚后困顿,用“灯火寒机”代替直白诉苦,强化宋词含蓄感。 - 结句“回身不共斜阳去”对应《氓》末尾“亦已焉哉”,不作哭诉,而以决绝收束。

从输出结果可以看出,整个创作流程经历了两次迭代。响应的消息中包含了两次创作的成果,和针对第一次创作的评估结果。从整个效果来看,这和我在基于评估结果针对Agent的循环调用使用自定义评估器没有本质区别。

2. 利用LLM评估当前输入是否回答了提出的问题

既然AIJudgeLoopEvaluator最终是利用LLM来评估当前迭代的输出,那么我们就可以通过它发送给LLM的输入来看看具体的评估是如何进行的。为了拦截发送给LLM用于评估的提示词,我们定义了如下一个用于模拟LLM调用的FakeChatClient

classFakeChatClient:IChatClient{publicvoidDispose(){}publicTask<ChatResponse>GetResponseAsync(IEnumerable<ChatMessage>messages,ChatOptions?options=null,CancellationTokencancellationToken=default){foreach(varmessageinmessages){Console.WriteLine($"""{newstring('-',20)}{message.Role}{newstring('-',20)}{message}""");}varresponse=newChatResponse(newChatMessage(ChatRole.Assistant,"""{"answered":false,"gapAnalysis":"<gap-analysis>"}"""));returnTask.FromResult(response);}publicobject?GetService(TypeserviceType,object?serviceKey=null)=>null;publicIAsyncEnumerable<ChatResponseUpdate>GetStreamingResponseAsync(IEnumerable<ChatMessage>messages,ChatOptions?options=null,CancellationTokencancellationToken=default)=>thrownewNotImplementedException();}

如上面的代码所示,FakeChatClient实现了IChatClientGetResponseAsync方法。我们在该方法中将所有的消息内容打印出来,并且生成了一个响应。AIJudgeLoopEvaluator采用结构化输出返回如下这个JudgeVerdict类型。它的Answered属性用于确定Agent当前输出的内容是否回答了最初的问题,如果没有,针对两者之间差距的分析通过GapAnalysis属性返回。所以GetResponseAsync方法最终返回的消息内容为符合此结构的JSON文本。

internalsealedclassJudgeVerdict{[Description("True if the agent has fully addressed the original request, otherwise false.")]publicboolAnswered{get;set;}[Description("When 'answered' is false, explain what is still missing or what work remains to fully address the original request.")]publicstringGapAnalysis{get;set;}=string.Empty;}

在如下的演示程序中,我们针对FakeChatClient对象创建了一个AIJudgeLoopEvaluator对象。然后创建了一个LoopContext对象作为调用其EvaluateAsync方法的输出。在初始化LoopContext时,我们指定了一个模拟的AIAgentAgentSession对象,以及初始化消息列表和最后的响应。在得到评估结果的LoopEvaluation对象之后,我们输出它的ShouldReinvokeFeedback属性。

usingMicrosoft.Agents.AI;usingMicrosoft.Extensions.AI;usingSystem.Text.Json;varevaluator=newAIJudgeLoopEvaluator(newFakeChatClient());varcontext=newLoopContext(agent:newFakeAgent(),session:newFakeSession(),initialMessages:[newChatMessage(ChatRole.User,"<initial-messages>")],lastResponse:newAgentResponse(newChatMessage(ChatRole.Assistant,"<last-response>")));varevaluation=awaitevaluator.EvaluateAsync(context);Console.WriteLine($"""{newstring('-',20)}evaluation{newstring('-',20)}ShouldReinvoke:{evaluation.ShouldReinvoke}Feedback:{evaluation.Feedback}""");classFakeAgent:AIAgent{protectedoverrideValueTask<AgentSession>CreateSessionCoreAsync(CancellationTokencancellationToken=default)=>thrownewNotImplementedException();protectedoverrideValueTask<AgentSession>DeserializeSessionCoreAsync(JsonElementserializedState,JsonSerializerOptions?jsonSerializerOptions=null,CancellationTokencancellationToken=default)=>thrownewNotImplementedException();protectedoverrideTask<AgentResponse>RunCoreAsync(IEnumerable<ChatMessage>messages,AgentSession?session=null,AgentRunOptions?options=null,CancellationTokencancellationToken=default)=>thrownewNotImplementedException();protectedoverrideIAsyncEnumerable<AgentResponseUpdate>RunCoreStreamingAsync(IEnumerable<ChatMessage>messages,AgentSession?session=null,AgentRunOptions?options=null,CancellationTokencancellationToken=default)=>thrownewNotImplementedException();protectedoverrideValueTask<JsonElement>SerializeSessionCoreAsync(AgentSessionsession,JsonSerializerOptions?jsonSerializerOptions=null,CancellationTokencancellationToken=default)=>thrownewNotImplementedException();}classFakeSession:AgentSession{}

输出结果:

--------------------system-------------------- You are an evaluator. You are given a user's original request and an agent's latest response. Decide whether the agent has fully addressed the original request. Set 'answered' to true if the request has been fully addressed, or false if more work is still required. When 'answered' is false, use 'gapAnalysis' to explain what is still missing or what work remains. If you cannot return structured output, reply with VERDICT: DONE when the request has been fully addressed, or VERDICT: MORE when more work is still required. --------------------user-------------------- # Has the original request been fully addressed? ## Original request: <initial-messages> ## Agent's latest response: <last-response> --------------------evaluation-------------------- ShouldReinvoke : True Feedback : Your previous response did not fully address the original request. The following is still missing or incomplete: <gap-analysis> Please continue and fully address the original request.

从输入可以看出,传递给LLM用于评估的消息有两条,

  • 系统消息:其核心是规定AIJudgeLoopEvaluator的评判逻辑与输出格式。它要求评估器比较用户原始请求和代理最新回答,判断是否已完全满足需求。如果满足,则返回answered: true;若不满足,则返回answered: false并在gapAnalysis中说明缺失内容或剩余工作。若无法返回结构化结果,则用简化文本标记:
    • VERDICT: DONE表示完成;
    • VERDICT:MORE 表示未完成。
  • 用户消息:描述了评估任务,并提供了原始的请求和Agent最后的响应内容。

从输出的评估结果可以看出,我们响应内容的answered字段会决定ShouldReinvoke属性的值,Feedback属性返回一段格式化文本,其中包含gapAnalysis字段的值。

3. AIJudgeLoopEvaluator

AIJudgeLoopEvaluatorOptionsAIJudgeLoopEvaluator的配置选项类,定义其中的三个配置选项属性都体现在上面的输出中。

publicsealedclassAIJudgeLoopEvaluatorOptions{publicstring?Instructions{get;set;}publicIEnumerable<string>?Criteria{get;set;}publicstring?FeedbackMessageTemplate{get;set;}}

三个配置选项说明如下:

  • Instructions: 提供给LLM的系统指令,默认设置会在上面属性的指令文本默认添加占位符{criteria}
  • Criteria:我们利用它提供额外的评估标准,指定的文本会用来填充系统指令模板的占位符{criteria}
  • FeedbackMessageTemplate:生成LoopEvaluationFeedback属性的模板,其中会包含占位符{gapAnalysis}用来接收LLM的反馈。

AIJudgeLoopEvaluator定义如下,我们在创建该对象时需要指定一个用来调用LLM的IChatClient和一个可选的AIJudgeLoopEvaluatorOptions配置选项。在重写的EvaluateAsync方法中,它会创建两个消息,一个是根据指定或者默认系统指令创建的System消息,另一个则是根据LoopContext提供的原始消息和最终响应生成的User消息。它将这两个消息组成的列表作为参数调用IChatClientGetResponseAsync<JudgeVerdict>方法返回一个JudgeVerdict对象,并据此生成返回的LoopEvaluation对象。

publicsealedclassAIJudgeLoopEvaluator:LoopEvaluator{publicAIJudgeLoopEvaluator(IChatClientjudgeClient,AIJudgeLoopEvaluatorOptions?options=null);publicoverrideasyncValueTask<LoopEvaluation>EvaluateAsync(LoopContextcontext,CancellationTokencancellationToken=default);}
http://www.jsqmd.com/news/1210933/

相关文章:

  • 天津劳力士回收价格查询和靠谱平台实测排行(2026年7月最新数据) - 天价名表回收平台
  • BERT-of-Theseus: Compressing BERT by Progressive Module Replacing 解读
  • 吴恩达《深度学习》之看懂梯度消失的“激活函数直觉”
  • Windows C++进程管理员权限检测:原理、API与完整实现
  • Codex国产模型接入卡点与CC-Switch协议路由方案
  • 2小时,我搭了一套员工档案管理系统
  • Android JSON解析方案对比:从fastjson到现代替代方案
  • Mac mini M4开发环境搭建与AI编程实战指南
  • C++异步编程实战:Future/Promise核心原理与避坑指南
  • PHP开发全攻略:从入门到精通的资源与工具清单
  • AI Agent代码执行安全:从Docker到微虚拟机的沙箱技术
  • 上海欧米茄回收价格查询及各大平台实测排行(2026年7月最新) - 诚收名表回收平台
  • Git推送,提交合并,以及hint: Updates were rejected because the tip of your current branch is behind
  • React性能优化:PureComponent与memo实战指南
  • Movement Pruning: Adaptive Sparsity by Fine-Tuning 解读
  • 飞腾 D3000M 迷你国产核心板硬件方案解析|狭小舱体高算力机载整机选型指南
  • NVIDIA Isaac Lab:机器人强化学习的仿真训练与Sim2Real迁移实战
  • AI给大学生带来的撕裂感:一个top3本科生的四年自述与架构师解读
  • 银行级多维聚合实战:滚动窗口、unstack与自定义聚合的生产规范
  • [Loop Engineering在MAF中的实现-05]MAF预定义的评估器
  • 三维地图引擎选型指南:Cesium与Mapbox对比
  • PHP开发者必备资源大全与工具链指南
  • 天津宝珀回收价格查询与靠谱平台实测排行(2026年7月最新) - 收的高名表回收平台
  • Python程序打包实战:PyInstaller详解与最佳实践
  • C++构建高性能教育推荐系统:架构设计与工程实践
  • WPF 六大集合容器控件完整对比
  • OpenAI全内部安全委员会:AI治理从外部合规到内生能力的范式转变
  • 技术平权——眨眼猫打造“一顿饭的会务智能体”,让每一场会务活动都能拥有自己的智能体小程序!
  • AI如何学会听懂无文字的闽南语:任务驱动的方言建模实践
  • AI落地物理世界的五大断点与七步实操法