FastGPT 工作流工具调用流程详解:从点击「运行」到模型响应
原创2025年10月30日大约 5 分钟
🚀 FastGPT 工作流工具调用流程详解:从点击「运行」到模型响应
在 FastGPT 的工作流编辑模式下,我们经常会点击 「运行 (Run)」 按钮来测试当前节点逻辑或工具调用效果。
那么,这个「运行」背后的完整执行流程是怎样的?
本文将带你从前端到服务端,一步步剖析 工作流工具节点的调用链路。
🧩 一、主流程概览
在编辑器中点击 “Run” 后,整个调用链路可以概括为以下几个阶段:
- 前端发起请求
- 后端 API 接收并调度
- 分发工作流节点
- 工具节点执行(Tool Call)
- 调用大模型 (LLM)
- 生成响应并返回
下面是对应的文件调用路径:
| 阶段 | 文件位置 | 说明 |
|---|---|---|
| 前端页面入口 | /app/detail?appId=xxxxxa6b6e683355dxxxxx | 前端页面 |
| 后端API入口 | /api/core/chat/chatTest.ts | 处理前端 run 请求 |
| 工作流调度 | /packages/service/core/workflow/dispatch/index.ts | 调用 dispatchWorkFlow |
| 节点类型映射 | callbackMap[node.flowNodeType] | 分发不同节点类型逻辑 |
| 工具节点执行 | /packages/service/core/workflow/dispatch/ai/agent/index.ts | runToolCall 入口 |
| 调用大模型 | /packages/service/core/workflow/dispatch/ai/agent/toolCall.ts | createLLMResponse 执行 |
| LLM 请求封装 | /packages/service/core/ai/llm/request.ts | createChatCompletion 负责最终调用 |
🧠 二、流程图(Mermaid)
下面这张 Mermaid 流程图 展示了从前端点击「Run」开始,到最终触发大模型响应的完整调用链:
🧩 三、关键模块解析
1️⃣ /api/core/chat/chatTest.ts
前端 “Run” 操作首先命中此 API。它的职责是:
- 解析请求参数;
- 初始化工作流上下文;
- 调用
dispatchWorkFlow进入工作流执行逻辑。
/* start process */
const {
flowResponses,
assistantResponses,
system_memories,
newVariables,
flowUsages,
durationSeconds
} = await dispatchWorkFlow({
res,
lang: getLocale(req),
requestOrigin: req.headers.origin,
mode: 'test',
timezone,
externalProvider,
uid: tmbId,
runningAppInfo: {
id: appId,
teamId: app.teamId,
tmbId: app.tmbId
},
runningUserInfo:await getRunningUserInfoByTmbId(tmbId),
chatId,
responseChatItemId,
runtimeNodes,
runtimeEdges: storeEdges2RuntimeEdges(edges, interactive),
variables,
query: removeEmptyUserInput(userQuestion.value),
lastInteractive: interactive,
chatConfig,
histories: newHistories,
stream: true,
maxRunTimes: WORKFLOW_MAX_RUN_TIMES,
workflowStreamResponse: workflowResponseWrite,
version: 'v2',
responseDetail: true
});2️⃣ dispatchWorkFlow 位于:
packages/service/core/workflow/dispatch/index.ts负责分发每个节点的执行逻辑,核心是根据节点类型从
callbackMap中找到对应执行函数。
// run module
const dispatchRes: NodeResponseType = await (async () => {
if (callbackMap[node.flowNodeType]) {
const targetEdges = runtimeEdges.filter((item) => item.source === node.nodeId);
try {
const result = (await callbackMap[node.flowNodeType](dispatchData)) as NodeResponseType;
const errorHandleId = getHandleId(node.nodeId, 'source_catch', 'right');
// ......
return {};
}catch (e) {
}
}
});3️⃣ 工具节点执行:runToolCall 当节点类型为工具(Tool Node)时,调用:
packages/service/core/workflow/dispatch/ai/agent/index.ts此函数会:
- 构造工具调用上下文;
- 生成 ToolCall 指令;
- 进入下一步 LLM 调用阶段。
const {
toolWorkflowInteractiveResponse,
dispatchFlowResponse, // tool flow response
toolCallInputTokens,
toolCallOutputTokens,
completeMessages = [], // The actual message sent to AI(just save text)
assistantResponses = [], // FastGPT system store assistant.value response
runTimes,
finish_reason
} = await (async () => {
const adaptMessages = chats2GPTMessages({
messages,
reserveId: false,
toolReserveBehavior: toolReserveBehavior
});
const requestParams = {
runtimeNodes,
runtimeEdges,
toolNodes,
toolModel,
messages: adaptMessages,
interactiveEntryToolParams: lastInteractive?.toolParams
};
return runToolCall({
...props,
...requestParams,
maxRunToolTimes: 30
});
})();4️⃣ 调用大模型:createLLMResponse 位于:
packages/service/core/workflow/dispatch/ai/agent/toolCall.ts职责是根据工具调用上下文,向 LLM 构造一次完整的对话请求。
let {
reasoningText: reasoningContent,
answerText: answer,
toolCalls = [],
finish_reason,
usage,
getEmptyResponseTip,
assistantMessage,
completeMessages
} = await createLLMResponse({
body: {
model: toolModel.model,
stream,
reasoning: aiChatReasoning,
messages: filterMessages,
tool_choice: 'auto',
toolCallMode: toolModel.toolChoice ? 'toolChoice' : 'prompt',
tools,
parallel_tool_calls: true,
temperature,
max_tokens,
top_p: aiChatTopP,
stop: aiChatStopSign,
response_format: {
type: aiChatResponseFormat as any,
json_schema: aiChatJsonSchema
},
retainDatasetCite,
useVision: aiChatVision,
requestOrigin
},
isAborted: () => res?.closed,
userKey: externalProvider.openaiAccount,
onReasoning({ text }) {
workflowStreamResponse?.({
write,
event: SseResponseEventEnum.answer,
data: textAdaptGptResponse({
reasoning_content: text
})
});
},
onStreaming({ text }) {
workflowStreamResponse?.({
write,
event: SseResponseEventEnum.answer,
data: textAdaptGptResponse({
text
})
});
},
onToolCall({ call }) {
const toolNode = toolNodesMap.get(call.function.name);
if (toolNode) {
workflowStreamResponse?.({
event: SseResponseEventEnum.toolCall,
data: {
tool: {
id: call.id,
toolName: toolNode.name,
toolAvatar: toolNode.avatar,
functionName: call.function.name,
params: call.function.arguments ?? '',
response: ''
}
}
});
}
},
onToolCall({ call }) {
const toolNode = toolNodesMap.get(call.function.name);
if (toolNode) {
workflowStreamResponse?.({
event: SseResponseEventEnum.toolCall,
data: {
tool: {
id: call.id,
toolName: toolNode.name,
toolAvatar: toolNode.avatar,
functionName: call.function.name,
params: call.function.arguments ?? '',
response: ''
}
}
});
}
},
onToolParam({ tool, params }) {
workflowStreamResponse?.({
write,
event: SseResponseEventEnum.toolParams,
data: {
tool: {
id: tool.id,
toolName: '',
toolAvatar: '',
params,
response: ''
}
}
});
}
});5️⃣ 最终请求:createChatCompletion 位于:
packages/service/core/ai/llm/request.ts这是底层封装的模型调用接口,通常会将请求参数统一转换为 OpenAI 或兼容接口格式,最终发出模型请求。
const requestBody = await llmCompletionsBodyFormat({
...body,
messages: rewriteMessages
});
const { response, isStreamResponse, getEmptyResponseTip } = await createChatCompletion({
body: requestBody,
userKey,
options: {
headers: {
Accept: 'application/json, text/plain, */*',
...custonHeaders
}
}
});
const { answerText, reasoningText, toolCalls, finish_reason, usage } = await (async () => {
if (isStreamResponse) {
return createStreamResponse({
response,
body,
isAborted: args.isAborted,
onStreaming: args.onStreaming,
onReasoning: args.onReasoning,
onToolCall: args.onToolCall,
onToolParam: args.onToolParam
});
} else {
return createCompleteResponse({
response,
body,
onStreaming: args.onStreaming,
onReasoning: args.onReasoning,
onToolCall: args.onToolCall
});
}
})();🔧 深度扩展:
- 调整请求的
Message Body等参数 - 可在
dispatchWorkFlow中添加日志,追踪节点执行顺序; - 分析
callbackMap的结构,了解不同节点类型; - 对 LLM 请求封装层(
createChatCompletion)增加埋点,监控模型延时与失败率。