Skip to content

第三章:下一步做什么,什么时候停 ​

Agent 第一次读网页超时,第二次还是超时,第三次又发出了相同请求。屏幕一直显示“正在处理”,任务却没有前进。

这时缺少的是什么?更大的模型、更长的运行时间,还是另一种处理失败的方法?只知道 Agent 会“思考、行动、观察”,还不足以回答这个问题。我们需要看清每一轮拿到了什么、谁负责处理失败,以及什么条件下应该结束。

本章沿用“查资料并形成技术简报”的案例,跟着一次任务走完六轮,再回头拆解 Hermes 的行动循环。读完后,你应该能判断:一次重试是否有价值,增加预算可能解决什么,以及为什么一段像样的最终答复仍不能证明任务已经完成。

本章怎样使用案例

下文的任务、网页返回和六轮过程都是教学示意,用于解释机制,不是一次真实运行的日志。轮数、重试次数和简报格式是本例的约定,不代表 Hermes 的默认配置。对 Hermes 行为的说明沿用本书的 v0.22.5 版本依据。

3.1 一次任务,为什么要反复请求模型 ​

先给 Hermes 一个要求:

核对这个稳定版中,任务达到运行预算后会怎样结束。写一份简短的技术简报,说明已确认的行为、适用条件和仍未确认的问题。只读公开材料,不改配置,也不向外发送简报。

这个任务不能靠“写一段关于预算的介绍”完成。它至少包含三项要求:找到对应版本的材料;分清“达到限制”和“任务成功”;把材料支持的结论与没有核实的部分分开。即使文字很通顺,漏掉其中一项也可能没有完成要求。

模型收到最初的问题时,还不知道网页里写了什么。它可以先提出“读取发布说明”的工具请求;等工具真正读到内容后,才能决定是继续查细节,还是已经可以写简报。

因此,行动循环的必要性来自信息尚未齐全,而且下一步往往取决于上一步的实际结果。 预先规定“检索一次、读两页、写总结”当然也能处理一部分任务,但第二页打不开、两页说法矛盾、版本不一致时,就需要根据新情况改变路线。

一轮里,三方怎样接力 ​

把一次普通的、包含工具调用的循环拆开,会看到这样的接力:

  1. 运行程序准备当前信息。 把任务要求、必要的历史、已有工具结果和可用工具说明组织成模型这次能读到的内容。
  2. 模型提出行动。 例如读取某个页面。模型产生的是调用请求,还没有访问网页。
  3. 运行程序承接请求。 在适用的规则与边界内调度工具,并维护请求和结果的对应关系。
  4. 工具接触真实环境。 返回页面内容,也可能返回超时、权限拒绝或其他错误。
  5. 结果进入后续上下文。 下一轮模型有机会根据真实结果调整行动。

如果模型给出了可以结束本次任务的文本答复,程序就会走向收尾处理。这里画的是主要路径;空答复、截断、恢复和停止检查还会带来其他分支,不能把“没有工具调用”机械地等同于“立刻结束”。

图 3-1 教学示意:循环连接的是一次次有结果的行动。模型提出请求与工具真正执行,是两个环节。 点击图解可放大
左右滑动查看图解细节
运行程序整理信息,模型决定下一步,工具执行后把真实结果带回后续判断;另有交付或说明限制的出口

图 3-1 教学示意:循环连接的是一次次有结果的行动。模型提出请求与工具真正执行,是两个环节。

有一个容易忽略的前提:模型只能利用这次请求里实际带入的信息。 工具曾经读到过一段内容,不等于下一轮模型必然看到了它。结果可能被截短,较早的历史可能被压缩,信息也可能在整理时遗漏。第五章会专门讨论这些限制;本章先记住,反馈必须进入后续判断,才可能影响行动。

先分清四种“次数” ​

一次用户任务,可能跨过多轮模型判断;一轮判断又可能提出多个工具调用。模型服务的请求如果遇到临时网络错误,还可能在运行程序内部重试。

计数对象本例中的含义容易出现的误解
用户任务核对行为并写出一份简报每一轮都要用户重新发消息
模型判断轮次读过当前信息后,给出一次行动或答复一轮只可能执行一个工具
工具调用读取某个页面、检索某项信息工具执行次数就是模型请求次数
模型服务请求尝试向模型服务发送请求,包括可能的失败重试网络重试时,模型一定已经重新规划

表中的“模型判断轮次”是为了讲解方便。Hermes 自己的迭代预算有具体记账规则,恢复路径和特定调用还可能影响计数。看见“最多运行若干次”时,要先问限制的是哪一种次数,不能直接换算成能读多少页。

3.2 把一份简报走完:六轮里发生了什么 ​

现在让任务开始。我们只观察输入、行动和结果,不假装知道模型内部的完整思考过程。

图 3-2 教学示意:第 2、3 轮都没有取得所需细节;第 4 轮改变了取材料的路径,第 5 轮补齐适用条件。第 6 轮直接答复,没有新的工具调用。 点击图解可放大
左右滑动查看图解细节
技术简报的六轮教学过程:读取发布说明,读取细节超时,重试仍超时,换官方入口,核对条件,输出最终答复

图 3-2 教学示意:第 2、3 轮都没有取得所需细节;第 4 轮改变了取材料的路径,第 5 轮补齐适用条件。第 6 轮直接答复,没有新的工具调用。

第 1 轮:先确定查的是哪个版本 ​

模型请求读取发布说明。工具返回了版本标识和变更摘要,其中提到运行结束行为有调整,但没有讲完触发条件。

这一轮解决了“材料属于哪个版本”,留下了“到底在什么条件下生效”。因此,继续读详细说明有明确目的。若此时直接把摘要改写成简报,文字可能已经像成品,却会把摘要没有覆盖的条件藏起来。

第 2 轮:读取细节,遇到超时 ​

模型请求读取详细页面,工具返回“读取超时”。这个结果只说明本次读取没有按时完成。它既不能证明页面里没有相关说明,也不能证明该行为不存在。

下一轮需要保留的状态应该是:版本已经确定,行为细节仍未取得,读取失败的原因是超时。 如果把它压成一句“没有查到”,后续行动就失去了区分失败原因的依据。

第 3 轮:允许一次重试,但仍然失败 ​

本例约定允许对临时读取错误重试一次。再次请求后,页面仍然超时。

这次没有取得新的正文,但也不是毫无反馈:同一路径连续失败,说明继续依赖它的把握下降了。接下来应该评估其他入口,而不是把“已经投入了两轮”当作再试一次的理由。

注意,这里说的是本例中模型选择再次调用读取工具。它不同于工具自己内部重试了几次,也不同于向模型服务发请求时发生的网络重试。

第 4 轮:换入口,目的保持不变 ​

模型改读另一个可公开访问的官方说明入口。这次取到了正文,知道达到某类限制后可能进入总结收尾,但适用条件还不完整。

“换入口”有用,是因为它改变了取得材料的路径,同时仍然服务于原问题。随便换一个搜索词、读到一篇无关介绍,虽然也是新动作,却没有减少本任务中的关键未知。

另一种错误是为了赶快成功,改用一个更容易读到的旧版本页面。访问成功了,版本却错了。这里必须保留第一轮确定的版本约束。

第 5 轮:补条件,不再泛泛搜索 ​

模型围绕剩余问题继续核对:哪些退出可以进入总结收尾?用户取消是否也一样?已有答复和没有答复时,处理是否相同?

工具返回的材料足以支撑一份有边界的简报。这时还有很多内容可以继续读,例如不同入口的界面表现、各种模型的措辞差异。但本例没有要求实测这些内容;只要明确它们尚未验证,就不必把“还能研究”当作“必须继续”。

第 6 轮:停止取材料,交付答复 ​

模型根据已有信息输出简报,把确认的机制、适用条件和未验证范围分开。本轮不再提出工具调用,进入正常收尾。

这六轮不是预先写好的固定剧本。若第 2 轮直接读到了完整说明,第 3、4 轮就可能不需要;若所有入口都无法访问,合理结果也可能是在更早的时候说明限制。循环提供调整路线的机会,具体路线仍取决于反馈、模型判断和运行边界。

3.3 怎样判断一轮是否让任务前进了 ​

前面的六轮中,“页面读取成功”不是唯一值得关注的事件。真正要跟踪的是:为了完成任务,还缺少什么?本轮结果改变了什么?

可以在纸上维护三栏:已确认的事实、尚未解决的问题、当前可行的下一步。 它们是帮助我们理解过程的教学记法,不表示 Hermes 内部恰好存在这样一张表。

例如,第 2 轮超时后可以记成:

观察对象当前状态
已确认找到了对应版本;摘要提到了相关调整
未解决具体触发条件;取消与预算耗尽是否一样
已知障碍详细页面本次读取超时
下一步候选有限重试;换公开官方入口;若仍不可得则说明缺口

第 3 轮仍超时,事实栏没有增加,但障碍栏发生了变化:这条路径的重试已经失败。第 4 轮取到正文后,事实栏增加,问题栏缩小。第 5 轮核对完条件,才有理由判断简报的材料基本齐全。

由此可以得到一个判断行动价值的方法:

这一步准备解决哪个未知?返回不同结果时,后续做法会有什么不同?

如果某次重试成功就继续读,失败就换入口,它有清楚的分支。如果无论返回什么都继续重复同一个请求,反馈实际上没有参与决策。

也不要把“有新信息”要求得过窄。发现一个来源不适用、确认一次执行失败、排除一条不可行路径,都可能推动任务。但这种收益会递减:已经知道参数格式错误,仍然拿同样参数调用十次,并不会得到十份新的证据。

Hermes 可以把错误和结果带回模型,也有针对部分异常的恢复措施。它不会因此自动保证每一轮都值得做。 模型仍可能忽略错误、误读内容,或迟迟不肯收尾。运行记录让这些问题可观察,预算为它们设上限,二者都不能代替任务判断。

3.4 同样显示“失败”,处理的人可能不同 ​

“Agent 请求失败了”至少可能指两件事:还没拿到模型响应,或已经按模型请求执行了工具但工具返回错误。分清这两处,才能知道所谓“重试”到底在重试什么。

图 3-3 教学示意:图中区分的是两处主要处理位置。工具内部也可能有自己的重试;不可恢复的错误和中断可以直接结束运行。 点击图解可放大
左右滑动查看图解细节
两类失败的教学对照:模型服务请求失败由运行程序按错误类型处理;工具返回的错误带入后续上下文,由模型选择后续行动

图 3-3 教学示意:图中区分的是两处主要处理位置。工具内部也可能有自己的重试;不可恢复的错误和中断可以直接结束运行。

模型服务请求失败:先恢复通信或请求条件 ​

运行程序向模型服务请求响应时,可能遇到连接中断、临时限流,或者请求本身不被接受。此时模型未必已经给出可用的行动,谈不上“模型看见错误后决定换个办法”。

Hermes 会区分错误类型,走相应的有限重试、恢复或退出路径;配置了可用的后备模型服务时,部分失败还可能尝试切换。这里的选择由运行程序和配置承接,不能概括成“所有错误都等几秒再试”。

这个设计减少了短暂故障对用户的打断,但也有代价:自动恢复会增加等待和请求开销;切换模型服务后,可用能力、上下文范围和输出表现也可能改变。它保证的是有规则地处理故障,不是保证最终结果一定正确。

工具返回错误:把失败当作下一轮的输入 ​

在简报案例里,模型已经提出读取页面的请求,真正超时的是读取工具。只要这类错误以结果形式正常返回,它就可以和成功结果一样,进入后续上下文。

模型接下来可以重试、修正请求、换方法、请求必要帮助,或说明无法继续。运行程序负责调度和边界,模型负责根据已经得到的信息提出下一步;不能指望“工具出错”四个字自动导出正确动作。

工具反馈下一步先判断什么有价值的处理
读取超时是否可能是暂时故障?已有多少次尝试?有限重试,失败后换允许的入口或说明缺口
参数格式错误工具要求什么,当前参数哪里不符?修正参数后再调用
权限拒绝当前任务是否具备所需授权?使用已有权限内的路径,或说明需要什么帮助
返回内容与任务无关来源、版本或检索条件是否错了?调整材料选择,而非仅重复摘要
返回空内容是页面确实为空,还是抓取方式不适用?区分“没取到”和“内容不存在”

参数错误通常需要改参数,权限问题通常需要改变授权条件,旧版本材料需要换材料。把这些错误全部当作暂时网络问题,增加重试次数只会扩大浪费。

超时也可能意味着“做了,但没拿到确认” ​

读取网页通常不会改变外部状态,重读的主要代价是时间和请求开销。把任务改成“将简报发给同事”之后,情况就不同了。

假设发送工具显示超时,邮件可能没有发出,也可能已经发出,只是确认结果没回来。此时原样重发,可能让收件人收到两封。没收到成功确认,不等于动作没有发生。

合理的下一步是先核对发送状态,或利用服务提供的去重机制,再决定是否重试。Hermes 的循环可以容纳这样的核对步骤,但它不能凭一次超时就替所有外部系统判断是否执行成功。是否允许自动重试,还取决于动作会不会留下外部影响,以及结果能否查证。

3.5 一轮有多个工具时,结果怎样接回来 ​

在前面的六轮图里,一轮只画了一个主要行动,方便看清变化。真实任务中,模型也可能一次提出两个读取请求:一份发布说明、一份对应的功能文档。

如果两次读取互不依赖,并发执行可以减少总等待时间。如果第二次读取的地址必须从第一份结果中提取出来,就不能靠同时发出两个请求来省掉这个依赖。并发适合独立工作,不能消除信息依赖。

Hermes 在处理一批工具调用时,可以并发执行多个调用;需要交互的调用则有顺序执行的处理。每个调用都有对应标识,用来把返回结果配回原请求。并发结果回到消息序列时,按原来的请求顺序放回,而不是按谁先完成就把谁放前面。

为什么要维护这个对应关系?假设请求 A 读取发布说明,请求 B 读取功能文档,B 先返回。如果把 B 的正文当作 A 的结果,后续模型可能把功能文档中的条件误认为发布说明已经确认的变化。内容是真的,归属却错了,判断仍会出问题。

一批调用里也可能一个成功、一个失败。这意味着只取得了一部分材料,不能因为其中一个成功,就把整轮记成“资料齐全”。下一轮应该利用已取得的部分,只对剩余缺口继续工作。

为什么记录过程也是循环的一部分 ​

一个更隐蔽的问题发生在记录失败时。工具结果已经在内存里,记录却没有保存成功,此时是否继续请求模型?

在本章依据的 Hermes 版本中,工具调用进入执行前有保存步骤;若这个步骤失败,不继续执行该批工具。工具执行后的结果记录若发生关键失败,也会停止当前轮次,不把仅存在于内存中的结果继续喂给模型。

这是一项明确的取舍:宁可中断当前推进,也要避免实际执行、模型所见和可恢复记录之间继续拉开差距。 对一个可能跨入口、跨时间运行的 Agent 来说,记录不是事后附加的聊天存档,它参与维持过程的一致性。

但记录成功也不等于外部动作成功,更不意味着失败时已经执行的动作会自动撤销。刚才的邮件例子仍然成立:外部服务的实际状态,需要对应的确认方式。

3.6 预算控制的是运行,不是答案质量 ​

如果模型一直觉得“还可以再查一点”,循环可能无限延长。工程上需要一个不依赖模型自觉的边界,例如迭代次数上限或运行时间限制。

这两种限制解决的问题不同。次数上限能限制反复调用,但某一次工具执行也可能很慢;时间上限能约束持续时间,却不能保证在结束前取得足够信息。Token 用量是模型读入和生成内容的计量,又会影响费用;它与时间、次数都没有固定换算关系。不能看见其中一种限制,就假定其他开销也被同样精确地限制了。

把六轮案例改成只允许四轮 ​

假设为了讲解,将案例的模型判断限制在四轮。第 4 轮刚从另一个入口读到正文,适用条件仍未核实,正常查证预算就用完了。

此时增加预算可能有用,因为已经找到可访问的材料,剩余问题也很明确。但如果四轮都在重复一个权限被拒绝的请求,增加预算很可能只允许更多次失败。提高上限之前,先看剩下的是值得继续的工作,还是没有改变条件的重复。

Hermes 的迭代计数也有比这张教学时间线更具体的规则。例如,部分恢复重启会退回迭代计数,某类程序化工具调用也有特殊记账处理。因此,“六个模型响应”与“预算恰好扣六次”不能直接画等号。

预算耗尽后,为什么还可能有一段总结 ​

立刻切断运行,用户可能只看到最后一次工具返回,无法知道做到哪里了。继续无限查证又违背了预算的目的,所以“继续做事”和“整理已有进展”需要分开。

Hermes 存在这样的收尾路径:在预算耗尽、没有可用最终答复,并且不是中断或其他失败退出等条件下,额外请求模型用已有信息做总结,不再让它通过工具继续推进。部分路径会保留已有候选答复,而不是重新生成。

这不是给所有退出都承诺一次总结,也不意味着总调用数永远严格等于设置的迭代上限。它表达的是一种产品选择:限制行动的同时,尽量留下可理解的进展说明。收尾请求本身仍可能失败,也仍然消耗时间和模型用量。

如果要严格控制整次任务的开销,还要考虑重试、收尾和委托等路径。Hermes 的子 Agent 有自己的迭代预算,父 Agent 的上限不能直接当作父子总消耗的上限。第十一章再讨论委托带来的额外成本。

3.7 什么时候应该停:先分清三种“结束” ​

在简报案例中,程序可能正常结束,用户却仍然没有得到可靠的简报。要判断到底完成了什么,可以把三个问题分开:

判断层次它回答的问题在简报案例中意味着什么
工具执行结束这次读取有结果了吗?可能拿到正文,也可能拿到超时错误
本次循环结束程序还会继续请求模型或执行工具吗?正常答复、达到限制、取消、失败都可能导致结束
用户目标完成原先要求的交付条件满足了吗?版本、结论、条件和未确认范围是否交代清楚

工具成功,只能说明某个动作完成了;模型写了最终答复,说明它准备交付。两者都需要与最初任务核对,才能判断目标是否完成。Hermes 的停止处理、异常恢复和记录机制,可以减少部分不完整退出,却不能普遍证明简报里每个结论都正确。

图 3-4 教学示意:图中省略了继续查证后的回路。正常交付与说明限制都可以结束当前运行,但代表的完成程度不同。 点击图解可放大
左右滑动查看图解细节
收到工具结果后继续判断:证据足够则交付,信息不足则继续查证,达到边界则说明限制;图中省略查证后的回路

图 3-4 教学示意:图中省略了继续查证后的回路。正常交付与说明限制都可以结束当前运行,但代表的完成程度不同。

信息已经足够:按任务范围交付 ​

第五轮之后,已有材料足以解释机制和适用条件。此时停止的理由是任务所需信息已经齐全,而不是“读了很多页”。

判断“足够”必须回到任务范围。用户只要求一份机制简报,明确说明尚未做运行实测是合理的;用户若要求“验证我当前环境中的表现”,仅凭文档就不够。相同材料能否支持交付,取决于交付承诺是什么。

达到边界:结束运行,承认工作仍有缺口 ​

预算用完、必要资料不可得、缺少授权时,继续行动可能没有条件。有效收尾需要告诉用户:已经确认什么、没有完成什么、为什么停止,以及继续需要什么条件。

下面两段都是教学示意:

较差的收尾:已完成核对。Hermes 会在达到预算后自动总结任务。

更清楚的收尾:已找到与该版本匹配的说明,确认存在预算耗尽后的总结收尾路径;适用条件尚未核对完整。本次已到运行上限,因此先交付阶段性结论。不能据此判断用户取消、服务故障等退出也一定生成总结。

第二段并没有完成全部研究,但它准确交代了当前状态。第一段把一个尚待限定的结论写成普遍保证,会让读者误以为后续不用再核实。

用户取消或系统中断:尊重新的停止条件 ​

用户说“停下”,不需要模型先认定目标完成。Hermes 有中断检查和可中断的等待处理,可以结束当前推进;但“已经收到取消”不能等同于所有外部进程、网络请求和副作用都在同一瞬间消失。

如果简报已经写入文件,取消不会天然把文件还原;如果发送已经到达外部服务,取消也不会自动撤回。后续恢复时,要先确定最后一项动作的实际状态,不能简单把中断前的请求全部重放。

因此,停止原因应该被保留下来。用户主动取消、预算耗尽、模型服务不可用、记录失败,虽然都会让循环停下,却需要不同的解释和恢复方式。

不写代码的小练习 ​

把六轮案例的第 3 轮改成“返回权限拒绝”,其余条件保持不变。为第 4 轮选择一个动作,并补上三句话:它想解决哪个未知?它是否改变了失败条件?如果仍然无法取得材料,准备怎样收尾?

接着把“只读材料”改成“把简报发送出去”,工具返回超时。再做同样的判断。你应该能发现:两个案例都出现了失败,但是否可以重试,取决于错误原因和动作是否已经影响外部世界。

本章要点 ​

  • 行动循环把任务、模型提出的行动、工具真实结果和后续判断连起来。结果必须进入后续上下文,才可能改变下一步。
  • 继续一次行动,要能说清它准备减少哪个未知。有限重试、修正参数和换入口分别适用于不同障碍。
  • 模型服务请求失败与工具执行失败处在不同位置;运行程序的恢复、工具自身的处理和模型的下一步选择不能混为一谈。
  • Hermes 通过调用与结果配对、过程保存、预算和中断来约束运行。这些机制各有成本,也都有适用边界。
  • 工具结束、循环结束和目标完成是三种判断。合理退出可以包含未完成项,可靠交付必须如实说明它们。

理解题 ​

1. 页面连续两次超时,第三次读取成功了。这说明每次尝试都合理吗?

不能只用最终成功倒推每次尝试都合理。要看当时是否有暂时故障的依据、是否设定了边界、是否存在更合适的入口,以及动作能否安全重复。偶然成功不能替代重试策略;反过来,一次有边界、有依据的尝试失败了,也不表示那次决策必然错误。

2. 模型一次请求读两份文档,其中一份成功,另一份超时。下一轮应该怎样理解这批结果?

将两个结果分别对应到原来的读取请求。成功结果只证明拿到了那份材料,超时结果说明另一份仍然缺失。若缺失部分影响结论,就继续补齐或明确限制;不能把整批调用概括成“资料读取成功”,也没有必要丢掉已取得的材料全部重来。

3. 迭代上限是十,观察到的模型服务请求却超过十次,一定是预算失效了吗?

不一定。先核对计数口径:是否包含失败重试、恢复路径、收尾请求或子 Agent 请求;迭代预算是否对特定调用有特殊记账。若要求严格的总费用或总时长边界,不能只依赖一个迭代次数设置。需要沿真实运行路径核对,而不是只比较两个数字。

4. 预算耗尽后,Hermes 生成了完整的三段简报。怎样判断任务是否完成?

先按原始要求检查内容,再看停止原因。三段文字可能只是已有材料的总结;格式完整不代表条件已核实。应逐项确认版本是否匹配、结论是否有材料支持、未确认范围是否披露。如果原任务还要求环境实测或发送简报,也要单独核对,不能因为出现最终答复就视为都已完成。

下一章继续看循环中的“执行工具”:模型提出的请求怎样被理解和执行,工具调用、MCP 与 Plugins 又分别解决什么问题。

社区学习手册 · 正文与原创图解 CC BY-SA 4.0 · 代码 MIT