技术解读
ReAct:让大模型把「想」和「做」缝进同一个循环
项目背景与痛点
2022 年前后,大模型应用基本分成两条路。一条是 Chain-of-Thought:让模型先把推理过程写出来,再给答案。它的问题很直接——推理链再漂亮,也是闭卷考试,模型手里没有证据,只能靠参数记忆硬编,多跳问题上一旦中间事实记错,整条链子跟着塌。另一条是纯 Action 路线,比如 WebGPT、SayCan:模型直接输出搜索、点击、移动等动作,拿环境反馈。这条路能接触真实信息,但模型缺少显式的规划层,几步之后就容易在长流程里迷路,失败也说不清为什么失败。
ReAct 的切入点就是把这两条路焊在一起:每一步先写一句 Thought 说明"我为什么这么做",再发一个 Action,环境回一个 Observation,Observation 又成为下一步 Thought 的依据。推理负责规划和纠错,行动负责提供事实和推进状态。论文在 HotpotQA、FEVER、ALFWorld、WebShop 四个任务上验证了这套循环,而这个仓库,就是那批实验的可复现代码。
核心技术揭秘
先说清楚定位:ysymyth/ReAct 不是一个 Agent 框架,它是实验脚本集合。没有 LangChain,没有插件抽象,没有 YAML 配置。技术栈是 Python 3 + OpenAI 早期 Completion API(text-davinci-002 一代)+ 四个任务各自的环境包装。它的价值恰恰在于这种"裸"——把 ReAct 还原成一件事:字符串拼接 + 一次 API 调用 + 一段正则解析。
真正值得看的是数据流。每个任务目录里都躺着几份手工写好的 prompt_*.txt,内容是若干条完整的 Thought / Action / Observation 示例轨迹,构造成 few-shot 上下文。运行时,脚本把当前 episode 已积累的轨迹前缀接到示例后面,调用模型,用 stop token 截在 Action 那一行,再解析出动作名和参数,路由到对应的工具或环境,把返回的 Observation 拼回上下文,开始下一轮。
这套设计里有三个隐含的技术难点,仓库代码基本都花在它们上面:
其一是动作空间的设计。 HotpotQA 只用 search[...]、lookup[...]、finish[...] 三个动作,ALFWorld 是一组文本化的家务指令。动作空间刻意做得极窄,因为动作越少,模型越不可能输出解析器吃不下的东西。这是范式层面的取舍:牺牲通用性换可控性。
其二是输出解析的鲁棒性。 GPT-3 时代没有 function calling,模型会输出多行、会自作主张续写、会把 Action 写成中文。早期脚本里大量 if/else 就在做截断、正则匹配、非法动作的降级处理。这部分代码不好看,但它决定了整个循环跑不跑得下去。
其三是上下文预算。 2048 token 的窗口,既要装 few-shot 示例,又要装越来越长的轨迹。实际做法是保留开头的示例和最近若干步,丢掉中间历史——这意味着 Agent 会"遗忘"早期搜到的证据,是长任务里最隐蔽的失败源。
功能亮点与差异
对比 CoT,ReAct 的关键差异是推理链里嵌入了外部证据,幻觉显著下降,因为模型的每一句判断都能指向一条 Observation。对比纯 Act 路线,它的杀手锏是那句 Thought:Thought 不调用任何 API、不消耗工具配额,只作为自然语言留在上下文里,却让整个决策过程可读、可审计,也让模型在 Observation 说"Nothing happens"之后有能力换策略而不是原地打转。
还有一点容易被忽略:ReAct 不需要训练。few-shot 提示即可生效,这是它能迅速成为后续 Agent 系统事实标准的原因。后来 LangChain 的 ReActAgent、AutoGPT 的循环骨架,本质上都是这个 prompt 模板的工程化放大。
应用场景与落地建议
适合的场景很明确:多跳问答、事实验证、需要检索的知识库客服、文本游戏与具身任务规划——共同点是任务需要外部信息、且过程需要多步决策。
真上生产,有几件事必须动手改:把文本解析换成结构化输出(JSON schema 或 function calling),这是对原仓库最大的现代化改造,能消灭掉一半的异常分支;做上下文管理,现在有 prompt caching 和更长的窗口,但每步重发全量 prompt 的 token 成本依然随步数线性增长;加护栏,最大步数、重复动作检测、死循环熔断,缺一不可;评估体系换掉,仓库里的 EM/F1 只适合论文对比,生产环境要看工具调用成功率、平均步数、人工抽检准确率。另外,模型生成的查询串会直接打到检索 API,注入和限流都得在工具层兜住。
综合评价
优点:用最少的代码把 Agent 的本质说清楚了——LLM 加工具加循环,剩下的都是工程细节。prompt 全部明文可见,实验可复现,指标可对齐,是极好的基线。
缺点:它是研究脚本,不是库。任务逻辑硬编码、模块之间强耦合、几乎零抽象;API 调用层停留在旧 Completion 接口,直接拿来用要重写;上下文裁剪粗糙,长任务上会丢证据。
一句话结论:别把它当框架依赖,把它当教科书。真正要落地,抄它的循环结构,换掉它的解析器和调用层。
评论