mirror of
https://github.com/labring/FastGPT.git
synced 2025-10-14 15:11:13 +00:00
perf: agent plan
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
import { NodeInputKeyEnum, NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
import type { NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||||
|
import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||||
import {
|
import {
|
||||||
ConfirmPlanAgentText,
|
ConfirmPlanAgentText,
|
||||||
DispatchNodeResponseKeyEnum,
|
DispatchNodeResponseKeyEnum,
|
||||||
@@ -17,6 +18,7 @@ import { type ChatItemType } from '@fastgpt/global/core/chat/type';
|
|||||||
import { ChatRoleEnum } from '@fastgpt/global/core/chat/constants';
|
import { ChatRoleEnum } from '@fastgpt/global/core/chat/constants';
|
||||||
import {
|
import {
|
||||||
GPTMessages2Chats,
|
GPTMessages2Chats,
|
||||||
|
chatValue2RuntimePrompt,
|
||||||
chats2GPTMessages,
|
chats2GPTMessages,
|
||||||
getSystemPrompt_ChatItemType,
|
getSystemPrompt_ChatItemType,
|
||||||
runtimePrompt2ChatsValue
|
runtimePrompt2ChatsValue
|
||||||
@@ -43,6 +45,7 @@ import { addFilePrompt2Input, getFileInputPrompt } from './sub/file/utils';
|
|||||||
import type { ChatCompletionMessageParam } from '@fastgpt/global/core/ai/type';
|
import type { ChatCompletionMessageParam } from '@fastgpt/global/core/ai/type';
|
||||||
import { dispatchFileRead } from './sub/file';
|
import { dispatchFileRead } from './sub/file';
|
||||||
import { dispatchApp, dispatchPlugin } from './sub/app';
|
import { dispatchApp, dispatchPlugin } from './sub/app';
|
||||||
|
import { getSubAppsPrompt } from './sub/plan/prompt';
|
||||||
|
|
||||||
export type DispatchAgentModuleProps = ModuleDispatchProps<{
|
export type DispatchAgentModuleProps = ModuleDispatchProps<{
|
||||||
[NodeInputKeyEnum.history]?: ChatItemType[];
|
[NodeInputKeyEnum.history]?: ChatItemType[];
|
||||||
@@ -84,7 +87,7 @@ export const dispatchRunAgent = async (props: DispatchAgentModuleProps): Promise
|
|||||||
params: {
|
params: {
|
||||||
model,
|
model,
|
||||||
systemPrompt,
|
systemPrompt,
|
||||||
userChatInput,
|
userChatInput: taskInput,
|
||||||
history = 6,
|
history = 6,
|
||||||
fileUrlList: fileLinks,
|
fileUrlList: fileLinks,
|
||||||
temperature,
|
temperature,
|
||||||
@@ -119,6 +122,9 @@ export const dispatchRunAgent = async (props: DispatchAgentModuleProps): Promise
|
|||||||
// Check interactive entry
|
// Check interactive entry
|
||||||
props.node.isEntry = false;
|
props.node.isEntry = false;
|
||||||
|
|
||||||
|
// 交互模式进来的话,这个值才是交互输入的值
|
||||||
|
const interactiveInput = lastInteractive ? chatValue2RuntimePrompt(query).text : '';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Get files
|
// Get files
|
||||||
const fileUrlInput = inputs.find((item) => item.key === NodeInputKeyEnum.fileUrlList);
|
const fileUrlInput = inputs.find((item) => item.key === NodeInputKeyEnum.fileUrlList);
|
||||||
@@ -165,15 +171,90 @@ export const dispatchRunAgent = async (props: DispatchAgentModuleProps): Promise
|
|||||||
const toolNode = subAppsMap.get(id) || systemSubInfo[id];
|
const toolNode = subAppsMap.get(id) || systemSubInfo[id];
|
||||||
return {
|
return {
|
||||||
name: toolNode?.name || '',
|
name: toolNode?.name || '',
|
||||||
avatar: toolNode?.avatar || ''
|
avatar: toolNode?.avatar || '',
|
||||||
|
toolDescription: toolNode?.toolDescription || toolNode?.name || ''
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* ===== Plan Agent ===== */
|
||||||
|
let planMessages: ChatCompletionMessageParam[] = [];
|
||||||
|
/*
|
||||||
|
Top agent
|
||||||
|
1. 首轮执行:有
|
||||||
|
2. 交互/check:有
|
||||||
|
3. Confirmed plan: 无
|
||||||
|
4. masteragent 的交互时间: 无
|
||||||
|
|
||||||
|
Sub agent
|
||||||
|
只会执行一次,肯定有。
|
||||||
|
*/
|
||||||
|
let masterPlanToolCallMessages: ChatCompletionMessageParam[] = [];
|
||||||
|
|
||||||
|
if (
|
||||||
|
// 不为 userSelect 和 userInput,或者如果为 agentPlanCheck 并且 interactiveInput !== ConfirmPlanAgentText 都会执行
|
||||||
|
(lastInteractive?.type !== 'userSelect' &&
|
||||||
|
lastInteractive?.type !== 'userInput' &&
|
||||||
|
lastInteractive?.type !== 'agentPlanCheck') ||
|
||||||
|
(lastInteractive?.type === 'agentPlanCheck' && interactiveInput !== ConfirmPlanAgentText)
|
||||||
|
) {
|
||||||
|
// 临时代码
|
||||||
|
const tmpText = '正在进行规划生成...\n';
|
||||||
|
workflowStreamResponse?.({
|
||||||
|
event: SseResponseEventEnum.answer,
|
||||||
|
data: textAdaptGptResponse({
|
||||||
|
text: tmpText
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
const {
|
||||||
|
answerText,
|
||||||
|
planList,
|
||||||
|
planToolCallMessages,
|
||||||
|
completeMessages,
|
||||||
|
usages,
|
||||||
|
interactiveResponse
|
||||||
|
} = await dispatchPlanAgent({
|
||||||
|
historyMessages: planHistoryMessages,
|
||||||
|
userInput: lastInteractive ? interactiveInput : taskInput,
|
||||||
|
interactive: lastInteractive,
|
||||||
|
subAppPrompt: getSubAppsPrompt({ subAppList, getSubAppInfo }),
|
||||||
|
model,
|
||||||
|
systemPrompt,
|
||||||
|
temperature,
|
||||||
|
top_p: aiChatTopP,
|
||||||
|
stream,
|
||||||
|
isTopPlanAgent: workflowDispatchDeep === 1
|
||||||
|
});
|
||||||
|
|
||||||
|
const text = `${answerText}${planList ? `\n\`\`\`json\n${JSON.stringify(planList, null, 2)}\n\`\`\`` : ''}`;
|
||||||
|
workflowStreamResponse?.({
|
||||||
|
event: SseResponseEventEnum.answer,
|
||||||
|
data: textAdaptGptResponse({
|
||||||
|
text
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
planMessages = completeMessages;
|
||||||
|
masterPlanToolCallMessages = planToolCallMessages;
|
||||||
|
|
||||||
|
// TODO: usage 合并
|
||||||
|
// Sub agent plan 不会有交互响应。Top agent plan 肯定会有。
|
||||||
|
if (interactiveResponse) {
|
||||||
|
return {
|
||||||
|
[DispatchNodeResponseKeyEnum.answerText]: `${tmpText}${text}`,
|
||||||
|
[DispatchNodeResponseKeyEnum.memories]: {
|
||||||
|
[planMessagesKey]: filterMemoryMessages(planMessages)
|
||||||
|
},
|
||||||
|
[DispatchNodeResponseKeyEnum.interactive]: interactiveResponse
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Master agent ===== */
|
||||||
|
|
||||||
// Get master request messages
|
// Get master request messages
|
||||||
const systemMessages = chats2GPTMessages({
|
const systemMessages = chats2GPTMessages({
|
||||||
messages: getSystemPrompt_ChatItemType(
|
messages: getSystemPrompt_ChatItemType(getMasterAgentDefaultPrompt()),
|
||||||
workflowDispatchDeep === 1 ? getMasterAgentDefaultPrompt() : systemPrompt
|
|
||||||
),
|
|
||||||
reserveId: false
|
reserveId: false
|
||||||
});
|
});
|
||||||
const historyMessages: ChatCompletionMessageParam[] = (() => {
|
const historyMessages: ChatCompletionMessageParam[] = (() => {
|
||||||
@@ -184,87 +265,24 @@ export const dispatchRunAgent = async (props: DispatchAgentModuleProps): Promise
|
|||||||
return chats2GPTMessages({ messages: chatHistories, reserveId: false });
|
return chats2GPTMessages({ messages: chatHistories, reserveId: false });
|
||||||
})();
|
})();
|
||||||
|
|
||||||
if (lastInteractive?.type !== 'userSelect' && lastInteractive?.type !== 'userInput') {
|
|
||||||
userChatInput = query[0].text?.content ?? userChatInput;
|
|
||||||
}
|
|
||||||
const userMessages = chats2GPTMessages({
|
const userMessages = chats2GPTMessages({
|
||||||
messages: [
|
messages: [
|
||||||
{
|
{
|
||||||
obj: ChatRoleEnum.Human,
|
obj: ChatRoleEnum.Human,
|
||||||
value: runtimePrompt2ChatsValue({
|
value: runtimePrompt2ChatsValue({
|
||||||
text: addFilePrompt2Input({ query: userChatInput, filePrompt: fileInputPrompt }),
|
text: addFilePrompt2Input({ query: taskInput, filePrompt: fileInputPrompt }),
|
||||||
files: []
|
files: []
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
reserveId: false
|
reserveId: false
|
||||||
});
|
});
|
||||||
|
const requestMessages = [
|
||||||
const requestMessages = [...systemMessages, ...historyMessages, ...userMessages];
|
...systemMessages,
|
||||||
|
...historyMessages,
|
||||||
// TODO: 执行 plan function(只有lastInteractive userselect/userInput 时候,才不需要进入 plan)
|
...masterPlanToolCallMessages,
|
||||||
if (
|
...userMessages
|
||||||
lastInteractive?.type !== 'userSelect' &&
|
];
|
||||||
lastInteractive?.type !== 'userInput' &&
|
|
||||||
userChatInput !== ConfirmPlanAgentText &&
|
|
||||||
workflowDispatchDeep === 1
|
|
||||||
) {
|
|
||||||
const planRequestMessages = [...planHistoryMessages, ...userMessages];
|
|
||||||
const { completeMessages, toolMessages, usages, interactiveResponse } =
|
|
||||||
await dispatchPlanAgent({
|
|
||||||
messages: planRequestMessages,
|
|
||||||
subApps: subAppList,
|
|
||||||
model,
|
|
||||||
temperature,
|
|
||||||
top_p: aiChatTopP,
|
|
||||||
systemPrompt,
|
|
||||||
stream,
|
|
||||||
onReasoning: ({ text }: { text: string }) => {
|
|
||||||
workflowStreamResponse?.({
|
|
||||||
event: SseResponseEventEnum.answer,
|
|
||||||
data: textAdaptGptResponse({
|
|
||||||
reasoning_content: text
|
|
||||||
})
|
|
||||||
});
|
|
||||||
},
|
|
||||||
onStreaming: ({ text }: { text: string }) => {
|
|
||||||
workflowStreamResponse?.({
|
|
||||||
event: SseResponseEventEnum.answer,
|
|
||||||
data: textAdaptGptResponse({
|
|
||||||
text
|
|
||||||
})
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (toolMessages) requestMessages.push(...toolMessages);
|
|
||||||
|
|
||||||
return {
|
|
||||||
[DispatchNodeResponseKeyEnum.memories]: {
|
|
||||||
[masterMessagesKey]: filterMemoryMessages(requestMessages),
|
|
||||||
[planMessagesKey]: filterMemoryMessages(completeMessages)
|
|
||||||
},
|
|
||||||
[DispatchNodeResponseKeyEnum.interactive]: interactiveResponse
|
|
||||||
|
|
||||||
// Mock: 返回 plan user input
|
|
||||||
// [DispatchNodeResponseKeyEnum.interactive]: {
|
|
||||||
// type: 'agentPlanAskUserForm',
|
|
||||||
// params: {
|
|
||||||
// description: '测试',
|
|
||||||
// inputForm: [
|
|
||||||
// {
|
|
||||||
// type: FlowNodeInputTypeEnum.input,
|
|
||||||
// key: 'test1',
|
|
||||||
// label: '测试1',
|
|
||||||
// value: '',
|
|
||||||
// valueType: WorkflowIOValueTypeEnum.string,
|
|
||||||
// required: true
|
|
||||||
// }
|
|
||||||
// ]
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const dispatchFlowResponse: ChatHistoryItemResType[] = [];
|
const dispatchFlowResponse: ChatHistoryItemResType[] = [];
|
||||||
const {
|
const {
|
||||||
@@ -371,7 +389,7 @@ export const dispatchRunAgent = async (props: DispatchAgentModuleProps): Promise
|
|||||||
isEnd: true
|
isEnd: true
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
// TODO: 现在是程序中强制执行的 Plan
|
// TODO: 可能会再次触发 plan
|
||||||
// else if (toolId === SubAppIds.plan) {
|
// else if (toolId === SubAppIds.plan) {
|
||||||
// const { completeMessages, response, usages, interactiveResponse } =
|
// const { completeMessages, response, usages, interactiveResponse } =
|
||||||
// await dispatchPlanAgent({
|
// await dispatchPlanAgent({
|
||||||
@@ -393,18 +411,26 @@ export const dispatchRunAgent = async (props: DispatchAgentModuleProps): Promise
|
|||||||
// };
|
// };
|
||||||
// }
|
// }
|
||||||
else if (toolId === SubAppIds.model) {
|
else if (toolId === SubAppIds.model) {
|
||||||
const { systemPrompt, task } = parseToolArgs<{
|
const params = parseToolArgs<{
|
||||||
systemPrompt: string;
|
systemPrompt: string;
|
||||||
task: string;
|
task: string;
|
||||||
}>(call.function.arguments);
|
}>(call.function.arguments);
|
||||||
|
|
||||||
|
if (!params) {
|
||||||
|
return {
|
||||||
|
response: 'params is not object',
|
||||||
|
usages: [],
|
||||||
|
isEnd: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
const { response, usages } = await dispatchModelAgent({
|
const { response, usages } = await dispatchModelAgent({
|
||||||
model,
|
model,
|
||||||
temperature,
|
temperature,
|
||||||
top_p: aiChatTopP,
|
top_p: aiChatTopP,
|
||||||
stream,
|
stream,
|
||||||
systemPrompt,
|
systemPrompt: params.systemPrompt,
|
||||||
task,
|
task: params.task,
|
||||||
onReasoning,
|
onReasoning,
|
||||||
onStreaming
|
onStreaming
|
||||||
});
|
});
|
||||||
@@ -414,10 +440,17 @@ export const dispatchRunAgent = async (props: DispatchAgentModuleProps): Promise
|
|||||||
isEnd: false
|
isEnd: false
|
||||||
};
|
};
|
||||||
} else if (toolId === SubAppIds.fileRead) {
|
} else if (toolId === SubAppIds.fileRead) {
|
||||||
const { file_indexes } = parseToolArgs<{
|
const params = parseToolArgs<{
|
||||||
file_indexes: string[];
|
file_indexes: string[];
|
||||||
}>(call.function.arguments);
|
}>(call.function.arguments);
|
||||||
if (!Array.isArray(file_indexes)) {
|
if (!params) {
|
||||||
|
return {
|
||||||
|
response: 'params is not object',
|
||||||
|
usages: [],
|
||||||
|
isEnd: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (!Array.isArray(params.file_indexes)) {
|
||||||
return {
|
return {
|
||||||
response: 'file_indexes is not array',
|
response: 'file_indexes is not array',
|
||||||
usages: [],
|
usages: [],
|
||||||
@@ -425,7 +458,7 @@ export const dispatchRunAgent = async (props: DispatchAgentModuleProps): Promise
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const files = file_indexes.map((index) => ({
|
const files = params.file_indexes.map((index) => ({
|
||||||
index,
|
index,
|
||||||
url: filesMap[index]
|
url: filesMap[index]
|
||||||
}));
|
}));
|
||||||
@@ -453,6 +486,15 @@ export const dispatchRunAgent = async (props: DispatchAgentModuleProps): Promise
|
|||||||
}
|
}
|
||||||
|
|
||||||
const toolCallParams = parseToolArgs(call.function.arguments);
|
const toolCallParams = parseToolArgs(call.function.arguments);
|
||||||
|
|
||||||
|
if (!toolCallParams) {
|
||||||
|
return {
|
||||||
|
response: 'params is not object',
|
||||||
|
usages: [],
|
||||||
|
isEnd: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// Get params
|
// Get params
|
||||||
const requestParams = (() => {
|
const requestParams = (() => {
|
||||||
const params: Record<string, any> = toolCallParams;
|
const params: Record<string, any> = toolCallParams;
|
||||||
@@ -582,16 +624,12 @@ export const dispatchRunAgent = async (props: DispatchAgentModuleProps): Promise
|
|||||||
const previewAssistantResponses = filterToolResponseToPreview(assistantResponses);
|
const previewAssistantResponses = filterToolResponseToPreview(assistantResponses);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
data: {
|
// 目前 Master 不会触发交互
|
||||||
[NodeOutputKeyEnum.answerText]: previewAssistantResponses
|
// [DispatchNodeResponseKeyEnum.interactive]: interactiveResponse,
|
||||||
.filter((item) => item.text?.content)
|
|
||||||
.map((item) => item.text?.content || '')
|
|
||||||
.join('')
|
|
||||||
},
|
|
||||||
// TODO: 需要对 memoryMessages 单独建表存储
|
// TODO: 需要对 memoryMessages 单独建表存储
|
||||||
[DispatchNodeResponseKeyEnum.memories]: {
|
[DispatchNodeResponseKeyEnum.memories]: {
|
||||||
[masterMessagesKey]: filterMemoryMessages(completeMessages),
|
[masterMessagesKey]: filterMemoryMessages(completeMessages),
|
||||||
[planMessagesKey]: [filterMemoryMessages(planHistoryMessages)]
|
[planMessagesKey]: [filterMemoryMessages(planMessages)]
|
||||||
},
|
},
|
||||||
[DispatchNodeResponseKeyEnum.assistantResponses]: previewAssistantResponses,
|
[DispatchNodeResponseKeyEnum.assistantResponses]: previewAssistantResponses,
|
||||||
[DispatchNodeResponseKeyEnum.nodeResponse]: {
|
[DispatchNodeResponseKeyEnum.nodeResponse]: {
|
||||||
@@ -601,7 +639,7 @@ export const dispatchRunAgent = async (props: DispatchAgentModuleProps): Promise
|
|||||||
toolCallOutputTokens: outputTokens,
|
toolCallOutputTokens: outputTokens,
|
||||||
childTotalPoints: toolTotalPoints,
|
childTotalPoints: toolTotalPoints,
|
||||||
model: modelName,
|
model: modelName,
|
||||||
query: userChatInput,
|
query: taskInput,
|
||||||
historyPreview: getHistoryPreview(
|
historyPreview: getHistoryPreview(
|
||||||
GPTMessages2Chats({ messages: completeMessages, reserveTool: false }),
|
GPTMessages2Chats({ messages: completeMessages, reserveTool: false }),
|
||||||
10000,
|
10000,
|
||||||
@@ -621,8 +659,7 @@ export const dispatchRunAgent = async (props: DispatchAgentModuleProps): Promise
|
|||||||
},
|
},
|
||||||
// Tool usage
|
// Tool usage
|
||||||
...subAppUsages
|
...subAppUsages
|
||||||
],
|
]
|
||||||
[DispatchNodeResponseKeyEnum.interactive]: interactiveResponse
|
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return getNodeErrResponse({ error });
|
return getNodeErrResponse({ error });
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
import type { ChatCompletionTool } from '@fastgpt/global/core/ai/type';
|
|
||||||
import { i18nT } from '../../../../../../../web/i18n/utils';
|
import { i18nT } from '../../../../../../../web/i18n/utils';
|
||||||
|
|
||||||
export enum SubAppIds {
|
export enum SubAppIds {
|
||||||
@@ -9,25 +8,33 @@ export enum SubAppIds {
|
|||||||
fileRead = 'file_read'
|
fileRead = 'file_read'
|
||||||
}
|
}
|
||||||
|
|
||||||
export const systemSubInfo: Record<string, { name: string; avatar: string }> = {
|
export const systemSubInfo: Record<
|
||||||
|
string,
|
||||||
|
{ name: string; avatar: string; toolDescription: string }
|
||||||
|
> = {
|
||||||
[SubAppIds.plan]: {
|
[SubAppIds.plan]: {
|
||||||
name: i18nT('chat:plan_agent'),
|
name: i18nT('chat:plan_agent'),
|
||||||
avatar: 'common/detail'
|
avatar: 'common/detail',
|
||||||
|
toolDescription: '分析和拆解用户问题,制定分步计划。'
|
||||||
},
|
},
|
||||||
[SubAppIds.fileRead]: {
|
[SubAppIds.fileRead]: {
|
||||||
name: i18nT('chat:file_parse'),
|
name: i18nT('chat:file_parse'),
|
||||||
avatar: 'core/workflow/template/readFiles'
|
avatar: 'core/workflow/template/readFiles',
|
||||||
|
toolDescription: '读取文件内容,并返回文件内容。'
|
||||||
},
|
},
|
||||||
[SubAppIds.ask]: {
|
[SubAppIds.ask]: {
|
||||||
name: 'Ask Agent',
|
name: 'Ask Agent',
|
||||||
avatar: 'core/workflow/template/agent'
|
avatar: 'core/workflow/template/agent',
|
||||||
|
toolDescription: '询问用户问题,并返回用户回答。'
|
||||||
},
|
},
|
||||||
[SubAppIds.stop]: {
|
[SubAppIds.stop]: {
|
||||||
name: 'Stop Agent',
|
name: 'Stop Agent',
|
||||||
avatar: 'core/workflow/template/agent'
|
avatar: 'core/workflow/template/agent',
|
||||||
|
toolDescription: '停止当前任务。'
|
||||||
},
|
},
|
||||||
[SubAppIds.model]: {
|
[SubAppIds.model]: {
|
||||||
name: 'Model Agent',
|
name: 'Model Agent',
|
||||||
avatar: 'core/workflow/template/agent'
|
avatar: 'core/workflow/template/agent',
|
||||||
|
toolDescription: '调用 LLM 模型完成一些通用任务。'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@@ -1,19 +1,28 @@
|
|||||||
import type { ChatCompletionTool } from '@fastgpt/global/core/ai/type';
|
import type { ChatCompletionTool } from '@fastgpt/global/core/ai/type';
|
||||||
import { SubAppIds } from '../../constants';
|
import { SubAppIds } from '../../constants';
|
||||||
|
|
||||||
export type AskAgentToolParamsType = Partial<{
|
export type AskAgentToolParamsType =
|
||||||
mode: 'select' | 'formInput' | 'input';
|
| {
|
||||||
prompt: string;
|
mode: 'select';
|
||||||
options: string[];
|
prompt?: string;
|
||||||
form: {
|
options: string[];
|
||||||
field: string;
|
}
|
||||||
type: 'textInput' | 'numberInput' | 'singleSelect' | 'multiSelect';
|
| {
|
||||||
required: boolean;
|
mode: 'formInput';
|
||||||
options: string[];
|
prompt?: string;
|
||||||
}[];
|
form: {
|
||||||
}>;
|
field: string;
|
||||||
|
type: 'textInput' | 'numberInput' | 'singleSelect' | 'multiSelect';
|
||||||
|
required: boolean;
|
||||||
|
options: string[];
|
||||||
|
}[];
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
mode: 'input';
|
||||||
|
prompt: string;
|
||||||
|
};
|
||||||
|
|
||||||
export const AskAgentTool: ChatCompletionTool = {
|
export const PlanAgentAskTool: ChatCompletionTool = {
|
||||||
type: 'function',
|
type: 'function',
|
||||||
function: {
|
function: {
|
||||||
name: SubAppIds.ask,
|
name: SubAppIds.ask,
|
||||||
@@ -30,7 +39,6 @@ export const AskAgentTool: ChatCompletionTool = {
|
|||||||
2. mode = "input"
|
2. mode = "input"
|
||||||
- 用于自由文本输入,适合用户提供个性化或开放式回答。
|
- 用于自由文本输入,适合用户提供个性化或开放式回答。
|
||||||
- prompt: 展示的问题提示,引导用户填写。
|
- prompt: 展示的问题提示,引导用户填写。
|
||||||
- options: 此模式下通常留空或忽略。
|
|
||||||
- 场景示例:
|
- 场景示例:
|
||||||
* 需要用户补充说明原因、填写备注、输入 URL/编号等。
|
* 需要用户补充说明原因、填写备注、输入 URL/编号等。
|
||||||
* 当 "select" 的选项无法覆盖用户真实答案时,可以再调用一次 "input" 追问。
|
* 当 "select" 的选项无法覆盖用户真实答案时,可以再调用一次 "input" 追问。
|
||||||
|
@@ -1,11 +1,18 @@
|
|||||||
import type { ChatCompletionTool } from '@fastgpt/global/core/ai/type';
|
import type { ChatCompletionTool } from '@fastgpt/global/core/ai/type';
|
||||||
import { SubAppIds } from '../constants';
|
import { SubAppIds, systemSubInfo } from '../constants';
|
||||||
|
import type { InteractiveNodeResponseType } from '@fastgpt/global/core/workflow/template/system/interactive/type';
|
||||||
|
|
||||||
|
export const PlanCheckInteractive: InteractiveNodeResponseType = {
|
||||||
|
type: 'agentPlanCheck',
|
||||||
|
params: {
|
||||||
|
confirmed: false
|
||||||
|
}
|
||||||
|
};
|
||||||
export const PlanAgentTool: ChatCompletionTool = {
|
export const PlanAgentTool: ChatCompletionTool = {
|
||||||
type: 'function',
|
type: 'function',
|
||||||
function: {
|
function: {
|
||||||
name: SubAppIds.plan,
|
name: SubAppIds.plan,
|
||||||
description: '分析和拆解用户问题,制定分步计划。',
|
description: systemSubInfo[SubAppIds.plan].toolDescription,
|
||||||
parameters: {}
|
parameters: {}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@@ -2,17 +2,21 @@ import type {
|
|||||||
ChatCompletionMessageParam,
|
ChatCompletionMessageParam,
|
||||||
ChatCompletionTool
|
ChatCompletionTool
|
||||||
} from '@fastgpt/global/core/ai/type.d';
|
} from '@fastgpt/global/core/ai/type.d';
|
||||||
import { createLLMResponse, type ResponseEvents } from '../../../../../../ai/llm/request';
|
import { createLLMResponse } from '../../../../../../ai/llm/request';
|
||||||
import { getPlanAgentPrompt } from './prompt';
|
import { getPlanAgentPrompt } from './prompt';
|
||||||
import { getLLMModel } from '../../../../../../ai/model';
|
import { getLLMModel } from '../../../../../../ai/model';
|
||||||
import { formatModelChars2Points } from '../../../../../../../support/wallet/usage/utils';
|
import { formatModelChars2Points } from '../../../../../../../support/wallet/usage/utils';
|
||||||
import type { ChatNodeUsageType } from '@fastgpt/global/support/wallet/bill/type';
|
import type { ChatNodeUsageType } from '@fastgpt/global/support/wallet/bill/type';
|
||||||
import { SubAppIds } from '../constants';
|
import { SubAppIds } from '../constants';
|
||||||
import type { InteractiveNodeResponseType } from '@fastgpt/global/core/workflow/template/system/interactive/type';
|
import type {
|
||||||
|
InteractiveNodeResponseType,
|
||||||
|
WorkflowInteractiveResponseType
|
||||||
|
} from '@fastgpt/global/core/workflow/template/system/interactive/type';
|
||||||
import { parseToolArgs } from '../../../utils';
|
import { parseToolArgs } from '../../../utils';
|
||||||
import { AskAgentTool, type AskAgentToolParamsType } from './ask/constants';
|
import { PlanAgentAskTool, type AskAgentToolParamsType } from './ask/constants';
|
||||||
|
import { PlanCheckInteractive } from './constants';
|
||||||
|
import type { AgentPlanType } from './type';
|
||||||
import { getNanoid } from '@fastgpt/global/common/string/tools';
|
import { getNanoid } from '@fastgpt/global/common/string/tools';
|
||||||
import { ChatCompletionRequestMessageRoleEnum } from '@fastgpt/global/core/ai/constants';
|
|
||||||
|
|
||||||
type PlanAgentConfig = {
|
type PlanAgentConfig = {
|
||||||
model: string;
|
model: string;
|
||||||
@@ -23,49 +27,67 @@ type PlanAgentConfig = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
type DispatchPlanAgentProps = PlanAgentConfig & {
|
type DispatchPlanAgentProps = PlanAgentConfig & {
|
||||||
messages: ChatCompletionMessageParam[];
|
historyMessages: ChatCompletionMessageParam[];
|
||||||
subApps: ChatCompletionTool[];
|
userInput: string;
|
||||||
onReasoning: ResponseEvents['onReasoning'];
|
interactive?: WorkflowInteractiveResponseType;
|
||||||
onStreaming: ResponseEvents['onStreaming'];
|
|
||||||
|
subAppPrompt: string;
|
||||||
|
isTopPlanAgent: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
type DispatchPlanAgentResponse = {
|
type DispatchPlanAgentResponse = {
|
||||||
response: string;
|
answerText: string;
|
||||||
usages: ChatNodeUsageType[];
|
planList?: AgentPlanType;
|
||||||
|
planToolCallMessages: ChatCompletionMessageParam[];
|
||||||
completeMessages: ChatCompletionMessageParam[];
|
completeMessages: ChatCompletionMessageParam[];
|
||||||
toolMessages?: ChatCompletionMessageParam[];
|
usages: ChatNodeUsageType[];
|
||||||
interactiveResponse?: InteractiveNodeResponseType;
|
interactiveResponse?: InteractiveNodeResponseType;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const dispatchPlanAgent = async ({
|
export const dispatchPlanAgent = async ({
|
||||||
messages,
|
historyMessages,
|
||||||
|
userInput,
|
||||||
subApps,
|
interactive,
|
||||||
|
subAppPrompt,
|
||||||
model,
|
model,
|
||||||
systemPrompt,
|
systemPrompt,
|
||||||
temperature,
|
temperature,
|
||||||
top_p,
|
top_p,
|
||||||
stream,
|
stream,
|
||||||
onReasoning,
|
isTopPlanAgent
|
||||||
onStreaming
|
|
||||||
}: DispatchPlanAgentProps): Promise<DispatchPlanAgentResponse> => {
|
}: DispatchPlanAgentProps): Promise<DispatchPlanAgentResponse> => {
|
||||||
const modelData = getLLMModel(model);
|
const modelData = getLLMModel(model);
|
||||||
|
|
||||||
const requestMessages: ChatCompletionMessageParam[] = [
|
const requestMessages: ChatCompletionMessageParam[] = [
|
||||||
{
|
{
|
||||||
role: 'system',
|
role: 'system',
|
||||||
content: getPlanAgentPrompt(systemPrompt)
|
content: getPlanAgentPrompt(subAppPrompt, systemPrompt)
|
||||||
},
|
},
|
||||||
...messages.filter((item) => item.role !== 'system')
|
...historyMessages.filter((item) => item.role !== 'system')
|
||||||
];
|
];
|
||||||
|
|
||||||
// TODO: 考虑一下 plan 要不要挂上 master 的工具组
|
// 分类:query/user select/user form
|
||||||
// const filterPlanTools = subApps.filter((item) => item.function.name !== SubAppIds.plan);
|
const lastMessages = requestMessages[requestMessages.length - 1];
|
||||||
// filterPlanTools.push(AskAgentTool);
|
if (
|
||||||
const tools = [AskAgentTool];
|
(interactive?.type === 'agentPlanAskUserSelect' ||
|
||||||
|
interactive?.type === 'agentPlanAskUserForm') &&
|
||||||
|
lastMessages.role === 'assistant' &&
|
||||||
|
lastMessages.tool_calls
|
||||||
|
) {
|
||||||
|
requestMessages.push({
|
||||||
|
role: 'tool',
|
||||||
|
tool_call_id: lastMessages.tool_calls[0].id,
|
||||||
|
content: userInput
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
requestMessages.push({
|
||||||
|
role: 'user',
|
||||||
|
content: userInput
|
||||||
|
});
|
||||||
|
}
|
||||||
|
console.log(JSON.stringify({ requestMessages }, null, 2));
|
||||||
|
|
||||||
const {
|
const {
|
||||||
reasoningText,
|
|
||||||
answerText,
|
answerText,
|
||||||
toolCalls = [],
|
toolCalls = [],
|
||||||
usage,
|
usage,
|
||||||
@@ -79,73 +101,50 @@ export const dispatchPlanAgent = async ({
|
|||||||
top_p,
|
top_p,
|
||||||
stream,
|
stream,
|
||||||
|
|
||||||
tools,
|
tools: isTopPlanAgent ? [PlanAgentAskTool] : [],
|
||||||
tool_choice: 'auto',
|
tool_choice: 'auto',
|
||||||
toolCallMode: modelData.toolChoice ? 'toolChoice' : 'prompt',
|
toolCallMode: modelData.toolChoice ? 'toolChoice' : 'prompt',
|
||||||
parallel_tool_calls: true
|
parallel_tool_calls: false
|
||||||
},
|
}
|
||||||
onReasoning,
|
|
||||||
onStreaming
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!answerText && !reasoningText && !toolCalls.length) {
|
if (!answerText && !toolCalls.length) {
|
||||||
return Promise.reject(getEmptyResponseTip());
|
return Promise.reject(getEmptyResponseTip());
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: 需要考虑多个 Interactive 并发的情况
|
/*
|
||||||
let interactiveResponse: InteractiveNodeResponseType = {
|
正常输出情况:
|
||||||
type: 'agentPlanCheck',
|
1. text: 正常生成plan
|
||||||
params: {}
|
2. toolCall: 调用ask工具
|
||||||
};
|
3. text + toolCall: 可能生成 plan + 调用ask工具
|
||||||
|
*/
|
||||||
|
|
||||||
for await (const call of toolCalls) {
|
// Text: 回答的文本;planList: 结构化的plan,只能有其中一个有值
|
||||||
const toolId = call.function.name;
|
const { text, planList } = (() => {
|
||||||
|
if (!answerText)
|
||||||
if (toolId === SubAppIds.ask) {
|
return {
|
||||||
const params = parseToolArgs<AskAgentToolParamsType>(call.function.arguments);
|
text: '',
|
||||||
|
planList: undefined
|
||||||
if (params.mode === 'select') {
|
};
|
||||||
interactiveResponse = {
|
const params = parseToolArgs<AgentPlanType>(answerText);
|
||||||
type: 'agentPlanAskUserSelect',
|
if (!params || !params.task || !params.steps) {
|
||||||
params: {
|
return {
|
||||||
description: params?.prompt ?? '选择选项',
|
text: answerText,
|
||||||
userSelectOptions: params?.options?.map((v, i) => {
|
planList: undefined
|
||||||
return { key: `option${i}`, value: v };
|
};
|
||||||
})
|
|
||||||
}
|
|
||||||
} as InteractiveNodeResponseType;
|
|
||||||
}
|
|
||||||
if (params.mode === 'input') {
|
|
||||||
interactiveResponse = {
|
|
||||||
type: 'agentPlanAskQuery',
|
|
||||||
params: {
|
|
||||||
content: params?.prompt ?? '输入详细信息'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
completeMessages.push({
|
|
||||||
tool_call_id: call.id,
|
|
||||||
role: ChatCompletionRequestMessageRoleEnum.Tool,
|
|
||||||
content: '等待用户输入内容'
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
return {
|
||||||
|
text: '',
|
||||||
const { totalPoints, modelName } = formatModelChars2Points({
|
planList: params
|
||||||
model: modelData.model,
|
};
|
||||||
inputTokens: usage.inputTokens,
|
})();
|
||||||
outputTokens: usage.outputTokens
|
const callPlanId = getNanoid(6);
|
||||||
});
|
const planToolCallMessages: ChatCompletionMessageParam[] = [
|
||||||
|
{
|
||||||
const toolMessages: ChatCompletionMessageParam[] = [];
|
role: 'assistant',
|
||||||
if (answerText) {
|
|
||||||
const toolId = getNanoid(6);
|
|
||||||
const toolCall: ChatCompletionMessageParam = {
|
|
||||||
role: ChatCompletionRequestMessageRoleEnum.Assistant,
|
|
||||||
tool_calls: [
|
tool_calls: [
|
||||||
{
|
{
|
||||||
id: toolId,
|
id: callPlanId,
|
||||||
type: 'function',
|
type: 'function',
|
||||||
function: {
|
function: {
|
||||||
name: SubAppIds.plan,
|
name: SubAppIds.plan,
|
||||||
@@ -153,17 +152,56 @@ export const dispatchPlanAgent = async ({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
},
|
||||||
const toolCallResponse: ChatCompletionMessageParam = {
|
{
|
||||||
role: ChatCompletionRequestMessageRoleEnum.Tool,
|
role: 'tool',
|
||||||
tool_call_id: toolId,
|
tool_call_id: callPlanId,
|
||||||
content: answerText
|
content: planList ? JSON.stringify(planList) : text || 'Create plan error'
|
||||||
};
|
}
|
||||||
toolMessages.push(toolCall, toolCallResponse);
|
];
|
||||||
}
|
|
||||||
|
// 只有顶层有交互模式
|
||||||
|
const interactiveResponse: InteractiveNodeResponseType | undefined = (() => {
|
||||||
|
if (!isTopPlanAgent) return;
|
||||||
|
|
||||||
|
const tooCall = toolCalls[0];
|
||||||
|
if (tooCall) {
|
||||||
|
const params = parseToolArgs<AskAgentToolParamsType>(tooCall.function.arguments);
|
||||||
|
if (params?.mode === 'select') {
|
||||||
|
return {
|
||||||
|
type: 'agentPlanAskUserSelect',
|
||||||
|
params: {
|
||||||
|
description: params.prompt ?? '',
|
||||||
|
userSelectOptions: params.options.filter(Boolean).map((v, i) => {
|
||||||
|
return { key: `option${i}`, value: v };
|
||||||
|
})
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (params?.mode === 'input' && params.prompt) {
|
||||||
|
return {
|
||||||
|
type: 'agentPlanAskQuery',
|
||||||
|
params: {
|
||||||
|
content: params.prompt ?? ''
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Plan 没有主动交互,则强制触发 check
|
||||||
|
return PlanCheckInteractive;
|
||||||
|
})();
|
||||||
|
|
||||||
|
const { totalPoints, modelName } = formatModelChars2Points({
|
||||||
|
model: modelData.model,
|
||||||
|
inputTokens: usage.inputTokens,
|
||||||
|
outputTokens: usage.outputTokens
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
response: answerText,
|
answerText: text,
|
||||||
|
planList,
|
||||||
|
planToolCallMessages,
|
||||||
usages: [
|
usages: [
|
||||||
{
|
{
|
||||||
moduleName: modelName,
|
moduleName: modelName,
|
||||||
@@ -174,7 +212,6 @@ export const dispatchPlanAgent = async ({
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
completeMessages,
|
completeMessages,
|
||||||
toolMessages,
|
|
||||||
interactiveResponse
|
interactiveResponse
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@@ -1,24 +1,52 @@
|
|||||||
export const getPlanAgentPrompt = (background?: string) => {
|
import type { ChatCompletionTool } from '@fastgpt/global/core/ai/type';
|
||||||
|
import { SubAppIds } from '../constants';
|
||||||
|
|
||||||
|
export const getSubAppsPrompt = ({
|
||||||
|
subAppList,
|
||||||
|
getSubAppInfo
|
||||||
|
}: {
|
||||||
|
subAppList: ChatCompletionTool[];
|
||||||
|
getSubAppInfo: (id: string) => {
|
||||||
|
name: string;
|
||||||
|
avatar: string;
|
||||||
|
toolDescription: string;
|
||||||
|
};
|
||||||
|
}) => {
|
||||||
|
return subAppList
|
||||||
|
.map((item) => {
|
||||||
|
const info = getSubAppInfo(item.function.name);
|
||||||
|
if (!info) return '';
|
||||||
|
return `@${info.name}(${info.toolDescription})`;
|
||||||
|
})
|
||||||
|
.filter(Boolean)
|
||||||
|
.join('; ');
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
subAppsPrompt:
|
||||||
|
@名字(功能); @名字(功能)
|
||||||
|
*/
|
||||||
|
export const getPlanAgentPrompt = (subAppsPrompt: string, systemPrompt?: string) => {
|
||||||
return `<role>
|
return `<role>
|
||||||
你是一个专业的项目规划助手,擅长将复杂任务分解为结构化的执行计划。
|
你是一个专业的项目规划助手,擅长将复杂任务分解为结构化的执行计划。
|
||||||
</role>
|
</role>
|
||||||
|
|
||||||
${
|
${
|
||||||
background
|
systemPrompt
|
||||||
? `<user_role>
|
? `<user_required>
|
||||||
${background}
|
${systemPrompt}
|
||||||
</user_role>`
|
</user_required>`
|
||||||
: ''
|
: ''
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
<process>
|
<process>
|
||||||
1. 解析用户输入,提取核心目标、关键要素、约束与本地化偏好。
|
- 解析用户输入,提取核心目标、关键要素、约束与本地化偏好。
|
||||||
2. 评估任务复杂度, 据此确定阶段数量。
|
- 在缺少完成任务的关键信息时,使用 [${SubAppIds.ask}] 工具来询问用户(如:未指定目的地、预算、时间等必要细节)
|
||||||
3. 禁止调用除"ask_agent"以外的任何工具.
|
- 你还可以使用这些工具来设计本轮执行计划: """${subAppsPrompt}"""。注意,你只有这些工具可以进行调用。
|
||||||
4. 语言风格本地化(根据用户输入语言进行术语与语序调整)。
|
${systemPrompt ? '- 制定本轮计划时,严格参考 <user_required></user_required> 中的内容进行设计,设计的计划不偏离<user_required></user_required>。' : ''}
|
||||||
5. 严格按照 JSON Schema 生成完整计划,不得输出多余内容。
|
- 输出语言风格本地化(根据用户输入语言进行术语与语序调整)。
|
||||||
6. 仅在缺少关键信息时使用"ask_agent"工具询问用户(如:未指定目的地、预算、时间等必要细节)
|
- 严格按照 JSON Schema 生成完整计划,不得输出多余内容。
|
||||||
7. 如果信息充足或用户已回答询问,必须直接输出JSON格式的完整计划,不再调用工具
|
|
||||||
</process>
|
</process>
|
||||||
|
|
||||||
<requirements>
|
<requirements>
|
||||||
@@ -34,21 +62,21 @@ ${background}
|
|||||||
},
|
},
|
||||||
"steps": {
|
"steps": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"description": "阶段步骤列表",
|
"description": "完成任务的步骤列表",
|
||||||
"items": {
|
"items": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"id": {
|
"id": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "唯一标识"
|
"description": "步骤的唯一标识"
|
||||||
},
|
},
|
||||||
"title": {
|
"title": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "阶段标题"
|
"description": "步骤标题"
|
||||||
},
|
},
|
||||||
"description": {
|
"description": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "阶段描述, 并在末尾@对应任务将要移交使用的工具/子智能体"
|
"description": "步骤的具体描述, 可以使用@符号声明需要用到的工具。"
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"required": ["id", "title", "description"]
|
"required": ["id", "title", "description"]
|
||||||
@@ -66,23 +94,21 @@ ${background}
|
|||||||
- 保持中立、客观;必要时指出风险与依赖。
|
- 保持中立、客观;必要时指出风险与依赖。
|
||||||
</guardrails>
|
</guardrails>
|
||||||
|
|
||||||
<output>
|
<example>
|
||||||
<format>
|
|
||||||
{
|
{
|
||||||
"task": "[主题] 深度调研计划",
|
"task": "[主题] 深度调研计划",
|
||||||
"steps": [
|
"steps": [
|
||||||
{
|
{
|
||||||
"id": "[id]",
|
"id": "step1",
|
||||||
"title": "[阶段名称]",
|
"title": "[步骤名称]",
|
||||||
"description": "[阶段描述] @sub_agent"
|
"description": "[步骤描述] @网络搜索"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "[id]",
|
"id": "step2",
|
||||||
"title": "[阶段名称]",
|
"title": "[步骤名称]",
|
||||||
"description": "[阶段描述] @sub_agent"
|
"description": "[步骤描述] @webhook机器人"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
</output>
|
</example>`;
|
||||||
`;
|
|
||||||
};
|
};
|
||||||
|
@@ -0,0 +1,9 @@
|
|||||||
|
export type AgentPlanStepType = {
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
};
|
||||||
|
export type AgentPlanType = {
|
||||||
|
task: string;
|
||||||
|
steps: AgentPlanStepType[];
|
||||||
|
};
|
@@ -23,7 +23,6 @@ import {
|
|||||||
} from '@fastgpt/global/core/ai/type';
|
} from '@fastgpt/global/core/ai/type';
|
||||||
import { ChatCompletionRequestMessageRoleEnum } from '@fastgpt/global/core/ai/constants';
|
import { ChatCompletionRequestMessageRoleEnum } from '@fastgpt/global/core/ai/constants';
|
||||||
import { type DispatchNodeResultType } from '@fastgpt/global/core/workflow/runtime/type';
|
import { type DispatchNodeResultType } from '@fastgpt/global/core/workflow/runtime/type';
|
||||||
import { ModelTypeEnum } from '../../../../../global/core/ai/model';
|
|
||||||
import {
|
import {
|
||||||
getExtractJsonPrompt,
|
getExtractJsonPrompt,
|
||||||
getExtractJsonToolPrompt
|
getExtractJsonToolPrompt
|
||||||
|
@@ -1,4 +1,8 @@
|
|||||||
import { replaceVariable, sliceStrStartEnd } from '@fastgpt/global/common/string/tools';
|
import {
|
||||||
|
replaceVariable,
|
||||||
|
sliceJsonStr,
|
||||||
|
sliceStrStartEnd
|
||||||
|
} from '@fastgpt/global/common/string/tools';
|
||||||
import type {
|
import type {
|
||||||
AIChatItemValueItemType,
|
AIChatItemValueItemType,
|
||||||
UserChatItemValueItemType
|
UserChatItemValueItemType
|
||||||
@@ -174,10 +178,10 @@ export const getToolNodesByIds = ({
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const parseToolArgs = <T = Record<string, any>>(toolArgs: string): T => {
|
export const parseToolArgs = <T = Record<string, any>>(toolArgs: string) => {
|
||||||
try {
|
try {
|
||||||
return json5.parse(toolArgs) as T;
|
return json5.parse(sliceJsonStr(toolArgs)) as T;
|
||||||
} catch {
|
} catch {
|
||||||
return {} as T;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user