mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-22 20:37:48 +00:00

* chore(ui): login page & workflow page (#3046) * login page & number input & multirow select & llm select * workflow * adjust nodes * New file upload (#3058) * feat: toolNode aiNode readFileNode adapt new version * update docker-compose * update tip * feat: adapt new file version * perf: file input * fix: ts * feat: add chat history time label (#3024) * feat:add chat and logs time * feat: add chat history time label * code perf * code perf --------- Co-authored-by: 勤劳上班的卑微小张 <jiazhan.zhang@ggimage.com> * add chatType (#3060) * pref: slow query of full text search (#3044) * Adapt findLast api;perf: markdown zh format. (#3066) * perf: context code * fix: adapt findLast api * perf: commercial plugin run error * perf: markdown zh format * perf: dockerfile proxy (#3067) * fix ui (#3065) * fix ui * fix * feat: support array reference multi-select (#3041) * feat: support array reference multi-select * fix build * fix * fix loop multi-select * adjust condition * fix get value * array and non-array conversion * fix plugin input * merge func * feat: iframe code block;perf: workflow selector type (#3076) * feat: iframe code block * perf: workflow selector type * node pluginoutput check (#3074) * feat: View will move when workflow check error;fix: ui refresh error when continuous file upload (#3077) * fix: plugin output check * fix: ui refresh error when continuous file upload * feat: View will move when workflow check error * add dispatch try catch (#3075) * perf: workflow context split (#3083) * perf: workflow context split * perf: context * 4.8.13 test (#3085) * perf: workflow node ui * chat iframe url * feat: support sub route config (#3071) * feat: support sub route config * dockerfile * fix upload * delete unused code * 4.8.13 test (#3087) * fix: image expired * fix: datacard navbar ui * perf: build action * fix: workflow file upload refresh (#3088) * fix: http tool response (#3097) * loop node dynamic height (#3092) * loop node dynamic height * fix * fix * feat: support push chat log (#3093) * feat: custom uid/metadata * to: custom info * fix: chat push latest * feat: add chat log envs * refactor: move timer to pushChatLog * fix: using precise log --------- Co-authored-by: Finley Ge <m13203533462@163.com> * 4.8.13 test (#3098) * perf: loop node refresh * rename context * comment * fix: ts * perf: push chat log * array reference check & node ui (#3100) * feat: loop start add index (#3101) * feat: loop start add index * update doc * 4.8.13 test (#3102) * fix: loop index;edge parent check * perf: reference invalid check * fix: ts * fix: plugin select files and ai response check (#3104) * fix: plugin select files and ai response check * perf: text editor selector;tool call tip;remove invalid image url; * perf: select file * perf: drop files * feat: source id prefix env (#3103) * 4.8.13 test (#3106) * perf: select file * perf: drop files * perf: env template * 4.8.13 test (#3107) * perf: select file * perf: drop files * fix: imple mode adapt files * perf: push chat log (#3109) * fix: share page load title error (#3111) * 4.8.13 perf (#3112) * fix: share page load title error * update file input doc * perf: auto add file urls * perf: auto ser loop node offset height * 4.8.13 test (#3117) * perf: plugin * updat eaction * feat: add more share config (#3120) * feat: add more share config * add i18n en * fix: missing subroute (#3121) * perf: outlink config (#3128) * update action * perf: outlink config * fix: ts (#3129) * 更新 docSite 文档内容 (#3131) * fix: null pointer (#3130) * fix: null pointer * perf: not input text * update doc url * perf: outlink default value (#3134) * update doc (#3136) * 4.8.13 test (#3137) * update doc * perf: completions chat api * Restore docSite content based on upstream/4.8.13-dev (#3138) * Restore docSite content based on upstream/4.8.13-dev * 4813.md缺少更正 * update doc (#3141) --------- Co-authored-by: heheer <heheer@sealos.io> Co-authored-by: papapatrick <109422393+Patrickill@users.noreply.github.com> Co-authored-by: 勤劳上班的卑微小张 <jiazhan.zhang@ggimage.com> Co-authored-by: Finley Ge <32237950+FinleyGe@users.noreply.github.com> Co-authored-by: a.e. <49438478+I-Info@users.noreply.github.com> Co-authored-by: Finley Ge <m13203533462@163.com> Co-authored-by: Jiangween <145003935+Jiangween@users.noreply.github.com>
22 KiB
22 KiB
title, description, icon, draft, toc, weight
title | description | icon | draft | toc | weight |
---|---|---|---|---|---|
实验室预约 | 展示高级编排操作数据库的能力 | database | false | true | 612 |
![]() |
![]() |
![]() |
![]() |
本示例演示了利用工具调用,自动选择调用知识库搜索实验室相关内容,或调用 HTTP 模块实现数据库的 CRUD 操作。
以一个实验室预约为例,用户可以通过对话系统预约、取消、修改预约和查询预约记录。
1. 全局变量使用
通过设计一个全局变量,让用户输入姓名,模拟用户身份信息。实际使用过程中,通常是直接通过嵌入 Token 来标记用户身份。
2. 工具调用
背景知识中,引导模型调用工具去执行不通的操作。
{{% alert icon="🤗" context="warning" %}} Tips: 这里需要增加适当的上下文,方便模型结合历史纪录进行判断和决策~ {{% /alert %}}
3. HTTP 模块
HTTP模块中,需要设置 3 个工具参数:
- 预约行为:可取 get, put, post, delete 四个值,分别对应查询、修改、新增、删除操作。当然,你也可以写4个HTTP模块,来分别处理。
- labname: 实验室名。非必填,因为查询和删除时候,不需要。
- time: 预约时间。
总结
- 工具调用模块是非常强大的功能,可以在一定程度上替代问题分类和内容提取。
- 通过工具模块,动态的调用不同的工具,可以将复杂业务解耦。
附件
编排配置
可直接复制,导入到 FastGPT 中。
{{% details title="编排配置" closed="true" %}}
{
"nodes": [
{
"nodeId": "userChatInput",
"name": "流程开始",
"intro": "当用户发送一个内容后,流程将会从这个模块开始执行。",
"avatar": "/imgs/workflow/userChatInput.svg",
"flowNodeType": "workflowStart",
"position": {
"x": 309.7143912167367,
"y": 1501.2761754220846
},
"inputs": [
{
"key": "userChatInput",
"renderTypeList": [
"reference",
"textarea"
],
"valueType": "string",
"label": "问题输入",
"required": true,
"toolDescription": "用户问题",
"type": "systemInput",
"showTargetInApp": false,
"showTargetInPlugin": false,
"connected": false,
"selectedTypeIndex": 0,
"value": [
"userChatInput",
"userChatInput"
]
}
],
"outputs": [
{
"id": "userChatInput",
"type": "static",
"key": "userChatInput",
"valueType": "string",
"label": "core.module.input.label.user question"
}
]
},
{
"nodeId": "eg5upi",
"name": "指定回复",
"intro": "该模块可以直接回复一段指定的内容。常用于引导、提示。非字符串内容传入时,会转成字符串进行输出。",
"avatar": "/imgs/workflow/reply.png",
"flowNodeType": "answerNode",
"position": {
"x": 1962.729630445213,
"y": 2295.9791334948304
},
"inputs": [
{
"key": "text",
"renderTypeList": [
"textarea",
"reference"
],
"valueType": "any",
"label": "core.module.input.label.Response content",
"description": "core.module.input.description.Response content",
"placeholder": "core.module.input.description.Response content",
"type": "textarea",
"showTargetInApp": true,
"showTargetInPlugin": true,
"connected": true,
"selectedTypeIndex": 1,
"value": [
"40clf3",
"result"
]
}
],
"outputs": []
},
{
"nodeId": "kge59i",
"name": "用户引导",
"intro": "可以配置应用的系统参数。",
"avatar": "/imgs/workflow/userGuide.png",
"flowNodeType": "userGuide",
"position": {
"x": -327.218389965887,
"y": 1504.8056414948464
},
"inputs": [
{
"key": "welcomeText",
"renderTypeList": [
"hidden"
],
"valueType": "string",
"label": "core.app.Welcome Text",
"type": "hidden",
"showTargetInApp": false,
"showTargetInPlugin": false,
"value": "你好,我是实验室助手,请问有什么可以帮助你的么?如需预约或修改预约实验室,请提供姓名、时间和实验室名称。\n[实验室介绍]\n[开放时间]\n[预约]",
"connected": false,
"selectedTypeIndex": 0
},
{
"key": "variables",
"renderTypeList": [
"hidden"
],
"valueType": "any",
"label": "core.module.Variable",
"value": [
{
"id": "gt9b23",
"key": "name",
"label": "name",
"type": "input",
"required": true,
"maxLen": 50,
"enums": [
{
"value": ""
}
]
}
],
"type": "hidden",
"showTargetInApp": false,
"showTargetInPlugin": false,
"connected": false,
"selectedTypeIndex": 0
},
{
"key": "questionGuide",
"valueType": "boolean",
"renderTypeList": [
"hidden"
],
"label": "",
"type": "switch",
"showTargetInApp": false,
"showTargetInPlugin": false,
"value": false,
"connected": false,
"selectedTypeIndex": 0
},
{
"key": "tts",
"renderTypeList": [
"hidden"
],
"valueType": "any",
"label": "",
"type": "hidden",
"showTargetInApp": false,
"showTargetInPlugin": false,
"value": {
"type": "model",
"model": "tts-1",
"voice": "alloy"
},
"connected": false,
"selectedTypeIndex": 0
},
{
"key": "whisper",
"renderTypeList": [
"hidden"
],
"valueType": "any",
"label": "",
"type": "hidden",
"showTargetInApp": false,
"showTargetInPlugin": false,
"connected": false,
"selectedTypeIndex": 0
},
{
"key": "scheduleTrigger",
"renderTypeList": [
"hidden"
],
"valueType": "any",
"label": "",
"value": null
}
],
"outputs": []
},
{
"nodeId": "40clf3",
"name": "HTTP请求",
"intro": "可以发出一个 HTTP 请求,实现更为复杂的操作(联网搜索、数据库查询等)",
"avatar": "/imgs/workflow/http.png",
"flowNodeType": "httpRequest468",
"showStatus": true,
"position": {
"x": 1118.6532653446993,
"y": 1955.886106913907
},
"inputs": [
{
"key": "system_httpMethod",
"renderTypeList": [
"custom"
],
"valueType": "string",
"label": "",
"value": "POST",
"required": true,
"type": "custom",
"showTargetInApp": false,
"showTargetInPlugin": false,
"connected": false,
"selectedTypeIndex": 0
},
{
"valueType": "string",
"renderTypeList": [
"reference"
],
"key": "action",
"label": "action",
"toolDescription": "预约行为,一共四种:\nget - 查询预约情况\nput - 更新预约\npost - 新增预约\ndelete - 删除预约",
"required": true,
"canEdit": true,
"editField": {
"key": true,
"description": true
}
},
{
"valueType": "string",
"renderTypeList": [
"reference"
],
"key": "labname",
"label": "labname",
"toolDescription": "实验室名称",
"required": false,
"canEdit": true,
"editField": {
"key": true,
"description": true
}
},
{
"valueType": "string",
"renderTypeList": [
"reference"
],
"key": "time",
"label": "time",
"toolDescription": "预约时间,按 YYYY/MM/DD HH:mm 格式返回",
"required": false,
"canEdit": true,
"editField": {
"key": true,
"description": true
}
},
{
"key": "system_httpReqUrl",
"renderTypeList": [
"hidden"
],
"valueType": "string",
"label": "",
"description": "core.module.input.description.Http Request Url",
"placeholder": "https://api.ai.com/getInventory",
"required": false,
"type": "hidden",
"showTargetInApp": false,
"showTargetInPlugin": false,
"value": "https://d8dns0.laf.dev/appointment-lab",
"connected": false,
"selectedTypeIndex": 0
},
{
"key": "system_httpHeader",
"renderTypeList": [
"custom"
],
"valueType": "any",
"value": [],
"label": "",
"description": "core.module.input.description.Http Request Header",
"placeholder": "core.module.input.description.Http Request Header",
"required": false,
"type": "custom",
"showTargetInApp": false,
"showTargetInPlugin": false,
"connected": false,
"selectedTypeIndex": 0
},
{
"key": "system_httpParams",
"renderTypeList": [
"hidden"
],
"valueType": "any",
"value": [],
"label": "",
"required": false,
"type": "hidden",
"showTargetInApp": false,
"showTargetInPlugin": false,
"connected": false,
"selectedTypeIndex": 0
},
{
"key": "system_httpJsonBody",
"renderTypeList": [
"hidden"
],
"valueType": "any",
"value": "{\r\n \"name\": \"{{name}}\",\r\n \"time\": \"{{time}}\",\r\n \"labname\": \"{{labname}}\",\r\n \"action\": \"{{action}}\"\r\n}",
"label": "",
"required": false,
"type": "hidden",
"showTargetInApp": false,
"showTargetInPlugin": false,
"connected": false,
"selectedTypeIndex": 0
},
{
"key": "system_addInputParam",
"renderTypeList": [
"addInputParam"
],
"valueType": "dynamic",
"label": "",
"required": false,
"description": "core.module.input.description.HTTP Dynamic Input",
"editField": {
"key": true,
"valueType": true
}
}
],
"outputs": [
{
"id": "system_addOutputParam",
"type": "dynamic",
"key": "system_addOutputParam",
"valueType": "dynamic",
"label": "",
"editField": {
"key": true,
"valueType": true
}
},
{
"id": "result",
"type": "static",
"key": "result",
"valueType": "string",
"label": "result",
"description": "result",
"canEdit": true,
"editField": {
"key": true,
"name": true,
"description": true,
"dataType": true
}
},
{
"id": "httpRawResponse",
"type": "static",
"key": "httpRawResponse",
"valueType": "any",
"label": "原始响应",
"description": "HTTP请求的原始响应。只能接受字符串或JSON类型响应数据。"
}
]
},
{
"nodeId": "fYxwWym8flYL",
"name": "工具调用",
"intro": "通过AI模型自动选择一个或多个功能块进行调用,也可以对插件进行调用。",
"avatar": "/imgs/workflow/tool.svg",
"flowNodeType": "tools",
"showStatus": true,
"position": {
"x": 933.9342354248961,
"y": 1229.3563445150553
},
"inputs": [
{
"key": "model",
"renderTypeList": [
"settingLLMModel",
"reference"
],
"label": "core.module.input.label.aiModel",
"valueType": "string",
"llmModelType": "all",
"value": "gpt-3.5-turbo"
},
{
"key": "temperature",
"renderTypeList": [
"hidden"
],
"label": "",
"value": 0,
"valueType": "number",
"min": 0,
"max": 10,
"step": 1
},
{
"key": "maxToken",
"renderTypeList": [
"hidden"
],
"label": "",
"value": 2000,
"valueType": "number",
"min": 100,
"max": 4000,
"step": 50
},
{
"key": "systemPrompt",
"renderTypeList": [
"textarea",
"reference"
],
"max": 3000,
"valueType": "string",
"label": "core.ai.Prompt",
"description": "core.app.tip.chatNodeSystemPromptTip",
"placeholder": "core.app.tip.chatNodeSystemPromptTip",
"value": "当前时间为: {{cTime}}\n你是实验室助手,用户可能会询问实验室相关介绍或预约实验室。\n请选择合适的工具去帮助他们。"
},
{
"key": "history",
"renderTypeList": [
"numberInput",
"reference"
],
"valueType": "chatHistory",
"label": "core.module.input.label.chat history",
"required": true,
"min": 0,
"max": 30,
"value": 6
},
{
"key": "userChatInput",
"renderTypeList": [
"reference",
"textarea"
],
"valueType": "string",
"label": "用户问题",
"required": true,
"value": [
"userChatInput",
"userChatInput"
]
}
],
"outputs": []
},
{
"nodeId": "JSSQtDgwmmbE",
"name": "知识库搜索",
"intro": "调用“语义检索”和“全文检索”能力,从“知识库”中查找实验室介绍和使用规则等信息。",
"avatar": "/imgs/workflow/db.png",
"flowNodeType": "datasetSearchNode",
"showStatus": true,
"position": {
"x": 447.0795498711184,
"y": 1971.5311041711186
},
"inputs": [
{
"key": "datasets",
"renderTypeList": [
"selectDataset",
"reference"
],
"label": "core.module.input.label.Select dataset",
"value": [],
"valueType": "selectDataset",
"list": [],
"required": true
},
{
"key": "similarity",
"renderTypeList": [
"selectDatasetParamsModal"
],
"label": "",
"value": 0.4,
"valueType": "number"
},
{
"key": "limit",
"renderTypeList": [
"hidden"
],
"label": "",
"value": 1500,
"valueType": "number"
},
{
"key": "searchMode",
"renderTypeList": [
"hidden"
],
"label": "",
"valueType": "string",
"value": "embedding"
},
{
"key": "usingReRank",
"renderTypeList": [
"hidden"
],
"label": "",
"valueType": "boolean",
"value": false
},
{
"key": "datasetSearchUsingExtensionQuery",
"renderTypeList": [
"hidden"
],
"label": "",
"valueType": "boolean",
"value": false
},
{
"key": "datasetSearchExtensionModel",
"renderTypeList": [
"hidden"
],
"label": "",
"valueType": "string",
"value": "gpt-3.5-turbo"
},
{
"key": "datasetSearchExtensionBg",
"renderTypeList": [
"hidden"
],
"label": "",
"valueType": "string",
"value": ""
},
{
"key": "userChatInput",
"renderTypeList": [
"reference",
"textarea"
],
"valueType": "string",
"label": "用户问题",
"required": true,
"toolDescription": "需要检索的内容"
}
],
"outputs": [
{
"id": "quoteQA",
"key": "quoteQA",
"label": "core.module.Dataset quote.label",
"description": "特殊数组格式,搜索结果为空时,返回空数组。",
"type": "static",
"valueType": "datasetQuote"
}
]
},
{
"nodeId": "IdntVQiTopHT",
"name": "工具调用终止",
"intro": "该模块需配置工具调用使用。当该模块被执行时,本次工具调用将会强制结束,并且不再调用AI针对工具调用结果回答问题。",
"avatar": "/imgs/workflow/toolStop.svg",
"flowNodeType": "stopTool",
"position": {
"x": 1969.73331750207,
"y": 2650.0258908119413
},
"inputs": [],
"outputs": []
}
],
"edges": [
{
"source": "40clf3",
"target": "eg5upi",
"sourceHandle": "40clf3-source-right",
"targetHandle": "eg5upi-target-left"
},
{
"source": "userChatInput",
"target": "fYxwWym8flYL",
"sourceHandle": "userChatInput-source-right",
"targetHandle": "fYxwWym8flYL-target-left"
},
{
"source": "fYxwWym8flYL",
"target": "40clf3",
"sourceHandle": "selectedTools",
"targetHandle": "selectedTools"
},
{
"source": "fYxwWym8flYL",
"target": "JSSQtDgwmmbE",
"sourceHandle": "selectedTools",
"targetHandle": "selectedTools"
},
{
"source": "40clf3",
"target": "IdntVQiTopHT",
"sourceHandle": "40clf3-source-right",
"targetHandle": "IdntVQiTopHT-target-left"
}
]
}
{{% /details %}}
Laf 云函数代码
可以在 Laf 中快速构建 HTTP 接口。
{{% details title="函数代码" closed="true" %}}
import cloud from '@lafjs/cloud'
const db = cloud.database()
type RequestType = {
name: string;
time?: string;
labname?: string;
action: 'post' | 'delete' | 'put' | 'get'
}
export default async function (ctx: FunctionContext) {
try {
const { action,...body } = ctx.body as RequestType
if (action === 'get') {
return await getRecord(ctx.body)
}
if (action === 'post') {
return await createRecord(ctx.body)
}
if (action === 'put') {
return await putRecord(ctx.body)
}
if (action === 'delete') {
return await removeRecord(ctx.body)
}
return {
result: "异常"
}
} catch (err) {
return {
result: "异常"
}
}
}
async function putRecord({ name, time, labname }: RequestType) {
const missData = []
if (!name) missData.push("你的姓名")
if (missData.length > 0) {
return {
result: `请提供: ${missData.join("、")}`
}
}
const { data: record } = await db.collection("LabAppointment").where({
name, status: "unStart"
}).getOne()
if (!record) {
return {
result: `${name} 还没有预约记录`
}
}
const updateWhere = {
name,
time: time || record.time,
labname: labname || record.labname
}
await db.collection("LabAppointment").where({
name, status: "unStart"
}).update(updateWhere)
return {
result: `修改预约成功。
姓名:${name}·
时间: ${updateWhere.time}
实验室名: ${updateWhere.labname}
` }
}
async function getRecord({ name }: RequestType) {
if (!name) {
return {
result: "请提供你的姓名"
}
}
const { data } = await db.collection('LabAppointment').where({ name, status: "unStart" }).getOne()
if (!data) {
return {
result: `${name} 没有预约中的记录`
}
}
return {
result: `${name} 有一条预约记录:
姓名:${data.name}
时间: ${data.time}
实验室名: ${data.labname}
`
}
}
async function removeRecord({ name }: RequestType) {
if (!name) {
return {
result: "请提供你的姓名"
}
}
const { deleted } = await db.collection('LabAppointment').where({ name, status: "unStart" }).remove()
if (deleted > 0) {
return {
result: `取消预约记录成功: ${name}`
}
}
return {
result: ` ${name} 没有预约中的记录`
}
}
async function createRecord({ name, time, labname }: RequestType) {
const missData = []
if (!name) missData.push("你的姓名")
if (!time) missData.push("需要预约的时间")
if (!labname) missData.push("实验室名名称")
if (missData.length > 0) {
return {
result: `请提供: ${missData.join("、")}`
}
}
const { data: record } = await db.collection("LabAppointment").where({
name, status: "unStart"
}).getOne()
if (record) {
return {
result: `您已经有一个预约记录了:
姓名:${record.name}
时间: ${record.time}
实验室名: ${record.labname}
每人仅能同时预约一个实验室名。
`
}
}
await db.collection("LabAppointment").add({
name, time, labname, status: "unStart"
})
return {
result: `预约成功。
姓名:${name}
时间: ${time}
实验室名: ${labname}
` }
}
{{% /details %}}