mirror of
https://github.com/labring/FastGPT.git
synced 2025-10-19 10:07:24 +00:00
Feat: system tool support stream response (#5206)
* Match SSE for FastGPT (#5168) * Match SSE for FastGPT * Modify the judgment * Optimize logic for SSE transmission * Refactor imports * directly use workflowStreamResponse from props * improve error handling and streamline onStreamData logic * Refactor API client configuration * perf: system tool support sse * update doc --------- Co-authored-by: Zhuangzai fa <143257420+ctrlz526@users.noreply.github.com>
This commit is contained in:
@@ -32,6 +32,10 @@ curl --location --request POST 'https://{{host}}/api/admin/initv4101' \
|
|||||||
|
|
||||||
- 给自动同步的知识库加入新的定时任务。
|
- 给自动同步的知识库加入新的定时任务。
|
||||||
|
|
||||||
|
## 🚀 新增内容
|
||||||
|
|
||||||
|
1. 系统工具支持流输出。
|
||||||
|
|
||||||
## ⚙️ 优化
|
## ⚙️ 优化
|
||||||
|
|
||||||
1. 定时任务报错日志记录到对话日志。
|
1. 定时任务报错日志记录到对话日志。
|
||||||
|
@@ -82,5 +82,5 @@ weight: 236
|
|||||||
|
|
||||||
### **相关示例**
|
### **相关示例**
|
||||||
|
|
||||||
- [谷歌搜索](https://doc.fastgpt.in/docs/use-cases/app-cases/google_search/)
|
- [谷歌搜索](https://doc.fastgpt.io/docs/use-cases/app-cases/google_search/)
|
||||||
- [发送飞书webhook](https://doc.fastgpt.in/docs/use-cases/app-cases/feishu_webhook/)
|
- [发送飞书webhook](https://doc.fastgpt.io/docs/use-cases/app-cases/feishu_webhook/)
|
@@ -22,7 +22,7 @@ weight: 602
|
|||||||
|
|
||||||
需要在 dev 环境下执行下面的操作。
|
需要在 dev 环境下执行下面的操作。
|
||||||
|
|
||||||
> 可参照 [FastGPT|快速开始本地开发](https://doc.fastgpt.in/docs/development/intro/)
|
> 可参照 [FastGPT|快速开始本地开发](https://doc.fastgpt.io/docs/development/intro/)
|
||||||
|
|
||||||
1. ### 在 FastGPT 工作台中,创建一个应用
|
1. ### 在 FastGPT 工作台中,创建一个应用
|
||||||
|
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
baseURL = "https://doc.tryfastgpt.ai"
|
baseURL = "https://doc.fastgpt.io"
|
||||||
languageCode = "en-GB"
|
languageCode = "en-GB"
|
||||||
contentDir = "content"
|
contentDir = "content"
|
||||||
enableEmoji = true
|
enableEmoji = true
|
||||||
@@ -114,7 +114,7 @@ defaultContentLanguageInSubdir = false
|
|||||||
# Link behaviour
|
# Link behaviour
|
||||||
intLinkTooltip = true # Enable a tooltip for internal links that displays info about the destination? default false
|
intLinkTooltip = true # Enable a tooltip for internal links that displays info about the destination? default false
|
||||||
# extLinkNewTab = false # Open external links in a new Tab? default true
|
# extLinkNewTab = false # Open external links in a new Tab? default true
|
||||||
logoLinkURL = "https://tryfastgpt.ai/" # Set a custom URL destination for the top header logo link.
|
logoLinkURL = "https://fastgpt.io/" # Set a custom URL destination for the top header logo link.
|
||||||
|
|
||||||
[params.flexsearch] # Parameters for FlexSearch
|
[params.flexsearch] # Parameters for FlexSearch
|
||||||
# enabled = true
|
# enabled = true
|
||||||
|
@@ -12768,8 +12768,8 @@ function main({secret}){
|
|||||||
|
|
||||||
### **相关示例**
|
### **相关示例**
|
||||||
|
|
||||||
- [谷歌搜索](https://doc.fastgpt.in/docs/use-cases/app-cases/google_search/)
|
- [谷歌搜索](https://doc.fastgpt.io/docs/use-cases/app-cases/google_search/)
|
||||||
- [发送飞书webhook](https://doc.fastgpt.in/docs/use-cases/app-cases/feishu_webhook/)
|
- [发送飞书webhook](https://doc.fastgpt.io/docs/use-cases/app-cases/feishu_webhook/)
|
||||||
|
|
||||||
# 用户选择
|
# 用户选择
|
||||||
## FastGPT 用户选择模块的使用说明
|
## FastGPT 用户选择模块的使用说明
|
||||||
@@ -18332,7 +18332,7 @@ Fastgpt 提供了工作流线路可以返回去执行的功能,所以我们可
|
|||||||
|
|
||||||
需要在 dev 环境下执行下面的操作。
|
需要在 dev 环境下执行下面的操作。
|
||||||
|
|
||||||
> 可参照 [FastGPT|快速开始本地开发](https://doc.fastgpt.in/docs/development/intro/)
|
> 可参照 [FastGPT|快速开始本地开发](https://doc.fastgpt.io/docs/development/intro/)
|
||||||
|
|
||||||
1. ### 在 FastGPT 工作台中,创建一个应用
|
1. ### 在 FastGPT 工作台中,创建一个应用
|
||||||
|
|
||||||
|
@@ -3,5 +3,6 @@ export enum TrackEnum {
|
|||||||
createApp = 'createApp',
|
createApp = 'createApp',
|
||||||
useAppTemplate = 'useAppTemplate',
|
useAppTemplate = 'useAppTemplate',
|
||||||
createDataset = 'createDataset',
|
createDataset = 'createDataset',
|
||||||
appNodes = 'appNodes'
|
appNodes = 'appNodes',
|
||||||
|
runSystemTool = 'runSystemTool'
|
||||||
}
|
}
|
||||||
|
@@ -10,7 +10,7 @@ import { type ShortUrlParams } from '@fastgpt/global/support/marketing/type';
|
|||||||
|
|
||||||
const createTrack = ({ event, data }: { event: TrackEnum; data: Record<string, any> }) => {
|
const createTrack = ({ event, data }: { event: TrackEnum; data: Record<string, any> }) => {
|
||||||
if (!global.feConfigs?.isPlus) return;
|
if (!global.feConfigs?.isPlus) return;
|
||||||
addLog.info('Push tracks', {
|
addLog.debug('Push tracks', {
|
||||||
event,
|
event,
|
||||||
...data
|
...data
|
||||||
});
|
});
|
||||||
@@ -65,5 +65,13 @@ export const pushTrack = {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (error) {}
|
} catch (error) {}
|
||||||
|
},
|
||||||
|
runSystemTool: (
|
||||||
|
data: PushTrackCommonType & { toolId: string; result: 1 | 0; usagePoint?: number; msg?: string }
|
||||||
|
) => {
|
||||||
|
return createTrack({
|
||||||
|
event: TrackEnum.runSystemTool,
|
||||||
|
data
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@@ -1,9 +1,12 @@
|
|||||||
import createClient, { type SystemVarType } from '@fastgpt-sdk/plugin';
|
import createClient, { RunToolWithStream } from '@fastgpt-sdk/plugin';
|
||||||
import { PluginSourceEnum } from '@fastgpt/global/core/app/plugin/constants';
|
import { PluginSourceEnum } from '@fastgpt/global/core/app/plugin/constants';
|
||||||
|
|
||||||
|
const BASE_URL = process.env.PLUGIN_BASE_URL || '';
|
||||||
|
const TOKEN = process.env.PLUGIN_TOKEN || '';
|
||||||
|
|
||||||
const client = createClient({
|
const client = createClient({
|
||||||
baseUrl: process.env.PLUGIN_BASE_URL || '',
|
baseUrl: BASE_URL,
|
||||||
token: process.env.PLUGIN_TOKEN || ''
|
token: TOKEN
|
||||||
});
|
});
|
||||||
|
|
||||||
export async function getSystemToolList() {
|
export async function getSystemToolList() {
|
||||||
@@ -26,26 +29,8 @@ export async function getSystemToolList() {
|
|||||||
return Promise.reject(res.body);
|
return Promise.reject(res.body);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function runTool({
|
const runToolInstance = new RunToolWithStream({
|
||||||
toolId,
|
baseUrl: BASE_URL,
|
||||||
inputs,
|
token: TOKEN
|
||||||
systemVar
|
|
||||||
}: {
|
|
||||||
toolId: string;
|
|
||||||
inputs: Record<string, any>;
|
|
||||||
systemVar: SystemVarType;
|
|
||||||
}) {
|
|
||||||
const res = await client.tool.run({
|
|
||||||
body: {
|
|
||||||
toolId,
|
|
||||||
inputs,
|
|
||||||
systemVar
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
export const runSystemTool = runToolInstance.run.bind(runToolInstance);
|
||||||
if (res.status === 200 && res.body.output) {
|
|
||||||
return res.body.output;
|
|
||||||
} else {
|
|
||||||
return Promise.reject(res.body);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
import { getErrText } from '@fastgpt/global/common/error/utils';
|
import { getErrText } from '@fastgpt/global/common/error/utils';
|
||||||
import { NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
import { NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||||
|
import type { SseResponseEventEnum } from '@fastgpt/global/core/workflow/runtime/constants';
|
||||||
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
|
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
|
||||||
import {
|
import {
|
||||||
type DispatchNodeResultType,
|
type DispatchNodeResultType,
|
||||||
@@ -9,11 +10,13 @@ import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
|||||||
import { MCPClient } from '../../../app/mcp';
|
import { MCPClient } from '../../../app/mcp';
|
||||||
import { getSecretValue } from '../../../../common/secret/utils';
|
import { getSecretValue } from '../../../../common/secret/utils';
|
||||||
import type { McpToolDataType } from '@fastgpt/global/core/app/mcpTools/type';
|
import type { McpToolDataType } from '@fastgpt/global/core/app/mcpTools/type';
|
||||||
import { runTool } from '../../../app/tool/api';
|
import { runSystemTool } from '../../../app/tool/api';
|
||||||
import { MongoSystemPlugin } from '../../../app/plugin/systemPluginSchema';
|
import { MongoSystemPlugin } from '../../../app/plugin/systemPluginSchema';
|
||||||
import { SystemToolInputTypeEnum } from '@fastgpt/global/core/app/systemTool/constants';
|
import { SystemToolInputTypeEnum } from '@fastgpt/global/core/app/systemTool/constants';
|
||||||
import type { StoreSecretValueType } from '@fastgpt/global/common/secret/type';
|
import type { StoreSecretValueType } from '@fastgpt/global/common/secret/type';
|
||||||
import { getSystemPluginById, splitCombinePluginId } from '../../../app/plugin/controller';
|
import { getSystemPluginById } from '../../../app/plugin/controller';
|
||||||
|
import { textAdaptGptResponse } from '@fastgpt/global/core/workflow/runtime/utils';
|
||||||
|
import { pushTrack } from '../../../../common/middle/tracks/utils';
|
||||||
|
|
||||||
type SystemInputConfigType = {
|
type SystemInputConfigType = {
|
||||||
type: SystemToolInputTypeEnum;
|
type: SystemToolInputTypeEnum;
|
||||||
@@ -39,13 +42,16 @@ export const dispatchRunTool = async (props: RunToolProps): Promise<RunToolRespo
|
|||||||
runningUserInfo,
|
runningUserInfo,
|
||||||
runningAppInfo,
|
runningAppInfo,
|
||||||
variables,
|
variables,
|
||||||
|
workflowStreamResponse,
|
||||||
node: { name, avatar, toolConfig, version }
|
node: { name, avatar, toolConfig, version }
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
|
const systemToolId = toolConfig?.systemTool?.toolId;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// run system tool
|
// run system tool
|
||||||
if (toolConfig?.systemTool?.toolId) {
|
if (systemToolId) {
|
||||||
const tool = await getSystemPluginById(toolConfig.systemTool!.toolId);
|
const tool = await getSystemPluginById(systemToolId);
|
||||||
|
|
||||||
const inputConfigParams = await (async () => {
|
const inputConfigParams = await (async () => {
|
||||||
switch (params.system_input_config?.type) {
|
switch (params.system_input_config?.type) {
|
||||||
@@ -73,7 +79,9 @@ export const dispatchRunTool = async (props: RunToolProps): Promise<RunToolRespo
|
|||||||
};
|
};
|
||||||
|
|
||||||
const formatToolId = tool.id.split('-')[1];
|
const formatToolId = tool.id.split('-')[1];
|
||||||
const result = await runTool({
|
|
||||||
|
const result = await (async () => {
|
||||||
|
const res = await runSystemTool({
|
||||||
toolId: formatToolId,
|
toolId: formatToolId,
|
||||||
inputs,
|
inputs,
|
||||||
systemVar: {
|
systemVar: {
|
||||||
@@ -91,10 +99,27 @@ export const dispatchRunTool = async (props: RunToolProps): Promise<RunToolRespo
|
|||||||
version
|
version
|
||||||
},
|
},
|
||||||
time: variables.cTime
|
time: variables.cTime
|
||||||
|
},
|
||||||
|
onMessage: ({ type, content }) => {
|
||||||
|
if (workflowStreamResponse && content) {
|
||||||
|
workflowStreamResponse({
|
||||||
|
event: type as unknown as SseResponseEventEnum,
|
||||||
|
data: textAdaptGptResponse({
|
||||||
|
text: content
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
if (res.error) {
|
||||||
|
return Promise.reject(res.error);
|
||||||
|
}
|
||||||
|
if (!res.output) return {};
|
||||||
|
|
||||||
const usagePoints = await (async () => {
|
return res.output;
|
||||||
|
})();
|
||||||
|
|
||||||
|
const usagePoints = (() => {
|
||||||
if (
|
if (
|
||||||
params.system_input_config?.type !== SystemToolInputTypeEnum.system ||
|
params.system_input_config?.type !== SystemToolInputTypeEnum.system ||
|
||||||
result[NodeOutputKeyEnum.systemError]
|
result[NodeOutputKeyEnum.systemError]
|
||||||
@@ -104,6 +129,16 @@ export const dispatchRunTool = async (props: RunToolProps): Promise<RunToolRespo
|
|||||||
return tool.currentCost ?? 0;
|
return tool.currentCost ?? 0;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
pushTrack.runSystemTool({
|
||||||
|
teamId: runningUserInfo.teamId,
|
||||||
|
tmbId: runningUserInfo.tmbId,
|
||||||
|
uid: runningUserInfo.tmbId,
|
||||||
|
toolId: tool.id,
|
||||||
|
result: 1,
|
||||||
|
usagePoint: usagePoints,
|
||||||
|
msg: result[NodeOutputKeyEnum.systemError]
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
[DispatchNodeResponseKeyEnum.nodeResponse]: {
|
[DispatchNodeResponseKeyEnum.nodeResponse]: {
|
||||||
toolRes: result,
|
toolRes: result,
|
||||||
@@ -142,6 +177,17 @@ export const dispatchRunTool = async (props: RunToolProps): Promise<RunToolRespo
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
if (systemToolId) {
|
||||||
|
pushTrack.runSystemTool({
|
||||||
|
teamId: runningUserInfo.teamId,
|
||||||
|
tmbId: runningUserInfo.tmbId,
|
||||||
|
uid: runningUserInfo.tmbId,
|
||||||
|
toolId: systemToolId,
|
||||||
|
result: 0,
|
||||||
|
msg: getErrText(error)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
[DispatchNodeResponseKeyEnum.nodeResponse]: {
|
[DispatchNodeResponseKeyEnum.nodeResponse]: {
|
||||||
moduleLogo: avatar,
|
moduleLogo: avatar,
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fastgpt-sdk/plugin": "^0.1.0",
|
"@fastgpt-sdk/plugin": "^0.1.1",
|
||||||
"@fastgpt/global": "workspace:*",
|
"@fastgpt/global": "workspace:*",
|
||||||
"@modelcontextprotocol/sdk": "^1.12.1",
|
"@modelcontextprotocol/sdk": "^1.12.1",
|
||||||
"@node-rs/jieba": "2.0.1",
|
"@node-rs/jieba": "2.0.1",
|
||||||
|
11
pnpm-lock.yaml
generated
11
pnpm-lock.yaml
generated
@@ -121,8 +121,8 @@ importers:
|
|||||||
packages/service:
|
packages/service:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@fastgpt-sdk/plugin':
|
'@fastgpt-sdk/plugin':
|
||||||
specifier: ^0.1.0
|
specifier: ^0.1.1
|
||||||
version: 0.1.0(@types/node@20.17.24)
|
version: 0.1.1(@types/node@20.17.24)
|
||||||
'@fastgpt/global':
|
'@fastgpt/global':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../global
|
version: link:../global
|
||||||
@@ -1943,8 +1943,8 @@ packages:
|
|||||||
resolution: {integrity: sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==}
|
resolution: {integrity: sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==}
|
||||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||||
|
|
||||||
'@fastgpt-sdk/plugin@0.1.0':
|
'@fastgpt-sdk/plugin@0.1.1':
|
||||||
resolution: {integrity: sha512-XesoJDaZ7p2U0el9rAFcbA8A6dp8l4jrwTOoShTODupJS+7ksY8PVLeC8N8uLCzimXtslB+G9H2nRXih3kBo7Q==}
|
resolution: {integrity: sha512-RiPTbVgUt0yVr8R7MDxXKhSjR/QCAWib7K1L5jdaRRTJQqJMmSdISNlRHzgF2HmbBLBoVomvVz9VYhHSiAqt/w==}
|
||||||
|
|
||||||
'@fastify/accept-negotiator@1.1.0':
|
'@fastify/accept-negotiator@1.1.0':
|
||||||
resolution: {integrity: sha512-OIHZrb2ImZ7XG85HXOONLcJWGosv7sIvM2ifAPQVhg9Lv7qdmMBNVaai4QTdyuaqbKM5eO6sLSQOYI7wEQeCJQ==}
|
resolution: {integrity: sha512-OIHZrb2ImZ7XG85HXOONLcJWGosv7sIvM2ifAPQVhg9Lv7qdmMBNVaai4QTdyuaqbKM5eO6sLSQOYI7wEQeCJQ==}
|
||||||
@@ -10998,8 +10998,9 @@ snapshots:
|
|||||||
|
|
||||||
'@eslint/js@8.57.1': {}
|
'@eslint/js@8.57.1': {}
|
||||||
|
|
||||||
'@fastgpt-sdk/plugin@0.1.0(@types/node@20.17.24)':
|
'@fastgpt-sdk/plugin@0.1.1(@types/node@20.17.24)':
|
||||||
dependencies:
|
dependencies:
|
||||||
|
'@fortaine/fetch-event-source': 3.0.6
|
||||||
'@ts-rest/core': 3.52.1(@types/node@20.17.24)(zod@3.25.51)
|
'@ts-rest/core': 3.52.1(@types/node@20.17.24)(zod@3.25.51)
|
||||||
zod: 3.25.51
|
zod: 3.25.51
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
|
Reference in New Issue
Block a user