首页 / 文章

AI智能体的循环结构设计:五个组成部分、四种形态及LangGraph实现方式

AI智能体的循环设计:五个部分、四种常见形态、LangGraph中的验证与重试研究智能体、故障防护机制,以及何时不应使用循环。

发布者:REACTAPP.TOP阅读约 15 分钟3382 词

来源: Loop Engineering with Agents

每个人工智能智能体都在循环中运行,但几乎没人会刻意设计这种循环。正是这一差异使得有些智能体能安静地完成任务,而另一些则会在自以为取得进展的同时一夜之间耗尽预算。填补这一差距的实践有个专门名称:循环工程。

从结构上看,它其实很简单。在每个步骤中,智能体会思考该做什么,执行诸如调用工具或进行搜索之类的操作,查看结果后再再次思考。这种推理、行动与观察的循环正是 Claude Code 和 Cursor 等工具的底层机制。有一段时间,人们更需要的技能是提示词工程,即尽可能精准地表述需求。而那些能够执行操作、进行搜索并阅读自身输出的系统则引出了一个更大的问题:究竟是什么决定了智能体的下一步行动,又是什么让它停止?

循环设计是一种刻意这样做的习惯。设计者先确定目标、检查条件以及终止点,然后构建一个简洁的系统,该系统仅明确一次目标,让智能体持续迭代直至任务完成。责任从逐步指导智能体转变为解决指令中可能出现的问题。

这是个很好的理念,但也是最困难的部分的起点。糟糕的循环会浪费资源、永无止境,或者自欺欺人地认为自己在取得进展。优秀的循环则讲究高效,能在恰当时机停止,并输出可靠的结果。更聪明的提示语无法缩小这一差距,而更好的循环却可以。

下面的示例使用 LangGraph,是因为它能清晰地展示循环的结构,但这里的内容并不局限于某一特定框架。同样的原理也适用于其他智能体框架或纯手写代码。框架可能会变化,但核心概念始终不变。

智能体循环的五个组成部分

在决定何时使用循环之前,先了解其构成结构会很有帮助。几乎所有的智能体循环都包含五个部分。

  • 触发器。某些事件会启动流程,比如有人输入“开始”,调度器触发,有工单到达或有人提交了拉取请求。如果没有触发器,智能体就会处于闲置状态。
  • 可验证的目标。循环必须明确“完成”的标准,最好是机器能够确认的形式。仅追求应用功能完善会导致无止境的迭代——要么让所有测试都通过,要么给出所有结论均有来源的答案,从而真正设定完成节点。
  • 工具。智能体既要能够执行操作,也要能观察结果,比如运行代码并读取错误信息,或搜索网络并查看搜索结果。如果环境从不反馈,智能体就只能靠猜测。
  • 状态。这是任务当前的进展状况:迄今为止的尝试次数、发现的结果、已完成的轮数。这是循环设计中最棘手的部分,因为过大的状态量会使得有用信息被噪声淹没。
  • 停止规则。它们决定了循环何时结束,共有三种情况:成功意味着目标已达成;放弃意味着尝试次数已用完;转交则意味着循环遇到了风险或不确定的情况,因此选择将问题交给他人处理而非自行猜测。

后续关于何时应该使用循环、何时不应使用以及如何使用的讨论,其实都源于这五种停止规则。

何时循环能带来成效

当仅一次模型遍历不足以完成任务,且任务确实需要智能体不断尝试、检查后再重复操作时,循环才显得有必要。有四个信号表明了这种情况。

  • 结果可被验证。这是最重要的。当某个结果可以通过测试通过或失败、响应是否引用了真实来源、JSON数据是否有效等方式自动检测时,循环就可以利用这些检测来找到正确答案。验证就像方向盘,而没有它的循环只会白白浪费资金。
  • 第一次尝试往往有误但可修正。代码、研究草稿以及杂乱数据的整理都会在反复实践中不断改进。智能体先生成某种结果,发现其中的缺陷后再加以修正。
  • 没人知道需要多少步骤才能解决。某种类型的问题今天可能需要两步,明天则可能需要七步。固定的流程无法如此灵活调整,而能够持续运行直至目标达成的循环则可以。
  • 没有人在监视。在夜间处理工单,或不断重试那些不稳定的集成直到其正常运行,都需要一个能够自行决定下一步操作而无需等待指令的系统。
  • 一个合适的例子是能够自我审核研究结果的研究代理。它会先草拟回复,检查各论点是否有相应依据,然后回到那些证据不足的部分继续深入研究。它会不断循环,直到回复完善或达到某种限制。这四种信号都存在,这样的代理结构会在后续进一步构建。

    循环的常见形态

    大多数代理循环都是几种基本形态的变体。识别这些形态有助于在开始整合任何组件之前确定问题属于哪种类型。

    生成与验证,有时也称为反射机制。首先创建一个输出结果,然后通过第二个步骤对其进行检查,这一过程会不断重复,直到检查通过为止。反馈信号为二元形式:要么通过验证,要么指出存在的问题。该方法适用于那些可以测试正确性的场景,比如需要通过测试的代码,或是其结论需要得到支持的科研工作。这便是后续要构建的模型形式。

       +-----------+      +-----------+
    -->| Generate  |----->|  Verify   |----- pass -----> [ done ]
       +-----------+      +-----+-----+
            ^                   |
            +------- fail ------+
    

    当存在可验证的正确性测试时,应选择此方法,且智能体需持续修复直至测试通过。一个执行查询并循环直到语句运行并返回合理结果的SQL编写智能体就是典型例子。

    评估器与优化器,也称为生成器与评分器。评分器会对每次尝试给出评分而非简单的通过或失败判定,循环过程会朝着最高分目标前进,而不仅仅是追求正确结果。在无法明确判定通过或失败,但仍然可以衡量优劣程度的情况下,这种方法很有用,比如调整提示词、优化广告文案或对结果进行排序时。

       +-----------+      +-----------+
    -->| Generate  |----->|  Score    |--- good enough --> [ done ]
       +-----------+      +-----+-----+
            ^                   |
            +-- improve --------+
                (use the score)
    

    当质量尚可量化时便对其进行评估。通过为产品标语设定评分标准来衡量其清晰度与感染力,再通过循环机制筛选出最佳方案,以此展现创意。

    规划、执行、重新规划。规划者制定步骤,执行者负责落实,而一旦某个步骤出现意外情况,循环机制便会促使人们重新调整计划。该循环围绕整个计划展开而非仅针对单一输出,因此非常适合研究或软件项目这类需要多步骤处理的开放性工作。

       +-----------+      +-----------+
    -->|   Plan    |----->|  Execute  |-- all steps done --> [ done ]
       +-----------+      +-----+-----+
            ^                   |
            +-- replan ---------+
                (hit a surprise)
    

    当任务包含多个步骤且并非所有步骤在初始阶段就能明确时,可选择此方式。将服务迁移到新框架也是可行的:先规划好各步骤,开始执行,一旦某个步骤出现意外的依赖问题,再重新规划。

    定时或监控循环。与单次运行中逐步实现目标不同,这种模式会在定时器触发或事件发生时启动,以便进行监控和响应,例如对新的工单进行分类处理、检查是否有构建失败,或是重试不可靠的任务。它跨越不同时间点,不会局限于单个任务之内。

       +-----------+     +-----------+     +-----------+
    -->|   Wait    |---->|   Check   |---->|    Act    |---+
       | (timer /  |     +-----------+     +-----------+   |
       |  trigger) |                                       |
       +-----------+ <-------------------------------------+
            (no fixed end — keeps watching over time)
    

    当不存在单一的终点线,目标在于持续监控并作出反应时,就可以采用这种方式,就像每隔几分钟查看一次收件箱,或每晚检查一次过期的拉取请求。

    这些模式并非相互排斥。实际系统往往会将它们嵌套使用,例如设置定时循环,在每次启动时执行生成与验证操作。最常见的模式就是生成与验证,接下来将介绍如何从头到尾构建这种模式。

    使用 LangGraph 构建循环

    需要构建的智能体是一名不信任自己初稿的研究人员。面对问题时,它会收集信息、撰写答案,然后逐一将每个论点与真实来源进行事实核查。缺乏依据的论点会被送回继续研究。这一循环会持续进行,直到形成完整的答案,或者达到重试次数上限,此时智能体会返回其最佳版本,并标明仍不确定的部分。简而言之,它先给出答案,再说服自己该答案是正确的,之后才将其呈现出来。

    这种自我核查的行为正是“生成与验证”循环,因此能够确保初次生成的结果就较为准确。

    LangGraph是个很好的匹配选项,因为它将智能体描述为图结构。节点代表执行任务的单元,边则代表决定下一步操作的方向。边允许指向反向,这正是形成循环的条件。简单的线性链无法重复自身,但图结构可以。

    该研究者有三项工作,因此对应三个节点。前两个节点将工作分为执行者与检查者,即执行者与批评者,这种分离方式在循环结构中很常见。

                        +------------------+
      START ----------> |     Research     | <-------------+
                        | (draft / revise) |               |
                        +--------+---------+               |
                                 |                         |
                                 v                         | needs work
                        +------------------+               | (+ feedback)
                        |      Verify      |               |
                        |  (check claims)  |               |
                        +--------+---------+               |
                                 |                         |
                                 v                         |
                           +-----------+   needs work      |
                           |  Decide   |-------------------+
                           | (router)  |
                           +-----+-----+
                                 | verified / out of tries
                                 v
                              [ END ]
    
    1. 研究阶段负责收集资料并起草答案。
    2. 验证阶段会审查草稿,检查每个论点是否有依据。
    3. 决策阶段则是一个小型路由器,它根据验证结果决定下一步行动:完成工作,还是返回去进一步研究存在的薄弱环节。

    该示例在Python 3.12环境下运行,需要三个软件包:

    pip install langgraph==1.2.6 langchain-openai==1.3.3 pydantic==2.13.4
    
    • langgraph 是用于处理图结构和循环的引擎,包含 StateGraph、START 和 END 等组件。
    • langchain-openai 将 OpenAI 聊天模型封装为 ChatOpenAI 类。
    • pydantic 用于定义验证器返回的结构化结果。

    在运行之前,环境中还必须准备好 OpenAI API 密钥:

    export OPENAI_API_KEY="your-key-here"
    
    from typing import TypedDict, Literal
    from langgraph.graph import StateGraph, START, END
    from langchain_openai import ChatOpenAI
    from pydantic import BaseModel, Field
    
    # A model client on OpenAI's Responses API, with the built-in web-search tool
    # bound on — so the model can search the web itself, no extra package needed.
    # "gpt-5" is a reasoning model; swap it for any current model you have access to.
    llm = ChatOpenAI(model="gpt-5", use_responses_api=True)
    searcher = llm.bind_tools([{"type": "web_search"}])
    
    MAX_ITERATIONS = 3         # a stop rule, decided up front
    
    # STATE — the shared memory passed between every node
    class ResearchState(TypedDict):
        question: str          # what we're answering
        draft: str             # the current best answer
        verdict: str           # "verified" or "needs_work"
        feedback: str          # what the verifier said to fix
        iterations: int        # how many times we've looped
    
    # The verifier returns a typed result, so the router gets a clean
    # "verified" / "needs_work" to branch on instead of parsing prose.
    class Verdict(BaseModel):
        status: str = Field(description='"verified" or "needs_work"')
        feedback: str = Field(description="claims lacking support, if any")
    
    # NODE 1 — the maker: search the web, then draft (or revise) the answer.
    def research(state: ResearchState) -> dict:
        prompt = "Search the web, then answer the question. Back every claim with a source.\n"
        if state.get("feedback"):
            prompt += f"A reviewer flagged these gaps — fix them:\n{state['feedback']}\n"
        prompt += f"\nQuestion: {state['question']}"
        draft = searcher.invoke(prompt).text
        return {"draft": draft, "iterations": state["iterations"] + 1}
    
    # NODE 2 — the checker: search for evidence, then critique the draft.
    def verify(state: ResearchState) -> dict:
        evidence = searcher.invoke(
            f"Search the web for evidence to fact-check claims about: {state['question']}"
        ).text
        checker = llm.with_structured_output(Verdict)
        result = checker.invoke(
            "You are a fact-checker. Using the evidence below, reply 'verified' "
            "only if every claim in the answer is supported; otherwise 'needs_work' "
            "and list the unsupported claims as feedback.\n\n"
            f"Evidence:\n{evidence}\n\nAnswer:\n{state['draft']}"
        )
        return {"verdict": result.status, "feedback": result.feedback}
    
    # ROUTER — the heart of the loop. Reads the verdict, picks the next step.
    def decide(state: ResearchState) -> Literal["research", "__end__"]:
        if state["verdict"] == "verified":
            return "__end__"                      # success: goal met
        if state["iterations"] >= MAX_ITERATIONS:
            return "__end__"                      # surrender: out of tries
        return "research"                         # loop back and fix the gaps
    
    # WIRE IT UP
    graph = StateGraph(ResearchState)
    graph.add_node("research", research)
    graph.add_node("verify", verify)
    
    graph.add_edge(START, "research")            # trigger
    graph.add_edge("research", "verify")         # always verify a fresh draft
    graph.add_conditional_edges("verify", decide, {
        "research": "research",                   # the backward arrow = the loop
        "__end__": END,
    })
    
    agent = graph.compile()
    
    result = agent.invoke({
        "question": "What were the main causes of the 2008 financial crisis?",
        "draft": "", "verdict": "", "feedback": "", "iterations": 0,
    })
    print(result["draft"])
    

    有两个要点值得注意。其一:两个节点均通过 OpenAI 内置的 web_search 工具并借助 bind_tools 功能接入实时网络。research 节点在撰写内容前会先进行搜索,以确保其结论有实际数据支撑;verify 节点则会再次搜索,用最新获取的证据而非模型内存中的信息来验证初稿,正是这次二次搜索为循环流程提供了客观依据。其二:verify 节点依赖于 with_structured_output 功能,该功能要求输出结构化的 verdict 和 feedback,而非普通文本,这样路由器就能在无需解析自由文本的情况下可靠地选择处理路径。

    循环流程的五个部分与代码对应关系十分清晰:

    • 触发条件:通过调用 invoke(...) 并传入问题即可启动流程。
    • 可检查的目标:将规则标记为verified或needs_work状态以进行验证。
    • 工具:两个节点均使用内置的网页搜索功能、research功能用于撰写内容,以及verify功能用于检查。
    • 状态:ResearchState字典负责在各个节点之间传递草稿、反馈信息以及迭代次数。
    • 停止规则:decide路由器在任务成功完成或达到MAX_ITERATIONS次迭代时终止运行。

    最后一点至关重要,因为循环设计的核心就在路由器中。仅用一行代码——若验证通过则停止,尝试三次后停止,否则返回重新处理——就能区分出那些能够持续改进答案的智能体与那些会无限消耗资源的智能体。

    该示例包含两个退出路径。实际应用中的循环往往还会增加第三个路径,即转交给人处理。遇到风险或不确定的情况时,智能体不应盲目猜测或默默停止,而应暂停并利用已收集的所有信息向上级汇报。在路由机制中,这只不过是又一个分支:当置信度较低或操作较为敏感时,escalate路径会终止循环,并展示草案、未解决的问题以及已进行的尝试。懂得何时不应做出决策是良好循环设计的重要体现。

    故障模式及其防护措施

    一旦循环开始自动运行,就会出现一些可预见的故障,每种故障都有相应的标准防护措施。

    • 无限循环。智能体永远不会认为任务已完成,会持续运行直到出现故障或资金耗尽。限制循环次数的方法是通过硬性上限,比如上文提到的MAX_ITERATIONS,这种退出机制不依赖智能体自身的判断。
    • 令牌消耗。每次迭代都会重新处理越来越多的上下文信息,导致成本在不知不觉中上升。应仅保留下一步所需的内容,即当前的草稿和具体反馈,而无需保存完整的历史记录,以此保持状态简洁。
    • 虚假进展。智能体会宣称已取得实际并未实现的成果,比如声称已修复了根本不存在的问题。绝不能让它在自己认为重要的方面自行标记完成状态。应通过独立的验证步骤,借助客观测试、实际运行的测试或真实存在的来源,来确保真正完成的任务才能被认定为已完成。
  • 重复同一个错误。循环会不断尝试相同的失败操作,并得到同样的失败结果。应将之前的失败信息传递到下一次尝试中,以便改变处理方式,这就是为什么research函数会接收验证器的feedback。
  • 缺乏可追溯性的操作。在长时间运行后,很难弄清楚发生了什么以及原因。需要记录每一步:智能体看到了什么、做出了什么决定以及采取了什么行动。一旦循环涉及到任何重要内容,可观测性就不再是可选的,而LangSmith之类的工具正是用于追踪此类运行的。
  • 从一开始就实现完全自主。从第一天起就无监督运行的循环尚未赢得信任。应分阶段推进:首先是仅输出报告的模式,说明它打算做什么;接着是有人员审核的辅助修改;最后才是无人值守的运行,每个阶段都需要在前一个阶段获得认可后才能进入下一个。
  • 何时不应使用循环

    循环功能强大,因此很容易被过度使用。在以下情况下,采用更简单的方法更为合适。

    • 一次处理即可。 摘要文档、翻译文本、回答事实性问题以及分类邮件都属于只需完成一次的任务。围绕这些任务使用循环只会增加成本、延迟,并带来新的出错可能。如果按顺序执行步骤就能解决问题,那就直接按顺序操作。
    • 无法判断是否成功。 当目标具有主观性或模糊性,或者只有人类才能判断时,循环就失去了判断依据,可能会随机结束或无限循环。无法验证的目标只会让程序变成一台老虎机,而非循环结构。
  • 错误可能带来高昂代价或造成永久性损害。如果每次循环都发送邮件、转账或删除数据,很快就会造成严重后果。应让相关人员持续参与审批流程,或避免对后续操作进行循环处理。
  • 速度与成本比自主性更重要。每次循环都会增加调用次数、消耗更多资源并占用更多时间。在处理高流量、利润微薄或对延迟敏感的功能时,一个可预测的单一调用往往比复杂但成本高昂的循环更优。
  • 一个经验法则:如果无法明确写出成功与放弃的条件,那就说明还不适合构建该循环。

    循环前的检查清单

    循环设计决定了任务的完成方式。编写完美的提示语远不如设计引导智能体的系统重要,后者包括触发条件、目标、工具、状态以及停止规则。即便如此,循环也只是众多工具之一,并非默认选择。首先应思考以下五个问题:

    1. 能否自动检测是否成功?如果无法检测,则无需使用循环,因为这样就没有依据来引导任务进展。
    2. 重复执行后任务效果会更好吗?如果一次执行就足够,那就保持简单。
    3. “完成”到底意味着什么?在编写代码之前先明确成功的标准。
    4. 何时应该停止?设定明确的限制,防止循环无限运行。
    5. 这些操作可以安全重复吗?如果某次迭代可能造成实际损害,应设置人工检查点或跳过该步骤的循环。

    只要对这五个问题给出诚实的回答,就能形成可靠的循环机制,而不仅仅是表面上的好看效果。最理想的是从一个小规模项目开始:按照上述方法进行一次研究与验证,同时在项目规模扩大之前就明确好停止规则。

    最后一点:循环机制的作用不仅仅是加快工作进度,它还会放大最初投入的判断力,以机器般的速度重复那些正确的决策和错误的决策。因此,目标并非仅仅建立好循环机制后就置之不理,而是要保持足够的关注度,持续了解该机制在独立运行后的表现,这样设计者才能始终扮演其维护者的角色,而不仅仅是按下启动按钮的人。

    相关阅读

  • 实用笔记:sys.exit(0) 漏洞:AI智能体如何伪造成功 — 《实用笔记:sys.exit(0) 漏洞:AI智能体如何伪造成功》的详细操作指南:为采用该模式的团队提供的接口定义、校验规则及可直接插入的代码片段。
  • 实用笔记:构建多智能体AI平台——第5部分:感知能力 — 《实用笔记:构建多智能体AI平台——第5部分:感知能力》的详细操作指南:为采用该模式的团队提供的接口定义、校验规则及可直接插入的代码片段。
  • 实用笔记:Agent Loop 工程:从博客到生产级 AI 的完整指南 — 该指南为采用此模式的团队提供了可操作的详细步骤,包括相关契约、校验机制以及可直接使用的代码片段。