Commit b0a58b98 by Archer Committed by GitHub

feat: toolcall stream response (#6009)

parent a7929bd5
...@@ -114,6 +114,7 @@ description: FastGPT 文档目录 ...@@ -114,6 +114,7 @@ description: FastGPT 文档目录
- [/docs/upgrading/4-14/4141](/docs/upgrading/4-14/4141) - [/docs/upgrading/4-14/4141](/docs/upgrading/4-14/4141)
- [/docs/upgrading/4-14/4142](/docs/upgrading/4-14/4142) - [/docs/upgrading/4-14/4142](/docs/upgrading/4-14/4142)
- [/docs/upgrading/4-14/4143](/docs/upgrading/4-14/4143) - [/docs/upgrading/4-14/4143](/docs/upgrading/4-14/4143)
- [/docs/upgrading/4-14/4144](/docs/upgrading/4-14/4144)
- [/docs/upgrading/4-8/40](/docs/upgrading/4-8/40) - [/docs/upgrading/4-8/40](/docs/upgrading/4-8/40)
- [/docs/upgrading/4-8/41](/docs/upgrading/4-8/41) - [/docs/upgrading/4-8/41](/docs/upgrading/4-8/41)
- [/docs/upgrading/4-8/42](/docs/upgrading/4-8/42) - [/docs/upgrading/4-8/42](/docs/upgrading/4-8/42)
......
---
title: 'V4.14.4(进行中)'
description: 'FastGPT V4.14.4 更新说明'
---
## 🚀 新增内容
1. 工具调用支持配置流输出
## ⚙️ 优化
## 🐛 修复
## 插件
{ {
"title": "4.14.x", "title": "4.14.x",
"description": "", "description": "",
"pages": ["4143", "4142", "4141", "4140"] "pages": ["4144", "4143", "4142", "4141", "4140"]
} }
...@@ -117,7 +117,7 @@ ...@@ -117,7 +117,7 @@
"document/content/docs/upgrading/4-14/4140.mdx": "2025-11-06T15:43:00+08:00", "document/content/docs/upgrading/4-14/4140.mdx": "2025-11-06T15:43:00+08:00",
"document/content/docs/upgrading/4-14/4141.mdx": "2025-11-19T10:15:27+08:00", "document/content/docs/upgrading/4-14/4141.mdx": "2025-11-19T10:15:27+08:00",
"document/content/docs/upgrading/4-14/4142.mdx": "2025-11-18T19:27:14+08:00", "document/content/docs/upgrading/4-14/4142.mdx": "2025-11-18T19:27:14+08:00",
"document/content/docs/upgrading/4-14/4143.mdx": "2025-11-25T17:08:33+08:00", "document/content/docs/upgrading/4-14/4143.mdx": "2025-11-26T20:52:05+08:00",
"document/content/docs/upgrading/4-8/40.mdx": "2025-08-02T19:38:37+08:00", "document/content/docs/upgrading/4-8/40.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/upgrading/4-8/41.mdx": "2025-08-02T19:38:37+08:00", "document/content/docs/upgrading/4-8/41.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/upgrading/4-8/42.mdx": "2025-08-02T19:38:37+08:00", "document/content/docs/upgrading/4-8/42.mdx": "2025-08-02T19:38:37+08:00",
......
...@@ -70,7 +70,8 @@ export const getHistoryPreview = ( ...@@ -70,7 +70,8 @@ export const getHistoryPreview = (
item.text?.content || item?.tools?.map((item) => item.toolName).join(',') || '' item.text?.content || item?.tools?.map((item) => item.toolName).join(',') || ''
); );
}) })
.join('') || '' .join('')
.trim() || ''
); );
} }
return ''; return '';
......
...@@ -53,6 +53,13 @@ export const AgentNode: FlowNodeTemplateType = { ...@@ -53,6 +53,13 @@ export const AgentNode: FlowNodeTemplateType = {
valueType: WorkflowIOValueTypeEnum.number valueType: WorkflowIOValueTypeEnum.number
}, },
{ {
key: NodeInputKeyEnum.aiChatIsResponseText,
renderTypeList: [FlowNodeInputTypeEnum.hidden],
label: '',
value: true,
valueType: WorkflowIOValueTypeEnum.boolean
},
{
key: NodeInputKeyEnum.aiChatVision, key: NodeInputKeyEnum.aiChatVision,
renderTypeList: [FlowNodeInputTypeEnum.hidden], renderTypeList: [FlowNodeInputTypeEnum.hidden],
label: '', label: '',
......
...@@ -265,7 +265,7 @@ export const loadRequestMessages = async ({ ...@@ -265,7 +265,7 @@ export const loadRequestMessages = async ({
| undefined | undefined
) => { ) => {
if (typeof content === 'string') { if (typeof content === 'string') {
return content || ''; return content?.trim() || '';
} }
// 交互节点 // 交互节点
if (!content) return ''; if (!content) return '';
...@@ -273,7 +273,10 @@ export const loadRequestMessages = async ({ ...@@ -273,7 +273,10 @@ export const loadRequestMessages = async ({
const result = content.filter((item) => item?.type === 'text'); const result = content.filter((item) => item?.type === 'text');
if (result.length === 0) return ''; if (result.length === 0) return '';
return result.map((item) => item.text).join('\n'); return result
.map((item) => item.text)
.join('\n')
.trim();
}; };
if (messages.length === 0) { if (messages.length === 0) {
......
...@@ -57,7 +57,8 @@ export const dispatchRunTools = async (props: DispatchToolModuleProps): Promise< ...@@ -57,7 +57,8 @@ export const dispatchRunTools = async (props: DispatchToolModuleProps): Promise<
history = 6, history = 6,
fileUrlList: fileLinks, fileUrlList: fileLinks,
aiChatVision, aiChatVision,
aiChatReasoning aiChatReasoning,
isResponseAnswerText = true
} }
} = props; } = props;
...@@ -235,7 +236,9 @@ export const dispatchRunTools = async (props: DispatchToolModuleProps): Promise< ...@@ -235,7 +236,9 @@ export const dispatchRunTools = async (props: DispatchToolModuleProps): Promise<
(sum, item) => sum + item.runTimes, (sum, item) => sum + item.runTimes,
0 0
), ),
[DispatchNodeResponseKeyEnum.assistantResponses]: previewAssistantResponses, [DispatchNodeResponseKeyEnum.assistantResponses]: isResponseAnswerText
? previewAssistantResponses
: undefined,
[DispatchNodeResponseKeyEnum.nodeResponse]: { [DispatchNodeResponseKeyEnum.nodeResponse]: {
// 展示的积分消耗 // 展示的积分消耗
totalPoints: totalPointsUsage, totalPoints: totalPointsUsage,
......
...@@ -33,7 +33,8 @@ export const runToolCall = async (props: DispatchToolModuleProps): Promise<RunTo ...@@ -33,7 +33,8 @@ export const runToolCall = async (props: DispatchToolModuleProps): Promise<RunTo
aiChatStopSign, aiChatStopSign,
aiChatResponseFormat, aiChatResponseFormat,
aiChatJsonSchema, aiChatJsonSchema,
aiChatReasoning aiChatReasoning,
isResponseAnswerText = true
} }
} = workflowProps; } = workflowProps;
...@@ -141,6 +142,7 @@ export const runToolCall = async (props: DispatchToolModuleProps): Promise<RunTo ...@@ -141,6 +142,7 @@ export const runToolCall = async (props: DispatchToolModuleProps): Promise<RunTo
}); });
}, },
onStreaming({ text }) { onStreaming({ text }) {
if (!isResponseAnswerText) return;
workflowStreamResponse?.({ workflowStreamResponse?.({
write, write,
event: SseResponseEventEnum.answer, event: SseResponseEventEnum.answer,
...@@ -150,6 +152,7 @@ export const runToolCall = async (props: DispatchToolModuleProps): Promise<RunTo ...@@ -150,6 +152,7 @@ export const runToolCall = async (props: DispatchToolModuleProps): Promise<RunTo
}); });
}, },
onToolCall({ call }) { onToolCall({ call }) {
if (!isResponseAnswerText) return;
const toolNode = toolNodesMap.get(call.function.name); const toolNode = toolNodesMap.get(call.function.name);
if (toolNode) { if (toolNode) {
workflowStreamResponse?.({ workflowStreamResponse?.({
...@@ -168,6 +171,7 @@ export const runToolCall = async (props: DispatchToolModuleProps): Promise<RunTo ...@@ -168,6 +171,7 @@ export const runToolCall = async (props: DispatchToolModuleProps): Promise<RunTo
} }
}, },
onToolParam({ tool, params }) { onToolParam({ tool, params }) {
if (!isResponseAnswerText) return;
workflowStreamResponse?.({ workflowStreamResponse?.({
write, write,
event: SseResponseEventEnum.toolParams, event: SseResponseEventEnum.toolParams,
...@@ -209,18 +213,20 @@ export const runToolCall = async (props: DispatchToolModuleProps): Promise<RunTo ...@@ -209,18 +213,20 @@ export const runToolCall = async (props: DispatchToolModuleProps): Promise<RunTo
// Format tool response // Format tool response
const stringToolResponse = formatToolResponse(toolRunResponse.toolResponses); const stringToolResponse = formatToolResponse(toolRunResponse.toolResponses);
workflowStreamResponse?.({ if (isResponseAnswerText) {
event: SseResponseEventEnum.toolResponse, workflowStreamResponse?.({
data: { event: SseResponseEventEnum.toolResponse,
tool: { data: {
id: call.id, tool: {
toolName: '', id: call.id,
toolAvatar: '', toolName: '',
params: '', toolAvatar: '',
response: sliceStrStartEnd(stringToolResponse, 5000, 5000) params: '',
response: sliceStrStartEnd(stringToolResponse, 5000, 5000)
}
} }
} });
}); }
toolRunResponses.push(toolRunResponse); toolRunResponses.push(toolRunResponse);
...@@ -258,18 +264,20 @@ export const runToolCall = async (props: DispatchToolModuleProps): Promise<RunTo ...@@ -258,18 +264,20 @@ export const runToolCall = async (props: DispatchToolModuleProps): Promise<RunTo
// console.dir(runtimeEdges, { depth: null }); // console.dir(runtimeEdges, { depth: null });
const stringToolResponse = formatToolResponse(toolRunResponse.toolResponses); const stringToolResponse = formatToolResponse(toolRunResponse.toolResponses);
workflowStreamResponse?.({ if (isResponseAnswerText) {
event: SseResponseEventEnum.toolResponse, workflowStreamResponse?.({
data: { event: SseResponseEventEnum.toolResponse,
tool: { data: {
id: toolParams.toolCallId, tool: {
toolName: '', id: toolParams.toolCallId,
toolAvatar: '', toolName: '',
params: '', toolAvatar: '',
response: sliceStrStartEnd(stringToolResponse, 5000, 5000) params: '',
response: sliceStrStartEnd(stringToolResponse, 5000, 5000)
}
} }
} });
}); }
toolRunResponses.push(toolRunResponse); toolRunResponses.push(toolRunResponse);
const assistantMessages = chats2GPTMessages({ const assistantMessages = chats2GPTMessages({
......
...@@ -31,6 +31,7 @@ export type DispatchToolModuleProps = ModuleDispatchProps<{ ...@@ -31,6 +31,7 @@ export type DispatchToolModuleProps = ModuleDispatchProps<{
[NodeInputKeyEnum.aiSystemPrompt]: string; [NodeInputKeyEnum.aiSystemPrompt]: string;
[NodeInputKeyEnum.aiChatTemperature]: number; [NodeInputKeyEnum.aiChatTemperature]: number;
[NodeInputKeyEnum.aiChatMaxToken]: number; [NodeInputKeyEnum.aiChatMaxToken]: number;
[NodeInputKeyEnum.aiChatIsResponseText]: boolean;
[NodeInputKeyEnum.aiChatVision]?: boolean; [NodeInputKeyEnum.aiChatVision]?: boolean;
[NodeInputKeyEnum.aiChatReasoning]?: boolean; [NodeInputKeyEnum.aiChatReasoning]?: boolean;
[NodeInputKeyEnum.aiChatTopP]?: number; [NodeInputKeyEnum.aiChatTopP]?: number;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment