从"单次推理"到"循环交互"
大语言模型(LLM)的原始形态是单次推理系统(One-shot Inference):输入Prompt,输出Completion,对话结束。这种"问答式"交互在面对复杂任务时显得力不从心——当问题需要多步骤验证、工具调用或环境反馈时,静态的输入-输出映射无法构建持续的问题解决能力。
Agent Loop(智能体循环)正是为解决这一局限而诞生的核心架构范式。它定义了一个持续运转的控制循环:感知(Perception) → 推理(Reasoning) → 决策(Decision) → 行动(Action) → 反馈(Feedback)。每一次循环迭代都将环境反馈纳入下一轮推理的上下文,形成闭环的认知-行动系统。
OODA循环与冯·诺依曼架构
Agent Loop的设计哲学深深植根于认知科学与控制论的经典理论:
观察-调整-决策-行动循环 (OODA Loop, Boyd, 1976) 最初由美国空军上校约翰·博伊德提出,用于描述战斗机飞行员的决策过程。其核心洞察是:在动态对抗环境中,决策速度取决于完成"观察(Observe)-调整(Orient)-决策(Decide)-行动(Act)"循环的速度。OODA循环强调反馈驱动和迭代适应,而非预设的线性计划。
冯·诺依曼架构 (von Neumann Architecture, 1945) 的"存储程序"概念为Agent Loop提供了工程实现基础:状态(内存)与计算(处理器)的分离,使得循环可以在不同状态间跳转,同时保留历史上下文。现代Agent框架中的StateGraph(如LangGraph的实现)正是这一思想的延续——节点代表计算,边代表状态转移,循环路径实现持续推理。
同步Loop vs 异步Event-Driven Loop
在工程实现层面,Agent Loop存在两种核心架构模式:
同步Loop采用阻塞式执行:每一轮循环等待前一步骤完全完成后才继续。其优势在于实现简单、状态一致性强,适合单线程的ReAct式推理。伪代码结构通常为:
while not done:
thought = llm.reason(context)
action = llm.decide(thought)
observation = environment.execute(action)
context.append(observation)
异步Event-Driven Loop则基于事件总线架构:感知、推理、行动作为独立服务,通过消息队列松耦合连接。当传感器数据到达时触发感知节点,推理节点订阅感知事件,行动节点响应决策事件。这种模式支持高并发、容错恢复和分布式部署,但引入了状态一致性管理的复杂度。AutoGen的Actor模型和CrewAI的Flow编排均体现了这一思路。
架构选型取决于场景需求:低延迟单任务场景适合同步Loop;多Agent协作、长周期任务或需要人工介入审批的流程,则应采用异步Event-Driven架构。
二、Loop的核心状态机设计
Agent Loop的工程实现必须建立在严格的状态机之上。状态机不仅定义了Loop的合法状态空间,更通过守卫条件确保状态转换的安全性与可预测性。
状态定义与语义
一个完整的Agent Loop状态机包含以下核心状态:
- IDLE:等待触发条件,Loop未激活
- PERCEIVING:接收并解析环境输入,构建内部数据结构
- REASONING:基于当前上下文进行认知处理
- ACTING:执行外部动作(工具调用、API请求等)
- WAITING_FOR_OBSERVATION:动作执行后等待环境反馈
- TERMINATED:目标达成或异常终止,Loop结束
状态转换条件与守卫
状态转换不是自动的,必须满足守卫条件:
| 当前状态 | 目标状态 | 守卫条件 |
|---|---|---|
| IDLE | PERCEIVING | 新任务到达或用户输入触发 |
| PERCEIVING | REASONING | 感知数据完整性校验通过 |
| REASONING | ACTING | 决策输出包含可执行动作 |
| REASONING | TERMINATED | LLM输出"Final Answer"标记 |
| ACTING | WAITING_FOR_OBSERVATION | 动作已提交至执行器 |
| WAITING_FOR_OBSERVATION | REASONING | 环境反馈数据到达且有效 |
| WAITING_FOR_OBSERVATION | TERMINATED | 超时或连续失败达到阈值 |
| 任意 | TERMINATED | 达到最大迭代次数或人工中断 |
状态机核心实现(伪代码)
from enum import Enum, auto
from typing import Optional, Dict, Any
from dataclasses import dataclass
class AgentState(Enum):
IDLE = auto()
PERCEIVING = auto()
REASONING = auto()
ACTING = auto()
WAITING_FOR_OBSERVATION = auto()
TERMINATED = auto()
@dataclass
class LoopContext:
iteration_count: int = 0
max_iterations: int = 10
history: list = None
memory: Dict[str, Any] = None
def __post_init__(self):
if self.history is None:
self.history = []
if self.memory is None:
self.memory = {}
class AgentLoopFSM:
"""Agent Loop有限状态机核心实现"""
def __init__(self, llm_engine, tool_registry, max_iter=10):
self.state = AgentState.IDLE
self.llm = llm_engine
self.tools = tool_registry
self.context = LoopContext(max_iterations=max_iter)
self._transition_map = {
AgentState.IDLE: [AgentState.PERCEIVING, AgentState.TERMINATED],
AgentState.PERCEIVING: [AgentState.REASONING, AgentState.TERMINATED],
AgentState.REASONING: [AgentState.ACTING, AgentState.TERMINATED],
AgentState.ACTING: [AgentState.WAITING_FOR_OBSERVATION, AgentState.TERMINATED],
AgentState.WAITING_FOR_OBSERVATION: [AgentState.REASONING, AgentState.TERMINATED],
}
def _can_transition(self, from_state: AgentState, to_state: AgentState) -> bool:
"""守卫条件检查"""
if to_state not in self._transition_map.get(from_state, []):
return False
# 特定状态转换的额外守卫
if from_state == AgentState.REASONING and to_state == AgentState.TERMINATED:
return self._is_goal_achieved()
if from_state == AgentState.WAITING_FOR_OBSERVATION:
# 超时检查
if self._is_observation_timeout():
return to_state == AgentState.TERMINATED
return to_state == AgentState.REASONING
return True
def _is_goal_achieved(self) -> bool:
"""目标达成检测:由LLM输出特定标记或启发式规则判断"""
last_output = self.context.history[-1] if self.context.history else ""
return "[FINAL_ANSWER]" in last_output or "[TASK_COMPLETE]" in last_output
def _is_observation_timeout(self) -> bool:
"""观察等待超时检测"""
# 实现具体的超时逻辑
return False
def transition_to(self, new_state: AgentState) -> bool:
"""执行状态转换"""
if not self._can_transition(self.state, new_state):
raise ValueError(f"非法状态转换: {self.state.name} -> {new_state.name}")
print(f"[FSM] {self.state.name} -> {new_state.name}")
self.state = new_state
return True
def run_cycle(self, user_input: str) -> str:
"""执行完整Loop周期"""
# 初始化
self.context = LoopContext(max_iterations=self.context.max_iterations)
self.context.history.append({"role": "user", "content": user_input})
self.transition_to(AgentState.PERCEIVING)
while self.state != AgentState.TERMINATED:
self.context.iteration_count += 1
if self.context.iteration_count > self.context.max_iterations:
print("[FSM] 达到最大迭代次数,强制终止")
self.transition_to(AgentState.TERMINATED)
break
try:
if self.state == AgentState.PERCEIVING:
self._do_perceive()
self.transition_to(AgentState.REASONING)
elif self.state == AgentState.REASONING:
reasoning_output = self._do_reason()
if self._is_goal_achieved():
self.transition_to(AgentState.TERMINATED)
return reasoning_output
self.transition_to(AgentState.ACTING)
elif self.state == AgentState.ACTING:
action_result = self._do_act()
self.context.last_action_result = action_result
self.transition_to(AgentState.WAITING_FOR_OBSERVATION)
elif self.state == AgentState.WAITING_FOR_OBSERVATION:
observation = self._do_observe()
self.context.history.append({
"role": "observation",
"content": observation
})
self.transition_to(AgentState.REASONING)
except Exception as e:
print(f"[FSM] 状态 {self.state.name} 执行异常: {e}")
self._handle_exception(e)
return self._extract_final_answer()
def _do_perceive(self):
"""感知阶段:输入解析与上下文构建"""
# 整合用户输入、环境状态、记忆检索
recent_memories = self._retrieve_relevant_memories()
self.context.working_memory = {
"input": self.context.history[0],
"retrieved_memories": recent_memories
}
def _do_reason(self) -> str:
"""推理阶段:LLM认知处理"""
prompt = self._build_reasoning_prompt()
response = self.llm.generate(prompt, context=self.context.history)
self.context.history.append({"role": "assistant", "content": response})
return response
def _do_act(self) -> Dict:
"""行动阶段:工具调用执行"""
# 解析LLM输出中的Action指令
action_cmd = self._parse_action(self.context.history[-1]["content"])
if action_cmd:
tool_name = action_cmd.get("tool")
tool_args = action_cmd.get("args", {})
result = self.tools.execute(tool_name, tool_args)
return result
return {"status": "no_action"}
def _do_observe(self) -> str:
"""观察阶段:获取环境反馈"""
return str(self.context.last_action_result)
def _handle_exception(self, error: Exception):
"""异常处理与熔断逻辑"""
# 具体实现见第五章
self.transition_to(AgentState.TERMINATED)
def _build_reasoning_prompt(self) -> str:
"""构建推理提示词"""
return f"""基于以下上下文进行推理:
历史: {self.context.history}
记忆: {self.context.memory}
请输出思考过程,如需使用工具请按格式:Action: [工具名] Args: [参数]
如需结束请标记 [FINAL_ANSWER]"""
def _parse_action(self, content: str) -> Optional[Dict]:
"""解析LLM输出中的动作指令"""
# 实现具体的解析逻辑
import re
match = re.search(r'Action:\s*(\w+)\s*Args:\s*(.+)', content)
if match:
return {"tool": match.group(1), "args": match.group(2)}
return None
def _retrieve_relevant_memories(self) -> list:
"""检索相关记忆"""
return []
def _extract_final_answer(self) -> str:
"""提取最终答案"""
for msg in reversed(self.context.history):
if msg["role"] == "assistant":
content = msg["content"]
if "[FINAL_ANSWER]" in content:
return content.split("[FINAL_ANSWER]")[-1].strip()
return content
return ""
上述实现展示了状态机的核心机制:显式状态定义、守卫条件检查、异常安全转换。与简单的while循环不同,FSM强制要求每个状态转换都经过合法性验证,防止非法跳转导致的系统不稳定。
三、Perception-Action循环的两种范式
Agent Loop并非单一层次的循环,而是嵌套的双层结构:内循环(Inner Loop)处理单轮推理中的认知扩展,外循环(Outer Loop)管理多轮交互中的目标追踪与计划修正。这种分层设计借鉴了控制理论中的级联控制思想。
内循环
内循环发生在单次LLM调用内部,处理思维链(Chain of Thought, CoT)或思维树(Tree of Thoughts, ToT)的扩展。它不负责与环境交互,而是专注于内部认知空间的探索。
在CoT模式下,内循环表现为"思考→思考→...→结论"的线性序列;
在ToT模式下,则分支为多个候选推理路径,通过评估函数选择最优分支。
内循环的终止条件通常是:达到最大思考深度、生成可执行动作指令、或置信度超过阈值。
内循环的关键价值在于推理深度的弹性控制。通过调整内循环的迭代次数或分支因子,可以在推理质量与计算成本之间做权衡。
外循环
外循环是Agent与环境的真实交互边界,每轮迭代对应一次完整的"思考-行动-观察"周期。外循环维护目标栈和计划状态,根据环境反馈动态调整策略。
外循环的核心职责包括:
- 目标追踪:维护当前目标与子目标的层次结构,检测目标达成或偏离
- 计划修正:当行动结果与预期不符时,触发重新规划(Replanning)
- 记忆更新:将本轮交互的关键信息写入长时记忆,供未来循环使用
- 上下文压缩:当历史记录超过上下文窗口时,执行摘要或剪枝
双循环的协同机制
内外循环通过工作记忆实现信息交换。内循环生成的推理结果写入工作记忆,成为外循环决策的输入;外循环获取的环境观察则触发新一轮内循环推理。
这种分层架构的优势在于关注点分离:内循环专注于"如何想",外循环专注于"何时做"。工程师可以独立优化推理策略(内循环)和交互策略(外循环),降低系统复杂度。
四、关键变体深度解析
Agent Loop的具体实现存在多种变体,每种变体针对特定场景优化了控制流结构。以下是三种最具代表性的范式:
ReAct Loop:推理与行动
ReAct (Reasoning + Acting, Yao et al., 2023) 是目前最广泛应用的Agent Loop范式。其核心创新是将推理轨迹与行动指令显式交错,形成Thought → Action → Observation的循环模式。
ReAct的控制流特点:
- 显式思考:LLM输出"Thought: ..."前缀的推理过程,增强可解释性
- 即时反馈:每轮行动后立即获取Observation,纳入下一轮推理
- 动态调整:无需预设计划,根据环境反馈实时调整策略
ReAct Agent Loop架构示意:
class ReActLoop(AgentLoopFSM):
"""ReAct Loop实现:Thought-Action-Observation循环"""
def run_react_cycle(self, query: str) -> str:
"""ReAct专用执行流程"""
self.state = AgentState.PERCEIVING
self.context.history = [{"role": "user", "content": query}]
while self.state != AgentState.TERMINATED and \
self.context.iteration_count < self.context.max_iterations:
self.context.iteration_count += 1
# Phase 1: Thought
self.transition_to(AgentState.REASONING)
thought_prompt = self._build_react_prompt("thought")
thought_output = self.llm.generate(thought_prompt)
# 解析Thought输出
if "[FINAL_ANSWER]" in thought_output:
self.transition_to(AgentState.TERMINATED)
return self._extract_answer(thought_output)
self.context.history.append({
"role": "thought",
"content": thought_output
})
# Phase 2: Action
self.transition_to(AgentState.ACTING)
action = self._parse_action_from_thought(thought_output)
if not action:
# 无明确动作,继续思考
continue
# 执行工具调用
try:
observation = self.tools.execute(
action["tool"],
action["args"]
)
except Exception as e:
observation = f"Error: {str(e)}"
# Phase 3: Observation
self.context.history.append({
"role": "observation",
"content": f"Action: {action['tool']}\nResult: {observation}"
})
self.transition_to(AgentState.WAITING_FOR_OBSERVATION)
self.transition_to(AgentState.REASONING) # 直接进入下一轮推理
return self._extract_final_answer()
def _build_react_prompt(self, phase: str) -> str:
"""构建ReAct格式提示词"""
few_shot_examples = """
示例1:
Thought: 我需要查询天气信息。
Action: weather_api Args: {"city": "北京"}
Observation: 北京今日晴,25°C。
示例2:
Thought: 根据天气结果,建议用户带伞。
Action: [FINAL_ANSWER] Args: 建议带伞,可能有雨。
"""
history_str = "\n".join([
f"{msg['role'].upper()}: {msg['content']}"
for msg in self.context.history
])
return f"""{few_shot_examples}
当前历史:
{history_str}
请继续输出Thought和Action(如需结束请使用[FINAL_ANSWER]):
Thought:"""
def _parse_action_from_thought(self, thought: str) -> Optional[Dict]:
"""从Thought输出中解析Action"""
import re
# 匹配 Action: tool_name Args: {...}
pattern = r'Action:\s*(\w+)\s*Args:\s*(\{.*?\}|[^\n]+)'
match = re.search(pattern, thought, re.DOTALL)
if match:
tool = match.group(1)
args_str = match.group(2)
try:
args = eval(args_str) if args_str.startswith('{') else {"query": args_str}
except:
args = {"raw": args_str}
return {"tool": tool, "args": args}
return None
ReAct的优势在于简单直接,适合信息收集、多步查询等任务。但其局限也明显:缺乏长期记忆积累,相同错误可能重复发生;无法从失败中系统性学习。
Reflexion Loop:自我反思的元认知层
Reflexion (Shinn et al., 2023) 在ReAct基础上引入了元认知层(Metacognitive Layer),通过"试错-反思-重试"的循环实现言语强化学习(Verbal Reinforcement Learning)。
Reflexion的核心组件:
- Actor:执行ReAct循环的策略模型
- Evaluator:评估轨迹质量的评判器(可以是LLM或启发式规则)
- Self-Reflector:生成语言形式反思的反思模型
- Episodic Memory:存储反思经验的记忆缓冲区
Reflexion与ReAct的关键差异在于控制流:
class ReflexionLoop(ReActLoop):
"""Reflexion Loop实现:带反思的试错学习"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.reflection_memory = [] # episodic memory存储反思
self.max_trials = 3 # 最大尝试次数
self.success_threshold = 0.8 # 成功阈值
def run_reflexion_cycle(self, query: str) -> str:
"""Reflexion完整控制流"""
trial = 0
best_result = None
best_score = 0.0
while trial < self.max_trials:
trial += 1
print(f"\n[Reflexion] Trial {trial}/{self.max_trials}")
# 执行ReAct轨迹
trajectory = self._run_single_trial(query, trial)
# 评估轨迹质量
score = self._evaluate_trajectory(trajectory)
if score >= self.success_threshold:
print(f"[Reflexion] 任务成功,得分: {score}")
return trajectory["final_answer"]
# 生成反思
if trial < self.max_trials: # 非最后一次尝试才反思
reflection = self._generate_reflection(trajectory, score)
self.reflection_memory.append({
"trial": trial,
"reflection": reflection,
"score": score
})
print(f"[Reflexion] 生成反思: {reflection[:100]}...")
if score > best_score:
best_score = score
best_result = trajectory["final_answer"]
print(f"[Reflexion] 达到最大尝试次数,返回最佳结果 (得分: {best_score})")
return best_result or "任务失败"
def _run_single_trial(self, query: str, trial_num: int) -> Dict:
"""执行单次ReAct试验"""
# 构建带反思历史的提示
context = self._build_trial_context(query, trial_num)
# 复用ReAct逻辑执行
self.context = LoopContext(max_iterations=self.context.max_iterations)
self.context.history = context
# 执行标准ReAct循环(简化版)
final_answer = self.run_react_cycle(query)
return {
"trajectory": self.context.history.copy(),
"final_answer": final_answer,
"iterations": self.context.iteration_count
}
def _build_trial_context(self, query: str, trial_num: int) -> list:
"""构建试验上下文,包含历史反思"""
context = [{"role": "user", "content": query}]
if self.reflection_memory and trial_num > 1:
# 注入之前的反思作为指导
reflections_text = "\n".join([
f"尝试 {r['trial']} 的教训: {r['reflection']}"
for r in self.reflection_memory
])
context.append({
"role": "system",
"content": f"基于之前失败的反思:\n{reflections_text}\n请避免重复这些错误。"
})
return context
def _evaluate_trajectory(self, trajectory: Dict) -> float:
"""评估轨迹质量(可由LLM或规则实现)"""
# 启发式评估:检查是否包含错误标记、迭代次数等
history = trajectory["trajectory"]
score = 1.0
# 惩罚错误
error_count = sum(1 for msg in history if "Error:" in str(msg.get("content", "")))
score -= error_count * 0.3
# 惩罚过长轨迹
score -= trajectory["iterations"] * 0.05
# 检查是否有最终答案
if not trajectory["final_answer"]:
score -= 0.5
return max(0.0, score)
def _generate_reflection(self, trajectory: Dict, score: float) -> str:
"""生成自我反思"""
history_text = "\n".join([
f"{msg['role']}: {msg['content'][:200]}..."
for msg in trajectory["trajectory"]
])
reflection_prompt = f"""分析以下失败的执行轨迹,总结导致低分({score})的原因,并提供改进建议:
{history_text}
请用第一人称总结教训(如"我意识到..."、"我应该..."):"""
reflection = self.llm.generate(reflection_prompt)
return reflection
Reflexion的核心价值在于跨试验学习:通过将失败经验转化为自然语言反思,Agent能够在不更新模型参数的情况下"学习"并改进策略。研究表明,这种言语强化学习在编程任务和决策任务上显著优于纯ReAct方法。
Plan-and-Solve Loop:先规划后执行的解耦模式
与前两种"边想边做"的交错模式不同,Plan-and-Solve采用解耦架构:先由规划器(Planner)生成完整计划,再由执行器(Executor)按步骤执行。这种模式适合可预测、结构化的任务场景。
Plan-and-Solve的控制流:
- 规划阶段:LLM生成任务分解和步骤序列
- 执行阶段:按序执行各步骤,每步可嵌入简单的ReAct循环处理意外
- 重规划触发:当步骤执行失败或环境变化时,重新调用规划器
三种范式的选择取决于任务特性:ReAct适合探索性、信息收集类任务;Reflexion适合需要迭代精进的复杂任务;Plan-and-Solve适合结构化、可预测的工作流。
五、工程实现
将Agent Loop从概念转化为生产级系统,需要解决一系列工程挑战:终止条件设计、异常处理与熔断、并发优化。
循环终止条件设计
Loop终止不是简单的"达到最大次数",而是需要多层次的终止策略:
目标达成检测:
- 显式标记:LLM输出特定终止标记(如
[FINAL_ANSWER]) - 启发式规则:输出格式符合预期(如JSON结构完整)
- 外部验证:通过单元测试、人工审核或评估器确认结果正确性
安全终止:
- 最大迭代限制:设置上限,防止无限循环
- 预算限制:Token消耗或API调用成本上限
- 时间限制: Wall-clock时间超时
智能终止:
- 收敛检测:连续多轮输出相似(通过文本相似度或哈希指纹判断),触发"死循环"检测
- 价值停滞:强化学习中的价值函数不再提升
异常处理:工具失败、幻觉传播与熔断机制
Agent Loop的健壮性取决于其异常处理能力:
异常处理与熔断机制流程图;工业线稿风格;展示正常循环路径、工具超时分支、幻觉检测分支、最终人工介入出口,使用红色标注异常路径;1200x800;
工具失败处理:
- 重试策略:指数退避重试,区分暂时性错误(网络超时)与永久性错误(权限拒绝)
- 降级方案:主工具失败时切换备选工具
- 错误传播:将错误信息作为Observation反馈给LLM,让其决定下一步
幻觉传播抑制:
- 自我验证:要求LLM对关键事实进行交叉验证
- 工具结果校验:对比多次工具调用的结果一致性
- 置信度阈值:低置信度时触发人工介入或额外验证
熔断机制:
class RobustAgentLoop(AgentLoopFSM):
"""带熔断机制的健壮Loop实现"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.error_counts = {} # 错误类型计数
self.circuit_states = {} # 熔断器状态: CLOSED, OPEN, HALF_OPEN
self.failure_threshold = 5 # 触发熔断的错误次数
self.recovery_timeout = 60 # 熔断后尝试恢复的时间(秒)
def _do_act(self) -> Dict:
"""带熔断保护的行动执行"""
action = self._parse_action(self.context.history[-1]["content"])
if not action:
return {"status": "no_action"}
tool_name = action["tool"]
# 检查熔断状态
if self._is_circuit_open(tool_name):
return {
"status": "circuit_open",
"error": f"工具 {tool_name} 当前不可用(熔断中)"
}
try:
# 执行工具调用(带超时)
result = self._execute_with_timeout(
tool_name,
action["args"],
timeout=30
)
# 成功则重置错误计数
self._record_success(tool_name)
return result
except ToolTimeoutError:
self._record_failure(tool_name, "timeout")
return {"status": "timeout", "tool": tool_name}
except ToolExecutionError as e:
self._record_failure(tool_name, "execution_error")
# 检查是否需要熔断
if self._should_trip_circuit(tool_name):
self._trip_circuit(tool_name)
return {"status": "error", "error": str(e)}
def _execute_with_timeout(self, tool: str, args: Dict, timeout: int) -> Dict:
"""带超时的工具执行"""
import concurrent.futures
with concurrent.futures.ThreadPoolExecutor() as executor:
future = executor.submit(self.tools.execute, tool, args)
try:
return future.result(timeout=timeout)
except concurrent.futures.TimeoutError:
raise ToolTimeoutError(f"工具 {tool} 执行超时")
def _is_circuit_open(self, tool_name: str) -> bool:
"""检查熔断器状态"""
state = self.circuit_states.get(tool_name, "CLOSED")
if state == "OPEN":
# 检查是否过了恢复期
last_failure = self.error_counts.get(f"{tool_name}_last_time", 0)
if time.time() - last_failure > self.recovery_timeout:
self.circuit_states[tool_name] = "HALF_OPEN"
return False
return True
return False
def _record_failure(self, tool_name: str, error_type: str):
"""记录失败"""
key = f"{tool_name}_{error_type}"
self.error_counts[key] = self.error_counts.get(key, 0) + 1
self.error_counts[f"{tool_name}_last_time"] = time.time()
def _record_success(self, tool_name: str):
"""记录成功,重置计数"""
self.circuit_states[tool_name] = "CLOSED"
for key in list(self.error_counts.keys()):
if key.startswith(tool_name):
del self.error_counts[key]
def _should_trip_circuit(self, tool_name: str) -> bool:
"""判断是否触发熔断"""
total_failures = sum(
count for key, count in self.error_counts.items()
if key.startswith(tool_name) and not key.endswith("_last_time")
)
return total_failures >= self.failure_threshold
def _trip_circuit(self, tool_name: str):
"""触发熔断"""
self.circuit_states[tool_name] = "OPEN"
print(f"[CircuitBreaker] 工具 {tool_name} 已熔断,{self.recovery_timeout}秒后尝试恢复")
def _handle_exception(self, error: Exception):
"""全局异常处理"""
if isinstance(error, HallucinationDetectedError):
# 幻觉检测触发,注入纠正提示
self.context.history.append({
"role": "system",
"content": "警告:检测到可能的幻觉输出,请基于已有事实重新推理。"
})
# 不终止,继续循环但标记状态
return
elif isinstance(error, CriticalToolFailureError):
# 关键工具失败,尝试人工介入
if self._request_human_intervention():
return
else:
self.transition_to(AgentState.TERMINATED)
else:
# 未知异常,记录并终止
print(f"[Error] 未处理异常: {error}")
self.transition_to(AgentState.TERMINATED)
def _request_human_intervention(self) -> bool:
"""请求人工介入"""
# 实现人工审批逻辑
return False
上述代码展示了分层防御的异常处理策略:工具层熔断防止级联故障,幻觉检测保障输出质量,全局异常处理确保系统最终可控。
并发优化:多Loop实例的状态隔离与资源共享
生产环境通常需要同时运行多个Agent Loop实例,面临以下挑战:
状态隔离:每个Loop实例必须有独立的上下文、记忆和状态机,防止实例间干扰。可通过依赖注入模式,为每个实例创建独立的Context对象。
资源共享:LLM推理引擎、工具连接池、向量数据库等昂贵资源应共享。使用连接池和缓存层(如Redis)减少重复初始化开销。
并发模型选择:
- 多线程:适合I/O密集型任务(如网络请求),受GIL限制
- 多进程:绕过GIL,适合CPU密集型推理,但内存开销大
- 异步协程:Python的
asyncio适合高并发轻量级任务,但复杂状态机实现困难
LangGraph的解决方案采用检查点(Checkpointing)机制:每个状态转换后持久化状态,支持中断恢复、时间旅行(回滚到历史状态)和并行分支执行。这种设计将状态管理外置,Loop实例变为无状态的计算节点,大大简化了并发控制。
六、从单Loop到多Loop协调
当单个Agent无法满足复杂任务需求时,多Agent系统的Loop协调成为关键挑战。
多Agent场景下的Loop同步
多Agent系统的核心问题是Loop间的交互模式:
消息传递:Agent间通过显式消息通信,Loop独立运行。AutoGen采用此模式,将多Agent协作建模为对话消息交换。消息传递松耦合,但时序控制困难。
共享状态:多个Loop实例读写共同的State对象。LangGraph的SharedState模式支持此架构,但需要仔细的并发控制防止竞态条件。
主从协调:中央Orchestrator维护主Loop,负责任务分解和分配;Worker Agent执行子任务,汇报结果后Orchestrator更新主状态。CrewAI和Magentic-One采用此模式。
层级Loop:策略与执行的嵌套
复杂系统常采用层级Loop架构:
顶层策略Loop:低频率运行(如每5分钟),负责目标设定、资源分配、异常策略调整。维护长期记忆和全局状态。
底层执行Loop:高频率运行(如每秒),负责传感器数据处理、实时控制、即时反馈响应。状态生命周期短,上下文窗口有限。
层级Loop通过命令接口通信:顶层Loop生成目标或约束,写入共享内存;底层Loop读取并执行,定期汇报进度。
七、总结
当前局限:循环深度与上下文窗口的权衡
Agent Loop面临的核心矛盾是无限循环需求与有限上下文窗口的冲突。随着迭代次数增加,历史记录线性增长,最终超过上下文限制。
当前解决方案包括:
- 上下文压缩:摘要旧历史、剪枝冗余信息、向量化存储关键记忆
- 滑动窗口:仅保留最近N轮交互,丢弃早期历史
- 分层记忆:外循环维护长期记忆(向量数据库),内循环仅使用工作记忆
但这些方案都涉及信息损失,如何在压缩中保留关键决策线索,仍是待解决的问题。
未来方向
Agent Loop的演化将沿以下方向展开:
持久化Loop:Loop状态持久化到数据库,支持跨会话恢复。Agent可以"暂停"数小时甚至数天后"继续"执行,实现真正的长周期任务处理。这需要解决状态序列化、版本兼容、分布式锁等技术挑战。
学习增强的循环策略:当前Loop的控制逻辑(何时终止、如何重试、是否反思)由硬编码规则或启发式决定。未来将出现元Agent,通过强化学习或进化算法优化Loop控制策略本身,实现自适应的循环参数调整。
Agent Loop作为AI系统的核心引擎,其设计哲学超越了简单的代码结构——它是对智能本质的工程诠释:不是静态的知识储备,而是持续的感知-行动-适应过程。理解并掌握Agent Loop的设计与优化,是构建AI Agent系统的关键能力。
欢迎关注公众号【dev派】,获取最前沿Ai时代技术发展新动态。