循环工程:利用验证器和停止规则构建智能体循环。
构建四个堆叠式智能体循环的实用指南:ReAct基础、评分系统、LangGraph路由、循环契约、事件触发器以及爬山算法与故障防护机制。
这一切背后的思路其实很简单:不要再逐条指令地操控人工智能,而应设计它所处的循环结构。需要牢记的是,限制你可信任范围的是验证器而非模型本身,可以想象的是四个相互嵌套的循环。具体构建方法包括:循环的各个组成部分、每层的代码实现、循环出错的原因,以及防止其耗尽预算的停止规则。掌握这些之后,即便你在睡觉时,也能让循环自动准备拉取请求。
代码示例均遵循已文档化的API,模型ID仅为占位符,任何仅为伪代码的片段都会在开头注释中说明。文中会贯穿一个典型示例,这也是该领域的常规入门案例:一个能够重现故障测试、修复问题、让非代理自身机构对修复结果进行验证,并最终创建草稿拉取请求的编程循环。
循环的五个组成部分
无论使用何种框架,一个完善的循环始终由五个部分构成。缺少其中任何一部分,循环都会出现异常、停滞或无限运行。
- 触发器。启动循环的要素,可以是人工输入、定时触发、Webhook消息或新的数据行。
- 机器可检测的目标。“让测试通过”符合要求,而“改进代码”则不符合。如果软件无法判断目标是否达成,循环同样无法做到。
- 能提供实时反馈的工具。代理需要通过运行代码、读取错误信息或调用API来对现实世界采取行动并查看结果。
- 精简且受控的状态管理。需保留目标、临时记录以及已尝试过的操作日志。过大的状态会导致循环运行变慢、偏离轨道并超出其上下文限制。
应规划三种退出方式而非两种。成功:验证通过,即可交付结果;放弃:预算或迭代次数已达上限,需停止并总结剩余工作;转交:智能体遇到了仅应由人类做出的决策,因此需要升级处理。设计良好循环的关键在于识别出它不应自行处理的场景。
循环1:智能体循环
所有智能体都在运行的核心流程就是2022年提出的ReAct模式:思考、通过调用工具执行操作、观察结果,然后重复此过程直至完成。到了2026年,这一流程已被刻意设计,不再依赖人工干预。在其最简单的形式中,仅包含一次函数调用:
from langchain.agents import create_agent
def run_tests() -> str:
"""Run the project's test suite and return the raw output."""
…
agent = create_agent(
model="anthropic:claude-opus-5",
tools=[run_tests],
system_prompt="You are a careful Python engineer. Fix failing tests.",
)
# create_agent returns a graph that calls tools in a loop, repeating
# until the model replies with no tool calls. The loop runs on .invoke()
那段简短的代码其实隐藏着一个循环,你应该能够想象出来。下面是同样的控制结构,仅以伪代码形式呈现,且未使用任何框架。请注意,所有的退出路径都是有限制的:
# PSEUDOCODE - shows the control structure a harness implements.
# The helper names below are yours to supply, not a real library API.
def run_loop(goal):
state = init_state(goal) # goal + scratchpad + attempt log
for step in range(MAX_STEPS): # hard cap: never loop forever
thought = model.reason(state) # ReAct: reason…
action = model.choose_action(state) # …then pick a tool call
result = tools.execute(action) # touch the real environment
state = update(state, thought, action, result)
state = compact(state) # keep context under budget
if verifier.passes(state): # deterministic check = reward
return success(state)
if no_progress(state) or budget.exhausted():
return escalate_to_human(state) # third exit: hand-off
return escalate_to_human(state)
在所有这些形状中,请记住这个。其余的都是它的变体。
循环2:添加验证器
单纯的智能体会自行决定何时完成任务,而依赖这种方式就容易导致虚假的成功结果。因此需要将智能体封装在评估器中,使其根据评分标准检查自己的工作。当检测到问题时,会将反馈重新传回智能体,循环继续进行,直到达到上限。验证中间件位于 deepagents 包中。
from deepagents import RubricMiddleware, create_deep_agent
from langchain.messages import HumanMessage
from langgraph.checkpoint.memory import InMemorySaver
RUBRIC = """
- All tests pass in run_tests
- No test is skipped or deleted to force a pass
"""
agent = create_deep_agent(
model="anthropic:claude-opus-5",
system_prompt="You are a careful Python engineer.",
middleware=[
RubricMiddleware(
model="anthropic:claude-haiku-4–5", # a cheap grader is fine
system_prompt="Grade against the rubric. Be strict.",
max_iterations=5, # the stop rule (default is 3)
),
],
checkpointer=InMemorySaver(),
)
# The rubric is passed at invoke time - not to the constructor.
result = agent.invoke(
{
"messages": [HumanMessage("Make the failing tests pass.")],
"rubric": RUBRIC,
},
config={"configurable": {"thread_id": "fix-tests-session"}},
)
其工作原理如下:每当智能体即将完成任务时,一个独立的评分子智能体会根据评分标准读取对话记录。若判定为needs_revision,则会将反馈以HumanMessage的形式重新放入对话中,智能体随后继续处理。只有satisfied、failed、max_iterations_reached和grader_error这几种情况才会使循环结束并终止流程。如果评分器需要自行执行实际检测,可为其提供作为BaseTool实例的工具。
验证器有两种类型,合理选择是关键所在。
- 确定性验证器:执行测试、验证架构并确定分数。成本低、速度快且不会给出虚假结果,因此应优先尝试这类验证器。
将其转化为图结构
当任务不再简单时,显式的图结构比隐藏的循环结构更佳:节点、边以及停止决策的节点都一目了然。一个研究智能体可由三个节点构成,所有的停止决策都由路由器来决定:
from typing import Literal, TypedDict
from pydantic import BaseModel, Field
from langgraph.graph import END, StateGraph
class ResearchState(TypedDict):
question: str
draft: str
verdict: str
feedback: str
iterations: int
class Verdict(BaseModel):
status: str = Field(description='"verified" or "needs_work"')
feedback: str = Field(description="claims lacking support, if any")
def decide(state: ResearchState) -> Literal["research", "__end__"]:
if state["verdict"] == "verified": # success exit
return "__end__"
if state["iterations"] >= MAX_ITERATIONS: # surrender exit
return "__end__"
return "research" # else: loop again with the feedback
builder = StateGraph(ResearchState)
builder.add_node("research", research_node) # generator
builder.add_node("verify", verify_node) # verifier
builder.add_edge("research", "verify")
builder.add_conditional_edges(
"verify", decide, {"research": "research", "__end__": END}
)
builder.set_entry_point("research")
graph = builder.compile()
那段代码中并没有什么巧妙的提示语句,真正的智慧体现在结构上:一个节点负责生成结果,另一个节点负责验证,而路由器则将验证结果转化为继续执行并反馈信息或停止执行。LangGraph将哨兵标记__end__与END视为相同的东西。
循环契约
正是在这里,思维方式的转变变得具体化。你不再需要编写指令,而是只需描述“完成”的条件,也就是奖励函数以及停止规则。这些内容就是你需要审查、对比并提交的成果:
目标:在 payments-refactor 分支上实现绿色 CI 构建。所谓“完成”,意味着所有测试都通过,且没有为作弊而跳过或删除任何测试。步骤:阅读失败的测试用例,修复可能的原因,然后重新运行。记忆机制:记录已尝试过的方法,避免重复操作。一旦出现绿色状态,就提交草稿 PR;经过六轮尝试后,总结剩余工作;或者当涉及身份验证或支付逻辑时,将任务交给其他人处理。
没有任何指令被输入模型。实际编写的内容包括目标、检查项、记忆规则以及三种退出条件,而这套规则体系就是循环工程。
第3和第4个循环:向外层叠加
一个设计良好的单个循环就已经很有帮助了。如果在它之外再包裹更多循环,且每个循环的运行速度更慢,其效果会呈指数级提升。第1和第2个循环负责完成正确的工作,而第3和第4个循环则使其具备连续性并能够自我改进。
循环3:事件
外部事件会将你的循环从由你调用的工具转变为可自动运行的服务。在任何内容发布之前,这里也是设置人工审批环节的理想位置:
# Loop 3: an event turns the loop into a service
from pydantic import BaseModel
class CIEvent(BaseModel):
branch: str
@app.post("/webhook/ci-failed")
def on_ci_failure(event: CIEvent):
if not event.branch.startswith("fix/"): # cheap triage first
return {"skipped": True}
result = agent.invoke(
{
"messages": [HumanMessage(
f"Fix the failing test on {event.branch}.")],
"rubric": TEST_GREEN_RUBRIC,
},
config={"configurable": {"thread_id": event.branch}},
)
open_draft_pr(result) # a human approves the merge, not the loop
return {"opened_pr": True}
第4轮循环:爬山法
最外层的循环速度最慢,它作用于循环本身。每次运行都会留下痕迹。分析模块会读取这些痕迹,找出不断重复出现的故障,并提出对相关组件的修改建议:包括提示语、工具以及供人类审核的评分标准。想象一下返回箭头——它不只是向起点反馈信息,还会深入到内层循环并对其进行修改。系统正在自我改进。
需要注意一点:外层循环会放大其内部的内容。只有当内层验证机制足够强大时才添加外层循环,因为在一个薄弱的验证机制基础上再加第四轮循环,只会大规模地生成错误的结果。
为何这属于工程实践
这些约束措施看似繁琐的官僚程序,但一旦将智能体视为闭环反馈控制器——一种点对点的映射关系——就不再有这种感觉了。目标值即为设定点,智能体则是控制器,而各种工具与环境共同构成被控系统。验证器则充当传感器的角色,它发出的“需要改进”判定即为误差信号,用于触发后续的修正动作。任务完成意味着系统已收敛。无论被控系统是喷气引擎还是测试套件,控制器都会根据设定点与传感器读数之间的差异来驱动运行。
同样的术语用于描述循环终止的两种方式:一种是振荡,无限重复同一修复步骤;另一种是发散,在资金不断消耗的同时逐渐偏离目标。约束条件不过是维持其行为范围的稳定性要求,而最重要的规则是安全机制必须确保程序能够终止,因为无法信任智能体来完成这一任务。
四种循环共同作用的一天
观察这四种循环在一天早晨中的运作过程。09:14时,支付重构相关的测试失败,随之触发了一个webhook,即第三种循环的启动,而此时并没有人进行任何操作。在接下来的七分钟内,智能体会读取失败信息、应用修复、重新运行测试,再次遇到新故障后又继续修复,并记录下所有的尝试过程(第一种循环)。每轮结束后,确定性评估工具会运行整套测试,确保没有为强行通过而跳过任何步骤(第二种循环)。到第四轮时,测试结果即为合格。
在09:22时,循环会以正确的方式结束,此时会生成一份说明变更内容及原因的PR草案。由于该变更涉及支付功能,必须由人工进行审批。在夜间,自动检测机制发现这是当周第三起时区相关错误,于是会生成一份新的检查规则草案,随后进入你的审核环节(第4轮循环)。明天的处理流程会比今天更高效。
你几乎错过了整个过程。早上只有待审核的PR草案以及需要做出的决定,却没有键盘可以操作。
当循环出错时
循环具有放大效应,且这种放大作用是双向的。每种故障模式都会在循环的特定位置产生影响,并都存在标准的防护机制,其核心原则始终如一:负责生成内容的模块绝不能同时承担评判功能。最简单的防护方法是在让验证器独立运行之前,先用已知正常的输入和已知异常的输入对其进行测试,确保它能拒绝那些异常输入——因为未经测试的验证器只不过是一种带有成本限制的观点而已。
何时不应构建循环
急于对所有内容都使用循环,本身就是一种故障模式。在以下情况下应将其视为单次调用即可:
- 只需一次处理就足够了,比如总结、翻译或数据提取等操作。循环只会增加成本和延迟。
- 无法对任何目标进行验证。如果没有办法判断“是否完成”,就不会有错误信号,从而导致循环持续运行并耗费资源。
循环设计不仅涉及如何构建循环,还关乎判断哪些问题适合使用循环来解决。
要像会一直从事这份工作一样来设计它
所需的工具包括:结构分析、智能体循环、验证器、图结构、契约、外部循环以及故障目录。应为循环配备强大的验证器,设置强制停止机制并限定其不可逾越的边界。在风险较高的环节加入人工检查点,并记住:即使循环找到了解决方案,也不代表你就完全理解了问题。之后就让它继续运行,就像那些打算长期从事工程师工作而非仅负责启动任务的人那样。
更高的层次
在让循环无人监控之前,有一个问题值得探讨:验证器即便功能极其弱小,仍能显示绿色状态吗?为此我们建立了一个基准测试。该测试记录了各种奖励操纵行为,并根据它们能通过的次数来评估各个关卡的设置效果。有一个关卡无视智能体自身的报告,而是重新运行之前提出的那种确定性检测方法作为首选方案,但它未能阻止八次尝试中的任何一次。重新运行测试套件仅能确认奖励条件已得到满足,而这恰恰正是奖励操纵行为所要达到的目的。
因此,如果验证机制限制了系统的发展,那么接下来最稀缺的技能就显而易见了:设计、版本控制以及不断改进验证流程本身。人们将这称为评估工程,即设定循环必须达到的标准。单个循环内的验证工作属于手工操作范畴,而评估工程则涉及多个循环,通过数据集和评分标准来判断整个系统是在进步还是退步。
强化某个验证环节就像爬梯子,其最终高度往往出乎意料。最有效的验证方式其实并非复杂的代码,而只是几条智能体永远无法看到的断言。因此,验证的限度处于一个尴尬的位置——它更取决于保留数据的质量以及能否防止这些数据泄露回循环中,而非验证环节本身的构建质量。