news 2026/10/15 20:53:28

[Loop Engineering在MAF中的实现-01]基于评估结果针对Agent的循环调用

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
[Loop Engineering在MAF中的实现-01]基于评估结果针对Agent的循环调用

Loop Engineering是2026年人工智能圈最火爆的核心概念,它指的是设计、运营和持续改进反馈循环的AI工程化实践。NVIDIA首席执行官黄仁勋将其形容为定义2026下半年AI发展的重大转变为:现在没人写提示词了,大家都在编写和管理循环(Loops)。它的核心思想是让你从一个向AI发送指令的人,变成一个设计自动运转系统,让AIAgent自主完成任务并自我修正的工程师。其实Loop Engineering没有很多说得那么玄乎,这篇文章我们会通过一个简单的例子通过几行代码实现针对Agent的循环调用。

1. Loop Engineering概述

这两年来,AI圈子没几天就会出现一个新词,加上很多人为了博取流量,与不惊人死不休,动不动就是XXX已死、YYY当立,导致很多人觉得:怎么昨天我刚听前沿技术,今天就成了明日黄花了。我前几天看了一篇文章的标题就是《Harness Engineering已死、Loop Engineering才是王道》,简直莫名其妙。不过很多人确实将AI工程演化分成四代:

  • Prompt Engineering
  • Context Engineering
  • Harness Engineering
  • Loop Engineering

我个人是不同意这种说法的。还记得定义Harness Engineering的如下这个公式吗?按照这个公式,Harness Engineering本质上就是在LLM基础上构建理想Agent的所有工程化手段。而LLM本身就是独立的,那岂不是Harness Engineering = Agent Engineering,我们应用在Agent上所有设计模式都是一种Harness手段,自然也包括Prompt Engineering和Context Engineering优化提示词和上下文的手段,也包括Loop Engineering根据动态评估反馈自动调用Agent的手段。

Agent = LLM + Harness

所以我的意思是,如果我们认同Harness Engineering的说法,意味着在它之前以及之后出现的所有Engineering都是它的子集,自然也包括Loop Engineering。这种说法可以在MAF中得到印证,因为用于实现Loop Engineering的LoopAgent中间件已经集成在HarnessAgent之中。而且很多平台直接将自己的Agent开发框架命名为Harness,比如DSH(DeepSeek Harness)。

在Loop Engineering之前,我们是这样使用Agent的:

  • 我们采用提示词来描述推理任务,并将其作为输入调用Agent,而且一般我们会使用Session保持与Agent对话的语境;
  • 单次Agent的调用一般会在一个ReAct循环中执行,并最终输出响应;
  • 我们根据输出响应,再次撰写提示词作为输入调用Agent。

整个过程完全是由用户主导,一切由输入的提示词来驱动。Loop Engineering引入了一种基于评估反馈的迭代机制,我们通过注入一个评估器对每一轮调用的结果进行评估,并由评估结果决定是否继续调用Agent。如果评估器决定继续,它一般会提供评估结果(比如理由和建议)并作为下次Agent调用的输入。

2. 利用MAF的LoopAgent实现针对Agent的循环调用

Loop Engineering在MAF中是通过LoopAgent这个继承自DelegatingAgent的Agent中间件实现的。它已经被集成在HarnessAgent中,当然它也可以被单独使用。接下来我们将使用它实现如下的应用场景:我们创建一个用于宋词创作的Agent,它能根据我们提供的主题和题材创作一首宋词。我们同时创建一个评估器,它能对每一轮Agent的创作结果进行评估,并根据评估结果决定是否继续创作。整个循环调用的过程如下:

  • 调用Agent进行创作;
  • 评估器对创作结果进行评估,评估的结果包括一个得分和一段评语:
    • 如果得到达到执行的分数,整个循环结束;
    • 否则,针对反馈的评语,重新调用Agent进行创作。

如下所示的是这个评估器类型ScoreBasedEvaluator的定义。它继承自LoopEvaluator,构造函数接收一个AIAgent对象作为评估器和一个目标分数。在重写得EvaluateAsync方法中,它将当前LoopContext中的初始消息和最后一次响应消息作为输入调用评估器进行评估。我们通过结构化输出的方式让AIAgent返回一个Review类型的对象,它包含一个整数类型的得分和一个字符串类型的评语。

classScoreBasedEvaluator(AIAgentreviwer,intscore):LoopEvaluator{publicoverrideasyncValueTask<LoopEvaluation>EvaluateAsync(LoopContextcontext,CancellationTokencancellationToken=default){ChatMessage[]input=[..context.InitialMessages,..context.LastResponse.Messages];varreview=(awaitreviwer.RunAsync<Review>(input)).Result;Console.WriteLine($"""{newstring('-',30)}Iteration{context.Iteration}{newstring('-',30)}{context.LastResponse}得分:{review.Score}评语:{review.Feeback}""");returnreview.Score>=score?LoopEvaluation.Stop():LoopEvaluation.Continue(review.Feeback);}}[Description("针对创作诗词的评估结果")]publicclassReview{[Description("得分,采用百分制")]publicintScore{get;set;}[Description("评语")]publicstring?Feeback{get;set;}}

在得到作为评估结果的Review对象后:

  • 如果得分达到预设的阈值,LoopEvaluator将返回通过调用LoopEvaluation.Stop()方法创建的LoopEvaluation对象,整个循环调用结束;
  • 如果得分未达到预设的阈值,LoopEvaluator将评语组为反馈调用LoopEvaluation.Continue(feedback)方法,并返回该方法创建的LoopEvaluation对象,整个循环调用继续,并将评语作为下一轮Agent调用的输入。

如下三个常量分别定义了创作Agent的提示词、评审Agent的提示词和整个循环调用的初始输入。创作Agent的提示词要求它根据提供的主题和意境以词牌名相见欢创作一首词。评审Agent的提示词要求它根据四个维度对创作的这首词进行评价,并给出一个得分和一段评语。初始输入是《卫风·氓》的原文。

conststringComposerInstructions="你是一个精通宋词创作的智能体,负责根据提供的主题和意境以词牌名**相见欢**创作一首词";conststringReviwerInstrucctions=""" 你是一个深谙古典文化和诗词的文化大家,请按照如下的标准对创作的这首词进行评价。评语保持200字以内,尽可能简洁。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分):是否只会堆砌**愁**、**泪**等陈词滥调。优秀的词作应当在传统框架下有独特的视角或新颖的构思。""";conststringPrompt=""" 基于如下这首《卫风·氓》的背景和情感基调,创作一首宋词。 原文如下: 氓之蚩蚩,抱布贸丝。匪来贸丝,来即我谋。 送子涉淇,至于顿丘。匪我愆期,子无良媒。 将子无怒,秋以为期。 乘彼垝垣,以望复关。不见复关,泣涕涟涟。 既见复关,载笑载言。尔卜尔筮,体无咎言。 以尔车来,以我贿迁。 桑之未落,其叶沃若。于嗟鸠兮,无食桑葚! 于嗟女兮,无与士耽!士之耽兮,犹可说也; 女之耽兮,不可说也。 桑之落矣,其黄而陨。自我徂尔,三岁食贫。 淇水汤汤,渐车帷裳。女也不爽,士贰其行。 士也罔极,二三其德。 三岁为妇,靡室劳矣;夙兴夜寐,靡有朝矣。 言既遂矣,至于暴怒。兄弟不知,咥其笑矣。 静言思之,躬自悼矣。 及尔偕老,老使我怨。淇则有岸,隰则有泮。 总角之宴,言笑晏晏。信誓旦旦,不思其反。 反是不思,亦已焉哉!""";

整个程序其实很简单,首先我们创建两个AIAgent,一个是创作Agent,一个是评审Agent。后者用来创建作为评估器的ScoreBasedEvaluator对象,并指定一个分数阈值(85分)。然后我们将创作Agent和评估器封装在LoopAgent中。最后我们调用LoopAgent的RunAsync方法,并传入初始Prompt。整个循环调用的过程会在控制台打印出每一轮的创作结果、评审结果和得分。

varcomposer=CreateAgent(name:"SongLyricsComposer",model:"gpt-5.2-chat",instructions:ComposerInstructions);varreviewer=CreateAgent(name:"SongLyricsReviwer",model:"gpt-5.2-chat",instructions:ReviwerInstrucctions);varagent=newLoopAgent(composer,newScoreBasedEvaluator(reviewer,85));varresponse=awaitagent.RunAsync(Prompt);varindex=1;foreach(varmessageinresponse.Messages){Console.WriteLine($"""{newstring('-',20)}Message{index++}{newstring('-',20)}{message}""");}AIAgentCreateAgent(stringname,stringinstructions,stringmodel){varapiKey=Environment.GetEnvironmentVariable("OPENAI_API_KEY")!;varendpoint=Environment.GetEnvironmentVariable("PROJECT_URL")!;returnnewAIProjectClient(newUri(endpoint),newAzureCliCredential()).AsAIAgent(name:name,model:model,instructions:instructions);}

整个输出总体分为两段,第一段是每次迭代后调用评估器的输出,包含创作结果、得分和评语。从如下的输出可以看出,整个流程经历了两次迭代,第一次评估得分为78分,评语指出了创作中存在的问题,并给出了改进建议。第二次迭代后,评估得分为86分,评语表明创作已经达到了预期的标准,整个循环调用结束。

------------------------------Iteration1------------------------------ 相见欢 淇桥初见匆匆。意朦胧。 笑把秋期轻许、趁东风。 桑阴翠,流年坠,人情空。 回首当时盟誓、已成鸿。 得分: 78 评语:此作依《相见欢》小令体式,句读大体齐整,然“笑把秋期轻许、趁东风”字数稍近散文化,平仄亦未尽合谱,韵脚统一尚可。意象取“淇桥”“桑阴”等,能扣《氓》本事,前后情绪递转自然。下片“流年坠,人情空”有兴衰之感,结句“盟誓已成鸿”含怨而不滞。语言清婉流畅,但部分措辞略近今人口吻,词味尚可再凝炼;情感层次由相悦至幻灭,虽较含蓄,仍具余韵。 ------------------------------Iteration2------------------------------ 相见欢 淇边细雨初晴。柳烟轻。 曾约复关南路、候君行。 桑青后,花零久,两心惊。 一片当时明月、照空盟。 得分: 86 评语:此作依《相见欢》小令体制,句式大体合拍,押“轻、行、惊、盟”庚青韵,尚称稳妥。上片写淇边候约,点出《氓》旧事;下片以“桑青后,花零久”暗承桑叶兴衰,意象简洁而有层次。语言清婉自然,有宋词婉约之致。“一片当时明月、照空盟”收束含怨不露,颇有余味。惟情感推进稍快,对负心与悔悟之沉痛着墨略浅,过片亦可更曲折深婉。

第二段是LoopAgent最终响应包含的消息。一共包括两条消息,第一条为第一次创作的结果,第二条为评估器给出的反馈,第三条为第二次创作的结果。由于此次传作业已经达到了预期的标准,整个循环调用结束。

--------------------Message1-------------------- 相见欢 淇桥初见匆匆。意朦胧。 笑把秋期轻许、趁东风。 桑阴翠,流年坠,人情空。 回首当时盟誓、已成鸿。 --------------------Message2-------------------- 此作依《相见欢》小令体式,句读大体齐整,然“笑把秋期轻许、趁东风”字数稍近散文化,平仄亦未尽合谱,韵脚统一尚可。意象取“淇桥”“桑阴”等,能扣《氓》本事,前后情绪递转自然。下片“流年坠,人情空”有兴衰之感,结句“盟誓已成鸿”含怨而不滞。语言清婉流畅,但部分措辞略近今人口吻,词味尚可再凝炼;情感层次由相悦至幻灭,虽较含蓄,仍具余韵。 --------------------Message3-------------------- 相见欢 淇边细雨初晴。柳烟轻。 曾约复关南路、候君行。 桑青后,花零久,两心惊。 一片当时明月、照空盟。

3. 直接使用HarnessAgent

我们已经说过,LoopAgent已经被集成在HarnessAgent中,所以我们可以直接使用HarnessAgent来实现Loop Engineering。如下所示,我们创建了一个用于创作的IChatClient对象,和一个用于评估的AIAgent对象,后者被用于创建一个ScoreBasedEvaluator对象。然后我们将创作的IChatClient对象和评估器封装在HarnessAgent中。

varapiKey=Environment.GetEnvironmentVariable("OPENAI_API_KEY")!;varendpoint=Environment.GetEnvironmentVariable("OPENAI_BASE_URL")!;varreviewer=newOpenAIClient(newApiKeyCredential(apiKey),newOpenAIClientOptions{Endpoint=newUri(endpoint)}).GetChatClient(model:"gpt-5.2-chat").AsIChatClient().AsAIAgent(name:"SongLyricsReviwer",instructions:ReviwerInstrucctions);varchatClient=newOpenAIClient(newApiKeyCredential(apiKey),newOpenAIClientOptions{Endpoint=newUri(endpoint)}).GetChatClient(model:"gpt-5.2-chat").AsIChatClient();varagent=newHarnessAgent(chatClient,newHarnessAgentOptions{Name="SongLyricsComposer",HarnessInstructions=ComposerInstructions,DisableWebSearch=true,DisableAgentModeProvider=true,DisableTodoProvider=true,DisableFileMemory=true,DisableFileAccess=true,LoopEvaluators=[newScoreBasedEvaluator(reviewer,85)],});varresponse=awaitagent.RunAsync(Prompt);varindex=1;foreach(varmessageinresponse.Messages){Console.WriteLine($"""{newstring('-',20)}Message{index++}{newstring('-',20)}{message}""");}

由于HarnessAgent会整和很多用于实现相应Harness手段的中间件,对此由兴趣的可以参考我的文章MAF的Harness-02:HarnessAgent究竟整合了哪些Harness手段?。为了屏蔽它们的干扰,我们在给定的HarnessAgentOptions中禁用了某些中间件。程序运行之后,也能得到我们希望的输出(这次进行了4次迭代):

------------------------------Iteration1------------------------------ 《相见欢·淇上初盟》 垝垣斜日轻红,望归鸿。犹记顿丘携手、语匆匆。 桑叶碧,春水急,意相从。谁料旧盟难守、各西东。 《相见欢·桑落》 桑黄淇水东流,冷汀洲。三载辛勤空付、旧时柔。 灯半灭,人未歇,泪还收。当日旦旦深誓、总成秋。 得分: 78 评语:两首皆能扣合《氓》之情事,由初盟至决绝,层次清楚。《相见欢》体式基本合拍,句读亦稳,押“ong”“ou”韵较自然。上阕“垝垣斜日”“桑黄淇水”皆有《诗经》遗意,画面感尚佳。然词味稍浅,“旧盟难守”“空付旧时柔”近于直白,少含蓄蕴藉。过片承转尚顺,但对人物情绪的递进尚未深挖,未能尽显《氓》由痴恋、怨怼至决绝的复杂波澜。整体清婉流畅,具宋词小令风致。 ------------------------------Iteration2------------------------------ 《相见欢·复关》 垝垣斜倚残曛,望归人。淇水悠悠不断、暮云深。 桑未落,鬓先损,泪沾襟。当日笑言犹在、却难寻。 《相见欢·已焉》 桑阴摇雨初秋,冷汀洲。帘外淇波犹自、向东流。 灯影薄,人语寂,恨难休。誓语当年如梦、一回收。 得分: 78 评语:两首皆能扣《氓》之弃妇哀怨,意象如“淇水”“桑阴”“垝垣”承袭《诗经》本色,情绪流转自然,有宋词婉约之致。《相见欢》词牌字数与分片基本合格,押“人、深、襟、寻”“秋、洲、流、休、收”亦较稳。然平仄未尽严谨,个别句法略近小令常套。上篇“鬓先损”较直白,下篇“誓语当年如梦”稍近熟语。整体胜在情感真切,能由盼望写至决绝,保留《氓》原作由爱生怨的层次。 ------------------------------Iteration3------------------------------ 《相见欢·淇上》 轻寒细雨孤村,掩重门。犹忆送郎淇上、语温存。 桑渐老,水空远,暮烟昏。回首复关何处、月微痕。 《相见欢·弃盟》 秋声吹冷蘅皋,夜迢迢。独倚疏灯无语、听寒潮。 当日意,而今恨,总难消。淇岸有涯人事、竟无聊。 得分: 82 评语:两首皆能扣《氓》之情脉,由相恋而怨别,意绪连贯。《相见欢》词牌字数大体合式,句读亦稳,然“犹忆送郎淇上”“独倚疏灯无语”等处平仄未尽严谨,韵脚稍嫌单调。意象承《诗经》之“淇水”“桑”“复关”,古典气息较足,尤“月微痕”“淇岸有涯”有余味。语言清婉流畅,但个别句略近小令常套,创新稍弱。第二首结句“人事、竟无聊”情感到位,然“无聊”略近今语,减损词味。总体能得哀而不怨之旨。 ------------------------------Iteration4------------------------------ 《相见欢·望复关》 晚云低护荒台,雨声催。独倚残垣凝望、雁初回。 桑叶尽,人情改,镜尘堆。惟有淇流如旧、去难回。 《相见欢·决绝》 露凉风紧蘅皋,夜萧骚。旧约依稀还似、梦魂遥。 灯影暗,佩声杳,恨迢迢。淇岸纵宽终有、此情消。 得分: 86 评语:两首皆合《相见欢》小令体制,句读齐整,押平声韵较稳,格律基本无失。上篇以“残垣”“雁回”“淇流”等意象承《氓》之望复关、情渐冷,画面清婉;下篇转入决绝,蘅皋、灯影、佩声等语颇具词味。语言凝练,无明显俗句,过片自然。惟情感层次稍简,未能充分展开《氓》中由热恋至怨弃的复杂心理;“镜尘堆”“梦魂遥”等语略近常套,创新度尚可再进。 --------------------Message1-------------------- 《相见欢·淇上初盟》 垝垣斜日轻红,望归鸿。犹记顿丘携手、语匆匆。 桑叶碧,春水急,意相从。谁料旧盟难守、各西东。 《相见欢·桑落》 桑黄淇水东流,冷汀洲。三载辛勤空付、旧时柔。 灯半灭,人未歇,泪还收。当日旦旦深誓、总成秋。 --------------------Message2-------------------- 两首皆能扣合《氓》之情事,由初盟至决绝,层次清楚。《相见欢》体式基本合拍,句读亦稳,押“ong”“ou”韵较自然。上阕“垝垣斜日”“桑黄淇水”皆有《诗经》遗意,画面感尚佳。然词味稍浅,“旧盟难守”“空付旧时柔”近于直白,少含蓄蕴藉。过片承转尚顺,但对人物情绪的递进尚未深挖,未能尽显《氓》由痴恋、怨怼至决绝的复杂波澜。整体清婉流畅,具宋词小令风致。 --------------------Message3-------------------- 《相见欢·复关》 垝垣斜倚残曛,望归人。淇水悠悠不断、暮云深。 桑未落,鬓先损,泪沾襟。当日笑言犹在、却难寻。 《相见欢·已焉》 桑阴摇雨初秋,冷汀洲。帘外淇波犹自、向东流。 灯影薄,人语寂,恨难休。誓语当年如梦、一回收。 --------------------Message4-------------------- 两首皆能扣《氓》之弃妇哀怨,意象如“淇水”“桑阴”“垝垣”承袭《诗经》本色,情绪流转自然,有宋词婉约之致。《相见欢》词牌字数与分片基本合格,押“人、深、襟、寻”“秋、洲、流、休、收”亦较稳。然平仄未尽严谨,个别句法略近小令常套。上篇“鬓先损”较直白,下篇“誓语当年如梦”稍近熟语。整体胜在情感真切,能由盼望写至决绝,保留《氓》原作由爱生怨的层次。 --------------------Message5-------------------- 《相见欢·淇上》 轻寒细雨孤村,掩重门。犹忆送郎淇上、语温存。 桑渐老,水空远,暮烟昏。回首复关何处、月微痕。 《相见欢·弃盟》 秋声吹冷蘅皋,夜迢迢。独倚疏灯无语、听寒潮。 当日意,而今恨,总难消。淇岸有涯人事、竟无聊。 --------------------Message6-------------------- 两首皆能扣《氓》之情脉,由相恋而怨别,意绪连贯。《相见欢》词牌字数大体合式,句读亦稳,然“犹忆送郎淇上”“独倚疏灯无语”等处平仄未尽严谨,韵脚稍嫌单调。意象承《诗经》之“淇水”“桑”“复关”,古典气息较足,尤“月微痕”“淇岸有涯”有余味。语言清婉流畅,但个别句略近小令常套,创新稍弱。第二首结句“人事、竟无聊”情感到位,然“无聊”略近今语,减损词味。总体能得哀而不怨之旨。 --------------------Message7-------------------- 《相见欢·望复关》 晚云低护荒台,雨声催。独倚残垣凝望、雁初回。 桑叶尽,人情改,镜尘堆。惟有淇流如旧、去难回。 《相见欢·决绝》 露凉风紧蘅皋,夜萧骚。旧约依稀还似、梦魂遥。 灯影暗,佩声杳,恨迢迢。淇岸纵宽终有、此情消。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/15 20:50:48

pure_live v2.6.0 阶段稳定版全解析:上游整合、稳定性设计与五平台构建

音视频直播移动开发 【免费下载链接】pure_live 纯粹直播:哔哩哔哩/虎牙/斗鱼/快手/抖音/网易cc/YY直播/Twitch直播/SOOP直播/M38自定义源应有尽有。 项目地址&#xff1a; https://gitcode.com/gh_mirrors/pur/pure_live 点击查看 免费下载 pure_live 是一款开源的多平台直播…

作者头像 李华
网站建设 2026/10/15 20:50:29

告别npm install慢:pnpm加速依赖安装的原理与迁移指南

前端工程化里有个很有意思的现状&#xff1a;项目越来越大&#xff0c;依赖越来越多&#xff0c;但npm install这个命令反而成了被吐槽最多的一环。一次冷启动安装动辄几百秒&#xff0c;node_modules 体积动辄几个 G&#xff0c;换个分支、跑个 CI 都要重新来一遍。我自己的感…

作者头像 李华
网站建设 2026/10/15 20:45:30

MySQL调优实战:从参数配置到SQL索引优化完整指南

做后端开发这些年&#xff0c;MySQL调优是我见过最容易被神化、也最容易走弯路的领域之一。一说调优&#xff0c;很多人第一反应就是翻出一堆参数&#xff0c;照着网上的“推荐配置”一顿改&#xff0c;结果不但没变快&#xff0c;反而把线上系统搞崩的案例我见过不少。实际上&…

作者头像 李华