一脸懵逼的AI面试:Agent里面的ReAct是什么?
AI训练营6期,12月中旬开班,欢迎咨询
最近有学员出去面试,他们面试的岗位为AI应用工程师、Agent应用工程师或者AI产品经理,而最近经常会遇到的一个问题是:
什么是ReAct,他主要是来解决什么问题的?
怎么说呢,这个问题问的太大了,他其实不太适合作为一般岗位的面试题的。
但要注意,这不是说ReAct不重要,相反ReAct本身很重要,只不过要完全理解几乎需要将整个Agent架构梳理清楚,所以多数人不大可能回答好这个问题;
另一方面,对于多数人这个词汇是比较“低频”的,因为多数(中小型公司)老板在用Agent做融资、讲故事,不准备真用Agent解决生产问题,所以很多同学并没有相关实践的机会,最终的结果就是:
多数人只在一些文章读到过,整体是很模糊的。所以,ReAct是什么呢?
ReAct = Reason + Act,是 2022 年 Google/Princeton 提出的一个范式:
Reasoning:让LLM思考"为什么"和"如何"执行行动; Acting:让LLM执行具体行动并与环境交互; 循环反馈:通过观察结果驱动下一步推理;
翻译翻译就是:先思考、再执行,但这个好像并不能回答为什么、是什么、如何做问题,所以就得追根溯源了!
Why ReAct?
从模型的演进来说,我们想解决的是他只能想/说,不能做的问题。
在这个基础上我们提出了Function Calling/MCP,其基本语法就是预设一些工具挂在模型(请求)上,每次由模型根据用户问题与工具参数(描述、name等)做判断是否调用。
比如最经典的问题,成都这两天天气怎么样?想要由模型自动调用就需要这样写:
# 把“工具”挂在模型上:这里是一个 get_weather 函数
{
"type": "function",
"function": {
"name": "get_weather",
"description": "查询未来几天某个城市的天气预报",
"parameters": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "城市名,例如:成都"
},
"days": {
"type": "integer",
"description": "查询多少天的预报(1-7)"
}
}
"required": ["city", "days"]
}
}
}
基本交互模型确定后,紧接着问题就出现了:真实场景工具太多、用户的问题太模糊、用户的意图过多...
反正所有的问题叠加在一起,就一句话:模型在工具调用一块表现很差。
于是这个时候思维链CoT就出现了:他需要对用户问题进行分析,将复杂的问题分解为一个个小步骤(小工具调用),再看着这些工具一个个执行,成功一个再执行下一个,希望由此增加整体AI产品体验:
最后总结一句,ReAct想要解决的核心问题是:把 “会思考” 和 “会操作外部世界” 这两件事绑在一起,形成一个可观察、可迭代的任务。
接下来我们用个简单例子,来看看ReAct架构详细实现:
ReAct架构核心
首先,ReAct架构是一套循环流程:
... → 推理(Thought) → 行动(Action) → 观察(Observation) → ...
这一范式的核心是在“思考-行动-观察”的循环中完成任务。也就是说,Agent一边思考如何解决问题,一边调用工具获取信息,然后根据观察到的结果调整下一步计划,直到得出最终答案。
下面通过一个实例演示这个过程,2018 年世界杯冠军国家的总统是谁?他可能的完整过程是:
Thought:用户的问题是“2018年世界杯冠军国家的总统”。这是一个复合问题,需要拆解成两个步骤:首先找到2018年世界杯的冠军是哪国,然后查明该国的总统是谁; Action:调用搜索引擎工具,查询关键词2018 年世界杯 冠军; Observation:返回:“2018年世界杯冠军是法国。”; Thought:Agent得知冠军国家是法国。需要知道法国总统是谁; Action:再次调用搜索引擎工具,查询关键词“法国总统是谁”; Observation:搜索结果显示:“法国现任总统是埃马纽埃尔·马克龙(Emmanuel Macron)。” 最终回答:综合前面的信息,Agent回答用户:“2018 年世界杯冠军法国的总统是埃马纽埃尔·马克龙。”
在解题过程中Agent经历了两轮“思考→行动→观察”的循环,逐步把复杂问题拆解并求解。
现在业内普遍认为并且有数据证明:CoT可以有效降低模型幻觉,这也是ReAct的重要意义之一,接下来我们来看看简单实现:
一、状态管理
├── 全局状态 (GlobalState)
│ ├── task_id: "query_???"
│ ├── original_query: "2018世界杯冠军国家的总统是谁"
│ ├── task_graph: 任务依赖图
│ └── verified_facts: {"france_won_2018": true}
│
├── 会话状态 (SessionState)
│ ├── current_plan: 当前执行计划
│ ├── available_tools: [search, calculator, ...]
│ └── context_window: 最近10轮思考-行动历史
│
└── 执行状态 (ExecutionState)
├── step_id: "step_001"
├── current_action: {"tool": "search", "params": {...}}
└── partial_results: {}
Agent架构实现到最后,难点大概都是上下文设计,现阶段常用的技巧是用一个“记事本”来记录复杂任务的信息,包括:
用户问了什么; 已经知道什么; 尝试过什么方法; 哪些信息被验证过; ...
要在AI工程中实现上述问题本身就挺难的,我们用的这种分层设计允许系统在不同粒度上管理状态,避免单一状态对象过于臃肿、也避免了整体项目复杂度。
这里具体的实现我们就不展开了,大家可以去OpenManus看看,我们这里给出伪代码即可:
状态对象 = {
任务ID: "查询_001",
原始问题: "2018世界杯冠军国家的总统是谁",
已验证事实: {
"冠军国家": "法国",
"法国总统": "马克龙"
},
思考记录: ["这是一个复合问题,需要两步..."],
行动记录: [
{工具: "搜索", 查询: "2018世界杯冠军"},
{工具: "搜索", 查询: "法国总统"}
],
当前步骤: 3
}
二、决策引擎
基础状态设计(也可以叫上下文工程)是第一步,第二步将AI的思考过程展示出来,就像我们解题过程:
分析当前情况 确定还需要什么信息 选择获取信息的方法(Tools) 评估结果并决定下一步
具体代码也不写了,整个流程如图:
开始
↓
分析当前状态
├── 已有足够信息? → 生成答案
├── 需要外部信息? → 选择工具执行
└── 需要更多分析? → 深入思考
↓
执行决策
↓
更新状态
↓
检查是否完成
├── 是 → 结束
└── 否 → 回到"分析当前状态"
三、工具调用
如上所述,除了自身能力,AI解决问题的办法只有Tools调用,包括这里用到的搜索引擎工具以及我们最常见的知识库查询工具,只要模型需要对外交互,那么都是工具调用,而ReAct模式中工具调用的部分流程很固定:
1. 匹配需求 → 确定需要什么工具
2. 选择工具 → 哪个工具最适合
3. 准备参数 → 工具需要什么输入
4. 执行调用 → 运行工具获取结果
5. 验证结果 → 检查结果是否可靠
四、案例流程代码化
这里问题依旧是:2018世界杯冠军国家的总统是谁?这里第一步就是状态初始化:
{
任务: "2018世界杯冠军国家的总统是谁?",
已知: {},
需要: ["2018冠军国家", "该国总统"]
}
然后是首次决策:
AI思考: "这是一个复合问题,先要找到冠军国家"
AI行动: 使用搜索工具,查询"2018世界杯冠军"
结果: "2018年世界杯冠军是法国队"
更新状态: 添加"冠军国家=法国"
然后是二次决策:
AI思考: "知道了冠军是法国,现在需要法国总统信息"
AI行动: 使用搜索工具,查询"法国现任总统"
结果: "法国现任总统是埃马纽埃尔·马克龙"
更新状态: 添加"法国总统=马克龙"
最终在这个基础下生成答案:
AI思考: "已收集全部信息,可以回答"
AI回答: "2018年世界杯冠军是法国,法国总统是埃马纽埃尔·马克龙"
上述流程在倒推时候好像很简单,但真的人模型一步步踩在点上,其实是有点难的,尤其是在复杂业务场景上,比如有很多问题要考虑:
如何判断信息是否足够? 如何选择搜索关键词? 如何处理不确定性? ...
上述每一次步骤失误就要完犊子,所以生产项目会有很多纠错,纠错的结果就是很浪费时间和Token。
下面是一些小技巧:
五、小技巧
首先,Thought的组织与生成是比较关键的,他的输入是状态信息和预设工具,输出是下一步行动计划,这里提供一套不错的模板:
基于当前已知信息 {已知信息},
我们还需要 {缺失信息} 来回答问题。
下一步应该 {行动计划},使用 {工具名称}
其次,在某些时候工具会很多,为防止模型乱调用,一般是需要对工具进行建模评分的,比如:
需求:查询实时天气
候选工具:
1. 天气API(实时、准确)→ 得分 90
2. 网页搜索(可能过时)→ 得分 60
3. 历史数据库(非实时)→ 得分 30
当然,你说建模没问题,具体依旧还是AI判断,是否有可能不准,这个是有可能的,而且暂时没办法避免...
然后,就是持续的状态管理,AI乱不乱状态(上下文)说了算:
1. 分层存储:短期记忆 + 长期记忆
2. 智能压缩:保留关键信息,删除冗余
3. 版本控制:支持回滚到之前状态
4. 依赖跟踪:记录信息之间的关联
最后,所有的AI产品都是需要测试数据集的,或者说需要一套好坏评估标准,比如:
任务完成率:用户问题被正确解决的比例 平均响应时间:从提问到获得答案的时间 对话轮次:平均需要多少轮交互 用户满意度:用户对答案的评价 思考质量:AI思考的相关性和有效性 工具准确率:工具返回正确结果的比例 循环效率:平均每个问题需要的循环次数 资源消耗:API调用次数、Token使用量 ...
这里就扯远了,我们就不展开了...
结语
没有完美的价格,ReAct与生俱来的会具有一些缺陷,这里也需要提一嘴:
一、响应时间过长/耗Token
当前大家都知道模型是不可尽信的,为了保证输出的稳定性,可能在流程上会有2次乃至3次校验,这样来回的结果就是Agent的响应时长很忙,并且Token消耗也很快。
比如最近一个Manus的案例就是用户一次PPT就把一个月的Token用完了,并且PPT还没完成,于是投诉要求退款。
二、过度思考
过度思考的原因是模型带来的,有可能换个模型就好了,但问题还是如第一点所示:AI并不知道问题简单与否,从保险的情况下他情愿在简单的场景下也多加验证,比如:
问题:在简单问题上过度分析
原因:缺乏问题复杂度判断
可能的解决方案又:
• 添加问题分类器(简单/复杂)
• 为简单问题设计快捷通道
• 设置思考"预算"(Token限制)
三、工具问题
虽然现在GPT本身也是支持MCP的,但是很多公司在使用的时候其实还是喜欢桥接一层,底层自己调用Function Calling,原因很简单没有生产级AI应用会毫无保留的使用第三方服务
四、状态混乱
应该说这不是ReAct的问题,只要是复杂的AI项目,只要涉及到意图识别,那么上下文工程就会很复杂,如何做好分层信息设计,这就是AI工程的核心了,这里不做展开...
......
虽然ReAct有这样那样的问题,但并不妨碍他现在成为事实上的标准了。现在回归面试题,ReAct是什么呢?
ReAct是一套Agent的交互模型,他的作用是让模型具有链接外部世界的能力,并且尽可能降低幻觉的发生,需要特别强调的是,ReAct的全局日志是可调式、可观测的,这也变相提高了我们AI产品的可控性。
以上就是今天的分享,希望对大家有用。
点击上方卡片关注叶小钗公众号,查看下方二维码,添加我个人微信:
往期推荐
《LangChain、 Dify、 n8n、 Coze:四大AI框架怎么选?》