Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
赵月辉
/
fastgpt-migrated
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Unverified
Commit
c4ce1236
authored
May 23, 2024
by
Archer
Committed by
GitHub
May 23, 2024
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
perf: tool promot and reg slice;query extension prompt (#1576)
parent
4eb2c9bd
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
85 additions
and
45 deletions
+85
-45
packages/global/common/string/tools.ts
+18
-0
packages/global/core/workflow/template/system/runApp.ts
+1
-0
packages/service/core/ai/functions/queryExtension.ts
+3
-3
packages/service/core/workflow/dispatch/agent/extract.ts
+3
-9
packages/service/core/workflow/dispatch/agent/runTool/constants.ts
+11
-6
packages/service/core/workflow/dispatch/agent/runTool/promptCall.ts
+49
-27
No files found.
packages/global/common/string/tools.ts
View file @
c4ce1236
...
@@ -64,4 +64,22 @@ export const getNanoid = (size = 12) => {
...
@@ -64,4 +64,22 @@ export const getNanoid = (size = 12) => {
return
`
${
firstChar
}${
randomsStr
}
`
;
return
`
${
firstChar
}${
randomsStr
}
`
;
};
};
/* Custom text to reg, need to replace special chats */
export
const
replaceRegChars
=
(
text
:
string
)
=>
text
.
replace
(
/
[
.*+?^${}()|[
\]\\]
/g
,
'\\$&'
);
export
const
replaceRegChars
=
(
text
:
string
)
=>
text
.
replace
(
/
[
.*+?^${}()|[
\]\\]
/g
,
'\\$&'
);
/* slice json str */
export
const
sliceJsonStr
=
(
str
:
string
)
=>
{
str
=
str
.
replace
(
/
(\\
n|
\\)
/g
,
''
).
replace
(
/ /g
,
''
);
const
jsonRegex
=
/{
[^
{}
]
*}/g
;
const
matches
=
str
.
match
(
jsonRegex
);
if
(
!
matches
)
{
return
''
;
}
// 找到第一个完整的 JSON 字符串
const
jsonStr
=
matches
[
0
];
return
jsonStr
;
};
packages/global/core/workflow/template/system/runApp.ts
View file @
c4ce1236
...
@@ -24,6 +24,7 @@ export const RunAppModule: FlowNodeTemplateType = {
...
@@ -24,6 +24,7 @@ export const RunAppModule: FlowNodeTemplateType = {
intro
:
'可以选择一个其他应用进行调用'
,
intro
:
'可以选择一个其他应用进行调用'
,
showStatus
:
true
,
showStatus
:
true
,
version
:
'481'
,
version
:
'481'
,
isTool
:
true
,
inputs
:
[
inputs
:
[
{
{
key
:
NodeInputKeyEnum
.
runAppSelectApp
,
key
:
NodeInputKeyEnum
.
runAppSelectApp
,
...
...
packages/service/core/ai/functions/queryExtension.ts
View file @
c4ce1236
...
@@ -65,7 +65,7 @@ Q: FastGPT 如何收费?
...
@@ -65,7 +65,7 @@ Q: FastGPT 如何收费?
A: FastGPT 收费可以参考……
A: FastGPT 收费可以参考……
"""
"""
原问题: 你知道 laf 么?
原问题: 你知道 laf 么?
检索词: ["laf
是什么?","如何使用laf?","laf的介绍
。"]
检索词: ["laf
的官网地址是多少?","laf 的使用教程。","laf 有什么特点和优势
。"]
----------------
----------------
历史记录:
历史记录:
"""
"""
...
@@ -75,7 +75,7 @@ A: 1. 开源
...
@@ -75,7 +75,7 @@ A: 1. 开源
3. 扩展性强
3. 扩展性强
"""
"""
原问题: 介绍下第2点。
原问题: 介绍下第2点。
检索词: ["介绍下 FastGPT 简便的优势"
, "FastGPT 为什么使用起来简便?","FastGPT的有哪些简便的功能?"
]。
检索词: ["介绍下 FastGPT 简便的优势"]。
----------------
----------------
历史记录:
历史记录:
"""
"""
...
@@ -85,7 +85,7 @@ Q: 什么是 Laf?
...
@@ -85,7 +85,7 @@ Q: 什么是 Laf?
A: Laf 是一个云函数开发平台。
A: Laf 是一个云函数开发平台。
"""
"""
原问题: 它们有什么关系?
原问题: 它们有什么关系?
检索词: ["FastGPT和Laf有什么关系?","
FastGPT的RAG是用Laf实现的么?
"]
检索词: ["FastGPT和Laf有什么关系?","
介绍下FastGPT","介绍下Laf
"]
----------------
----------------
历史记录:
历史记录:
"""
"""
...
...
packages/service/core/workflow/dispatch/agent/extract.ts
View file @
c4ce1236
...
@@ -12,7 +12,7 @@ import { NodeInputKeyEnum, NodeOutputKeyEnum } from '@fastgpt/global/core/workfl
...
@@ -12,7 +12,7 @@ import { NodeInputKeyEnum, NodeOutputKeyEnum } from '@fastgpt/global/core/workfl
import
{
DispatchNodeResponseKeyEnum
}
from
'@fastgpt/global/core/workflow/runtime/constants'
;
import
{
DispatchNodeResponseKeyEnum
}
from
'@fastgpt/global/core/workflow/runtime/constants'
;
import
type
{
ModuleDispatchProps
}
from
'@fastgpt/global/core/workflow/type/index.d'
;
import
type
{
ModuleDispatchProps
}
from
'@fastgpt/global/core/workflow/type/index.d'
;
import
{
Prompt_ExtractJson
}
from
'@fastgpt/global/core/ai/prompt/agent'
;
import
{
Prompt_ExtractJson
}
from
'@fastgpt/global/core/ai/prompt/agent'
;
import
{
replaceVariable
}
from
'@fastgpt/global/common/string/tools'
;
import
{
replaceVariable
,
sliceJsonStr
}
from
'@fastgpt/global/common/string/tools'
;
import
{
LLMModelItemType
}
from
'@fastgpt/global/core/ai/model.d'
;
import
{
LLMModelItemType
}
from
'@fastgpt/global/core/ai/model.d'
;
import
{
getHistories
}
from
'../utils'
;
import
{
getHistories
}
from
'../utils'
;
import
{
ModelTypeEnum
,
getLLMModel
}
from
'../../../ai/model'
;
import
{
ModelTypeEnum
,
getLLMModel
}
from
'../../../ai/model'
;
...
@@ -348,10 +348,9 @@ Human: ${content}`
...
@@ -348,10 +348,9 @@ Human: ${content}`
const
answer
=
data
.
choices
?.[
0
].
message
?.
content
||
''
;
const
answer
=
data
.
choices
?.[
0
].
message
?.
content
||
''
;
// parse response
// parse response
const
start
=
answer
.
indexOf
(
'{'
);
const
jsonStr
=
sliceJsonStr
(
answer
);
const
end
=
answer
.
lastIndexOf
(
'}'
);
if
(
start
===
-
1
||
end
===
-
1
)
{
if
(
!
jsonStr
)
{
return
{
return
{
rawResponse
:
answer
,
rawResponse
:
answer
,
tokens
:
await
countMessagesTokens
(
messages
),
tokens
:
await
countMessagesTokens
(
messages
),
...
@@ -359,11 +358,6 @@ Human: ${content}`
...
@@ -359,11 +358,6 @@ Human: ${content}`
};
};
}
}
const
jsonStr
=
answer
.
substring
(
start
,
end
+
1
)
.
replace
(
/
(\\
n|
\\)
/g
,
''
)
.
replace
(
/ /g
,
''
);
try
{
try
{
return
{
return
{
rawResponse
:
answer
,
rawResponse
:
answer
,
...
...
packages/service/core/workflow/dispatch/agent/runTool/constants.ts
View file @
c4ce1236
...
@@ -3,7 +3,7 @@ export const Prompt_Tool_Call = `<Instruction>
...
@@ -3,7 +3,7 @@ export const Prompt_Tool_Call = `<Instruction>
工具使用了 JSON Schema 的格式声明,其中 toolId 是工具的 description 是工具的描述,parameters 是工具的参数,包括参数的类型和描述,required 是必填参数的列表。
工具使用了 JSON Schema 的格式声明,其中 toolId 是工具的 description 是工具的描述,parameters 是工具的参数,包括参数的类型和描述,required 是必填参数的列表。
请你根据工具描述,决定回答问题或是使用工具。在完成任务过程中,USER代表用户的输入,TOOL_RESPONSE代表工具运行结果
。ASSISTANT
代表你的输出。
请你根据工具描述,决定回答问题或是使用工具。在完成任务过程中,USER代表用户的输入,TOOL_RESPONSE代表工具运行结果
,ANSWER
代表你的输出。
你的每次输出都必须以0,1开头,代表是否需要调用工具:
你的每次输出都必须以0,1开头,代表是否需要调用工具:
0: 不使用工具,直接回答内容。
0: 不使用工具,直接回答内容。
1: 使用工具,返回工具调用的参数。
1: 使用工具,返回工具调用的参数。
...
@@ -12,14 +12,20 @@ export const Prompt_Tool_Call = `<Instruction>
...
@@ -12,14 +12,20 @@ export const Prompt_Tool_Call = `<Instruction>
USER: 你好呀
USER: 你好呀
ANSWER: 0: 你好,有什么可以帮助你的么?
ANSWER: 0: 你好,有什么可以帮助你的么?
USER: 今天杭州的天气如何
USER: 现在几点了?
ANSWER: 1: {"toolId":"testToolId",arguments:{"city": "杭州"}}
ANSWER: 1: {"toolId":"timeToolId"}
TOOL_RESPONSE: """
2022/5/5 12:00 Thursday
"""
ANSWER: 0: 现在是2022年5月5日,星期四,中午12点。
USER: 今天杭州的天气如何?
ANSWER: 1: {"toolId":"testToolId","arguments":{"city": "杭州"}}
TOOL_RESPONSE: """
TOOL_RESPONSE: """
晴天......
晴天......
"""
"""
ANSWER: 0: 今天杭州是晴天。
ANSWER: 0: 今天杭州是晴天。
USER: 今天杭州的天气适合去哪里玩?
USER: 今天杭州的天气适合去哪里玩?
ANSWER: 1: {"toolId":"testToolId2",
arguments
:{"query": "杭州 天气 去哪里玩"}}
ANSWER: 1: {"toolId":"testToolId2",
"arguments"
:{"query": "杭州 天气 去哪里玩"}}
TOOL_RESPONSE: """
TOOL_RESPONSE: """
晴天. 西湖、灵隐寺、千岛湖……
晴天. 西湖、灵隐寺、千岛湖……
"""
"""
...
@@ -35,5 +41,4 @@ ANSWER: 0: 今天杭州是晴天,适合去西湖、灵隐寺、千岛湖等地
...
@@ -35,5 +41,4 @@ ANSWER: 0: 今天杭州是晴天,适合去西湖、灵隐寺、千岛湖等地
下面是正式的对话内容:
下面是正式的对话内容:
USER: {{question}}
USER: {{question}}
ANSWER:
ANSWER: `
;
`
;
packages/service/core/workflow/dispatch/agent/runTool/promptCall.ts
View file @
c4ce1236
...
@@ -20,7 +20,7 @@ import { dispatchWorkFlow } from '../../index';
...
@@ -20,7 +20,7 @@ import { dispatchWorkFlow } from '../../index';
import
{
DispatchToolModuleProps
,
RunToolResponse
,
ToolNodeItemType
}
from
'./type.d'
;
import
{
DispatchToolModuleProps
,
RunToolResponse
,
ToolNodeItemType
}
from
'./type.d'
;
import
json5
from
'json5'
;
import
json5
from
'json5'
;
import
{
countGptMessagesTokens
}
from
'../../../../../common/string/tiktoken/index'
;
import
{
countGptMessagesTokens
}
from
'../../../../../common/string/tiktoken/index'
;
import
{
getNanoid
,
replaceVariable
}
from
'@fastgpt/global/common/string/tools'
;
import
{
getNanoid
,
replaceVariable
,
sliceJsonStr
}
from
'@fastgpt/global/common/string/tools'
;
import
{
AIChatItemType
}
from
'@fastgpt/global/core/chat/type'
;
import
{
AIChatItemType
}
from
'@fastgpt/global/core/chat/type'
;
import
{
GPTMessages2Chats
}
from
'@fastgpt/global/core/chat/adapt'
;
import
{
GPTMessages2Chats
}
from
'@fastgpt/global/core/chat/adapt'
;
import
{
updateToolInputValue
}
from
'./utils'
;
import
{
updateToolInputValue
}
from
'./utils'
;
...
@@ -33,6 +33,8 @@ type FunctionCallCompletion = {
...
@@ -33,6 +33,8 @@ type FunctionCallCompletion = {
toolAvatar
?:
string
;
toolAvatar
?:
string
;
};
};
const
ERROR_TEXT
=
'Tool run error'
;
export
const
runToolWithPromptCall
=
async
(
export
const
runToolWithPromptCall
=
async
(
props
:
DispatchToolModuleProps
&
{
props
:
DispatchToolModuleProps
&
{
messages
:
ChatCompletionMessageParam
[];
messages
:
ChatCompletionMessageParam
[];
...
@@ -122,14 +124,23 @@ export const runToolWithPromptCall = async (
...
@@ -122,14 +124,23 @@ export const runToolWithPromptCall = async (
}
}
})();
})();
const
parseAnswerResult
=
parseAnswer
(
answer
);
const
{
answer
:
replaceAnswer
,
toolJson
}
=
parseAnswer
(
answer
);
// console.log(parseAnswer, '==11==');
// console.log(parseAnswer, '==11==');
// No tools
// No tools
if
(
typeof
parseAnswerResult
===
'string'
)
{
if
(
!
toolJson
)
{
if
(
replaceAnswer
===
ERROR_TEXT
&&
stream
&&
detail
)
{
responseWrite
({
res
,
event
:
SseResponseEventEnum
.
answer
,
data
:
textAdaptGptResponse
({
text
:
replaceAnswer
})
});
}
// No tool is invoked, indicating that the process is over
// No tool is invoked, indicating that the process is over
const
gptAssistantResponse
:
ChatCompletionAssistantMessageParam
=
{
const
gptAssistantResponse
:
ChatCompletionAssistantMessageParam
=
{
role
:
ChatCompletionRequestMessageRoleEnum
.
Assistant
,
role
:
ChatCompletionRequestMessageRoleEnum
.
Assistant
,
content
:
parseAnswerResult
content
:
replaceAnswer
};
};
const
completeMessages
=
filterMessages
.
concat
(
gptAssistantResponse
);
const
completeMessages
=
filterMessages
.
concat
(
gptAssistantResponse
);
const
tokens
=
await
countGptMessagesTokens
(
completeMessages
,
undefined
);
const
tokens
=
await
countGptMessagesTokens
(
completeMessages
,
undefined
);
...
@@ -148,18 +159,16 @@ export const runToolWithPromptCall = async (
...
@@ -148,18 +159,16 @@ export const runToolWithPromptCall = async (
// Run the selected tool.
// Run the selected tool.
const
toolsRunResponse
=
await
(
async
()
=>
{
const
toolsRunResponse
=
await
(
async
()
=>
{
if
(
!
parseAnswerResult
)
return
Promise
.
reject
(
'tool run error'
);
const
toolNode
=
toolNodes
.
find
((
item
)
=>
item
.
nodeId
===
toolJson
.
name
);
const
toolNode
=
toolNodes
.
find
((
item
)
=>
item
.
nodeId
===
parseAnswerResult
.
name
);
if
(
!
toolNode
)
return
Promise
.
reject
(
'tool not found'
);
if
(
!
toolNode
)
return
Promise
.
reject
(
'tool not found'
);
parseAnswerResult
.
toolName
=
toolNode
.
name
;
toolJson
.
toolName
=
toolNode
.
name
;
parseAnswerResult
.
toolAvatar
=
toolNode
.
avatar
;
toolJson
.
toolAvatar
=
toolNode
.
avatar
;
// run tool flow
// run tool flow
const
startParams
=
(()
=>
{
const
startParams
=
(()
=>
{
try
{
try
{
return
json5
.
parse
(
parseAnswerResult
.
arguments
);
return
json5
.
parse
(
toolJson
.
arguments
);
}
catch
(
error
)
{
}
catch
(
error
)
{
return
{};
return
{};
}
}
...
@@ -172,11 +181,11 @@ export const runToolWithPromptCall = async (
...
@@ -172,11 +181,11 @@ export const runToolWithPromptCall = async (
event
:
SseResponseEventEnum
.
toolCall
,
event
:
SseResponseEventEnum
.
toolCall
,
data
:
JSON
.
stringify
({
data
:
JSON
.
stringify
({
tool
:
{
tool
:
{
id
:
parseAnswerResult
.
id
,
id
:
toolJson
.
id
,
toolName
:
toolNode
.
name
,
toolName
:
toolNode
.
name
,
toolAvatar
:
toolNode
.
avatar
,
toolAvatar
:
toolNode
.
avatar
,
functionName
:
parseAnswerResult
.
name
,
functionName
:
toolJson
.
name
,
params
:
parseAnswerResult
.
arguments
,
params
:
toolJson
.
arguments
,
response
:
''
response
:
''
}
}
})
})
...
@@ -211,7 +220,7 @@ export const runToolWithPromptCall = async (
...
@@ -211,7 +220,7 @@ export const runToolWithPromptCall = async (
event
:
SseResponseEventEnum
.
toolResponse
,
event
:
SseResponseEventEnum
.
toolResponse
,
data
:
JSON
.
stringify
({
data
:
JSON
.
stringify
({
tool
:
{
tool
:
{
id
:
parseAnswerResult
.
id
,
id
:
toolJson
.
id
,
toolName
:
''
,
toolName
:
''
,
toolAvatar
:
''
,
toolAvatar
:
''
,
params
:
''
,
params
:
''
,
...
@@ -237,7 +246,7 @@ export const runToolWithPromptCall = async (
...
@@ -237,7 +246,7 @@ export const runToolWithPromptCall = async (
// 合并工具调用的结果,使用 functionCall 格式存储。
// 合并工具调用的结果,使用 functionCall 格式存储。
const
assistantToolMsgParams
:
ChatCompletionAssistantMessageParam
=
{
const
assistantToolMsgParams
:
ChatCompletionAssistantMessageParam
=
{
role
:
ChatCompletionRequestMessageRoleEnum
.
Assistant
,
role
:
ChatCompletionRequestMessageRoleEnum
.
Assistant
,
function_call
:
parseAnswerResult
function_call
:
toolJson
};
};
const
concatToolMessages
=
[
const
concatToolMessages
=
[
...
filterMessages
,
...
filterMessages
,
...
@@ -248,7 +257,7 @@ export const runToolWithPromptCall = async (
...
@@ -248,7 +257,7 @@ export const runToolWithPromptCall = async (
...
concatToolMessages
,
...
concatToolMessages
,
{
{
role
:
ChatCompletionRequestMessageRoleEnum
.
Function
,
role
:
ChatCompletionRequestMessageRoleEnum
.
Function
,
name
:
parseAnswerResult
.
name
,
name
:
toolJson
.
name
,
content
:
toolsRunResponse
.
toolResponsePrompt
content
:
toolsRunResponse
.
toolResponsePrompt
}
}
];
];
...
@@ -266,7 +275,7 @@ export const runToolWithPromptCall = async (
...
@@ -266,7 +275,7 @@ export const runToolWithPromptCall = async (
:
[
toolsRunResponse
.
moduleRunResponse
];
:
[
toolsRunResponse
.
moduleRunResponse
];
// get the next user prompt
// get the next user prompt
lastMessage
.
content
+=
`
${
a
nswer
}
lastMessage
.
content
+=
`
${
replaceA
nswer
}
TOOL_RESPONSE: """
TOOL_RESPONSE: """
${
toolsRunResponse
.
toolResponsePrompt
}
${
toolsRunResponse
.
toolResponsePrompt
}
"""
"""
...
@@ -362,24 +371,37 @@ async function streamResponse({
...
@@ -362,24 +371,37 @@ async function streamResponse({
return
{
answer
:
textAnswer
.
trim
()
};
return
{
answer
:
textAnswer
.
trim
()
};
}
}
const
parseAnswer
=
(
str
:
string
):
FunctionCallCompletion
|
string
=>
{
const
parseAnswer
=
(
// 首先,使用正则表达式提取TOOL_ID和TOOL_ARGUMENTS
str
:
string
const
prefix
=
'1:'
;
):
{
answer
:
string
;
toolJson
?:
FunctionCallCompletion
;
}
=>
{
str
=
str
.
trim
();
str
=
str
.
trim
();
if
(
str
.
startsWith
(
prefix
))
{
// 首先,使用正则表达式提取TOOL_ID和TOOL_ARGUMENTS
const
toolString
=
str
.
substring
(
prefix
.
length
).
trim
();
const
prefixReg
=
/^1
(
:|:
)
/
;
if
(
prefixReg
.
test
(
str
))
{
const
toolString
=
sliceJsonStr
(
str
);
try
{
try
{
const
toolCall
=
json5
.
parse
(
toolString
);
const
toolCall
=
json5
.
parse
(
toolString
);
return
{
return
{
id
:
getNanoid
(),
answer
:
`1:
${
toolString
}
`
,
name
:
toolCall
.
toolId
,
toolJson
:
{
arguments
:
JSON
.
stringify
(
toolCall
.
arguments
||
toolCall
.
parameters
)
id
:
getNanoid
(),
name
:
toolCall
.
toolId
,
arguments
:
JSON
.
stringify
(
toolCall
.
arguments
||
toolCall
.
parameters
)
}
};
};
}
catch
(
error
)
{
}
catch
(
error
)
{
return
str
;
return
{
answer
:
ERROR_TEXT
};
}
}
}
else
{
}
else
{
return
str
;
return
{
answer
:
str
};
}
}
};
};
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment