第 2 章:Agent 执行框架,ReAct → IterResearch
讲清 ReAct 为什么在长程调研里会「上下文爆炸」,IterResearch 怎么用「演进报告」把它压成常量空间,并能在 ReAct / IterResearch / ReWOO / Reflexion 之间按场景选型
📊 学习时长:55-70 分钟 🎯 完成后能力:讲清 ReAct 为什么在长程调研里会「上下文爆炸」,IterResearch 怎么用「演进报告」把它压成常量空间,并能在 ReAct / IterResearch / ReWOO / Reflexion 之间按场景选型 🔗 关联面试题:5 道(覆盖 5 个角度,见 Part 3)
这一章你会学到什么
- ✓ 零依赖也能跟着做:用一段代码亲眼看到 ReAct 的上下文怎么「线性暴涨」,而 IterResearch 怎么「纹丝不动」
- ✓ 看懂 ReAct 的核心:推理(Reasoning)和行动(Acting)交织,以及它的消息格式怎么设计
- ✓ 想透 ReAct 在长任务里的两个硬伤:上下文爆炸 + 信息污染
- ✓ 掌握 IterResearch 的关键创新:把调研看成一个「状态机」,用演进报告当常量大小的中央记忆
- ✓ 学会一条「问题逐层加码、方案逐层升级」的主线:ReAct → IterResearch → ReSum
- ✓ 建立框架选型直觉:ReAct / IterResearch / ReWOO / Reflexion / Research-Synthesis 各适合什么,以及测试时扩展怎么用计算换质量
本章按三段式组织:
段落 给谁看 内容 占比 🚀 Part 1 · 主线实战 零基础,想先跑起来 ReAct 原理 + 消息格式 + 上下文增长对比 demo ~45% 🎯 Part 2 · 面试深度 想讲透、备战面试 IterResearch / ReSum / 其他框架 / 选型 / 测试时扩展 + 私货 ~45% 🏆 Part 3 · 验收串题 检验学到位没 关联面试题 + 自检清单 ~10%
🚀 Part 1 · 主线实战 | ~45% 这部分零依赖,直接跑。你会亲眼看到「为什么长任务下 ReAct 会撑不住」,这是理解后面一切的前提。
先讲个真实场景(这是本章的「为什么」)
上一章那个「三选一」选型问题,我们的调研 Agent 跑通了。但当工程师把问题换成更狠的:
「帮我梳理近一年主流开源向量库的能力演进格局,列出主要玩家、各自的索引 / 部署形态 / 生态,和最新进展。」
这个问题逼着 Agent 查了二十多轮:一个个项目查、一版版更新翻、索引和部署形态交叉比对。结果跑到第十几轮,它开始胡言乱语,把 A 项目的特性安到 B 项目头上、把一年前的旧版本当成最新的。
扒日志一看,根因不是模型变笨了,而是:我们用最朴素的 ReAct,把每一轮搜到的文档正文,原样堆进上下文。二十多轮下来,上下文又长又乱,一方面快撑爆模型的窗口,另一方面前面几十段不相关的旧文档内容,把模型的注意力彻底稀释了。
一句话:ReAct 在短任务里又快又好,但「把观察只增不减地堆进上下文」这个朴素做法,扛不住长程调研。 这一章,就是讲怎么扛住它。
概念 1:ReAct 是什么
ReAct(Reasoning + Acting),是最基础也最常用的一种 Agent 框架。核心一句话:把「想」和「做」交织起来,想一步(Thought)、做一个动作(Action)、看观察结果(Observation),再想下一步,如此循环。
上一章那个 mini-agent 就是一个最朴素的 ReAct:思考 → search → 观察 → 再思考。它的循环长这样:
消息格式怎么设计
ReAct 靠特定标签区分每一类内容,让程序能解析、让模型能学:
Thought:模型的推理(我现在该干什么)Action:要调用的工具和参数(search("..."))Observation:工具返回的结果(由程序填进去,不是模型生成的)- 循环往复,直到模型输出
Final:(最终答案)
这套「标签化的对话」就是 Agent 的「汇编语言」,朴素、通用、好实现。绝大多数 Agent 框架,本质都是在这套循环上做加法。
概念 2:ReAct 的两个硬伤(长任务下)
ReAct 有个朴素做法:每一轮的观察(搜来的文档正文),都原样塞回上下文。短任务没事,但调研类任务动辄几十轮,两个问题就暴露了:
- 上下文爆炸:观察越堆越多,很快撑爆模型的上下文窗口(开篇那个二十多轮就是这么崩的)。
- 信息污染:前面几十段临时文档内容混在一起,大部分对「当前这一步」根本没用,却稀释了模型的注意力,越查越迷。
这两个硬伤,不是把模型换强一点就能解决的,它是**「只增不减地堆上下文」这个结构**本身的问题。下面我们用代码把它「逼」出来给你看。
🛠️ 跟着做:亲眼看上下文怎么「越堆越长」
下面这段零依赖代码,对比两种做法在 6 轮调研后的「上下文大小」。新建 ctx_growth.py:
# 零依赖,直接 python ctx_growth.py
# 模拟 6 轮工具返回,每轮约 200 字的文档正文
observations = [f"第{i}轮搜到的文档内容:" + "正文" * 100 for i in range(1, 7)]
def react():
"""ReAct:每轮观察都原样堆进上下文"""
context = "系统提示 + 用户问题"
for i, obs in enumerate(observations, 1):
context += "\n[思考]\n" + obs # ← 观察全堆进去,只增不减
print(f"ReAct 第 {i} 轮后,上下文 = {len(context):>5} 字符")
def iter_research(report_cap=320):
"""IterResearch:只维护一个固定大小的「演进报告」"""
report = "【演进报告】"
for i, obs in enumerate(observations, 1):
# 把新观察「融进」报告:只保留确认的关键结论,丢弃临时正文,大小受控
report = ("【演进报告】已确认要点:" + "; ".join(f"结论{j}" for j in range(1, i + 1)))[:report_cap]
print(f"Iter 第 {i} 轮后,报告 = {len(report):>5} 字符(上限 {report_cap})")
react(); print(); iter_research()
运行
python ctx_growth.py
你应该看到(ReAct 线性暴涨,IterResearch 稳在上限内,这是确定性输出,你跑出来一模一样):
ReAct 第 1 轮后,上下文 = 228 字符
ReAct 第 2 轮后,上下文 = 445 字符
ReAct 第 3 轮后,上下文 = 662 字符
ReAct 第 4 轮后,上下文 = 879 字符
ReAct 第 5 轮后,上下文 = 1096 字符
ReAct 第 6 轮后,上下文 = 1313 字符
Iter 第 1 轮后,报告 = 15 字符(上限 320)
Iter 第 2 轮后,报告 = 20 字符(上限 320)
Iter 第 3 轮后,报告 = 25 字符(上限 320)
Iter 第 4 轮后,报告 = 30 字符(上限 320)
Iter 第 5 轮后,报告 = 35 字符(上限 320)
Iter 第 6 轮后,报告 = 40 字符(上限 320)
看那两列数字:ReAct 每轮稳定 +217,一路线性涨;IterResearch 始终被 report_cap 摁在 320 以内。 轮数越多,差距越夸张。
🐛 跑不通看这里
- 报错
SyntaxError?这段是 Python 3,确认用python3跑。- 数字和上面差一两位?正常,取决于你机器上字符串长度的细微差异(比如换行符计法),趋势才是重点:ReAct 一路涨、Iter 被摁住。
- 看不出差距?把
range(1, 7)改成range(1, 30)再跑(见下方动手实验)。
🛠️ 动手实验:把轮数从 6 改成 30
把两处 range(1, 7) 都改成 range(1, 30),再跑一次。你会看到 ReAct 的上下文冲到 6000+ 字符(真实场景里就是这样,几十轮直接撑爆几千 / 几万 token 的窗口),而 IterResearch 的报告几乎纹丝不动,稳在两百字符以内。这就是 IterResearch 能支持「无限深度」调研的根本原因,用常量大小的工作空间,换取无限的调研深度。
📌 说清楚:这是教学最小实现。真实的「演进报告」不是简单截断字符串,而是用一次 LLM 调用,把「旧报告 + 新观察」重写成一份更新后的报告(保留关键结论、丢弃临时正文);这里用字符串拼接 + 截断,只为让你零成本看到「常量 vs 线性」这个本质差别。真实做法见下面 Part 2。
🧭 你刚才做的,等于真实系统的什么? 你写的
iter_research()把「堆全部历史观察」换成了「维护一份大小受控的报告」,这正是 IterResearch 的核心思想。真实系统里,这份报告由模型每轮智能地重写,而不是机械截断。
🎯 Part 2 · 面试深度 | ~45% 这部分讲透 IterResearch 的设计、ReSum 兜底、其他主流框架,以及怎么选型,这些是 Agent 岗面试的高频深水区。
2.1 IterResearch:把调研看成一个「状态机」
IterResearch 的关键创新,是不再把「全部历史」喂给模型,而是维护一个固定大小的「演进报告」(Evolving Report)当中央记忆。你可以把整个调研过程理解成一个状态机(学术上常用马尔可夫决策过程 MDP 来刻画):
- 状态(State) = 当前的演进报告,大小固定;
- 每一轮:模型读「报告 + 最新观察」→ 把有用的信息融进报告、丢弃临时内容 → 决定下一个动作;
- 关键:每轮只携带固定大小的状态往前走,临时信息用完即弃,从根上避免上下文污染。
注:把调研「看成 MDP」是一种便于理解和工程化的建模视角(当前状态决定下一步,与更早的历史无关),不必纠结它是否严格满足马尔可夫性,重点是「只带固定状态往前走」这个工程思想。
演进报告怎么设计
演进报告是 IterResearch 的灵魂,它要同时满足三个要求,这三个要求互相拉扯,是设计的难点:
- 信息完整:已发现的关键结论都得在,不能丢;
- 结构清晰:分点、带出处,模型好读也好更新;
- 大小可控:不能无限增长,否则又退化成 ReAct。
实务里,报告通常按「已确认结论 / 待验证假设 / 信息缺口 / 下一步计划」这样的结构组织,既是中央记忆,也天然就是最终调研报告的雏形。
2.2 上下文还兜不住怎么办:ReSum 动态摘要
就算用了演进报告,有些超长任务(比如要查上百个来源)还是会逼近上下文上限。这时再加一层 ReSum(动态摘要):当上下文将满时,触发一次摘要,把历史压缩成精华,再带着精华继续。
把这三者串起来,就是一条非常漂亮的「问题逐层加码、方案逐层升级」的主线:
- ReAct:朴素堆叠,短任务够用
- IterResearch:演进报告把状态控成常量,扛住长程调研
- ReSum:上下文真要满了,动态摘要兜底,扛住超长任务
业内行话:面试聊到「长任务上下文管理」,能把这三层串起来讲(每一层解决上一层扛不住的那个新问题),而不是只甩一个「IterResearch」的名词,面试官立刻知道你不是看过一篇博客,而是真在长任务里被上下文坑过、并且知道每一层在治什么病。这条「问题在哪、方案怎么逐层升级」的叙事,是本章最值钱的面试资产。
2.3 其他主流框架(建立坐标系)
ReAct 不是唯一的执行框架。面试常问「你还知道哪些」,知道这几个的取舍就够:
ReWOO(Reasoning WithOut Observation):先规划,再批量执行。
模型先把「要做哪几步、每步用什么工具」一次性规划好,再批量执行、最后汇总。好处是省 LLM 调用(不用每步都问一次模型);代价是不够灵活,计划定死了,中途发现方向错了不好改。适合「步骤相对确定」的任务。
Reflexion:引入自我反思。
Agent 做完一轮后,自己反思「哪里做得不好」,把教训记下来,下一轮带着教训重做。好处是能在多次尝试里自我改进;代价是更慢更贵。适合「允许多次尝试、追求质量」的任务。
Research-Synthesis:并行多 Agent,再综合。
同时跑多个独立的调研 Agent(从不同角度查),最后把结果综合。好处是提高可靠性(交叉验证、降低单条链路跑偏的影响);代价是成本翻倍。适合「对可靠性要求高、预算充足」的场景。
2.4 怎么选:一张决策图
| 框架 | 一句话 | 适合 |
|---|---|---|
| ReAct | 想一步做一步 | 短任务、几轮就完,首选(简单直观) |
| IterResearch | 演进报告控常量 | 长程调研,几十轮 |
| ReSum | 动态摘要兜底 | 超长任务,上下文要爆 |
| ReWOO | 先规划后批量 | 步骤确定,想省调用 |
| Reflexion | 自我反思迭代 | 允许多试、追质量 |
| Research-Synthesis | 并行多 Agent | 重可靠性、预算足 |
讲师私货:别把 IterResearch 当银弹、无脑上。短任务用 ReAct 又快又简单,硬上 IterResearch 反而增加「维护演进报告」的开销和出错面(报告写错了,后面全错)。判断点还是那句话:任务会不会长到把上下文堆爆? 会,才上 IterResearch;再要爆,才叠 ReSum。选最低够用的那档,这和上一章「该不该上 Deep Research」是同一种工程审美。
2.5 测试时扩展(Test-Time Scaling):用计算换质量
最后一个高频考点:推理时,怎么用「多花点计算」来换「更好的结果」?
- Best-of-N:同一个问题跑 N 次(不同采样),再选/综合最好的一个,简单粗暴但有效。
- 自我检查与修正:让模型对自己的答案再检查一遍、发现问题就修,类似 Reflexion 的轻量版。
核心思想:训练时的能力是上限,但推理时多投入计算,能把这个上限更充分地兑现出来。代价当然是延迟和成本,所以也要按场景权衡。
🧭 这一章到这儿:执行框架的原理、ReAct 与 IterResearch 的取舍、推理侧实现都讲透了,demo 也能跑起来。但有个根本问题本章没解决:模型本身「会不会用这些框架」?一个没经过训练的通用模型,未必懂得「该收手时收手、该更新报告时更新报告」。怎么用数据和强化学习把它训得真正擅长这些,正是第 5-6 章的主题。
🏆 Part 3 · 验收串题 | ~10% 学到这一步,做几道题验证一下。点进去是题库里的完整解析。
关联面试题(5 道,覆盖 5 个角度)
- 【ReAct 工作流】 以 ReAct(Reasoning + Acting)框架为例,详细解释它的工作流:Thought / Action / Observation 怎么交织?
- 【长上下文表现】 ReAct 与 Plan-and-Execute 在处理长上下文任务时各有什么表现差异?
- 【框架取舍】 ReAct 与 Plan-and-Execute 两种推理框架的取舍是什么?什么场景选哪个?
- 【主流框架对比】 系统比较主流 Agent 框架(LangChain / LlamaIndex 等)的架构差异。
- 【长上下文改进】 如何设计 / 改进大模型的记忆机制,提升长上下文建模与任务持续能力?
自检清单
- 能讲清 ReAct「推理 + 行动交织」的核心思想和消息格式(Thought/Action/Observation)
- 能在本机跑通上下文增长 demo,并解释 ReAct 为什么会爆、IterResearch 为什么不会
- 能讲清 IterResearch「演进报告 = 常量大小中央记忆」的设计,以及报告的三个要求
- 能把 ReAct → IterResearch → ReSum 三层「问题逐层加码、方案逐层升级」串成一段叙事
- 能说出 ReWOO / Reflexion / Research-Synthesis 各自的取舍,以及框架选型的判断标准
- 能讲清测试时扩展(Best-of-N / 自我检查)是「用计算换质量」
学完这一章,你已经理解了 Agent 执行框架这条主线,从 ReAct 的朴素,到 IterResearch 的常量工作空间,再到一系列变体的取舍。下一章,我们深入「工具集」:Search / Visit / 计算器 怎么设计,以及统一工具网关、容错和缓存怎么做,让 Agent 真正「会用工具」。