mirror of
https://github.com/labring/FastGPT.git
synced 2025-10-21 03:10:50 +00:00
feat: limit prompt
This commit is contained in:
1
client/src/api/response/chat.d.ts
vendored
1
client/src/api/response/chat.d.ts
vendored
@@ -5,6 +5,7 @@ export interface InitChatResponse {
|
|||||||
chatId: string;
|
chatId: string;
|
||||||
modelId: string;
|
modelId: string;
|
||||||
systemPrompt?: string;
|
systemPrompt?: string;
|
||||||
|
limitPrompt?: string;
|
||||||
model: {
|
model: {
|
||||||
name: string;
|
name: string;
|
||||||
avatar: string;
|
avatar: string;
|
||||||
|
@@ -26,7 +26,7 @@ const MySelect = ({ placeholder, value, width = 'auto', list, onchange, ...props
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Menu autoSelect={false} onOpen={onOpen} onClose={onClose}>
|
<Menu autoSelect={false} onOpen={onOpen} onClose={onClose}>
|
||||||
<MenuButton as={'span'}>
|
<MenuButton style={{ width: '100%' }} as={'span'}>
|
||||||
<Button
|
<Button
|
||||||
width={width}
|
width={width}
|
||||||
px={3}
|
px={3}
|
||||||
|
@@ -82,6 +82,7 @@ export const defaultModel: ModelSchema = {
|
|||||||
searchLimit: 5,
|
searchLimit: 5,
|
||||||
searchEmptyText: '',
|
searchEmptyText: '',
|
||||||
systemPrompt: '',
|
systemPrompt: '',
|
||||||
|
limitPrompt: '',
|
||||||
temperature: 0,
|
temperature: 0,
|
||||||
maxToken: 4000,
|
maxToken: 4000,
|
||||||
chatModel: OpenAiChatEnum.GPT35
|
chatModel: OpenAiChatEnum.GPT35
|
||||||
|
@@ -101,6 +101,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
|||||||
},
|
},
|
||||||
chatModel: model.chat.chatModel,
|
chatModel: model.chat.chatModel,
|
||||||
systemPrompt: isOwner ? model.chat.systemPrompt : '',
|
systemPrompt: isOwner ? model.chat.systemPrompt : '',
|
||||||
|
limitPrompt: isOwner ? model.chat.limitPrompt : '',
|
||||||
history
|
history
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@@ -28,7 +28,11 @@ type Response = {
|
|||||||
userSystemPrompt: {
|
userSystemPrompt: {
|
||||||
obj: ChatRoleEnum;
|
obj: ChatRoleEnum;
|
||||||
value: string;
|
value: string;
|
||||||
};
|
}[];
|
||||||
|
userLimitPrompt: {
|
||||||
|
obj: ChatRoleEnum;
|
||||||
|
value: string;
|
||||||
|
}[];
|
||||||
quotePrompt: {
|
quotePrompt: {
|
||||||
obj: ChatRoleEnum;
|
obj: ChatRoleEnum;
|
||||||
value: string;
|
value: string;
|
||||||
@@ -130,17 +134,24 @@ export async function appKbSearch({
|
|||||||
|
|
||||||
// 计算固定提示词的 token 数量
|
// 计算固定提示词的 token 数量
|
||||||
const userSystemPrompt = model.chat.systemPrompt // user system prompt
|
const userSystemPrompt = model.chat.systemPrompt // user system prompt
|
||||||
? {
|
? [
|
||||||
obj: ChatRoleEnum.Human,
|
{
|
||||||
value: model.chat.systemPrompt
|
obj: ChatRoleEnum.System,
|
||||||
}
|
value: model.chat.systemPrompt
|
||||||
: {
|
}
|
||||||
obj: ChatRoleEnum.Human,
|
]
|
||||||
value: `知识库是关于 ${model.name} 的内容,参考知识库回答问题。与 "${model.name}" 无关内容,直接回复: "我不知道"。`
|
: [];
|
||||||
};
|
const userLimitPrompt = [
|
||||||
|
{
|
||||||
|
obj: ChatRoleEnum.Human,
|
||||||
|
value: model.chat.limitPrompt
|
||||||
|
? model.chat.limitPrompt
|
||||||
|
: `知识库是关于 ${model.name} 的内容,参考知识库回答问题。与 "${model.name}" 无关内容,直接回复: "我不知道"。`
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
const fixedSystemTokens = modelToolMap[model.chat.chatModel].countTokens({
|
const fixedSystemTokens = modelToolMap[model.chat.chatModel].countTokens({
|
||||||
messages: [userSystemPrompt]
|
messages: [...userSystemPrompt, ...userLimitPrompt]
|
||||||
});
|
});
|
||||||
|
|
||||||
// filter part quote by maxToken
|
// filter part quote by maxToken
|
||||||
@@ -164,6 +175,7 @@ export async function appKbSearch({
|
|||||||
return {
|
return {
|
||||||
rawSearch,
|
rawSearch,
|
||||||
userSystemPrompt,
|
userSystemPrompt,
|
||||||
|
userLimitPrompt,
|
||||||
quotePrompt: {
|
quotePrompt: {
|
||||||
obj: ChatRoleEnum.System,
|
obj: ChatRoleEnum.System,
|
||||||
value: quoteText
|
value: quoteText
|
||||||
|
@@ -108,11 +108,12 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
|
|||||||
const {
|
const {
|
||||||
rawSearch = [],
|
rawSearch = [],
|
||||||
userSystemPrompt = [],
|
userSystemPrompt = [],
|
||||||
|
userLimitPrompt = [],
|
||||||
quotePrompt = []
|
quotePrompt = []
|
||||||
} = await (async () => {
|
} = await (async () => {
|
||||||
// 使用了知识库搜索
|
// 使用了知识库搜索
|
||||||
if (model.chat.relatedKbs?.length > 0) {
|
if (model.chat.relatedKbs?.length > 0) {
|
||||||
const { rawSearch, userSystemPrompt, quotePrompt } = await appKbSearch({
|
const { rawSearch, quotePrompt, userSystemPrompt, userLimitPrompt } = await appKbSearch({
|
||||||
model,
|
model,
|
||||||
userId,
|
userId,
|
||||||
fixedQuote: history[history.length - 1]?.quote,
|
fixedQuote: history[history.length - 1]?.quote,
|
||||||
@@ -123,21 +124,29 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
rawSearch,
|
rawSearch,
|
||||||
userSystemPrompt: userSystemPrompt ? [userSystemPrompt] : [],
|
userSystemPrompt,
|
||||||
|
userLimitPrompt,
|
||||||
quotePrompt: [quotePrompt]
|
quotePrompt: [quotePrompt]
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (model.chat.systemPrompt) {
|
return {
|
||||||
return {
|
userSystemPrompt: model.chat.systemPrompt
|
||||||
userSystemPrompt: [
|
? [
|
||||||
{
|
{
|
||||||
obj: ChatRoleEnum.System,
|
obj: ChatRoleEnum.System,
|
||||||
value: model.chat.systemPrompt
|
value: model.chat.systemPrompt
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
: [],
|
||||||
}
|
userLimitPrompt: model.chat.limitPrompt
|
||||||
return {};
|
? [
|
||||||
|
{
|
||||||
|
obj: ChatRoleEnum.Human,
|
||||||
|
value: model.chat.limitPrompt
|
||||||
|
}
|
||||||
|
]
|
||||||
|
: []
|
||||||
|
};
|
||||||
})();
|
})();
|
||||||
|
|
||||||
// search result is empty
|
// search result is empty
|
||||||
@@ -167,7 +176,13 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
|
|||||||
}
|
}
|
||||||
|
|
||||||
// api messages. [quote,context,systemPrompt,question]
|
// api messages. [quote,context,systemPrompt,question]
|
||||||
const completePrompts = [...quotePrompt, ...prompts.slice(0, -1), ...userSystemPrompt, prompt];
|
const completePrompts = [
|
||||||
|
...quotePrompt,
|
||||||
|
...userSystemPrompt,
|
||||||
|
...prompts.slice(0, -1),
|
||||||
|
...userLimitPrompt,
|
||||||
|
prompt
|
||||||
|
];
|
||||||
// chat temperature
|
// chat temperature
|
||||||
const modelConstantsData = ChatModelMap[model.chat.chatModel];
|
const modelConstantsData = ChatModelMap[model.chat.chatModel];
|
||||||
// FastGpt temperature range: 1~10
|
// FastGpt temperature range: 1~10
|
||||||
@@ -176,7 +191,7 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
|
|||||||
);
|
);
|
||||||
|
|
||||||
await sensitiveCheck({
|
await sensitiveCheck({
|
||||||
input: `${prompt.value}`
|
input: `${userSystemPrompt[0]?.value}\n${userLimitPrompt[0]?.value}\n${prompt.value}`
|
||||||
});
|
});
|
||||||
|
|
||||||
// start model api. responseText and totalTokens: valid only if stream = false
|
// start model api. responseText and totalTokens: valid only if stream = false
|
||||||
@@ -259,7 +274,7 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
|
|||||||
...(showAppDetail
|
...(showAppDetail
|
||||||
? {
|
? {
|
||||||
quote: rawSearch,
|
quote: rawSearch,
|
||||||
systemPrompt: userSystemPrompt?.[0]?.value
|
systemPrompt: `${userSystemPrompt[0]?.value}\n\n${userLimitPrompt[0]?.value}`
|
||||||
}
|
}
|
||||||
: {})
|
: {})
|
||||||
}
|
}
|
||||||
|
@@ -219,7 +219,7 @@ const Chat = ({ modelId, chatId }: { modelId: string; chatId: string }) => {
|
|||||||
...item,
|
...item,
|
||||||
status: 'finish',
|
status: 'finish',
|
||||||
quoteLen,
|
quoteLen,
|
||||||
systemPrompt: chatData.systemPrompt
|
systemPrompt: `${chatData.systemPrompt}\n\n${chatData.limitPrompt}`
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
}));
|
}));
|
||||||
@@ -234,13 +234,14 @@ const Chat = ({ modelId, chatId }: { modelId: string; chatId: string }) => {
|
|||||||
[
|
[
|
||||||
chatId,
|
chatId,
|
||||||
modelId,
|
modelId,
|
||||||
chatData.systemPrompt,
|
|
||||||
setChatData,
|
setChatData,
|
||||||
loadHistory,
|
|
||||||
loadMyModels,
|
|
||||||
generatingMessage,
|
generatingMessage,
|
||||||
setForbidLoadChatData,
|
setForbidLoadChatData,
|
||||||
router
|
router,
|
||||||
|
chatData.systemPrompt,
|
||||||
|
chatData.limitPrompt,
|
||||||
|
loadHistory,
|
||||||
|
loadMyModels
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -749,7 +750,7 @@ const Chat = ({ modelId, chatId }: { modelId: string; chatId: string }) => {
|
|||||||
px={[2, 4]}
|
px={[2, 4]}
|
||||||
onClick={() => setShowSystemPrompt(item.systemPrompt || '')}
|
onClick={() => setShowSystemPrompt(item.systemPrompt || '')}
|
||||||
>
|
>
|
||||||
提示词
|
提示词 & 限定词
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
{!!item.quoteLen && (
|
{!!item.quoteLen && (
|
||||||
|
@@ -1,5 +1,15 @@
|
|||||||
import React, { useCallback, useState, useMemo } from 'react';
|
import React, { useCallback, useState, useMemo } from 'react';
|
||||||
import { Box, Flex, Button, FormControl, Input, Textarea, Divider } from '@chakra-ui/react';
|
import {
|
||||||
|
Box,
|
||||||
|
Flex,
|
||||||
|
Button,
|
||||||
|
FormControl,
|
||||||
|
Input,
|
||||||
|
Textarea,
|
||||||
|
Divider,
|
||||||
|
Tooltip
|
||||||
|
} from '@chakra-ui/react';
|
||||||
|
import { QuestionOutlineIcon } from '@chakra-ui/icons';
|
||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import { useForm } from 'react-hook-form';
|
import { useForm } from 'react-hook-form';
|
||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
@@ -20,6 +30,11 @@ import Avatar from '@/components/Avatar';
|
|||||||
import MySelect from '@/components/Select';
|
import MySelect from '@/components/Select';
|
||||||
import MySlider from '@/components/Slider';
|
import MySlider from '@/components/Slider';
|
||||||
|
|
||||||
|
const systemPromptTip =
|
||||||
|
'模型固定的引导词,通过调整该内容,可以引导模型聊天方向。该内容会被固定在上下文的开头。';
|
||||||
|
const limitPromptTip =
|
||||||
|
'限定模型对话范围,会被放置在本次提问前,拥有强引导和限定性。例如:\n1. 知识库是关于 Laf 的介绍,参考知识库回答问题,与 "Laf" 无关内容,直接回复: "我不知道"。\n2. 你仅回答关于 "xxx" 的问题,其他问题回复: "xxxx"';
|
||||||
|
|
||||||
const Settings = ({ modelId }: { modelId: string }) => {
|
const Settings = ({ modelId }: { modelId: string }) => {
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@@ -60,7 +75,7 @@ const Settings = ({ modelId }: { modelId: string }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return max;
|
return max;
|
||||||
}, [getValues, setValue, refresh]);
|
}, [getValues, setValue]);
|
||||||
|
|
||||||
// 提交保存模型修改
|
// 提交保存模型修改
|
||||||
const saveSubmitSuccess = useCallback(
|
const saveSubmitSuccess = useCallback(
|
||||||
@@ -211,7 +226,7 @@ const Settings = ({ modelId }: { modelId: string }) => {
|
|||||||
介绍
|
介绍
|
||||||
</Box>
|
</Box>
|
||||||
<Textarea
|
<Textarea
|
||||||
rows={5}
|
rows={4}
|
||||||
maxLength={500}
|
maxLength={500}
|
||||||
placeholder={'给你的 AI 应用一个介绍'}
|
placeholder={'给你的 AI 应用一个介绍'}
|
||||||
{...register('intro')}
|
{...register('intro')}
|
||||||
@@ -225,11 +240,14 @@ const Settings = ({ modelId }: { modelId: string }) => {
|
|||||||
对话模型
|
对话模型
|
||||||
</Box>
|
</Box>
|
||||||
<MySelect
|
<MySelect
|
||||||
width={['200px', '240px']}
|
width={['100%', '280px']}
|
||||||
value={getValues('chat.chatModel')}
|
value={getValues('chat.chatModel')}
|
||||||
list={chatModelList.map((item) => ({
|
list={chatModelList.map((item) => ({
|
||||||
id: item.chatModel,
|
id: item.chatModel,
|
||||||
label: item.name
|
label: `${item.name} (${formatPrice(
|
||||||
|
ChatModelMap[getValues('chat.chatModel')]?.price,
|
||||||
|
1000
|
||||||
|
)} 元/1k tokens)`
|
||||||
}))}
|
}))}
|
||||||
onchange={(val: any) => {
|
onchange={(val: any) => {
|
||||||
setValue('chat.chatModel', val);
|
setValue('chat.chatModel', val);
|
||||||
@@ -237,15 +255,6 @@ const Settings = ({ modelId }: { modelId: string }) => {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Flex alignItems={'center'} mt={5}>
|
|
||||||
<Box w={['60px', '100px', '140px']} flexShrink={0}>
|
|
||||||
价格
|
|
||||||
</Box>
|
|
||||||
<Box fontSize={['sm', 'md']}>
|
|
||||||
{formatPrice(ChatModelMap[getValues('chat.chatModel')]?.price, 1000)}
|
|
||||||
元/1K tokens(包括上下文和回答)
|
|
||||||
</Box>
|
|
||||||
</Flex>
|
|
||||||
<Flex alignItems={'center'} my={10}>
|
<Flex alignItems={'center'} my={10}>
|
||||||
<Box w={['60px', '100px', '140px']} flexShrink={0}>
|
<Box w={['60px', '100px', '140px']} flexShrink={0}>
|
||||||
温度
|
温度
|
||||||
@@ -269,7 +278,7 @@ const Settings = ({ modelId }: { modelId: string }) => {
|
|||||||
</Flex>
|
</Flex>
|
||||||
<Flex alignItems={'center'} mt={12} mb={10}>
|
<Flex alignItems={'center'} mt={12} mb={10}>
|
||||||
<Box w={['60px', '100px', '140px']} flexShrink={0}>
|
<Box w={['60px', '100px', '140px']} flexShrink={0}>
|
||||||
最大长度
|
回复上限
|
||||||
</Box>
|
</Box>
|
||||||
<Box flex={1} ml={'10px'}>
|
<Box flex={1} ml={'10px'}>
|
||||||
<MySlider
|
<MySlider
|
||||||
@@ -292,15 +301,29 @@ const Settings = ({ modelId }: { modelId: string }) => {
|
|||||||
<Flex mt={10} alignItems={'flex-start'}>
|
<Flex mt={10} alignItems={'flex-start'}>
|
||||||
<Box w={['60px', '100px', '140px']} flexShrink={0}>
|
<Box w={['60px', '100px', '140px']} flexShrink={0}>
|
||||||
提示词
|
提示词
|
||||||
|
<Tooltip label={systemPromptTip}>
|
||||||
|
<QuestionOutlineIcon display={['none', 'inline']} ml={1} />
|
||||||
|
</Tooltip>
|
||||||
</Box>
|
</Box>
|
||||||
<Textarea
|
<Textarea
|
||||||
rows={8}
|
rows={8}
|
||||||
placeholder={
|
placeholder={systemPromptTip}
|
||||||
'模型默认的 prompt 词,通过调整该内容,可以引导模型聊天方向。\n\n如果使用了知识库搜索,没有填写该内容时,系统会自动补充提示词;如果填写了内容,则以填写的内容为准。'
|
|
||||||
}
|
|
||||||
{...register('chat.systemPrompt')}
|
{...register('chat.systemPrompt')}
|
||||||
></Textarea>
|
></Textarea>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
<Flex mt={5} alignItems={'flex-start'}>
|
||||||
|
<Box w={['60px', '100px', '140px']} flexShrink={0}>
|
||||||
|
限定词
|
||||||
|
<Tooltip label={limitPromptTip}>
|
||||||
|
<QuestionOutlineIcon display={['none', 'inline']} ml={1} />
|
||||||
|
</Tooltip>
|
||||||
|
</Box>
|
||||||
|
<Textarea
|
||||||
|
rows={5}
|
||||||
|
placeholder={limitPromptTip}
|
||||||
|
{...register('chat.limitPrompt')}
|
||||||
|
></Textarea>
|
||||||
|
</Flex>
|
||||||
|
|
||||||
<Flex mt={5} alignItems={'center'}>
|
<Flex mt={5} alignItems={'center'}>
|
||||||
<Box w={['60px', '100px', '140px']} flexShrink={0}></Box>
|
<Box w={['60px', '100px', '140px']} flexShrink={0}></Box>
|
||||||
|
@@ -43,7 +43,10 @@ const ModelSchema = new Schema({
|
|||||||
default: ''
|
default: ''
|
||||||
},
|
},
|
||||||
systemPrompt: {
|
systemPrompt: {
|
||||||
// 系统提示词
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
limitPrompt: {
|
||||||
type: String,
|
type: String,
|
||||||
default: ''
|
default: ''
|
||||||
},
|
},
|
||||||
|
1
client/src/types/mongoSchema.d.ts
vendored
1
client/src/types/mongoSchema.d.ts
vendored
@@ -43,6 +43,7 @@ export interface ModelSchema {
|
|||||||
searchLimit: number;
|
searchLimit: number;
|
||||||
searchEmptyText: string;
|
searchEmptyText: string;
|
||||||
systemPrompt: string;
|
systemPrompt: string;
|
||||||
|
limitPrompt: string;
|
||||||
temperature: number;
|
temperature: number;
|
||||||
maxToken: number;
|
maxToken: number;
|
||||||
chatModel: ChatModelType; // 聊天时用的模型,训练后就是训练的模型
|
chatModel: ChatModelType; // 聊天时用的模型,训练后就是训练的模型
|
||||||
|
Reference in New Issue
Block a user