惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
AWS News Blog
AWS News Blog
V
Vulnerabilities – Threatpost
D
Darknet – Hacking Tools, Hacker News & Cyber Security
量子位
博客园 - 叶小钗
AI
AI
T
Tor Project blog
Forbes - Security
Forbes - Security
W
WeLiveSecurity
博客园_首页
爱范儿
爱范儿
J
Java Code Geeks
B
Blog
G
GRAHAM CLULEY
aimingoo的专栏
aimingoo的专栏
Cloudbric
Cloudbric
C
CXSECURITY Database RSS Feed - CXSecurity.com
TaoSecurity Blog
TaoSecurity Blog
L
LINUX DO - 热门话题
阮一峰的网络日志
阮一峰的网络日志
有赞技术团队
有赞技术团队
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Simon Willison's Weblog
Simon Willison's Weblog
云风的 BLOG
云风的 BLOG
Google DeepMind News
Google DeepMind News
H
Help Net Security
博客园 - 三生石上(FineUI控件)
C
Cisco Blogs
C
Cybersecurity and Infrastructure Security Agency CISA
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
P
Palo Alto Networks Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Recent Commits to openclaw:main
Recent Commits to openclaw:main
博客园 - 司徒正美
The Last Watchdog
The Last Watchdog
Blog — PlanetScale
Blog — PlanetScale
T
The Blog of Author Tim Ferriss
S
Secure Thoughts
Spread Privacy
Spread Privacy
F
Fortinet All Blogs
月光博客
月光博客
大猫的无限游戏
大猫的无限游戏
S
SegmentFault 最新的问题
H
Hackread – Cybersecurity News, Data Breaches, AI and More
A
About on SuperTechFans
Security Latest
Security Latest
Webroot Blog
Webroot Blog
Scott Helme
Scott Helme
Hugging Face - Blog
Hugging Face - Blog

博客园_首页

Linux实操--组管理、权限管理和定时任务 Java + EasyExcel 实现单个接口导出多个Excel Mem0 源码解析系列(二):提示词工程的深度剖析 Openclaw TaskFlow究竟是什么?和普通Skill技能有什么区别 博文阅读密码验证 - 博客园 嘉立创开源:应该是全网MicroPython教程最多的开发板 Hermes Agent 集成实践:从协议到生产 2026年AI编程工具横评:Cursor、Codex、Claude Code、Zed、Windsurf Java程序员必看的RAG入门教程 2026 AI效率神器:Superpowers + Claude Code 保姆级教程 本地大模型部署全攻略:从 0 到 1 玩转 Ollama 【从0到1构建一个ClaudeAgent】内存管理-上下文压缩 .NET 高级开发 | 设计、实现一个事件总线框架 电子小白入门之NE555 3. WorkBuddy:隐藏玩法,一键召唤专家,让 AI 以"专家身份"给你干活 和AI一起搞事情#3:Claude Teammate 游戏开发翻车实录 【OpenClaw】通过 Nanobot 源码学习架构---(7)Memory C# .NET 周刊|2026年3月3期 我在 Debian 11 上把 K8s 单机搭起来了,过程没你想的那么顺(/opt 目录版) 深度学习进阶(七)Data-efficient Image Transformer CLI+Skill搭建浏览器AI自动化框架,告别一切重复枯燥任务 告别Token账单无底洞:OpenClaw本地部署,重塑企业数据主权的唯一解 FastAPI+Vue:文件分片上传+秒传+断点续传,这坑我帮你踩平了! SBTI 爆火后,我做了个程序员版的 CBTI。。已开源 + 附开发过程 多模态检索开始进入工程期:用 Sentence Transformers 搭建可落地的 Multimodal RAG 100多行代码实现一个最简单的Agent(用ReAct) Claude Code 通关手册(八):推荐 5 个 Hooks,代码质量提升 3 倍 老板:“有人截图了!”。安全部门:“收到,马上查暗水印!” - why技术 技术之外,皆是人间 C#/.NET/.NET Core技术前沿周刊 | 第 69 期(2026年4.01-4.12) Snack JSONPath 项目架构分析 Claude Code Buddy 小析:一个非核心功能,如何体现产品的细节完成度 AI新时代下的图床管理方案-Cloudflare图床+MCP+Skills方案指南 化繁为简:顺丰速运App如何通过 HarmonyOS SDK实现专业级空间测量 从零实现富文本编辑器#13-React非编辑节点的内容渲染 AI开发-python-langchain框架(3-23-OpenAI Functions风格Tool Calling智能助手) .NET + AI 进阶实战:基于类的技能开发 - 打造可治理的 Agent 能力模块 【从0到1构建一个ClaudeAgent】规划与协调-技能 上周热点回顾(4.6-4.12) 电子小白的工具三件套:面包板、杜邦线、万能板 单表五亿数据的查询优化 | Mysql、StarRocks 2. WorkBuddy:从“我是谁”到“帮我干活” C# 如何减少代码运行时间:7 个实战技巧 基于HelixToolkit.SharpDX 渲染3D模型 - 笺上知微 从零开始的双臂具身VLA起源及现阶段发展综述 - SkyXZ 记对 xonsh shell 的使用, 脚本编写, 迁移及调优 - pluvium27 受够了Vibe Coding的失控?换个起点,让AI事半功倍 从开始配置漏洞环境到漏洞复现流程 - 難しい 关于10年工作经验的程序员对OpenClaw的实战经验分享以及看法 - 虚无境 Any metadata 的内存布局 C# .NET 周刊|2026年3月2期 - InCerry 我帮你测过了,测试圈排名第二的 Skill 依然很牛逼 Skill Discovery | 无监督技能发现的经典工作总结 - MoonOut PbootCMS 网站内容数量多导致访问慢?这些实用优化方案帮你提速! - 家兴网络技术工作室 上下文工程是什么?过时了么?一文讲明白! - 一枫说码 网站漏洞怎么发现并修复?一篇实用指南(附完整流程) - 家兴网络技术工作室 开了 TUN 模式还是直连?90% 的人都踩过这个坑 Github日报|2026年04月12日 - AI一族 AScript扩展多种脚本语言 - rockey627 AI 学习笔记:Agent 的记忆机制 你能被装进一个文件里吗?——7 万人把同事"蒸馏"成了 AI - 我没有三颗心脏 Claude Code 通关手册(七):给 AI 装上技能包——Skills 完全指南 - 暮色之狐 在浏览器中快速编辑代码:VSCode Web 集成实践 - Newbe36524 蒸馏自己 skill?基于 Deepseek 的蒸馏器,丐版蒸馏方式,简单便捷 - To_Carpe_Diem Spring AI Aliababa和AgentScope,哪个更好? - 苏三说技术 Etsy 把 1000 个 MySQL 分片迁进 Vitess:425TB 数据背后的真正问题不是性能,而是运维规模 MicroPython LVGL基础知识和概念:底层渲染与性能优化 - FreakStudio 数据库草图算法 Python 潮流周刊#146:CPython 引入 Rust 的进展 - 豌豆花下猫 最小生成树 - mofei1116 红日靶场七:从外网入口、容器逃逸到 AD 接管的完整利用链复盘 - YouDiscovered1t 分享四款开源且实用的 Kafka 管理工具 - 追逐时光者 vLLM 权重加载机制全解析:从挑战到理想架构 LCT 学习笔记 - ACehomoxue Avalonia UI 12.0.0 正式发布:架构演进和性能飞跃 - 张善友 当 AI Agent 把调用链拉长,延迟开始成为一门生意 conhost.exe 无法显示 U+2717 - 145a 太秀了,我把自己蒸馏成了 Skill!已开源 - 程序员鱼皮 ASP.NET Core 内存缓存实战:一篇搞懂该怎么配、怎么避坑 基于 Ghostty 带有分割标签页和为 Claude 编程设计的通知终端 - BugShare AI 焊死入口:教育的“操作系统级”重塑 - 郝hai 初级Java开发工程师使用sql脚本编写代码的过程是简单而且不糊涂 - CoderOilStation Claude Code通关手册(六):MCP协议完全指南 - 暮色之狐 边框灯光环绕动画特效实现指南 - Newbe36524 开源:子木蒸馏版的 SEO 审计工具 seo-audit-skill v1.0 我所理解的Python元模型 【从0到1构建一个ClaudeAgent】规划与协调-TodoWrite - 程序员Seven Claude 和 Codex 在审计 Skill 上性能差异探究 - ACai_sec AScript如何实现中文脚本引擎 - rockey627 【渗透测试】HTB Season10 Garfield 全过程wp - dynasty_chenzi Android 开发者为什么必须掌握 AI 能力?端侧视角下的技术变革 树状数组正确性证明 - AC-wyr 你的 AI 焦虑,可能比 AI 本身更危险——ATM 机没有消灭银行柜员,但恐慌消灭了你的判断力 - 我没有三颗心脏 一个拉胯的分库分表方案有多绝望?整个部门都在救火! - 冰河团队 动态规划入门必学之走方格问题 - Ofnoname PostgREST 与 PostgreSQL 角色权限配置全解析(生产级实践) - SheepDog1998 使用 UEFI 图形输出协议 GOP 在屏幕上显示图像的方法 - 阿源- Claude Code通关手册(五):组建你的AI专家团队,子代理系统 - 暮色之狐 一个程序员到架构师的催婚路之感悟(整整10年后的催婚相亲感悟) - MisterLip 用 Agent Skill 自动生成工作周报 - 赵康
AI Agent 30天速成|Day6 学习笔记
云淡风轻YangG · 2026-06-23 · via 博客园_首页

AI Agent 全日制30天速成|Day6 教学笔记

今日总学习目标

  1. 吃透 ReAct 动态反思智能体完整逻辑,对比 Day4 Plan-Solve 静态规划差异
  2. 实现带自我反思、循环迭代的 ReAct Agent,支持中途修正工具调用逻辑
  3. 统一封装全局工具网关,标准化管理所有工具(计算器、RAG检索、接口调用)
  4. 完善工具鉴权、参数校验、超时熔断、失败降级,形成生产级工具调度层
    每日时长分配(全天8h)
  • 理论笔记阅读+理解:2.5h
  • 代码编写调试:4h
  • 复盘+面试背诵:1.5h

一、核心理论教学笔记

1. ReAct 推理行动框架深度解析

1.1 核心循环三元组(Thought → Action → Observation)

  1. Thought(思考):模型读取当前全部上下文、已有工具返回结果,自主判断当前信息是否充足、下一步需要执行什么工具;若信息足够直接输出最终答案,终止循环。
  2. Action(行动):输出标准化工具调用指令,包含工具名称、入参;不做一次性全任务规划,只决策单步操作。
  3. Observation(观察):程序执行工具,捕获返回结果、异常信息,把结果回填对话上下文,进入下一轮思考。

循环上限控制:单轮对话限制最大迭代次数(默认5次),防止无限循环调用工具。

1.2 ReAct VS Plan-Solve 核心对比(面试高频)

维度 Plan-Solve(Day4静态规划) ReAct(Day6动态反思)
规划时机 对话开头一次性生成全部子任务清单 每执行完一步动态思考下一步,无预先完整计划
纠错能力 前期规划出错,后续任务全部失效,无法动态修正 每轮可根据工具返回结果调整思路,支持自我纠错
适用场景 固定流程、依赖明确、简单复合型问题 开放式复杂问题、结果不确定、需要多轮试错检索/计算
Token消耗 一次性规划消耗大量Token 每轮思考轻量化,分步消耗,灵活可控
实现难度 中等,调度器串行执行预设任务 偏高,需维护循环上下文、反思逻辑

1.3 ReAct 自我反思机制

普通ReAct仅执行「思考-行动」,增强版增加反思逻辑:
工具返回结果后,额外让模型判断3个问题:

  1. 当前信息是否足够回答用户原始问题?
  2. 当前工具返回是否存在错误、缺失关键数据?
  3. 是否需要更换工具、补充检索、重新计算?
    反思结论决定是否继续循环,大幅减少无效工具调用。

2. 统一工具网关设计(生产工程必备)

前几日工具分散定义,新增工具需要修改多处代码,不利于维护,今日抽象统一网关层:

2.1 三层工具架构

  1. 工具元定义层:统一注册工具名称、描述、入参Schema、异步执行函数、权限标签
  2. 网关调度层:统一接收模型工具调用请求,路由分发到对应工具
  3. 拦截中间件层:统一处理参数校验、超时、限流、异常捕获、日志、熔断降级

2.2 网关内置拦截能力

  1. 参数校验:Pydantic统一校验,非法参数直接返回错误观察值
  2. 并发限流:全局信号量控制工具并行调用数量
  3. 超时熔断:单工具执行超时阈值,超时直接返回失败信息
  4. 异常捕获:统一捕获代码/接口异常,格式化错误回填上下文
  5. 权限过滤:支持给不同会话开放/禁用指定工具
  6. 日志埋点:记录工具调用耗时、入参、结果、成功失败状态

2.3 标准化工具注册规范

新增工具无需修改调度逻辑,仅需注册元数据:

ToolMeta(
    name="xxx",
    description="工具功能描述",
    params_model=Pydantic参数模型,
    run_func=异步执行函数,
    timeout=10,
    enable=True
)

3. ReAct + 工具网关 + 分层记忆 完整串联链路

用户提问

  1. Redis读取会话记忆,自动滑动窗口+摘要压缩,构建上下文消息
  2. 进入ReAct循环:
    • Thought:模型判断下一步动作(工具调用/直接回答)
    • Action:输出工具调用参数,交给统一工具网关
    • 网关中间件校验、执行工具,返回Observation观察结果
    • 结果回填上下文,执行自我反思,判断是否继续循环
  3. 循环终止,LLM整合全部观察输出最终答案
  4. 保存本轮问答至Redis持久化记忆

4. 工具熔断降级策略

  • 连续失败阈值:同一工具连续调用2次失败,临时禁用该工具,返回降级提示
  • 超时降级:工具超时后不重试,直接告知用户当前工具暂时不可用
  • 权限降级:无权限工具拦截,返回提示不执行调用

二、今日学习重点

  1. 掌握ReAct循环推理流程、自我反思实现逻辑
  2. 区分ReAct动态推理与Plan-Solve静态规划的适用场景
  3. 封装通用可扩展工具网关,统一管理所有工具(计算器、RAG检索)
  4. 实现带循环上限、反思纠错的完整ReAct智能体
  5. 整合Day5分层记忆,实现持久化会话+动态反思Agent一体化

三、今日难点 & 解决方案

难点1:ReAct无限循环重复调用同一工具

解决方案:

  1. 设置全局最大迭代轮次,到达上限强制终止循环,直接汇总现有结果
  2. 反思Prompt约束:连续两次调用相同工具且无新信息,停止调用
  3. 上下文记录每一轮工具执行记录,模型可看到历史操作,避免重复动作

难点2:工具零散、新增工具需要大量修改代码,维护成本高

解决方案:
统一工具网关注册机制,所有工具集中注册;网关自动路由、统一拦截,新增工具仅新增元数据与执行函数,无侵入改动核心调度代码。

难点3:工具执行超时、接口报错导致整个ReAct流程卡死

解决方案:
网关层统一设置工具独立超时;全局捕获所有异常,格式化错误信息作为Observation回填上下文,循环不中断;连续失败触发熔断降级。

难点4:模型反思判断失效,明明信息充足仍反复调用工具

解决方案:

  1. 反思环节单独提供标准化判断模板,强制输出布尔判断结果
  2. temperature=0,保证反思结论稳定,减少误判
  3. Few-shot示例展示信息充足时直接终止循环的案例

四、完整练习代码(基于Day1~Day5全部代码扩展)

依赖不变

aiohttp、pydantic、faiss-cpu、aioredis、fastapi、uvicorn、numpy

1. 统一工具网关 tool_gateway.py

import asyncio
from pydantic import BaseModel, Field, ValidationError
from typing import Dict, List, Optional, Callable, Any
# 复用已有工具能力
from rag_store import RAGService

# 工具元数据模型
class ToolMeta(BaseModel):
    name: str
    description: str
    params_model: type[BaseModel]
    run_func: Callable
    timeout: int = 10
    enable: bool = True

# 计算器参数模型
class CalcParams(BaseModel):
    num1: float = Field(description="数字1")
    num2: float = Field(description="数字2")
    op: str = Field(description="运算符 +-*/")

# RAG检索参数模型
class RagSearchParams(BaseModel):
    query: str = Field(description="知识库检索关键词")
    top_k: int = Field(default=2, description="返回片段数量")

# 异步工具函数
async def calculator(num1: float, num2: float, op: str) -> str:
    try:
        match op:
            case "+": res = num1 + num2
            case "-": res = num1 - num2
            case "*": res = num1 * num2
            case "/":
                if num2 == 0:
                    return "工具错误:除数不能为0"
                res = num1 / num2
            case _: return f"不支持运算符 {op}"
        return f"计算结果:{num1} {op} {num2} = {res}"
    except Exception as e:
        return f"计算异常:{str(e)}"

# 全局RAG实例
global_rag = RAGService()
async def rag_search(query: str, top_k: int):
    res = await global_rag.retrieve(query, top_k)
    if not res:
        return "知识库未查询到相关内容"
    text = "\n".join([item["text"] for item in res])
    return f"知识库检索结果:\n{text}"

# 统一工具网关
class ToolGateway:
    def __init__(self):
        self.tool_registry: Dict[str, ToolMeta] = {}
        self.semaphore = asyncio.Semaphore(5)
        self.fail_counter: Dict[str, int] = {}  # 工具连续失败计数
        self.max_continuous_fail = 2

    # 注册工具
    def register_tool(self, meta: ToolMeta):
        self.tool_registry[meta.name] = meta
        self.fail_counter[meta.name] = 0

    # 获取OpenAI标准tools定义,直接传给LLM
    def get_openai_tools_schema(self) -> List[Dict]:
        tools = []
        for meta in self.tool_registry.values():
            if not meta.enable:
                continue
            tools.append({
                "type": "function",
                "function": {
                    "name": meta.name,
                    "description": meta.description,
                    "parameters": meta.params_model.model_json_schema()
                }
            })
        return tools

    # 执行单一工具
    async def execute_tool(self, tool_name: str, args_raw: dict) -> str:
        # 熔断判断
        if self.fail_counter.get(tool_name, 0) >= self.max_continuous_fail:
            return f"工具{tool_name}已触发熔断,暂时无法使用"
        if tool_name not in self.tool_registry:
            return f"不存在工具:{tool_name}"
        meta = self.tool_registry[tool_name]
        # 参数校验
        try:
            params = meta.params_model(**args_raw)
        except ValidationError as e:
            return f"参数校验失败:{str(e)}"
        # 带超时执行
        try:
            async with self.semaphore:
                result = await asyncio.wait_for(
                    meta.run_func(**params.model_dump()),
                    timeout=meta.timeout
                )
            self.fail_counter[tool_name] = 0
            return result
        except asyncio.TimeoutError:
            self.fail_counter[tool_name] += 1
            return f"工具{tool_name}执行超时"
        except Exception as e:
            self.fail_counter[tool_name] += 1
            return f"工具执行异常:{str(e)}"

# 网关初始化并注册工具
gateway = ToolGateway()
gateway.register_tool(ToolMeta(
    name="calculator",
    description="数学加减乘除计算器,仅处理数字运算",
    params_model=CalcParams,
    run_func=calculator
))
gateway.register_tool(ToolMeta(
    name="rag_search",
    description="检索私有知识库,查询RAG、Agent相关专业知识",
    params_model=RagSearchParams,
    run_func=rag_search
))

2. ReAct 动态反思智能体 react_agent.py

import asyncio
import json
import re
from pydantic import BaseModel
from typing import List, Dict
# 复用模块
from llm_client_v2 import AsyncLLMClientV2
from memory_store import RedisChatMemory, MemoryCompressor
from tool_gateway import gateway

# 反思判断结果模型
class ReflectResult(BaseModel):
    enough_info: bool
    need_new_tool: bool
    reason: str

class ReActAgent:
    def __init__(self, model_name="qwen-turbo"):
        self.llm = AsyncLLMClientV2(model_name)
        self.memory = RedisChatMemory()
        self.compressor = MemoryCompressor(self.llm)
        self.max_loop = 5  # ReAct最大循环轮次
        self.tools_schema = gateway.get_openai_tools_schema()
        self.system_prompt = """
你是ReAct智能体,遵循 Thought -> Action -> Observation 循环。
规则:
1. Thought:思考当前信息是否足够回答用户问题,是否需要调用工具
2. Action:需要工具则输出tool_calls;信息充足直接输出最终回答
3. 可用工具:calculator数学计算、rag_search知识库检索
每轮执行完工具后,会进行自我反思判断是否继续循环。
禁止编造知识库不存在的信息,数学计算必须调用计算器。
"""
        self.reflect_prompt = """
根据用户原始问题、历史对话、所有工具返回结果,判断两点:
1. enough_info:现有信息是否足够完整回答用户问题(true/false)
2. need_new_tool:是否需要继续调用新工具补充信息(true/false)
输出仅标准JSON,key:enough_info, need_new_tool, reason
用户问题:{user_query}
当前全部上下文:{context}
"""

    async def init_memory(self):
        await self.memory.connect()

    async def close_memory(self):
        await self.memory.close()

    # 单轮反思,判断是否终止循环
    async def reflect(self, user_query: str, messages: List[Dict]) -> ReflectResult:
        context_text = "\n".join([f"{m['role']}:{m['content']}" for m in messages])
        prompt = self.reflect_prompt.format(user_query=user_query, context=context_text)
        raw = await self.llm.chat([{"role": "user", "content": prompt}], temperature=0.0)
        match = re.search(r"\{.*\}", raw, re.S)
        json_str = match.group()
        return ReflectResult.model_validate_json(json_str)

    # ReAct主循环
    async def react_loop(self, user_query: str, messages: List[Dict]) -> str:
        loop_count = 0
        while loop_count < self.max_loop:
            loop_count += 1
            # 1. Thought阶段:请求LLM,判断是否调用工具
            resp = await self.llm._request(messages, tools=self.tools_schema)
            msg = resp["choices"][0]["message"]
            # 无工具调用,直接返回答案,终止循环
            if "tool_calls" not in msg or not msg["tool_calls"]:
                return msg["content"]
            # 2. Action阶段:执行工具
            tool_call = msg["tool_calls"][0]
            call_id = tool_call["id"]
            func_name = tool_call["function"]["name"]
            func_args = json.loads(tool_call["function"]["arguments"])
            obs = await gateway.execute_tool(func_name, func_args)
            # 3. Observation回填上下文
            messages.append(msg)
            messages.append({
                "role": "tool",
                "tool_call_id": call_id,
                "content": obs
            })
            # 4. 自我反思判断是否继续
            reflect_res = await self.reflect(user_query, messages)
            if reflect_res.enough_info and not reflect_res.need_new_tool:
                break
        # 循环达到上限,汇总所有信息输出最终回答
        final_resp = await self.llm.chat(messages, temperature=0.1)
        return final_resp

    # 完整对话入口(带记忆)
    async def chat(self, session_id: str, user_query: str):
        # 读取历史记忆
        history = await self.memory.load_history(session_id)
        messages = [{"role": "system", "content": self.system_prompt}] + history
        messages.append({"role": "user", "content": user_query})
        # 自动压缩超长上下文
        compressed_msg = await self.compressor.auto_compress(messages)
        # ReAct循环推理
        final_ans = await self.react_loop(user_query, compressed_msg)
        # 持久化本轮对话
        await self.memory.append_message(session_id, "user", user_query)
        await self.memory.append_message(session_id, "assistant", final_ans)
        # 压缩覆盖历史防止膨胀
        clean_history = compressed_msg[1:]
        await self.memory.override_history(session_id, clean_history)
        return {
            "session_id": session_id,
            "query": user_query,
            "answer": final_ans,
            "max_loop_limit": self.max_loop
        }

# 测试入口
async def test_react():
    agent = ReActAgent()
    await agent.init_memory()
    # 预加载知识库
    await gateway.rag_search("RAG是什么", top_k=3)
    # 复合型问题,需要多轮反思
    q = "先计算 (120+80)*5,再介绍RAG的作用,最后把计算结果和介绍整合"
    res = await agent.chat("react_test_001", q)
    print("最终回答:\n", res["answer"])
    await agent.close_memory()

if __name__ == "__main__":
    asyncio.run(test_react())

3. FastAPI 接口 main_react.py

from fastapi import FastAPI, Query
import asyncio
from react_agent import ReActAgent

app = FastAPI(title="Day6 ReAct动态反思Agent + 统一工具网关")
agent = ReActAgent("qwen-turbo")

@app.on_event("startup")
async def startup():
    await agent.init_memory()

@app.on_event("shutdown")
async def shutdown():
    await agent.close_memory()

@app.get("/agent/react_chat")
async def react_chat(
    session_id: str = Query(..., description="会话唯一ID"),
    prompt: str = Query(..., description="用户提问")
):
    result = await agent.chat(session_id, prompt)
    return result

if __name__ == "__main__":
    import uvicorn
    uvicorn.run("main_react:app", reload=True)

五、今日必做练习任务

  1. 运行tool_gateway.py,新增自定义工具(如取模运算),验证注册机制无需修改调度代码
  2. 执行ReAct测试代码,观察「思考→工具调用→反思→循环」完整流程
  3. 修改max_loop循环上限,测试达到上限强制汇总逻辑
  4. 制造工具连续报错,验证网关熔断机制,工具临时禁用
  5. 多轮连续对话,验证Redis记忆持久化、自动压缩功能
  6. 对比Plan-Solve与ReAct处理同一复杂问题,观察两者执行流程差异

六、今日配套面试题(高阶Agent核心)

基础问答

  1. 简述ReAct三元循环 Thought-Action-Observation 完整流程
  2. ReAct和Plan-Solve静态规划的核心区别,各自适用场景?
  3. 统一工具网关有什么工程价值?分层结构是怎样的?
  4. ReAct为什么需要设置最大循环轮次?不限制会出现什么问题?
  5. 工具网关熔断降级机制的作用是什么?

工程实操题

  1. ReAct出现无限重复调用同一工具,如何从代码层面多重限制?
  2. 统一工具网关需要实现哪些通用拦截中间件能力?
  3. 如何实现ReAct自我反思,让模型自主判断是否停止调用工具?
  4. 新增业务工具,如何做到不修改Agent核心调度代码?

拓展思考题(大厂Agent面试)

  1. 如何实现并行工具调用ReAct,一次性执行多个无依赖工具?
  2. 工具网关如何增加权限控制,不同用户分组开放不同工具?
  3. ReAct循环Token持续上涨,除了记忆压缩还有什么优化方案?
  4. 如何给ReAct增加记忆反思,让模型自动遗忘无用历史对话?

面试题标准答案

基础问答

  1. ReAct三元循环
    Thought:模型读取上下文,思考是否需要调用工具;
    Action:输出标准化工具调用参数;
    Observation:网关执行工具,结果回填对话;
    循环直至信息充足或达到最大轮次,输出最终答案。

  2. ReAct vs Plan-Solve
    Plan-Solve:一次性生成全部任务,静态串行执行,适合流程固定、依赖清晰的简单复合问题;无法动态纠错。
    ReAct:单步动态思考,每轮根据工具返回调整思路,支持自我反思纠错,适合开放式、信息不确定、需要多轮试错的复杂问题。

  3. 工具网关工程价值
    统一管理所有工具,标准化注册、调用、拦截;新增工具无侵入;统一处理参数校验、限流、超时、熔断、日志;上层Agent无需关心工具底层实现,解耦业务工具与推理核心。
    三层结构:工具元注册层、网关调度层、中间件拦截层。

  4. 最大循环轮次作用
    防止模型无限循环重复调用工具,造成API资源浪费、Token爆炸、接口超时;到达上限强制停止工具调用,基于已有信息汇总回答。

  5. 熔断降级作用
    同一工具连续多次失败后临时禁用,避免持续无效请求消耗额度;防止单个工具故障拖垮整个Agent对话流程,提升服务稳定性。

工程实操题

  1. 防止无限重复调用工具
    ① 设置全局最大循环次数;② 反思Prompt约束连续重复调用需停止;③ 上下文记录历史工具操作,模型可见过往调用记录;④ 网关增加单轮最大调用次数限制。

  2. 网关中间件能力
    参数校验、并发限流、独立超时控制、异常捕获格式化、连续失败熔断、权限过滤、调用日志埋点、鉴权拦截。

  3. ReAct自我反思实现
    单独构造反思Prompt,传入全部对话与工具结果,强制模型输出结构化JSON判断是否信息充足、是否需要继续调用工具;temperature=0保证判断稳定,根据返回布尔值决定是否继续循环。

  4. 无侵入新增工具
    仅需要定义Pydantic参数模型、异步执行函数、构造ToolMeta元数据,调用gateway.register_tool完成注册;网关自动生成OpenAI标准工具Schema,Agent调度逻辑完全无需改动。

拓展思考题

  1. 并行ReAct
    一轮Thought输出多个无依赖tool_calls,使用asyncio.gather并发执行所有工具,全部Observation统一回填上下文,大幅提升多独立查询场景效率。
  2. 工具权限控制
    工具元数据增加权限标签;网关接收会话权限参数,过滤当前用户无权限的工具;LLM仅能获取用户可见工具列表,无法调用受限工具。
  3. ReAct循环Token优化
    每次循环精简工具返回冗余文本;分层记忆滑动窗口裁剪旧对话;单次循环只保留关键Observation,丢弃无关闲聊;长工具返回结果摘要压缩。
  4. 记忆反思遗忘机制
    每次反思时让模型评估历史对话权重,低价值闲聊、过期信息标记;记忆压缩阶段优先丢弃低权重内容,只保留高价值计算、知识库、业务参数记录。

学习总结

Day6完成工业级动态ReAct智能体与统一工具网关两大核心模块,弥补Day4静态规划无法动态纠错的短板。
统一工具网关是工程落地必备分层设计,解决工具散乱、维护困难问题;ReAct动态反思是复杂开放式业务场景首选推理框架,面试高频考察两种规划框架对比。
目前全套体系:异步LLM、SSE流式、Function Calling、RAG、Plan-Solve静态规划、Redis分层持久记忆、统一工具网关、ReAct动态反思智能体,完整覆盖中小型Agent项目全部底层能力。
下一日学习内容:多模态Agent、图文Embedding、本地轻量向量库Chroma持久化。