游乐游手机版
首页/AI热点日报/热点详情

快速GPT智能体ReAct源码与人工智能框架深度解析

类型:热点整理2026-05-29
FastGPT智能体基于反应模式实现工具调用,对比反应与计划执行模式的性能差异。详解三种调用方式(工具选择、函数调用、提示调用)及代码架构,说明工具调用替代函数调用的演进。阐述工具调用流程与递归终止条件。

深入解析FastGPT Agent的ReAct实现,揭秘大模型推理的三种高效工具调用模式。

核心内容:

1. ReAct与Plan-and-Execute两种推理模式的性能对比与应用场景

2. FastGPT工具调用的三种实现方式及代码架构解析

3. 新旧版本函数调用机制(tool_calls vs function_call)的技术演进

本文介绍了 ReAct 、Plan-and-Execute 两种大模型推理模式,以及 FastGPT 对 ReAct 的三种实现方式。

01 ReAct 和 Plan

先聊聊大模型推理领域两个非常核心的模式:ReAct 和 Plan-and-Execute。理解它们的差异,是把握Agent工作流程的基石。

ReAct,全称Reasoning and Acting,核心逻辑是让大模型进入一个“观察-思考-行动”的循环。它自主决定调用什么工具,解决问题,然后根据结果继续观察、思考、行动,直到任务完成或达到终止条件。从代码实现角度看,这本质就是一个递归或循环过程。循环的结束条件也很直白:要么是问题解决了,要么是调用次数超限了。

而Plan-and-Execute则走了另一条路。它会先让大模型制定一个详细的计划——拆解出若干步骤或子任务,然后按部就班地执行。在执行过程中,虽然允许根据实际情况对计划进行调整,但整体上是一个“先规划后行动”的模式。

从一些公开的评测数据来看,这两者各有千秋。ReAct的优势在于响应速度快,token消耗少;但在处理复杂、多步骤的任务时,表现往往不如Plan-and-Execute。这个结果其实并不意外,毕竟计划和拆解本身就是应对复杂问题的有效策略。

值得注意的是,在实际生产环境中,尤其是在智能客服这类需要即时响应的场景,ReAct往往是最优解。而且,大部分情况下,ReAct所需的“计划”能力,完全可以通过基于Chain-of-Thought(CoT)设计模式的Prompt来完成,不必引入一个独立的规划阶段。

FastGPT中的“工具调用”功能,正是沿用了ReAct的思路。

02 FastGPT 代码

代码所在目录:

1. 入口与主流程

工具调用的核心入口是 dispatchRunTools(位于 runTool/index.ts)。这个函数负责根据当前节点状态、上下文对话历史、用户输入等,动态判断是否需要调用工具,并组装好调用所需的全部参数和上下文信息。

2. 工具调用的三种模式

根据所调用大模型的能力不同,FastGPT提供了三种不同的工具调用方式:

  • ToolChoice(如OpenAI的 tool_calls):通过 runToolWithToolChoice 实现。
  • FunctionCall(如OpenAI的 function_call):通过 runToolWithFunctionCall 实现。
  • PromptCall:通过精心设计的Prompt,引导大模型自主决定是否调用工具,由 runToolWithPromptCall 处理。

dispatchRunTools 会根据模型能力,自动选择最合适的方式。

这里有必要科普一下 tool_callsfunction_call 的演进关系:

function_call(旧版本)

  • 每次只能请求调用一个函数。
  • 此方式已标记为废弃(deprecated)。

tool_calls(新版本)

  • 支持并行调用多个函数。
  • 是目前推荐的标准化做法。

当前最新的模型,主要使用 tool_calls 方式。只需向大模型提供标准的tool schema,无需通过显式的Prompt进行干预。不过,了解一下古老的 PromptCall 是如何处理的,也颇有价值,下面是源码中的Prompt定义:

import { replaceVariable } from '@fastgpt/global/common/string/tools';export const Prompt_Tool_Call = `你是一个智能机器人,除了可以回答用户问题外,你还掌握工具的使用能力。有时候,你可以依赖工具的运行结果,来更准确的回答用户。工具使用了 JSON Schema 的格式声明,其中 toolId 是工具的唯一标识, description 是工具的描述,parameters 是工具的参数及参数表述,required 是必填参数的列表。请你根据工具描述,决定回答问题或是使用工具。在完成任务过程中,USER代表用户的输入,TOOL_RESPONSE代表工具运行结果,ANSWER 代表你的输出。你的每次输出都必须以0,1开头,代表是否需要调用工具:0: 不使用工具,直接回答内容。1: 使用工具,返回工具调用的参数。例如:USER: 你好呀ANSWER: 0: 你好,有什么可以帮助你的么?USER: 现在几点了?ANSWER:  1: {"toolId":"searchToolId1"}TOOL_RESPONSE: """2022/5/5 12:00 Thursday"""ANSWER: 0: 现在是2022年5月5日,星期四,中午12点。USER: 今天杭州的天气如何?ANSWER: 1: {"toolId":"searchToolId2","arguments":{"city": "杭州"}}TOOL_RESPONSE: """晴天......"""ANSWER: 0: 今天杭州是晴天。USER: 今天杭州的天气适合去哪里玩?ANSWER: 1: {"toolId":"searchToolId3","arguments":{"query": "杭州 天气 去哪里玩"}}TOOL_RESPONSE: """晴天. 西湖、灵隐寺、千岛湖……"""ANSWER: 0: 今天杭州是晴天,适合去西湖、灵隐寺、千岛湖等地玩。------现在,我们开始吧!下面是你本次可以使用的工具:"""{{toolsPrompt}}"""下面是正式的对话内容:USER: {{question}}ANSWER: `;export const getMultiplePrompt = (obj: {  fileCount: number;  imgCount: number;  question: string;}) => {  const prompt = `Number of session file inputs:Document:{{fileCount}}Image:{{imgCount}}------{{question}}`;  return replaceVariable(prompt, obj);};

3. 工具调用的详细流程

runToolWithToolChoice 为例,它的执行流程(见 runTool/toolChoice.ts)非常清晰:

  1. 准备工具描述:将所有可用的工具节点(toolNodes)转换为OpenAI标准的tool schema,并将其传递给大模型。
  2. 构造对话历史:将系统prompt、历史消息、用户最新输入等整合,形成完整的对话上下文。
  3. 请求大模型:带着定义好的tools schema,向大模型发起请求。模型会根据上下文和工具描述,自主决定是否需要调用工具,并返回 tool_calls
  4. 执行工具:根据大模型返回的 tool_calls,找到对应的工具节点,解析参数,并实际执行该工具。本质上是调度workflow的一个子流程。
  5. 结果回传:将工具执行结果通过SSE(Server-Sent Events)或直接返回给前端,同时递归判断是否需要继续调用工具,或者结束本轮交互。

工具节点的定义与参数

  • 工具节点(toolNodes)包含了工具的唯一标识(nodeId)、描述、以及参数schema(遵循JSON Schema格式)。
  • 工具参数的定义和校验也在节点schema中完成,最终会被序列化为JSON格式传递给大模型。

4. 递归结束条件

为了防止ReAct循环无限进行下去,系统设定了明确的终止条件:

  1. 工具有交互节点,并被选择:当某个工具节点本身包含了需要用户交互的环节,且被大模型选中,流程会在此等待用户响应。
  2. 没有工具需要调用:这是最直接的结束条件。如果大模型返回的结果中,toolCallsfunctionCallstoolJson 为空,说明模型认为无需再调用任何工具,流程自然结束。
  3. 递归次数达到上限:这是一个关键的保护机制。系统设有一个 maxRunToolTimes 参数(以ToolChoice为例,默认值为30),一旦递归调用次数超过此上限,会强制终止整个流程,防止陷入死循环。
来源:https://www.53ai.com/news/LargeLanguageModel/2025080238071.html

相关热点

继续查看同栏目近期热点。

延伸阅读

补充最近整理过的热点入口。