02:Agent Loop 深度剖析:ReAct 循环的工程实现

引言

Agent Loop 是 CountBot 的核心引擎,实现了经典的 ReAct(Reasoning + Acting)循环模式。本文将深入分析其工程实现,探讨如何将学术概念转化为可靠的生产代码。

ReAct 循环原理

ReAct 模式的核心思想是让 LLM 交替进行"推理"和"行动":

复制代码
用户提问 → LLM 推理 → 决定调用工具 → 执行工具 → 将结果反馈给 LLM → 继续推理 → ... → 最终回答

这个循环可能执行多轮,直到 LLM 认为已经收集到足够信息来回答用户问题。

AgentLoop 核心实现

初始化参数

python 复制代码
class AgentLoop:
    def __init__(
        self,
        provider,              # LLM Provider 实例
        workspace: Path,       # 工作空间路径
        tools,                 # ToolRegistry 实例
        context_builder=None,  # 上下文构建器
        session_manager=None,  # 会话管理器
        subagent_manager=None, # 子代理管理器
        model: str | None = None,
        max_iterations: int = 25,   # 最大循环次数(安全阀)
        max_retries: int = 3,       # LLM 调用重试次数
        retry_delay: float = 1.0,   # 重试延迟
        temperature: float = 0.7,
        max_tokens: int = 4096,
    ):

关键设计点:

  • max_iterations = 25 作为安全阀,防止 LLM 陷入无限工具调用循环
  • max_retries = 3 处理 LLM API 的瞬时故障
  • 所有依赖通过构造函数注入,便于测试和替换

消息处理流程

python 复制代码
async def process_message(
    self, message, session_id, context=None, 
    media=None, channel=None, chat_id=None, cancel_token=None
) -> AsyncIterator[str]:

process_message 是一个异步生成器,通过 yield 逐步返回流式响应。这种设计使得调用方可以实时获取 LLM 的输出,而不必等待整个处理完成。

工具调用编排

当 LLM 返回 tool_call 时,AgentLoop 执行以下步骤:

  1. 解析工具调用 :从 StreamChunk.tool_call 中提取工具名和参数
  2. 参数验证 :通过 Tool.validate_params() 验证参数合法性
  3. 执行工具 :调用 ToolRegistry.execute() 执行工具
  4. 结果注入 :将工具执行结果作为 tool 角色消息注入对话历史
  5. 继续推理:将更新后的消息列表再次发送给 LLM
python 复制代码
# 伪代码展示核心循环
for iteration in range(self.max_iterations):
    async for chunk in self.provider.chat_stream(messages, tools):
        if chunk.is_content:
            yield chunk.content  # 流式输出文本
        if chunk.is_tool_call:
            tool_calls.append(chunk.tool_call)
    
    if not tool_calls:
        break  # LLM 没有请求工具调用,循环结束
    
    for tc in tool_calls:
        result = await self.tools.execute(tc.name, **tc.arguments)
        messages.append({"role": "tool", "content": result, "tool_call_id": tc.id})
    
    tool_calls.clear()

取消令牌机制

CountBot 实现了优雅的任务取消机制:

python 复制代码
# 全局取消令牌管理
_session_cancel_tokens: dict[str, CancellationToken] = {}

def cancel_session(session_id: str) -> bool:
    if session_id in _session_cancel_tokens:
        _session_cancel_tokens[session_id].cancel()
        return True
    return False

在 AgentLoop 的每次迭代中检查取消令牌,确保用户可以随时中断长时间运行的任务。

错误处理策略

分层错误处理

  1. LLM 调用层:自动重试 + 指数退避
  2. 工具执行层:捕获异常并将错误信息作为工具结果返回给 LLM
  3. 循环层max_iterations 防止无限循环

工具执行错误的优雅降级

当工具执行失败时,错误信息会被格式化后返回给 LLM,让 LLM 自行决定如何处理:

python 复制代码
try:
    result = await tool.execute(**arguments)
except Exception as e:
    result = f"工具执行失败: {str(e)}"
# 无论成功失败,都将结果反馈给 LLM
messages.append({"role": "tool", "content": result})

这种设计让 LLM 有机会尝试其他方案或向用户解释失败原因。

性能优化

流式响应

整个链路都是流式的:LLM 流式生成 → AgentLoop 流式 yield → WebSocket 流式推送。用户可以在 LLM 生成第一个 token 时就看到响应开始。

上下文窗口管理

通过 ContextBuilder 智能管理上下文窗口:

  • 系统提示词(固定)
  • 记忆摘要(压缩的历史信息)
  • 最近 N 条对话历史(滑动窗口)
  • 当前消息

与业界实践的对比

方面 CountBot LangChain Agent AutoGPT
循环控制 max_iterations 硬限制 可配置 无限制
工具调用 原生 Function Calling Tool/Agent 抽象 自定义协议
流式支持 全链路流式 部分支持 不支持
错误恢复 错误反馈给 LLM 异常传播 自我修复

总结

CountBot 的 Agent Loop 实现展示了如何将 ReAct 理论优雅地工程化。通过异步生成器实现流式响应、通过安全阀防止失控、通过错误反馈实现自愈,这些设计模式值得在任何 AI Agent 项目中借鉴。

相关推荐
2301_8038756123 分钟前
CSS如何制作导航栏平滑移动_使用transition与left属性
jvm·数据库·python
2501_933329555 小时前
媒介宣发技术实践:Infoseek舆情系统的AI中台架构与应用解析
开发语言·人工智能·架构·数据库开发
热爱生活的五柒5 小时前
026主流三大模型(GPT / Gemini / Claude Code)总结
人工智能·gpt
DuHz6 小时前
论文精读:大语言模型 (Large Language Models, LLM) —— 一项调查
论文阅读·人工智能·深度学习·算法·机器学习·计算机视觉·语言模型
AI木马人6 小时前
9.【AI任务队列实战】如何在高并发下保证系统不崩?(Redis + Celery完整方案)
数据库·人工智能·redis·神经网络·缓存
陈天伟教授6 小时前
GPT Image 2-桂林山水
人工智能·神经网络·安全·架构
offer收割机小鹅6 小时前
大学生求职必备:AI面试、AI写作与设计工具助力职场发展
人工智能·ai·面试·aigc·ai写作
茅盾体6 小时前
汽车零件订单自动同步系统方案
python
2401_883600256 小时前
golang如何理解weak pointer弱引用_golang weak pointer弱引用总结
jvm·数据库·python
FreakStudio6 小时前
和做工厂系统的印尼老哥,复刻了一套属于 MicroPython 的包管理系统
python·单片机·嵌入式·大学生·面向对象·并行计算·电子diy·电子计算机