ReAct 是很多人实现 Agent 的第一步。
模型先根据当前问题决定一个动作,程序执行工具,把结果交回模型,模型再决定下一步。这个循环直观、灵活,几十行代码就能跑起来。
做一个两三步的小任务时,它往往很好用:搜索候选,打开正文,给出答案。
问题出现在长程研究。
一个 Deep Research 任务可能要比较多个对象、访问很多来源、处理冲突并生成报告。如果每轮都把之前的问题、动作和网页内容完整追加到上下文,模型看到的历史会越来越长。早期的一段噪声会被反复携带,后面的每一步都要重新读取;关键事实反而可能被埋在大量临时内容中。
于是系统出现一种很典型的现象:它一直在行动,却越来越不知道自己为什么行动。
所以面试官问“ReAct 有什么局限”时,不会满足于一句“上下文会爆”,他还会继续追问:
ReAct 的消息为什么随步骤增长?长上下文怎样放大成本、遗忘和错误?哪些问题仍然适合 ReAct,什么时候应该升级为受控状态或演进报告?
ReAct 的核心是闭环行动
ReAct 的基本循环可以抽象成四步。
第一,读取当前任务和可用状态。
第二,选择一个动作,例如 Search、Visit 或计算。
第三,程序执行动作,返回 Observation。
第四,根据新观察决定继续行动还是给出最终结果。
它比固定 Workflow 灵活,因为下一步不必在任务开始前全部写死。搜索结果暴露一个新实体,Agent 可以继续追;网页打不开,Agent 可以换来源;证据已经充分,Agent 可以收口。
生产系统需要记录可审计的行动、工具参数、观察摘要和决策理由,但不必向用户展示模型内部逐字推理。真正重要的是外部行为能够回放,而不是把隐式思维链当成产品功能。

循环本身可以保留;真正拖垮长任务的是把不断增长的原始历史直接当成唯一状态。
为什么上下文会线性增长?
最朴素的消息列表通常从系统要求和用户问题开始。
第一轮加入模型动作和搜索结果。
第二轮在原消息后继续加入动作和网页正文。
第三轮再加入新的搜索、错误或计算结果。
如果每一步 Observation 的平均长度接近,消息总长度会随着步骤数近似线性增加。运行到后面,一次模型调用要重新读取之前所有内容。
总调用成本的增长会更快。第一步读取一份上下文,第二步读取更长的上下文,后面每一步都在前一步基础上增加。把每轮读取量累加,长轨迹会产生明显的重复计算。
这里不需要背一个固定公式。面试时要说清两个事实:当前上下文随步骤增加;每一轮都会再次处理累积历史。任务越长,这个结构性开销越明显。
上下文没超过窗口,也可能已经失效
很多回答把问题只归结为“超过模型最大 Token”。实际上,在触碰硬上限前,质量已经可能下降。
第一,临时信息污染。
网页正文里有导航、广告、无关段落和旧版本说明。如果全部保留,模型后续每一步都要在噪声中寻找关键事实。
第二,关键内容被淹没。
任务开头确定的硬约束、早期找到的重要证据,可能落在长上下文中间。模型即使能够读取,也未必稳定使用。
第三,状态不清楚。
同一个主张在不同轮次被修改,消息里同时存在旧结论和新结论。若没有显式状态,模型可能引用已经被推翻的版本。
第四,错误不断累积。
早期搜索把两个相似实体混在一起,后面所有查询都围绕错误对象展开。ReAct 会根据当前历史继续做出看似合理的动作,但链路方向已经偏了。
第五,重复行动。
历史很长时,模型可能忘记某个关键词已经搜索过,再次调用同一工具。动作成功,却没有增加证据。
因此,“窗口还装得下”不是系统健康的充分条件。
ReAct 的两个长任务硬伤
第一个硬伤是状态与原始历史没有分开。
网页正文、工具错误、临时推断、最终事实全部混在消息列表中。模型必须自己从一长串记录里恢复当前状态。
第二个硬伤是错误成本会向后传播。
固定流水线某一步失败,通常只影响一个节点;ReAct 的下一步由当前观察决定,错误观察会改变后续动作。步骤越多,可传播的距离越长。
这并不意味着固定 Workflow 一定更好。Workflow 对已知、稳定的业务步骤更可控,ReAct 对需要根据环境变化选择动作的任务更灵活。工程选型要看任务到底需要多少自由度。
一个教学例子:研究链怎样越跑越偏
下面是教学情境,不代表真实客户或线上 Trace。
任务要求比较三个技术方案的部署和维护边界。
第一轮 Search 返回一篇旧文章,文章把两个版本的能力混在一起。
第二轮 Agent 根据旧文章中的功能名称继续搜索,却没有记录版本条件。
第三轮 Visit 打开一篇转载,正文重复第一篇说法,Agent 误以为得到第二个独立来源。
第四轮开始写比较结论,发现另一个候选资料不足,又重复搜索同一关键词。
第五轮上下文里已经有两份重复正文、一个错误版本和多个临时判断。即使模型语言能力很强,它面对的状态本身也不干净。
真正的修复需要让每一步输出进入证据层和状态层:原始页面单独保存,当前状态只留下来源、版本、已确认事实、冲突和缺口。单纯更换更长上下文模型,只会推迟问题出现;错误版本被发现后,旧主张仍要明确失效。
为什么长上下文模型不能直接解决?
更大的上下文窗口可以延后硬溢出,却不会自动解决信息组织。
如果输入里有大量重复网页,窗口变大只是允许系统保存更多重复。
如果旧结论和新结论并存,窗口变大不会告诉模型哪个状态有效。
如果每轮都重新输入全部历史,窗口变大也不消除重复计算和调用成本。
如果来源关系在摘要前就没有保存,模型能读更多文本也无法恢复证据映射。
所以长上下文是一种资源,不是状态管理方案。它应该与结构化研究状态、外部证据存储和摘要机制组合使用。
哪些任务仍然最适合 ReAct?
第一,步骤较少的开放工具任务。
例如先搜索一个候选,再打开官方页面核实。下一步由当前结果决定,但整个链路不会很长。
第二,Observation 短且结构清楚。
工具返回几个字段,而不是整页网页。上下文增长慢,状态冲突也少。
第三,失败容易恢复。
某个工具失败后可以换一次来源,不会让之前几十步全部失效。
第四,任务结束条件明确。
找到特定事实、完成一次计算或验证一个条件后即可结束。
第五,团队需要先跑通最小闭环。
在还没有证明任务需要长程研究时,ReAct 是更简单的起点。过早引入复杂状态更新和摘要,也会增加新的错误面。
什么时候应该升级?
任务经常超过少量步骤,原始工具结果很长,重复和遗忘开始出现时,需要把原始历史和当前状态分开。
一种升级方向是 IterResearch。它不再把全部 Observation 当作唯一记忆,而是维护一份大小受控的演进报告。每轮用新观察更新报告,保留已确认结论、来源、冲突、缺口和下一步,临时网页正文放到外部。
如果演进报告和当前工具交互仍接近窗口上限,再增加 ReSum 动态摘要。摘要触发时必须保留关键事实和来源,不能只保留通顺结论。
升级顺序应该由问题推动:短任务用 ReAct;长任务出现历史堆积时引入受控状态;更长任务才使用动态摘要。不要因为框架名字更高级就默认上最复杂的一档。

每一级只解决上一级已经真实出现的问题,避免为不存在的复杂度付费。
受控研究状态应该保留什么?
任务目标和硬约束必须保留,否则后续动作可能偏离用户要求。
已确认事实要带来源 ID、时间和适用条件,不能只剩一句结论。
冲突信息要同时保留支持和反对证据,不能在状态更新时静默选择一个。
信息缺口要明确列出,下一步动作才知道为什么执行。
已执行动作需要做去重,避免搜索同一查询或反复访问同一来源。
预算和停止状态也要保留,让 Agent 知道还允许做多少工作。
原始网页、完整工具返回和详细日志不必全部进入模型上下文,但要存在外部存储中,通过稳定 ID 可以重新读取。
状态越短越好吗?也不是。压得太狠会丢证据和限定条件。目标是受控、结构清楚、可以更新,而不是追求最小字符数。
怎样避免演进报告自己写错?
把全部历史压成一份报告,会产生新的单点风险。报告更新错了,后续步骤都基于错误状态。
所以更新过程要校验。
第一,关键字段使用固定 Schema,避免每轮自由改结构。
第二,来源 ID、数字、时间和否定关系做规则检查,不能在重写时悄悄变化。
第三,旧状态和新状态做差异比较。新增结论需要新证据,删除结论需要说明被推翻或不再相关。
第四,定期从外部证据重新核对关键 Claim,避免多次摘要后产生漂移。
第五,保留状态版本。出现错误时能回退到上一个可靠版本,而不是只能从头研究。
这也说明 IterResearch 不是银弹。它用状态更新的复杂度,换取对长上下文的控制。任务很短时,这笔交换未必划算。
ReAct 长任务怎么做故障诊断?
先看上下文组成。统计系统要求、用户问题、模型动作、工具结果和摘要分别占多少,不要只看总 Token。
再看重复率。相同意图的查询、重复 URL、相似正文和已经关闭的任务是否反复出现。
再看关键事实保留。把任务开始时的硬约束和中途确认的关键证据设为检查点,看后续步骤是否还能正确使用。
再看错误传播。某个错误主张第一次出现在哪一轮,后面哪些动作依赖它,是否存在纠错入口。
最后看停止行为。任务是证据充分后结束,还是跑到最大步骤被迫结束。

上下文长度只是症状之一,还要定位噪声、重复、遗忘和错误传播。
怎样设计对照实验?
准备同一批研究问题,覆盖短任务、中等任务和长任务。
基线一使用朴素 ReAct,完整保留所有历史。
基线二仍用 ReAct,但工具只返回与当前目标相关的短内容,并增加查询和来源去重。
方案三使用受控演进报告,原始证据外置。
若任务足够长,再测试动态摘要方案。
每种方案观察当前上下文长度、累计输入量、重复动作、关键事实保留、来源映射、任务完成状态和最终报告质量。
不要只比较“能跑多少轮”。系统跑了更多轮,可能只是允许它更久地重复错误。真正的目标是在合理资源内完成可核验研究。
实验还要报告任务分布。短任务上,复杂状态方案可能没有优势;长任务上,受控状态才可能体现价值。把所有问题混成一个平均分,会掩盖选型边界。
从 ReAct 迁移时,不要一次重写全部系统
已有 ReAct 项目出现长任务问题时,可以先做最小改造。
第一阶段只收紧工具输出。Search 保留候选,Visit 根据当前目标抽取相关内容,不再把整页正文塞回上下文。同时保存原始页面,避免以后无法核验。
第二阶段增加动作和来源去重。即使还没有演进报告,也能先减少最明显的无效循环。
第三阶段提取受保护状态。把任务契约、已确认 Claim、来源、缺口和停止原因从聊天历史中独立出来,每轮都显式传入。
第四阶段才替换为演进报告更新。此时可以用前几个阶段收集的 Trace 对比报告是否丢信息,而不是在没有基线时直接切换框架。
第五阶段根据真实窗口压力决定是否引入 ReSum。若大多数任务在受控状态下已经完成,额外摘要只会增加调用和新的漂移风险。
渐进迁移还有一个好处:每一步都能独立回滚。若工具裁剪导致关键信息缺失,可以调整抽取;若报告更新不稳定,可以暂时保留旧执行器,而不必推翻整套 Agent。
状态更新失败时怎样降级?
演进报告本身也是一次模型或程序处理,也可能超时、格式错误或删除关键字段。
更新前先保存旧版本。新状态通过 Schema、来源 ID 和关键约束检查后再提交。校验失败时,可以重试一次结构修复,仍失败则继续使用旧状态并标记当前观察尚未合并,不能用损坏状态覆盖可靠版本。
如果某次工具结果特别长,可以先保存原文和抽取片段,再更新状态。不要在更新失败后把整页正文永久追加回主上下文,否则系统会悄悄退回最初的膨胀模式。
这类降级也要进入 Trace。否则团队只看到最终报告错误,却不知道是搜索、证据抽取还是状态更新阶段丢了信息。
四类 bad case 怎样修?
Bad case 一:同一搜索反复调用
建立标准化动作记录和已访问来源集合。检测到重复后返回可读提示,引导换维度或基于现有证据收口。只在 Prompt 里提醒“不要重复”通常不够。
Bad case 二:后面忘了用户硬约束
把任务契约放进受保护状态,每轮更新不能删除。测试时故意把硬约束放在任务开头,检查长轨迹后是否仍然遵守。
Bad case 三:错误版本污染后续结论
所有关键 Claim 带版本和来源。发现旧资料后,不只新增正确事实,还要把旧 Claim 标为失效,并检查依赖它的任务和结论。
Bad case 四:上下文没超限,但成本失控
查看每轮重复输入量、工具返回长度和无效动作。优先缩短 Visit 输出、外置原文、去重和提前终止,而不是只换更便宜模型。
面试官继续追问,怎么接?
追问一:ReAct 和 Workflow 怎么选?
步骤稳定、规则明确、需要强确定性时用 Workflow;下一步必须根据环境观察动态决定时用 ReAct。可以把高风险固定环节放在 Workflow,局部探索交给 Agent。
追问二:为什么不每轮都做摘要?
摘要需要额外调用,也可能丢信息。短任务没有必要;长任务应在状态增长或窗口压力出现时触发,并验证关键事实与来源保留。
追问三:IterResearch 真的能让上下文恒定吗?
更准确的说法是把主要工作状态控制在设定范围内。工具交互、系统要求和报告本身仍占空间,报告更新也可能丢信息,不能承诺绝对恒定或无限深度。
追问四:原始 Observation 不放上下文,模型需要时怎么办?
原始证据存外部库,状态里保留来源 ID 和摘要。需要复核时按 ID 重新读取相关片段,而不是永久携带所有正文。
追问五:怎样证明错误真的来自上下文?
做分层回放。固定模型和问题,分别使用完整历史、去重后的历史和受控状态,比较同一错误是否消失;同时定位错误 Claim 首次出现和传播路径,不能凭感觉归因。
怎样回答“ReAct 为什么越跑越重”
ReAct 的优势是让决策和行动交替进行,下一步可以根据当前 Observation 动态选择,所以很适合步骤少、工具结果短的任务。它在长程 Deep Research 里的问题,主要来自最朴素实现把所有动作和网页内容一直追加。当前上下文随步骤增长,每轮又要重读旧内容,临时噪声、旧结论和重复来源会污染状态,早期错误也会沿后续动作传播。
我不会因此直接放弃 ReAct,而会按任务长度逐层升级。短任务继续用 ReAct,同时限制 Visit 输出并做动作去重;长任务把原始证据放到外部,只维护一份包含任务约束、已确认事实、来源、冲突、缺口和下一步的受控研究状态;再接近窗口上限时才做动态摘要。状态更新需要固定 Schema、差异检查和版本回退,避免演进报告自己漂移。
验证时我会用短、中、长三类任务比较朴素 ReAct、去重和裁剪后的 ReAct、受控状态方案,观察上下文组成、累计输入、重复动作、关键事实保留、错误传播、停止原因和最终报告质量。轮数本身不决定胜负,能够以可控代价完成可核验研究才是验收重点。

长程 ReAct 改造的验收清单
不要只画外置证据库架构;用短、中、长任务的对照记录证明状态压缩没有丢掉关键事实和来源。
- 你的工具 Observation 平均多长,是否直接塞入整页正文?
- 能否展示上下文随步骤增长的实际 Trace,而不是只说“会爆”?
- 是否记录关键 Claim 第一次出现和被更新的过程?
- 演进报告是否有固定 Schema、来源 ID 和版本?
- 没有真实对照实验时,不要宣称上下文成本从某种复杂度降到另一种复杂度。
ReAct 并不过时。真正过时的是:把一条不断膨胀的聊天记录,当成长期研究系统唯一的记忆。