尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
[Loop Engineering在MAF中的实现-02]循环调用在LoopAgent中的实现
在上一篇文章中我们介绍了Loop Engineering基本原理并通过两个简单的示例分别演示使用LoopAgent和HarnessAgent来实现Agent循环调用的基本方法。在本篇文章中我们将介绍LoopAgent在MAF的中定义和背后的设计和实现原理。1. 利用LoopEvaluator评估每次调用迭代Loop Engineering并不是简单地循环调用Agent必须对每次调用的结果实施评估。如果满足预先设定的条件则停止循环调用否则继续调用。如果决定继续还应该将评估的结果反馈给下一次调用迭代。这样的评估工作落在了具有如下定义的LoopEvaluator的肩上。publicabstractclassLoopEvaluator{publicabstractValueTaskLoopEvaluationEvaluateAsync(LoopContextcontext,CancellationTokencancellationTokendefault);}LoopEvaluator这个抽象类定义了唯一的抽象方法EvaluateAsync作为输入的是表示当前循环调用上下文的LoopContext对象评估的结果体现为返回的LoopEvaluation对象上。1.1 LoopContextLoopEvaluator的任务是对上一次调用Agent生成的结果实施评估所以被评估的核心材料有三个分别是描述原始任务的初始消息列表、上一次Agent返回的响应和之前提供的评估反馈。它们分别体现在作为循环上下文对象LoopContext的InitialMessages、LastResponse和Feedback属性上。除了这三个核心输入之外LoopContext还提供了其他一些属性来描述当前循环调用的上下文信息publicsealedclassLoopContext{publicAIAgentAgent{get;}publicAgentSessionSession{get;}publicIReadOnlyListChatMessageInitialMessages{get;}publicAgentRunOptions?RunOptions{get;}publicintIteration{get;}publicAgentResponseLastResponse{get;}publicIReadOnlyListstring?Feedback{get;}publicAdditionalPropertiesDictionaryAdditionalProperties{get;}newAdditionalPropertiesDictionary();}LoopContext承载的上下文信息包括Agent当前循环调用的Agent对象Session当前循环调用的Agent会话对象InitialMessages描述原始任务的初始消息列表RunOptions当前循环调用的Agent运行选项Iteration当前循环调用的迭代次数LastResponse上一次Agent调用的响应结果Feedback之前的评估结果反馈列表AdditionalProperties一个字典对象用于存储额外的上下文信息开发者可以在评估过程中使用这个字典来传递自定义的上下文数据。1.2 LoopEvaluation表示评估结果的LoopEvaluation类型定义如下。它利用ShouldReinvoke属性来指示是否继续循环调用利用Feedback属性来提供评估的反馈信息。Feedback属性提供的文本会转换成一条角色为User消息反馈给后续的跌倒。我们也可以直接利用Messages属性来提供反馈消息而这只能选其一。publicsealedclassLoopEvaluation{publicboolShouldReinvoke{get;}publicstring?Feedback{get;}internalIReadOnlyListChatMessage?Messages{get;}privateLoopEvaluation(boolshouldReinvoke,string?feedback,IReadOnlyListChatMessage?messages){ShouldReinvokeshouldReinvoke;Feedbackfeedback;Messagesmessages;}}由于LoopEvaluation的构造函数是私有的所以我们需要通过静态方法来创建LoopEvaluation对象。LoopEvaluation提供了三个静态方法publicsealedclassLoopEvaluation{privatestaticreadonlyLoopEvaluations_stopnewLoopEvaluation(shouldReinvoke:false,null,null);publicstaticLoopEvaluationStop()s_stop;publicstaticLoopEvaluationContinue(string?feedbacknull)newLoopEvaluation(shouldReinvoke:true,feedback);publicstaticLoopEvaluationContinueWithMessages(IEnumerableChatMessagemessages)newLoopEvaluation(shouldReinvoke:true,null,(messagesasIReadOnlyListChatMessage)??messages.ToList());}三个静态方法分别是Stop表示停止循环调用以单例形式返回一个LoopEvaluation对象ShouldReinvoke属性为falseContinue表示继续循环调用ShouldReinvoke属性为true并可提供一个反馈信息但是Messages为nullContinueWithMessages表示继续循环调用并提供下一次调用的消息列表但是Feedback为null。2. LoopAgentOptions在正式介绍LoopAgent之前我们先来看看它对应的配置选项类型LoopAgentOptions的定义。LoopAgentOptions提供的配置选项循环迭代Agent的行为作相应的控制。publicsealedclassLoopAgentOptions{publicint?MaxIterations{get;set;}publicboolFreshContextPerIteration{get;set;}publicstring?OnBehalfOfAuthorName{get;set;}publicboolExcludeOnBehalfOfMessages{get;set;}publicboolNonStreamingReturnsLastResponseOnly{get;set;}publicFuncAgentSession,CancellationToken,ValueTask?SessionCreatedCallback{get;set;}}具体的配置选项包括MaxIterations最大循环迭代次数如果为null则表示没有限制FreshContextPerIteration是否在每次迭代中使用新的Agent上下文true每次迭代都会重建输入消息只保留原始输入 聚合的反馈日志不会把前面的对话历史带入false每次迭代会在已有的对话基础上追加反馈。此为默认值。OnBehalfOfAuthorName给循环LoopEvaluator自动注入的消息打上作者标记区分哪些消息是循环自动生成的哪些是用户真实输入。默认值为null意味着不标记ExcludeOnBehalfOfMessages是否在下一次迭代中排除掉LoopEvaluator注入的消息false调用方能看到循环的自主行为此为默认值true调用方只看到封装Agent的响应不看到循环注入的消息。NonStreamingReturnsLastResponseOnly控制非流式运行的返回策略false返回完整的聚合消息包括所有迭代的消息此为默认值true 只返回最后一次迭代的响应。FreshContextPerIteration配置选项还体现了针对Session的控制。如果此选项设置为true,意味着如果调用方提供了AgentSession此AgentSession会以序列化的形式生成一个快照每次迭代都会利用此快照重建AgentSession对象并以此调用Agent否则循环会在每次迭代创建一个新的AgentSession。3. LoopAgent作为一个继承自DelegatingAIAgent的Agent中间件我们在构建一个LoopAgent的时候除了需要执行innerAgent还可以指定一个或者多个LoopEvaluator。在实施评估的时候会依次调用每个LoopEvaluator直到返回一个ShouldReinvoke为false的LoopEvaluation。也就是说只有所有LoopEvaluator决定循环可以终止才可以阻止迭代循环前提是迭代次数没有超过MaxIterations选项的设置。publicsealedclassLoopAgent:DelegatingAIAgent{publicLoopAgent(AIAgentinnerAgent,LoopEvaluatorevaluator,LoopAgentOptions?optionsnull,ILoggerFactory?loggerFactorynull);publicLoopAgent(AIAgentinnerAgent,IEnumerableLoopEvaluatorevaluators,LoopAgentOptions?optionsnull,ILoggerFactory?loggerFactorynull);protectedoverrideasyncTaskAgentResponseRunCoreAsync(IEnumerableChatMessagemessages,AgentSession?sessionnull,AgentRunOptions?optionsnull,CancellationTokencancellationTokendefault);protectedoverrideasyncIAsyncEnumerableAgentResponseUpdateRunCoreStreamingAsync(IEnumerableChatMessagemessages,AgentSession?sessionnull,AgentRunOptions?optionsnull,CancellationTokencancellationTokendefault);}LoopAgent针对innerAgent的循环调用实现在重写的RunCoreAsync和RunCoreStreamingAsync方法中在整个流程的执行受LoopAgentOptions配置选项的控制。我们将在下篇对整个循环的执行流程进行系统的介绍接下来我们简单介绍LoopAgent默认采用的循环迭代流程。4. 默认的循环迭代流程为了探测在默认情况下保留LoopAgentOptions的默认配置LoopAgent采用怎样的方式循环调用Agent和实施评估我们定义了如下这个基于迭代次数的LoopEvaluator。顾名思义这个InterationCountEvaluator单纯判断迭代次数是否超过设置的阈值决定是否继续相当于MaxIterations配置选项。在重写的EvaluateAsync方法中我们会输出LoopContext上下文提供的迭代次数、原始消息、上一次响应消息、之前的返回以及当前提供的反馈如果决定继续。classInterationCountEvaluator(intallowedIterations):LoopEvaluator{publicoverrideValueTaskLoopEvaluationEvaluateAsync(LoopContextcontext,CancellationTokencancellationTokendefault){Console.WriteLine(${newstring(-,30)}Evaluator{newstring(-,30)}Iteration:{context.Iteration}Initialmessages:{string.Join(\n ,context.InitialMessages.Select(it${it}))}Lastresponse:{string.Join(\n ,context.LastResponse.Messages.Select(it${it}))}Previousfeedback:{string.Join(\n ,context.Feedback)});if(context.IterationallowedIterations){returnValueTask.FromResult(LoopEvaluation.Stop());}varfeedback$Feedback for iteration{context.Iteration};Console.WriteLine($Feedback:{feedback}\n);returnValueTask.FromResult(LoopEvaluation.Continue(feedback));}}为了确定LoopAgent调用inerAgent提供的消息和返回的响应我们定义了如下这个FakeChatClient来模拟与LLM的交互。在重写的GetResponseAsync方法中我们调用ChatMessageGenerator的静态方法GenerateMessage方法生成一个响应消息消息内容会携带自增的序号。我们会输出传入的消息和响应的消息。classFakeChatClient:IChatClient{publicvoidDispose(){}publicTaskChatResponseGetResponseAsync(IEnumerableChatMessagemessages,ChatOptions?optionsnull,CancellationTokencancellationTokendefault){varmessageChatMessageGenerator.GenerateMessage(Response message from LLM.,ChatRole.Assistant);Console.WriteLine(${newstring(-,30)}LLM{newstring(-,30)}Incomingmessages:{string.Join(\n ,messages.Select(it${it}))}Outgoingresponse:{message});returnTask.FromResult(newChatResponse(message));}publicobject?GetService(TypeserviceType,object?serviceKeynull)null;publicIAsyncEnumerableChatResponseUpdateGetStreamingResponseAsync(IEnumerableChatMessagemessages,ChatOptions?optionsnull,CancellationTokencancellationTokendefault)thrownewNotImplementedException();}internalstaticclassChatMessageGenerator{privatestaticint_counter0;publicstaticChatMessageGenerateMessage(stringcontent,ChatRolerole){returnnewChatMessage(role:role,content:$[{Interlocked.Increment(ref_counter)}]{content});}}整个演示程序很简单。如下面的代码所示我们创建了一个FakeChatClient对象并将其转换成AIAgent然后根据它和创建InterationCountEvaluator对象将LoopAgent创建出来并将允许的迭代次数设置为3。usingMicrosoft.Agents.AI;usingMicrosoft.Extensions.AI;varagentnewLoopAgent(innerAgent:newFakeChatClient().AsAIAgent(),evaluator:newInterationCountEvaluator(3));ListChatMessageinput[ChatMessageGenerator.GenerateMessage(Original message from user.,ChatRole.User),ChatMessageGenerator.GenerateMessage(Original response from LLM.,ChatRole.Assistant),ChatMessageGenerator.GenerateMessage(Original message from user.,ChatRole.User),];varresponseawaitagent.RunAsync(input);varindex1;foreach(varmessageinresponse.Messages){Console.WriteLine(${newstring(-,20)}Message{index}{newstring(-,20)}{message});}我们调用ChatMessageGenerator的GenerateMessage方法创建了三个消息我们将它们组成消息列表作为输入调用LoopAgent的RunAsync后输出响应携带的所有消息。程序运行后针对FakeChatClient和InterationCountEvaluator的迭代调用会体现在如下的输出中------------------------------LLM------------------------------ Incoming messages: [1]Original message from user. [2]Original response from LLM. [3]Original message from user. Outgoing response: [4]Response message from LLM. ------------------------------Evaluator------------------------------ Iteration: 1 Initial messages: [1]Original message from user. [2]Original response from LLM. [3]Original message from user. Last response: [4]Response message from LLM. Previous feedback: Feedback:Feedback for iteration 1 ------------------------------LLM------------------------------ Incoming messages: [1]Original message from user. [2]Original response from LLM. [3]Original message from user. [4]Response message from LLM. Feedback for iteration 1 Outgoing response: [5]Response message from LLM. ------------------------------Evaluator------------------------------ Iteration: 2 Initial messages: [1]Original message from user. [2]Original response from LLM. [3]Original message from user. Last response: [5]Response message from LLM. Previous feedback: Feedback for iteration 1 Feedback:Feedback for iteration 2 ------------------------------LLM------------------------------ Incoming messages: [1]Original message from user. [2]Original response from LLM. [3]Original message from user. [4]Response message from LLM. Feedback for iteration 1 [5]Response message from LLM. Feedback for iteration 2 Outgoing response: [6]Response message from LLM. ------------------------------Evaluator------------------------------ Iteration: 3 Initial messages: [1]Original message from user. [2]Original response from LLM. [3]Original message from user. Last response: [6]Response message from LLM. Previous feedback: Feedback for iteration 1 Feedback for iteration 2从输出可以看出整个流程经历三次针对LLMEvaluator的迭代调用。Evaluator的输入只有原始的消息列表上一次的响应之前的评估反馈。调用LLM提供的对话历史则包括原始的消息列表之前LLM的响应Evaluator提供的反馈。作为LoopAgent最终的响应它携带的消息体现在如下的输出中。可以看出LLM的响应和Evaluator的反馈均在其中。--------------------Message1-------------------- [4]Response message from LLM. --------------------Message2-------------------- Feedback for iteration 1 --------------------Message3-------------------- [5]Response message from LLM. --------------------Message4-------------------- Feedback for iteration 2 --------------------Message5-------------------- [6]Response message from LLM.如果你希望看到LoopAgent完整的循环流程请看Loop Engineering在MAF中的实现-03:Agent循环调用流程详解
RELATED

相关推荐

用 PTerm 的 Section 打印机为长输出划分章节:从 DefaultSection 到自定义样式

用 PTerm 的 Section 打印机为长输出划分章节:从 DefaultSection 到自定义样式

开发工具 【免费下载链接】pterm ✨ PTerm is a modern Go module to easily beautify console output. Featuring charts, progressbars, tables, trees, text input, select menus and much more 🚀 Its completely configurable and 100% cross-platform compati…

📅 2026/10/15 3:12:48
foobox-cn 上手指南:给 foobar2000 换一套顺手的新界面

foobox-cn 上手指南:给 foobar2000 换一套顺手的新界面

foobox-cn 上手指南:给 foobar2000 换一套顺手的新界面 【免费下载链接】foobox-cn DUI 配置 for foobar2000 项目地址: https://gitcode.com/GitHub_Trending/fo/foobox-cn foobar2000 的内核功能很强,但默认界面确实朴素:灰底面板、…

📅 2026/10/15 3:12:48
foobox-cn:foobar2000 界面美化的完整上手指南(新手 5 分钟换装)

foobox-cn:foobar2000 界面美化的完整上手指南(新手 5 分钟换装)

foobox-cn:foobar2000 界面美化的完整上手指南(新手 5 分钟换装) 【免费下载链接】foobox-cn DUI 配置 for foobar2000 项目地址: https://gitcode.com/GitHub_Trending/fo/foobox-cn foobar2000 是出了名耐用的老牌播放器&#xff0c…

📅 2026/10/15 3:12:48
MORE NEWS

更多资讯

📰

PoB离线Build规划:天赋树与伤害计算一次算清

PoB离线Build规划:天赋树与伤害计算一次算清 【免费下载链接】PathOfBuilding Offline build planner for Path of Exile. 项目地址: https://gitcode.com/GitHub_Trending/pa/PathOfBuilding 凌晨两点,你又一次在天赋树上手动数格子:…

📰

微信API发送失败别盲目重试:个人微信二次开发判断法

客服反馈:「发货通知怎么发了两条?」 打开日志,往往是这样:第一次请求超时了,程序自动又发了一次;其实第一条早就到了。 个人微信 API 二次开发里,失败就重试听着负责,却是双发和失…

📰

CKEditor 4 聚焦状态下销毁内联编辑器的空引用崩溃:`isInline of null` 问题与 Bender 手动测试解析

前端UI组件 【免费下载链接】ckeditor4 The best enterprise-grade WYSIWYG editor. Fully customizable with countless features and plugins. 项目地址: https://gitcode.com/gh_mirrors/ck/ckeditor4 点击查看 免费下载 导读 本文围绕 CKEditor 4 官方仓库中的…

📰

如何在电脑上运行《索尼克:释放》:Unleashed Recompiled 静态重编译版完整上手指南

如何在电脑上运行《索尼克:释放》:Unleashed Recompiled 静态重编译版完整上手指南 【免费下载链接】UnleashedRecomp An unofficial PC port of the Xbox 360 version of Sonic Unleashed created through the process of static recompilation. 项目…

📰

叉积判向:从三角形朝向到背面剔除的工程实战

做图形学的人,早晚都会撞上"叉积"这堵墙。第一次在代码里写cross(a, b) ax*by - ay*bx的时候,我压根没意识到,这个只有一行乘减运算的小东西,居然能决定三角形到底是顺时针还是逆时针,进而影响到背面剔除、…

📰

Wing 语言 inflight Handler 单例语义剖析:以 `inflight_handler_singleton.test.w` 快照测试为例

编程语言编译器云原生语言运行时 【免费下载链接】wing A programming language for the cloud ☁️ A unified programming model, combining infrastructure and runtime code into one language ⚡ 项目地址: https://gitcode.com/gh_mirrors/wi/wing 点击查看 免…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬