diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/404.html b/404.html new file mode 100644 index 000000000000..c87440a2eb5f --- /dev/null +++ b/404.html @@ -0,0 +1,5 @@ +
FastGPT 开源许可证
FastGPT 项目在 Apache License 2.0 许可下开源,同时包含以下附加条件:
FastGPT 允许被用于商业化,例如作为其他应用的“后端即服务”使用,或者作为应用开发平台提供给企业。然而,当满足以下条件时,必须联系作者获得商业许可:
请通过电子邮件 yujinlong@sealos.io 联系我们咨询许可事宜。
作为贡献者,你必须同意将你贡献的代码用于以下用途:
除此之外,所有其他权利和限制均遵循 Apache License 2.0。如果你需要更多详细信息,可以参考 Apache License 2.0 的完整版本。本产品的交互设计受到外观专利保护。© 2023 Sealos.
FastGPT 隐私政策
最后更新时间:2024年3月3日
我们非常重视您的隐私保护,在您使用FastGPT云服务时(以下简称为“本服务”),我们将按照以下政策收集、使用、披露和保护您的个人信息。请您仔细阅读并充分理解本隐私政策。
我们可能需要收集的信息
我们如何使用收集的信息?
信息披露
我们不会向任何第三方披露您的个人信息,除非:
我们可能与关联公司、合作伙伴分享您的个人信息,但我们会采取相应的保密措施,确保信息安全。
信息保护
用户权利
隐私政策更新
未成年人保护
我们非常重视对未成年人个人信息的保护,如您为未成年人,请在监护人指导下使用本服务,并请监护人帮助您在使用本服务过程中正确处理个人信息。
跨境数据传输
由于我们的服务器可能位于不同国家或地区,您同意我们可能需要将您的个人信息传输至其他国家或地区,并在该等国家或地区存储和处理以向您提供服务。我们会采取适当措施确保跨境传输的数据仍然受到适当保护。
联系我们
FastGPT 服务协议
最后更新时间:2024年3月3日
FastGPT 服务协议是您与珠海环界云计算有限公司(以下简称“我们”或“本公司”)之间就FastGPT云服务(以下简称“本服务”)的使用等相关事项所订立的协议。请您仔细阅读并充分理解本协议各条款,特别是免除或者限制我们责任的条款、对您权益的限制条款、争议解决和法律适用条款等。如您不同意本协议任一内容,请勿注册或使用本服务。
第1条 服务内容
第2条 用户注册与账户管理
第3条 使用规则
第4条 费用及支付
第5条 服务免责与责任限制
第6条 知识产权
第7条 其他条款
加入 FastGPT 开发者社区和我们一起成长
FastGPT 是一个由用户和贡献者参与推动的开源项目,如果您对产品使用存在疑问和建议,可尝试以下方式寻求支持。我们的团队与社区会竭尽所能为您提供帮助。
📱 扫码加入社区微信交流群👇
🐞 请将任何 FastGPT 的 Bug、问题和需求提交到 GitHub Issue。
FastGPT 配置参数介绍
由于环境变量不利于配置复杂的内容,新版 FastGPT 采用了 ConfigMap 的形式挂载配置文件,你可以在 projects/app/data/config.json
看到默认的配置文件。可以参考 docker-compose 快速部署 来挂载配置文件。
开发环境下,你需要将示例配置文件 config.json
复制成 config.local.json
文件才会生效。
这个配置文件中包含了系统参数和各个模型配置:
+ {
+ "feConfigs": {
+ "lafEnv": "https://laf.dev" // laf环境。 https://laf.run (杭州阿里云) ,或者私有化的laf环境。如果使用 Laf openapi 功能,需要最新版的 laf 。
+ },
+ "systemEnv": {
+ "vectorMaxProcess": 15, // 向量处理线程数量
+ "qaMaxProcess": 15, // 问答拆分线程数量
+ "tokenWorkers": 50, // Token 计算线程保持数,会持续占用内存,不能设置太大。
+ "pgHNSWEfSearch": 100 // 向量搜索参数。越大,搜索越精确,但是速度越慢。设置为100,有99%+精度。
+ },
+ "llmModels": [
+ {
+ "provider": "OpenAI", // 模型提供商,主要用于分类展示,目前已经内置提供商包括:https://github.com/labring/FastGPT/blob/main/packages/global/core/ai/provider.ts, 可 pr 提供新的提供商,或直接填写 Other
+ "model": "gpt-4o-mini", // 模型名(对应OneAPI中渠道的模型名)
+ "name": "gpt-4o-mini", // 模型别名
+ "maxContext": 125000, // 最大上下文
+ "maxResponse": 16000, // 最大回复
+ "quoteMaxToken": 120000, // 最大引用内容
+ "maxTemperature": 1.2, // 最大温度
+ "charsPointsPrice": 0, // n积分/1k token(商业版)
+ "censor": false, // 是否开启敏感校验(商业版)
+ "vision": true, // 是否支持图片输入
+ "datasetProcess": true, // 是否设置为文本理解模型(QA),务必保证至少有一个为true,否则知识库会报错
+ "usedInClassify": true, // 是否用于问题分类(务必保证至少有一个为true)
+ "usedInExtractFields": true, // 是否用于内容提取(务必保证至少有一个为true)
+ "usedInToolCall": true, // 是否用于工具调用(务必保证至少有一个为true)
+ "usedInQueryExtension": true, // 是否用于问题优化(务必保证至少有一个为true)
+ "toolChoice": true, // 是否支持工具选择(分类,内容提取,工具调用会用到。)
+ "functionCall": false, // 是否支持函数调用(分类,内容提取,工具调用会用到。会优先使用 toolChoice,如果为false,则使用 functionCall,如果仍为 false,则使用提示词模式)
+ "customCQPrompt": "", // 自定义文本分类提示词(不支持工具和函数调用的模型
+ "customExtractPrompt": "", // 自定义内容提取提示词
+ "defaultSystemChatPrompt": "", // 对话默认携带的系统提示词
+ "defaultConfig": {}, // 请求API时,挟带一些默认配置(比如 GLM4 的 top_p)
+ "fieldMap": {} // 字段映射(o1 模型需要把 max_tokens 映射为 max_completion_tokens)
+ },
+ {
+ "provider": "OpenAI",
+ "model": "gpt-4o",
+ "name": "gpt-4o",
+ "maxContext": 125000,
+ "maxResponse": 4000,
+ "quoteMaxToken": 120000,
+ "maxTemperature": 1.2,
+ "charsPointsPrice": 0,
+ "censor": false,
+ "vision": true,
+ "datasetProcess": true,
+ "usedInClassify": true,
+ "usedInExtractFields": true,
+ "usedInToolCall": true,
+ "usedInQueryExtension": true,
+ "toolChoice": true,
+ "functionCall": false,
+ "customCQPrompt": "",
+ "customExtractPrompt": "",
+ "defaultSystemChatPrompt": "",
+ "defaultConfig": {},
+ "fieldMap": {}
+ },
+ {
+ "provider": "OpenAI",
+ "model": "o1-mini",
+ "name": "o1-mini",
+ "maxContext": 125000,
+ "maxResponse": 65000,
+ "quoteMaxToken": 120000,
+ "maxTemperature": 1.2,
+ "charsPointsPrice": 0,
+ "censor": false,
+ "vision": false,
+ "datasetProcess": true,
+ "usedInClassify": true,
+ "usedInExtractFields": true,
+ "usedInToolCall": true,
+ "usedInQueryExtension": true,
+ "toolChoice": false,
+ "functionCall": false,
+ "customCQPrompt": "",
+ "customExtractPrompt": "",
+ "defaultSystemChatPrompt": "",
+ "defaultConfig": {
+ "temperature": 1,
+ "max_tokens": null,
+ "stream": false
+ }
+ },
+ {
+ "provider": "OpenAI",
+ "model": "o1-preview",
+ "name": "o1-preview",
+ "maxContext": 125000,
+ "maxResponse": 32000,
+ "quoteMaxToken": 120000,
+ "maxTemperature": 1.2,
+ "charsPointsPrice": 0,
+ "censor": false,
+ "vision": false,
+ "datasetProcess": true,
+ "usedInClassify": true,
+ "usedInExtractFields": true,
+ "usedInToolCall": true,
+ "usedInQueryExtension": true,
+ "toolChoice": false,
+ "functionCall": false,
+ "customCQPrompt": "",
+ "customExtractPrompt": "",
+ "defaultSystemChatPrompt": "",
+ "defaultConfig": {
+ "temperature": 1,
+ "max_tokens": null,
+ "stream": false
+ }
+ }
+ ],
+ "vectorModels": [
+ {
+ "provider": "OpenAI",
+ "model": "text-embedding-3-small",
+ "name": "text-embedding-3-small",
+ "charsPointsPrice": 0,
+ "defaultToken": 512,
+ "maxToken": 3000,
+ "weight": 100
+ },
+ {
+ "provider": "OpenAI",
+ "model": "text-embedding-3-large",
+ "name": "text-embedding-3-large",
+ "charsPointsPrice": 0,
+ "defaultToken": 512,
+ "maxToken": 3000,
+ "weight": 100,
+ "defaultConfig": {
+ "dimensions": 1024
+ }
+ },
+ {
+ "provider": "OpenAI",
+ "model": "text-embedding-ada-002", // 模型名(与OneAPI对应)
+ "name": "Embedding-2", // 模型展示名
+ "charsPointsPrice": 0, // n积分/1k token
+ "defaultToken": 700, // 默认文本分割时候的 token
+ "maxToken": 3000, // 最大 token
+ "weight": 100, // 优先训练权重
+ "defaultConfig": {}, // 自定义额外参数。例如,如果希望使用 embedding3-large 的话,可以传入 dimensions:1024,来返回1024维度的向量。(目前必须小于1536维度)
+ "dbConfig": {}, // 存储时的额外参数(非对称向量模型时候需要用到)
+ "queryConfig": {} // 参训时的额外参数
+ }
+ ],
+ "reRankModels": [],
+ "audioSpeechModels": [
+ {
+ "provider": "OpenAI",
+ "model": "tts-1",
+ "name": "OpenAI TTS1",
+ "charsPointsPrice": 0,
+ "voices": [
+ { "label": "Alloy", "value": "alloy", "bufferId": "openai-Alloy" },
+ { "label": "Echo", "value": "echo", "bufferId": "openai-Echo" },
+ { "label": "Fable", "value": "fable", "bufferId": "openai-Fable" },
+ { "label": "Onyx", "value": "onyx", "bufferId": "openai-Onyx" },
+ { "label": "Nova", "value": "nova", "bufferId": "openai-Nova" },
+ { "label": "Shimmer", "value": "shimmer", "bufferId": "openai-Shimmer" }
+ ]
+ }
+ ],
+ "whisperModel": {
+ "provider": "OpenAI",
+ "model": "whisper-1",
+ "name": "Whisper1",
+ "charsPointsPrice": 0
+ }
+}
+
为了方便模型分类展示,FastGPT 内置了部分模型提供商的名字和 Logo。如果你期望补充提供商,可提交 Issue,并提供几个信息:
目前已支持的提供商, 复制 “-” 之前的字符串,作为 provider 的值。
由于 OneAPI 不支持 Rerank 模型,所以需要单独配置接入,这里
有免费的 bge-reranker-v2-m3
模型可以使用。
+ {
+ "reRankModels": [
+ {
+ "model": "BAAI/bge-reranker-v2-m3", // 这里的model需要对应 siliconflow 的模型名
+ "name": "BAAI/bge-reranker-v2-m3",
+ "requestUrl": "https://api.siliconflow.cn/v1/rerank",
+ "requestAuth": "siliconflow 上申请的 key"
+ }
+ ]
+}
+
请使用 4.6.6-alpha 以上版本,配置文件中的 reRankModels
为重排模型,虽然是数组,不过目前仅有第1个生效。
reRankModels
, 4.6.6 以前是 ReRankModels
。
+ {
+ "reRankModels": [
+ {
+ "model": "bge-reranker-base", // 随意
+ "name": "检索重排-base", // 随意
+ "charsPointsPrice": 0,
+ "requestUrl": "{{host}}/v1/rerank",
+ "requestAuth": "安全凭证,已自动补 Bearer"
+ }
+ ]
+}
+
接入 bge-rerank 重排模型
推荐配置如下:
模型名 | 内存 | 显存 | 硬盘空间 | 启动命令 |
---|---|---|---|---|
bge-reranker-base | >=4GB | >=4GB | >=8GB | python app.py |
bge-reranker-large | >=8GB | >=8GB | >=8GB | python app.py |
bge-reranker-v2-m3 | >=8GB | >=8GB | >=8GB | python app.py |
3 个模型代码分别为:
+ pip install -r requirements.txt
+
3个模型的 huggingface 仓库地址如下:
在对应代码目录下 clone 模型。目录结构:
+ bge-reranker-base/
+app.py
+Dockerfile
+requirements.txt
+
+ python app.py
+
启动成功后应该会显示如下地址:
这里的
http://0.0.0.0:6006
就是连接地址。
镜像名分别为:
端口
6006
环境变量
+ ACCESS_TOKEN=访问安全凭证,请求时,Authorization: Bearer ${ACCESS_TOKEN}
+
运行命令示例
+ # auth token 为mytoken
+docker run -d --name reranker -p 6006:6006 -e ACCESS_TOKEN=mytoken --gpus all registry.cn-hangzhou.aliyuncs.com/fastgpt/bge-rerank-base:v0.1
+
docker-compose.yml示例
+ version: "3"
+services:
+ reranker:
+ image: registry.cn-hangzhou.aliyuncs.com/fastgpt/bge-rerank-base:v0.1
+ container_name: reranker
+ # GPU运行环境,如果宿主机未安装,将deploy配置隐藏即可
+ deploy:
+ resources:
+ reservations:
+ devices:
+ - driver: nvidia
+ count: all
+ capabilities: [gpu]
+ ports:
+ - 6006:6006
+ environment:
+ - ACCESS_TOKEN=mytoken
+
参考 ReRank模型接入,host 变量为部署的域名。
Bus error (core dumped)
尝试增加 docker-compose.yml
配置项 shm_size
,以增加容器中的共享内存目录大小。
+ ...
+services:
+ reranker:
+ ...
+ container_name: reranker
+ shm_size: '2gb'
+ ...
+
将 FastGPT 接入私有化模型 ChatGLM2和m3e-large
FastGPT 默认使用了 OpenAI 的 LLM 模型和向量模型,如果想要私有化部署的话,可以使用 ChatGLM2 和 m3e-large 模型。以下是由用户@不做了睡大觉 提供的接入方法。该镜像直接集成了 M3E-Large 和 ChatGLM2-6B 模型,可以直接使用。
stawky/chatglm2-m3e:latest
registry.cn-hangzhou.aliyuncs.com/fastgpt_docker/chatglm2-m3e:latest
+ # 设置安全凭证(即oneapi中的渠道密钥)
+默认值:sk-aaabbbcccdddeeefffggghhhiiijjjkkk
+也可以通过环境变量引入:sk-key。有关docker环境变量引入的方法请自寻教程,此处不再赘述。
+
为 chatglm2 和 m3e-large 各添加一个渠道,参数如下:
这里我填入 m3e 作为向量模型,chatglm2 作为语言模型
curl 例子:
+ curl --location --request POST 'https://domain/v1/embeddings' \
+--header 'Authorization: Bearer sk-aaabbbcccdddeeefffggghhhiiijjjkkk' \
+--header 'Content-Type: application/json' \
+--data-raw '{
+ "model": "m3e",
+ "input": ["laf是什么"]
+}'
+
+ curl --location --request POST 'https://domain/v1/chat/completions' \
+--header 'Authorization: Bearer sk-aaabbbcccdddeeefffggghhhiiijjjkkk' \
+--header 'Content-Type: application/json' \
+--data-raw '{
+ "model": "chatglm2",
+ "messages": [{"role": "user", "content": "Hello!"}]
+}'
+
Authorization 为 sk-aaabbbcccdddeeefffggghhhiiijjjkkk。model 为刚刚在 One API 填写的自定义模型。
修改 config.json 配置文件,在 llmModels 中加入 chatglm2, 在 vectorModels 中加入 M3E 模型:
+ "llmModels": [
+ //其他对话模型
+ {
+ "model": "chatglm2",
+ "name": "chatglm2",
+ "maxToken": 8000,
+ "price": 0,
+ "quoteMaxToken": 4000,
+ "maxTemperature": 1.2,
+ "defaultSystemChatPrompt": ""
+ }
+],
+"vectorModels": [
+ {
+ "model": "text-embedding-ada-002",
+ "name": "Embedding-2",
+ "price": 0.2,
+ "defaultToken": 500,
+ "maxToken": 3000
+ },
+ {
+ "model": "m3e",
+ "name": "M3E(测试使用)",
+ "price": 0.1,
+ "defaultToken": 500,
+ "maxToken": 1800
+ }
+],
+
M3E 模型的使用方法如下:
创建知识库时候选择 M3E 模型。
注意,一旦选择后,知识库将无法修改向量模型。
导入数据
搜索测试
应用绑定知识库
注意,应用只能绑定同一个向量模型的知识库,不能跨模型绑定。并且,需要注意调整相似度,不同向量模型的相似度(距离)会有所区别,需要自行测试实验。
chatglm2 模型的使用方法如下: +模型选择 chatglm2 即可
将 FastGPT 接入私有化模型 ChatGLM2-6B
FastGPT 允许你使用自己的 OpenAI API KEY 来快速调用 OpenAI 接口,目前集成了 GPT-3.5, GPT-4 和 embedding,可构建自己的知识库。但考虑到数据安全的问题,我们并不能将所有的数据都交付给云端大模型。
那么如何在 FastGPT 上接入私有化模型呢?本文就以清华的 ChatGLM2 为例,为各位讲解如何在 FastGPT 中接入私有化模型。
ChatGLM2-6B 是开源中英双语对话模型 ChatGLM-6B 的第二代版本,具体介绍可参阅 ChatGLM2-6B 项目主页。
注意,ChatGLM2-6B 权重对学术研究完全开放,在获得官方的书面许可后,亦允许商业使用。本教程只是介绍了一种用法,无权给予任何授权!
依据官方数据,同样是生成 8192 长度,量化等级为 FP16 要占用 12.8GB 显存、int8 为 8.1GB 显存、int4 为 5.1GB 显存,量化后会稍微影响性能,但不多。
因此推荐配置如下:
类型 | 内存 | 显存 | 硬盘空间 | 启动命令 |
---|---|---|---|---|
fp16 | >=16GB | >=16GB | >=25GB | python openai_api.py 16 |
int8 | >=16GB | >=9GB | >=25GB | python openai_api.py 8 |
int4 | >=16GB | >=6GB | >=25GB | python openai_api.py 4 |
pip install -r requirements.txt
;verify_token
方法中配置 token,这里的 token 只是加一层验证,防止接口被人盗用;python openai_api.py --model_name 16
。这里的数字根据上面的配置进行选择。然后等待模型下载,直到模型加载完毕为止。如果出现报错先问 GPT。
启动成功后应该会显示如下地址:
这里的
http://0.0.0.0:6006
就是连接地址。
镜像和端口
stawky/chatglm2:latest
registry.cn-hangzhou.aliyuncs.com/fastgpt_docker/chatglm2:latest
+ # 设置安全凭证(即oneapi中的渠道密钥)
+默认值:sk-aaabbbcccdddeeefffggghhhiiijjjkkk
+也可以通过环境变量引入:sk-key。有关docker环境变量引入的方法请自寻教程,此处不再赘述。
+
为 chatglm2 添加一个渠道,参数如下:
这里我填入 chatglm2 作为语言模型
curl 例子:
+ curl --location --request POST 'https://domain/v1/chat/completions' \
+--header 'Authorization: Bearer sk-aaabbbcccdddeeefffggghhhiiijjjkkk' \
+--header 'Content-Type: application/json' \
+--data-raw '{
+ "model": "chatglm2",
+ "messages": [{"role": "user", "content": "Hello!"}]
+}'
+
Authorization 为 sk-aaabbbcccdddeeefffggghhhiiijjjkkk。model 为刚刚在 One API 填写的自定义模型。
修改 config.json 配置文件,在 llmModels 中加入 chatglm2 模型:
+ "llmModels": [
+ //已有模型
+ {
+ "model": "chatglm2",
+ "name": "chatglm2",
+ "maxContext": 4000,
+ "maxResponse": 4000,
+ "quoteMaxToken": 2000,
+ "maxTemperature": 1,
+ "vision": false,
+ "defaultSystemChatPrompt": ""
+ }
+]
+
chatglm2 模型的使用方法如下:
模型选择 chatglm2 即可
FastGPT 对接本地模型
将 FastGPT 接入私有化模型 M3E
FastGPT 默认使用了 openai 的 embedding 向量模型,如果你想私有部署的话,可以使用 M3E 向量模型进行替换。M3E 向量模型属于小模型,资源使用不高,CPU 也可以运行。下面教程是基于 “睡大觉” 同学提供的一个的镜像。
镜像名: stawky/m3e-large-api:latest
国内镜像: registry.cn-hangzhou.aliyuncs.com/fastgpt_docker/m3e-large-api:latest
+端口号: 6008
+环境变量:
+ # 设置安全凭证(即oneapi中的渠道密钥)
+默认值:sk-aaabbbcccdddeeefffggghhhiiijjjkkk
+也可以通过环境变量引入:sk-key。有关docker环境变量引入的方法请自寻教程,此处不再赘述。
+
添加一个渠道,参数如下:
curl 例子:
+ curl --location --request POST 'https://domain/v1/embeddings' \
+--header 'Authorization: Bearer xxxx' \
+--header 'Content-Type: application/json' \
+--data-raw '{
+ "model": "m3e",
+ "input": ["laf是什么"]
+}'
+
Authorization 为 sk-key。model 为刚刚在 One API 填写的自定义模型。
修改 config.json 配置文件,在 vectorModels 中加入 M3E 模型:
+ "vectorModels": [
+ {
+ "model": "text-embedding-ada-002",
+ "name": "Embedding-2",
+ "price": 0.2,
+ "defaultToken": 500,
+ "maxToken": 3000
+ },
+ {
+ "model": "m3e",
+ "name": "M3E(测试使用)",
+ "price": 0.1,
+ "defaultToken": 500,
+ "maxToken": 1800
+ }
+]
+
创建知识库时候选择 M3E 模型。
注意,一旦选择后,知识库将无法修改向量模型。
导入数据
搜索测试
应用绑定知识库
注意,应用只能绑定同一个向量模型的知识库,不能跨模型绑定。并且,需要注意调整相似度,不同向量模型的相似度(距离)会有所区别,需要自行测试实验。
使用 Marker 解析 PDF 文档,可实现图片提取和布局识别
PDF 是一个相对复杂的文件格式,在 FastGPT 内置的 pdf 解析器中,依赖的是 pdfjs 库解析,该库基于逻辑解析,无法有效的理解复杂的 pdf 文件。所以我们在解析 pdf 时候,如果遇到图片、表格、公式等非简单文本内容,会发现解析效果不佳。
市面上目前有多种解析 PDF 的方法,比如使用 Marker,该项目使用了 Surya 模型,基于视觉解析,可以有效提取图片、表格、公式等复杂内容。为了可以让 Marker 快速接入 FastGPT,我们做了一个自定义解析的拓展 Demo。
在 FastGPT 4.8.15 版本中,你可以通过增加一个环境变量,来替换掉 FastGPT 系统内置解析器,实现自定义的文档解析服务。该功能只是 Demo 阶段,后期配置模式和交互规则会发生改动。
参考文档 Marker 安装教程,安装 Marker 模型。封装的 API 已经适配了 FastGPT 自定义解析服务。
这里介绍快速 Docker 安装的方法:
+ docker pull crpi-h3snc261q1dosroc.cn-hangzhou.personal.cr.aliyuncs.com/marker11/marker_images:latest
+docker run --gpus all -itd -p 7231:7231 --name model_pdf_v1 crpi-h3snc261q1dosroc.cn-hangzhou.personal.cr.aliyuncs.com/marker11/marker_images:latest
+
+ CUSTOM_READ_FILE_URL=http://xxxx.com/v1/parse/file
+CUSTOM_READ_FILE_EXTENSION=pdf
+
通过知识库上传一个 pdf 文件,并确认上传,可以在日志中看到 LOG (LOG_LEVEL需要设置 info 或者 debug):
+ [Info] 2024-12-05 15:04:42 Parsing files from an external service
+[Info] 2024-12-05 15:07:08 Custom file parsing is complete, time: 1316ms
+
然后你就可以发现,通过 Marker 解析出来的 pdf 会携带图片链接:
以清华的 ChatDev Communicative Agents for Software Develop.pdf 为例,展示 Marker 解析的效果:
上图是分块后的结果,下图是 pdf 原文。整体图片、公式、表格都可以提取出来,效果还是杠杠的。
不过要注意的是,Marker 的协议是GPL-3.0 license
,请在遵守协议的前提下使用。
一站式本地 LLM 私有化部署
Xinference 是一款开源模型推理平台,除了支持 LLM,它还可以部署 Embedding 和 ReRank 模型,这在企业级 RAG 构建中非常关键。同时,Xinference 还提供 Function Calling 等高级功能。还支持分布式部署,也就是说,随着未来应用调用量的增长,它可以进行水平扩展。
Xinference 支持多种推理引擎作为后端,以满足不同场景下部署大模型的需要,下面会分使用场景来介绍一下这三种推理后端,以及他们的使用方法。
如果你的目标是在一台 Linux 或者 Window 服务器上部署大模型,可以选择 Transformers 或 vLLM 作为 Xinference 的推理后端:
假设你服务器配备 NVIDIA 显卡,可以参考这篇文章中的指令来安装 CUDA,从而让 Xinference 最大限度地利用显卡的加速功能。
你可以使用 Xinference 官方的 Docker 镜像来一键安装和启动 Xinference 服务(确保你的机器上已经安装了 Docker),命令如下:
+ docker run -p 9997:9997 --gpus all xprobe/xinference:latest xinference-local -H 0.0.0.0
+
首先我们需要准备一个 3.9 以上的 Python 环境运行来 Xinference,建议先根据 conda 官网文档安装 conda。 然后使用以下命令来创建 3.11 的 Python 环境:
+ conda create --name py311 python=3.11
+conda activate py311
+
以下两条命令在安装 Xinference 时,将安装 Transformers 和 vLLM 作为 Xinference 的推理引擎后端:
+ pip install "xinference[transformers]"
+pip install "xinference[vllm]"
+pip install "xinference[transformers,vllm]" # 同时安装
+
PyPi 在 安装 Transformers 和 vLLM 时会自动安装 PyTorch,但自动安装的 CUDA 版本可能与你的环境不匹配,此时你可以根据 PyTorch 官网中的安装指南来手动安装。
只需要输入如下命令,就可以在服务上启动 Xinference 服务:
+ xinference-local -H 0.0.0.0
+
Xinference 默认会在本地启动服务,端口默认为 9997。因为这里配置了-H 0.0.0.0参数,非本地客户端也可以通过机器的 IP 地址来访问 Xinference 服务。
如果你想在自己的 Macbook 或者个人电脑上部署大模型,推荐安装 CTransformers 作为 Xinference 的推理后端。CTransformers 是用 GGML 实现的 C++ 版本 Transformers。
GGML 是一个能让大语言模型在消费级硬件上运行的 C++ 库。 GGML 最大的特色在于模型量化。量化一个大语言模型其实就是降低权重表示精度的过程,从而减少使用模型所需的资源。 例如,表示一个高精度浮点数(例如 0.0001)比表示一个低精度浮点数(例如 0.1)需要更多空间。由于 LLM 在推理时需要加载到内存中的,因此你需要花费硬盘空间来存储它们,并且在执行期间有足够大的 RAM 来加载它们,GGML 支持许多不同的量化策略,每种策略在效率和性能之间提供不同的权衡。
通过以下命令来安装 CTransformers 作为 Xinference 的推理后端:
+ pip install xinference
+pip install ctransformers
+
因为 GGML 是一个 C++ 库,Xinference 通过 llama-cpp-python
这个库来实现语言绑定。对于不同的硬件平台,我们需要使用不同的编译参数来安装:
CMAKE_ARGS="-DLLAMA_METAL=on" pip install llama-cpp-python
CMAKE_ARGS="-DLLAMA_CUBLAS=on" pip install llama-cpp-python
CMAKE_ARGS="-DLLAMA_HIPBLAS=on" pip install llama-cpp-python
安装后只需要输入 xinference-local
,就可以在你的 Mac 上启动 Xinference 服务。
Xinference 启动之后,在浏览器中输入: http://127.0.0.1:9997
,我们可以访问到本地 Xinference 的 Web UI。
打开“Launch Model”标签,搜索到 qwen-chat,选择模型启动的相关参数,然后点击模型卡片左下方的小火箭🚀按钮,就可以部署该模型到 Xinference。 默认 Model UID 是 qwen-chat(后续通过将通过这个 ID 来访问模型)。
当你第一次启动 Qwen 模型时,Xinference 会从 HuggingFace 下载模型参数,大概需要几分钟的时间。Xinference 将模型文件缓存在本地,这样之后启动时就不需要重新下载了。 Xinference 还支持从其他模型站点下载模型文件,例如 modelscope。
我们也可以使用 Xinference 的命令行工具来启动模型,默认 Model UID 是 qwen-chat(后续通过将通过这个 ID 来访问模型)。
+ xinference launch -n qwen-chat -s 14 -f pytorch
+
除了 WebUI 和命令行工具, Xinference 还提供了 Python SDK 和 RESTful API 等多种交互方式, 更多用法可以参考 Xinference 官方文档。
One API 的部署和接入请参考这里。
为 qwen1.5-chat 添加一个渠道,这里的 Base URL 需要填 Xinference 服务的端点,并且注册 qwen-chat (模型的 UID) 。
可以使用以下命令进行测试:
+ curl --location --request POST 'https://<oneapi_url>/v1/chat/completions' \
+--header 'Authorization: Bearer <oneapi_token>' \
+--header 'Content-Type: application/json' \
+--data-raw '{
+ "model": "qwen-chat",
+ "messages": [{"role": "user", "content": "Hello!"}]
+}'
+
将 <oneapi_url> 替换为你的 One API 地址,<oneapi_token> 替换为你的 One API 令牌。model 为刚刚在 One API 填写的自定义模型。
修改 FastGPT 的 config.json
配置文件的 llmModels 部分加入 qwen-chat 模型:
+ ...
+ "llmModels": [
+ {
+ "model": "qwen-chat", // 模型名(对应OneAPI中渠道的模型名)
+ "name": "Qwen", // 模型别名
+ "avatar": "/imgs/model/Qwen.svg", // 模型的logo
+ "maxContext": 125000, // 最大上下文
+ "maxResponse": 4000, // 最大回复
+ "quoteMaxToken": 120000, // 最大引用内容
+ "maxTemperature": 1.2, // 最大温度
+ "charsPointsPrice": 0, // n积分/1k token(商业版)
+ "censor": false, // 是否开启敏感校验(商业版)
+ "vision": true, // 是否支持图片输入
+ "datasetProcess": true, // 是否设置为知识库处理模型(QA),务必保证至少有一个为true,否则知识库会报错
+ "usedInClassify": true, // 是否用于问题分类(务必保证至少有一个为true)
+ "usedInExtractFields": true, // 是否用于内容提取(务必保证至少有一个为true)
+ "usedInToolCall": true, // 是否用于工具调用(务必保证至少有一个为true)
+ "usedInQueryExtension": true, // 是否用于问题优化(务必保证至少有一个为true)
+ "toolChoice": true, // 是否支持工具选择(分类,内容提取,工具调用会用到。)
+ "functionCall": false, // 是否支持函数调用(分类,内容提取,工具调用会用到。会优先使用 toolChoice,如果为false,则使用 functionCall,如果仍为 false,则使用提示词模式)
+ "customCQPrompt": "", // 自定义文本分类提示词(不支持工具和函数调用的模型
+ "customExtractPrompt": "", // 自定义内容提取提示词
+ "defaultSystemChatPrompt": "", // 对话默认携带的系统提示词
+ "defaultConfig": {} // 请求API时,挟带一些默认配置(比如 GLM4 的 top_p)
+ }
+ ],
+...
+
然后重启 FastGPT 就可以在应用配置中选择 Qwen 模型进行对话:
FastGPT 数据集中文件与数据的设计方案
在 FastGPT 中,文件会通过 MongoDB 的 FS 存储,而具体的数据会通过 PostgreSQL 存储,PG 中的数据会有一列 file_id,关联对应的文件。考虑到旧版本的兼容,以及手动输入、标注数据等,我们给 file_id 增加了一些特殊的值,如下:
注意,file_id 仅在插入数据时会写入,变更时无法修改。
unused
状态used
,并将数据推送到 mongo training
表中等待训练使用 Docker Compose 快速部署 FastGPT
MongoDB:用于存储除了向量外的各类数据
PostgreSQL/Milvus:存储向量数据
OneAPI: 聚合各类 AI API,支持多模型调用 (任何模型问题,先自行通过 OneAPI 测试校验)
体验测试首选
环境 | 最低配置(单节点) | 推荐配置 |
---|---|---|
测试 | 2c2g | 2c4g |
100w 组向量 | 4c8g 50GB | 4c16g 50GB |
500w 组向量 | 8c32g 200GB | 16c64g 200GB |
生产部署首选,对于千万级以上向量性能更优秀。
环境 | 最低配置(单节点) | 推荐配置 |
---|---|---|
测试 | 2c8g | 4c16g |
100w 组向量 | 未测试 | |
500w 组向量 |
Milvus 的全托管服务,性能优于 Milvus 并提供 SLA,点击使用 Zilliz Cloud。
由于向量库使用了 Cloud,无需占用本地资源,无需太关注。
如果使用OpenAI
等国外模型接口,请确保可以正常访问,否则会报错:Connection error
等。 方案可以参考:代理方案
非 Linux 环境或无法访问外网环境,可手动创建一个目录,并下载配置文件和对应版本的docker-compose.yml
,在这个文件夹中依据下载的配置文件运行docker,若作为本地开发使用推荐docker-compose-pgvector
版本,并且自行拉取并运行sandbox
和fastgpt
,并在docker配置文件中注释掉sandbox
和fastgpt
的部分
所有 docker-compose.yml
配置文件中 MongoDB
为 5.x,需要用到AVX指令集,部分 CPU 不支持,需手动更改其镜像版本为 4.4.24**(需要自己在docker hub下载,阿里云镜像没做备份)
Linux 快速脚本
+ mkdir fastgpt
+cd fastgpt
+curl -O https://raw.githubusercontent.com/labring/FastGPT/main/projects/app/data/config.json
+
+# pgvector 版本(测试推荐,简单快捷)
+curl -o docker-compose.yml https://raw.githubusercontent.com/labring/FastGPT/main/files/docker/docker-compose-pgvector.yml
+# milvus 版本
+# curl -o docker-compose.yml https://raw.githubusercontent.com/labring/FastGPT/main/files/docker/docker-compose-milvus.yml
+# zilliz 版本
+# curl -o docker-compose.yml https://raw.githubusercontent.com/labring/FastGPT/main/files/docker/docker-compose-zilliz.yml
+
找到 yml 文件中,fastgpt 容器的环境变量进行下面操作:
在 docker-compose.yml 同级目录下执行。请确保docker-compose
版本最好在2.17以上,否则可能无法执行自动化命令。
+ # 启动容器
+docker-compose up -d
+# 等待10s,OneAPI第一次总是要重启几次才能连上Mysql
+sleep 10
+# 重启一次oneapi(由于OneAPI的默认Key有点问题,不重启的话会提示找不到渠道,临时手动重启一次解决,等待作者修复)
+docker restart oneapi
+
可以通过ip:3001
访问OneAPI,默认账号为root
密码为123456
。
在OneApi中添加合适的AI模型渠道。点击查看相关教程
目前可以通过 ip:3000
直接访问(注意防火墙)。登录用户名为 root
,密码为docker-compose.yml
环境变量里设置的 DEFAULT_ROOT_PSW
。
如果需要域名访问,请自行安装并配置 Nginx。
首次运行,会自动初始化 root 用户,密码为 1234
(与环境变量中的DEFAULT_ROOT_PSW
一致),日志里会提示一次MongoServerError: Unable to read from a snapshot due to pending collection catalog changes;
可忽略。
最新的 docker-compose 示例优化 Mongo 副本集初始化,实现了全自动。目前在 unbuntu20,22 centos7, wsl2, mac, window 均通过测试。仍无法正常启动,大部分是因为 cpu 不支持 AVX 指令集,可以切换 Mongo4.x 版本。
如果是由于,无法自动初始化副本集合,可以手动初始化副本集:
+ openssl rand -base64 756 > ./mongodb.key
+chmod 600 ./mongodb.key
+# 修改密钥权限,部分系统是admin,部分是root
+chown 999:root ./mongodb.key
+
+ mongo:
+ # image: mongo:5.0.18
+ # image: registry.cn-hangzhou.aliyuncs.com/fastgpt/mongo:5.0.18 # 阿里云
+ container_name: mongo
+ ports:
+ - 27017:27017
+ networks:
+ - fastgpt
+ command: mongod --keyFile /data/mongodb.key --replSet rs0
+ environment:
+ # 默认的用户名和密码,只有首次允许有效
+ - MONGO_INITDB_ROOT_USERNAME=myusername
+ - MONGO_INITDB_ROOT_PASSWORD=mypassword
+ volumes:
+ - ./mongo/data:/data/db
+ - ./mongodb.key:/data/mongodb.key
+
+ docker-compose down
+docker-compose up -d
+
+ # 查看 mongo 容器是否正常运行
+docker ps
+# 进入容器
+docker exec -it mongo bash
+
+# 连接数据库(这里要填Mongo的用户名和密码)
+mongo -u myusername -p mypassword --authenticationDatabase admin
+
+# 初始化副本集。如果需要外网访问,mongo:27017 。如果需要外网访问,需要增加Mongo连接参数:directConnection=true
+rs.initiate({
+ _id: "rs0",
+ members: [
+ { _id: 0, host: "mongo:27017" }
+ ]
+})
+# 检查状态。如果提示 rs0 状态,则代表运行成功
+rs.status()
+
默认是写了OneAPi的连接地址和密钥,可以通过修改docker-compose.yml
中,fastgpt容器的环境变量实现。
OPENAI_BASE_URL
(API 接口的地址,需要加/v1)
+CHAT_API_KEY
(API 接口的凭证)。
修改完后重启:
+ docker-compose down
+docker-compose up -d
+
查看更新文档,确认要升级的版本,避免跨版本升级。
修改镜像 tag 到指定版本
执行下面命令会自动拉取镜像:
+ docker-compose pull
+docker-compose up -d
+
执行初始化脚本(如果有)
修改config.json
文件,并执行docker-compose down
再执行docker-compose up -d
重起容器。具体配置,参考配置详解。
docker logs fastgpt
可以查看日志,在启动容器后,第一次请求网页,会进行配置文件读取,可以看看有没有读取成功以及有无错误日志。docker exec -it fastgpt sh
进入 FastGPT 容器,可以通过ls data
查看目录下是否成功挂载config.json
文件。可通过cat data/config.json
查看配置文件。可能不生效的原因
invalid json
,配置文件需要是标准的 JSON 文件。docker-compose down
再docker-compose up -d
,restart是不会重新挂载文件的。docker exec -it fastgpt sh
进入 FastGPT 容器。env
命令查看所有环境变量。本地模型
镜像 docker-compose.yml
中使用了桥接的模式建立了fastgpt
网络,如想通过0.0.0.0或镜像名访问其它镜像,需将其它镜像也加入到网络中。
docker-compose 端口定义为:映射端口:运行端口
。
桥接模式下,容器运行端口不会有冲突,但是会有映射端口冲突,只需将映射端口修改成不同端口即可。
如果容器1
需要连接容器2
,使用容器2:运行端口
来进行连接即可。
(自行补习 docker 基本知识)
PG 数据库没有连接上/初始化失败,可以查看日志。FastGPT 会在每次连接上 PG 时进行表初始化,如果报错会有对应日志。
可能原因:
auth_codes.findOne()
buffering timed out after 10000ms mongo连接失败,查看mongo的运行状态对应日志。
可能原因:
Illegal instruction.... Waiting for MongoDB to start
: cpu 不支持 AVX,无法用 mongo5,需要换成 mongo4.x日志会有错误提示。大概率是没有启动 Mongo 副本集模式。
没配置 SSL 证书,无权使用部分功能。
由于服务初始化错误,系统重启导致。
修改docker-compose.yml
文件中DEFAULT_ROOT_PSW
并重启即可,密码会自动更新。
FastGPT 私有部署常见问题
遇到问题先按下面方式排查。
docker ps -a
查看所有容器运行状态,检查是否全部 running,如有异常,尝试docker logs 容器名
查看对应日志。docker logs 容器名
查看报错日志requestId
的,都是 OneAPI 提示错误,大部分都是因为模型接口报错。具体内容参考https://fael3z0zfze.feishu.cn/wiki/OFpAw8XzAi36Guk8dfucrCKUnjg。
可以。需要准备好向量模型和LLM模型。
toolChoice=false
和functionCall=false
,就会默认走提示词模式。目前内置提示词仅针对了商业模型API进行测试。问题分类基本可用,内容提取不太行。customCQPrompt
来自定义提示词。URI malformed
,请 Issue 反馈具体操作和页面,这是由于特殊字符串编码解析报错。
+ # curl 例子。
+curl --location --request POST 'https://xxx.cn/v1/chat/completions' \
+--header 'Authorization: Bearer sk-xxxx' \
+--header 'Content-Type: application/json' \
+--data-raw '{
+ "model": "gpt-3.5-turbo",
+ "stream": true,
+ "temperature": 1,
+ "max_tokens": 3000,
+ "messages": [
+ {
+ "role": "user",
+ "content": "你是谁"
+ }
+ ]
+}'
+
页面中是用 stream=true 模式,所以API也需要设置 stream=true 来进行测试。部分模型接口(国产居多)非 Stream 的兼容有点垃圾。 +和上一个问题一样,curl 测试。
先看日志报错信息。有以下几种情况:
网络异常。国内服务器无法请求OpenAI,自行检查与AI模型的连接是否正常。
或者是FastGPT请求不到 OneAPI(没放同一个网络)
带有 requestId 的都是 OneAPI 的报错。
OneAPI 账号的余额不足,默认 root 用户只有 200 刀,可以手动修改。
路径:打开OneAPI -> 用户 -> root用户右边的编辑 -> 剩余余额调大
FastGPT 模型配置文件中的 model 必须与 OneAPI 渠道中的模型对应上,否则就会提示这个错误。可检查下面内容:
如果OneAPI中,没有配置对应的模型,config.json
中也不要配置,否则容易报错。
OneAPI 的 API Key 配置错误,需要修改OPENAI_API_KEY
环境变量,并重启容器(先 docker-compose down 然后再 docker-compose up -d 运行一次)。
可以exec
进入容器,env
查看环境变量是否生效。
该错误是由于 stream 模式下,oneapi 直接结束了流请求,并且未返回任何内容导致。
4.8.10 版本新增了错误日志,报错时,会在日志中打印出实际发送的 Body 参数,可以复制该参数后,通过 curl 向 oneapi 发起请求测试。
由于 oneapi 在 stream 模式下,无法正确捕获错误,有时候可以设置成 stream=false
来获取到精确的错误。
可能的报错问题:
测试示例如下,可复制报错日志中的请求体进行测试:
+ curl --location --request POST 'https://api.openai.com/v1/chat/completions' \
+--header 'Authorization: Bearer sk-xxxx' \
+--header 'Content-Type: application/json' \
+--data-raw '{
+ "model": "xxx",
+ "temperature": 0.01,
+ "max_tokens": 1000,
+ "stream": true,
+ "messages": [
+ {
+ "role": "user",
+ "content": " 你是饿"
+ }
+ ]
+}'
+
需要模型提供商和 oneapi 同时支持工具调用才可使用,测试方法如下:
curl
向 oneapi
发起第一轮 stream 模式的 tool 测试。
+ curl --location --request POST 'https://oneapi.xxx/v1/chat/completions' \
+--header 'Authorization: Bearer sk-xxxx' \
+--header 'Content-Type: application/json' \
+--data-raw '{
+ "model": "gpt-4o-mini",
+ "temperature": 0.01,
+ "max_tokens": 8000,
+ "stream": true,
+ "messages": [
+ {
+ "role": "user",
+ "content": "几点了"
+ }
+ ],
+ "tools": [
+ {
+ "type": "function",
+ "function": {
+ "name": "hCVbIY",
+ "description": "获取用户当前时区的时间。",
+ "parameters": {
+ "type": "object",
+ "properties": {},
+ "required": []
+ }
+ }
+ }
+ ],
+ "tool_choice": "auto"
+}'
+
如果能正常调用工具,会返回对应 tool_calls
参数。
+ {
+ "id": "chatcmpl-A7kwo1rZ3OHYSeIFgfWYxu8X2koN3",
+ "object": "chat.completion.chunk",
+ "created": 1726412126,
+ "model": "gpt-4o-mini-2024-07-18",
+ "system_fingerprint": "fp_483d39d857",
+ "choices": [
+ {
+ "index": 0,
+ "delta": {
+ "role": "assistant",
+ "content": null,
+ "tool_calls": [
+ {
+ "index": 0,
+ "id": "call_0n24eiFk8OUyIyrdEbLdirU7",
+ "type": "function",
+ "function": {
+ "name": "mEYIcFl84rYC",
+ "arguments": ""
+ }
+ }
+ ],
+ "refusal": null
+ },
+ "logprobs": null,
+ "finish_reason": null
+ }
+ ],
+ "usage": null
+}
+
curl
向 oneapi
发起第二轮 stream 模式的 tool 测试。第二轮请求是把工具结果发送给模型。发起后会得到模型回答的结果。
+ curl --location --request POST 'https://oneapi.xxxx/v1/chat/completions' \
+--header 'Authorization: Bearer sk-xxx' \
+--header 'Content-Type: application/json' \
+--data-raw '{
+ "model": "gpt-4o-mini",
+ "temperature": 0.01,
+ "max_tokens": 8000,
+ "stream": true,
+ "messages": [
+ {
+ "role": "user",
+ "content": "几点了"
+ },
+ {
+ "role": "assistant",
+ "tool_calls": [
+ {
+ "id": "kDia9S19c4RO",
+ "type": "function",
+ "function": {
+ "name": "hCVbIY",
+ "arguments": "{}"
+ }
+ }
+ ]
+ },
+ {
+ "tool_call_id": "kDia9S19c4RO",
+ "role": "tool",
+ "name": "hCVbIY",
+ "content": "{\n \"time\": \"2024-09-14 22:59:21 Sunday\"\n}"
+ }
+ ],
+ "tools": [
+ {
+ "type": "function",
+ "function": {
+ "name": "hCVbIY",
+ "description": "获取用户当前时区的时间。",
+ "parameters": {
+ "type": "object",
+ "properties": {},
+ "required": []
+ }
+ }
+ }
+ ],
+ "tool_choice": "auto"
+}'
+
本地开发 FastGPT 必看
对 FastGPT 进行开发调试
本文档介绍了如何设置开发环境以构建和测试 FastGPT,。
您需要在计算机上安装和配置以下依赖项才能构建 FastGPT:
Asia/Shanghai
,非 linux 环境时候,获取系统时间会异常,本地开发时候,可以将用户的时区调整成 UTC(+0)。您需要 Fork 存储库。
克隆您在 GitHub 上 Fork 的存储库:
+ git clone git@github.com:<github_username>/FastGPT.git
+
目录简要说明
projects
目录下为 FastGPT 应用代码。其中 app
为 FastGPT 核心应用。(后续可能会引入其他应用)src/pages/api
目录内。packages
目录为共用代码,通过 workspace 被注入到 projects
中,已配置 monorepo 自动注入,无需额外打包。第一次开发,需要先部署数据库,建议本地开发可以随便找一台 2C2G 的轻量小数据库实践,或者新建文件夹并配置相关文件用以运行docker。数据库部署教程:Docker 快速部署。部署完了,可以本地访问其数据库。
Mongo 数据库需要注意,需要注意在连接地址中增加 directConnection=true
参数,才能连接上副本集的数据库。
以下文件均在 projects/app
路径下。
1. 环境变量
复制.env.template
文件,在同级目录下生成一个.env.local
文件,修改.env.local
里内容才是有效的变量。变量说明见 .env.template,主要需要修改API_KEY
和数据库的地址与端口以及数据库账号的用户名和密码,具体配置需要和docker配置文件相同,其中用户名和密码如需修改需要修改docker配置文件、数据库和.env.local
文件,不能只改一处。
2. config 配置文件
复制 data/config.json
文件,生成一个 data/config.local.json
配置文件,具体配置参数说明,可参考 config 配置说明
注意:json 配置文件不能包含注释,介绍中为了方便看才加入的注释
这个文件大部分时候不需要修改。只需要关注 systemEnv
里的参数:
vectorMaxProcess
: 向量生成最大进程,根据数据库和 key 的并发数来决定,通常单个 120 号,2c4g 服务器设置 10~15。qaMaxProcess
: QA 生成最大进程pgHNSWEfSearch
: PostgreSQL vector 索引参数,越大搜索精度越高但是速度越慢,具体可看 pgvector 官方说明。可参考项目根目录下的 dev.md
,第一次编译运行可能会有点慢,需要点耐心哦
+ # 给自动化脚本代码执行权限(非 linux 系统, 可以手动执行里面的 postinstall.sh 文件内容)
+chmod -R +x ./scripts/
+# 代码根目录下执行,会安装根 package、projects 和 packages 内所有依赖
+# 如果提示 isolate-vm 安装失败,可以参考:https://github.com/laverdet/isolated-vm?tab=readme-ov-file#requirements
+pnpm i
+
+# 非 Make 运行
+cd projects/app
+pnpm dev
+
+# Make 运行
+make dev name=app
+
+ # Docker cmd: Build image, not proxy
+docker build -f ./projects/app/Dockerfile -t registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.8.1 . --build-arg name=app
+# Make cmd: Build image, not proxy
+make build name=app image=registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.8.1
+
+# Docker cmd: Build image with proxy
+docker build -f ./projects/app/Dockerfile -t registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.8.1 . --build-arg name=app --build-arg proxy=taobao
+# Make cmd: Build image with proxy
+make build name=app image=registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.8.1 proxy=taobao
+
如果不使用 docker
打包,需要手动把 Dockerfile
里 run 阶段的内容全部手动执行一遍(非常不推荐)。
如果遇到问题,比如合并冲突或不知道如何打开拉取请求,请查看 GitHub 的拉取请求教程,了解如何解决合并冲突和其他问题。一旦您的 PR 被合并,您将自豪地被列为贡献者表中的一员。
host
改成localhost
或127.0.0.1
directConnection=true
参数,才能连接上副本集的数据库。mongocompass
客户端进行连接测试和可视化管理。navicat
进行连接和管理。FastGPT 在pnpm i
后会执行postinstall
脚本,用于自动生成ChakraUI
的Type
。如果没有权限,可以先执行chmod -R +x ./scripts/
,再执行pnpm i
。
仍不可行的话,可以手动执行./scripts/postinstall.sh
里的内容。
+如果是Windows下的话,可以使用git bash给postinstall
脚本添加执行权限并执行sh脚本
删除所有的node_modules
,用 Node18 重新 install 试试,可能最新的 Node 有问题。 本地开发流程:
pnpm i
config.json
-> config.local.json
.env.template
-> .env.local
cd projects/app
pnpm dev
这个错误可能是之前停止容器时有文件残留导致的,首先需要确认相关镜像都全部关闭,然后手动删除相关文件或者重启docker即可
遇到困难了吗?有任何问题吗? 加入飞书群与开发者和用户保持沟通。
FastGPT 使用了 nextjs 的 page route 作为框架。为了区分好前后端代码,在目录分配上会分成 global, service, web 3个自目录,分别对应着 前后端共用
、后端专用
、前端专用
的代码。
FastGPT 采用 pnpm workspace 方式构建 monorepo 项目,主要分为两个部分:
FastGPT 在代码模块划分时,按DDD的思想进行划分,主要分为以下几个领域:
core - 核心功能(知识库,工作流,应用,对话) +support - 支撑功能(用户体系,计费,鉴权等) +common - 基础功能(日志管理,文件读写等)
.
+├── .github // github 相关配置
+├── .husky // 格式化配置
+├── docSite // 文档
+├── files // 一些外部文件,例如 docker-compose, helm
+├── packages // 子包
+│ ├── global // 前后端通用子包
+│ ├── plugins // 工作流插件(需要自定义包时候使用到)
+│ ├── service // 后端子包
+│ └── web // 前端子包
+├── projects
+│ └── app // FastGPT 主项目
+├── python // 存放一些模型代码,和 FastGPT 本身无关
+└── scripts // 一些自动化脚本
+ ├── icon // icon预览脚本,可以在顶层 pnpm initIcon(把svg写入到代码中), pnpm previewIcon(预览icon)
+ └── postinstall.sh // chakraUI自定义theme初始化 ts 类型
+├── package.json // 顶层monorepo
+├── pnpm-lock.yaml
+├── pnpm-workspace.yaml // monorepo 声明
+├── Dockerfile
+├── LICENSE
+├── README.md
+├── README_en.md
+├── README_ja.md
+├── dev.md
+
FastGPT Docker 数据库备份和迁移
Docker 部署数据库都会通过 volume 挂载本地的目录进入容器,如果要迁移,直接复制这些目录即可。
PG 数据
: pg/data
+Mongo 数据
: mongo/data
FastGPT Docker Mongo迁移
如何使用Mongodump来完成从A环境到B环境的Fastgpt的mongodb迁移
前提说明:
A环境:我在阿里云上部署的fastgpt,现在需要迁移到B环境。 +B环境:是新环境比如腾讯云新部署的fastgpt,更特殊一点的是,NAS(群晖或者QNAP)部署了fastgpt,mongo必须改成4.2或者4.4版本(其实云端更方便,支持fastgpt mongo默认版本) +C环境:妥善考虑,用本地电脑作为C环境过渡,保存相关文件并分离操作 +
+ docker exec -it mongo sh
+mongo -u 'username' -p 'password'
+>> show dbs
+
看到fastgpt数据库,以及其它几个,确定下导出数据库名称 +准备: +检查数据库,容器和宿主机都创建一下 backup 目录 【A环境 + C环境】
检查数据库,容器和宿主机都创建一下“数据导出导入”临时目录 ,比如data/backup 【A环境建目录 + C环境建目录用于同步到容器中】
容器:(先进入fastgpt docker容器)
+ docker exec -it fastgpt sh
+mkdir -p /data/backup
+
建好后,未来导出mongo的数据,会在A环境本地fastgpt的安装目录/Data/下看到自动同步好的目录,数据会在data\backup中,然后可以衔接后续的压缩和下载转移动作。如果没有同步到本地,也可以手动建一下,配合docker cp 把文件拷到本地用(基本不会发生)
到fastgpt目录,进入mongo目录,有data目录,下面建backup
+ mkdir -p /fastgpt/data/backup
+
准备好后,后续上传
+ ### 新fastgpt环境【B】中也需要建一个,比如/fastgpt/mongobackup目录,注意不要在fastgpt/data目录下建立目录
+
mkdir -p /fastgpt/mongobackup
+
+###2. 正题开始,从fastgpt老环境【A】中导出数据
+进入A环境,使用mongodump 导出mongo数据库。
+
+#### 2.1 导出
+可以使用mongodump在源头容器中导出数据文件, 导出路径为上面指定临时目录,即"data\backup"
+
+[导出的文件在代码中指定为/data/backup,因为fastgpt配置文件已经建立了data的持久化,所以会同步到容器所在环境本地fast/mongo/data应该就能看到这个导出的目录:backup,里面有文件]
+
+一行指令导出代码,在服务器本地环境运行,不需要进入容器。
+
docker exec -it mongo bash -c “mongodump –db fastgpt -u ‘username’ -p ‘password’ –authenticationDatabase admin –out /data/backup”
+
+也可以进入环境,熟手可以结合建目录,一次性完成建导出目录,以及使用mongodump导出数据到该目录
+
1.docker exec -it fastgpt sh
2.mkdir -p /data/backup
+ docker cp mongo:/data/backup <A环境本地fastgpt目录>:/fastgpt/data/backup>
+```
+
+2.2 对新手,建议稳妥起见,压缩这个文件目录,并将压缩文件下载到本地过渡环境【A环境 -> C环境】;原因是因为留存一份,并且检查文件数量是否一致。
+
+ 熟手可以直接复制到新部署服务器(腾讯云或者NAS)【A环境-> B环境】
+
+
+2.2.1 先进入 【A环境】源头系统的本地环境 fastgpt/mongo/data 目录
+
cd /usr/fastgpt/mongo/data
+
+#执行,压缩文件命令
+
tar -czvf ../fastgpt-mongo-backup-$(date +%Y-%m-%d).tar.gz ./ 【A环境】
+ #接下来,把压缩包下载到本地 【A环境-> C环境】,以便于检查和留存版本。熟手,直接将该压缩包同步到B环境中新fastgpt目录data目录下备用。
+
scp -i /Users/path/<user.pem换成你自己的pem文件链接> root@<fastgpt所在云服务器地址>:/usr/fastgpt/mongo/fastgptbackup-2024-05-03.tar.gz /<本地电脑路径>/Downloads/fastgpt
+ 熟手直接换成新环境地址
+
+
scp -i /Users/path/<user.pem换成你自己的pem文件链接> root@<老环境fastgpt服务器地址>:/usr/fastgpt/mongo/fastgptbackup-2024-05-03.tar.gz root@<新环境fastgpt服务器地址>:/Downloads/fastgpt2
+
+2.2 【C环境】检查压缩文件是否完整,如果不完整,重新导出。事实上,我也出现过问题,因为跨环境scp会出现丢数据的情况。
+
+压缩数据包导入到C环境本地后,可以考虑在宿主机目录解压缩,放在一个自定义目录比如. < user/fastgpt/mongobackup/data>
+
tar -xvzf fastgptbackup-2024-05-03.tar.gz -C user/fastgpt/mongobackup/data
+ 解压缩后里面是bson文件,这里可以检查下,压缩文件数量是否一致。如果不一致,后续启动新环境的fastgpt容器,也不会有任何数据。
+
+<img width="1561" alt="image" src="https://github.com/labring/FastGPT/assets/103937568/cbb8a93c-5834-4a0d-be6c-c45c701f593e">
+
+
+如果没问题,准备进入下一步,将压缩包文件上传到B环境,也就是新fastgpt环境里的指定目录,比如/fastgpt/mongobackup, 注意不要放到fastgpt/data目录下,因为下面会先清空一次这个目录,否则导入会报错。
+
scp -rfv <本地电脑路径>/Downloads/fastgpt/fastgptbackup-2024-05-03.tar.gz root@<新环境fastgpt服务器地址>:/Downloads/fastgpt/backup
+
+## 3 导入恢复: 实际恢复和导入步骤
+
+### 3.1. 进入新fastgpt本地环境的安装目录后,找到迁移的压缩文件包fastgptbackup-2024-05-03.tar.gz,解压缩到指定目录
+
tar -xvzf fastgptbackup-2024-05-03.tar.gz -C user/fastgpt/mongobackup/data
+ 再次核对文件数量,和上面对比一下。
+
+熟手可以用tar指令检查文件完整性,上面是给新手准备的,便于比对核查。
+
+
+### 3.2 手动上传新fastgpt docker容器里备用 【C环境】
+说明:因为没有放在data里,所以不会自动同步到容器里。而且要确保容器的data目录被清理干净,否则导入时会报错。
+
docker cp user/fastgpt/mongobackup/data mongo:/tmp/backup +```
如果不是初始化的 mongo/db 目录, mongorestore 导入可能会报错。如果报错,建议尝试初始化mongo。
操作指令
+ cd /fastgpt安装目录/mongo/data
+rm -rf *
+
4.恢复: mongorestore 恢复 [C环境】 +简单一点,退回到本地环境,用 docker 命令一键导入,当然你也可以在容器里操作
+ docker exec -it mongo mongorestore -u "username" -p "password" --authenticationDatabase admin /tmp/backup/ --db fastgpt
+
5.重启容器 【C环境】
+ docker compose restart
+docker logs -f mongo **强烈建议先检查mongo运行情况,在去做登录动作,如果mongo报错,访问web也会报错”
+
如果mongo启动正常,显示的是类似这样的,而不是 “mongo is restarting”,后者就是错误 +
报错情况 +
FastGPT 迁移&备份
本模型配置方案
通过 OneAPI 接入模型
FastGPT 目前采用模型分离的部署方案,FastGPT 中只兼容 OpenAI 的模型规范(OpenAI 不存在的模型采用一个较为通用的规范),并通过 One API 来实现对不同模型接口的统一。
One API 是一个 OpenAI 接口管理 & 分发系统,可以通过标准的 OpenAI API 格式访问所有的大模型,开箱即用。
可以把 One API 当做一个网关,FastGPT 与 One API 关系:
docker-compose.yml
文件已加入了 OneAPI 配置,可直接使用。默认暴露在 3001 端口。
部署完后,可以打开 OneAPI 访问链接,进行下一步操作。
Api Key
,这个 Api Key
可以是GPT、微软、ChatGLM、文心一言的。一个Api Key
通常可以调用同一个厂商的多个模型。模型
来决定使用哪一个渠道
,如果一个模型对应了多个渠道
,则会随机调用。1
个凭证即可访问One API
上配置的模型。因此FastGPT
中,只需要配置One API
的baseurl
和令牌
即可。令牌不要设置任何的模型范围权限,否则容易报错。model
参数,匹配对应的渠道(根据渠道里的模型进行匹配,必须完全一致)。如果匹配到多个渠道,则随机选择一个(同优先级)。在 One API 中添加对应渠道,直接点击 【添加基础模型】,不要遗漏了向量模型(Embedding)
One API 默认 root 用户只有 200刀,可以自行修改编辑。
有了 One API 令牌后,FastGPT 可以通过修改 baseurl
和 key
去请求到 One API,再由 One API 去请求不同的模型。修改下面两个环境变量:
+ # 务必写上 v1。如果在同一个网络内,可改成内网地址。
+OPENAI_BASE_URL=https://xxxx.cloud.sealos.io/v1
+# 下面的 key 是由 One API 提供的令牌
+CHAT_API_KEY=sk-xxxxxx
+
以添加文心一言为例:
类型选择百度文心千帆。
可以在 /projects/app/src/data/config.json
里找到配置文件(本地开发需要复制成 config.local.json),按下面内容修改配置文件,最新/更具体的配置说明,可查看FastGPT 配置文件说明。
配置模型关键点在于model
需要与 OneAPI 渠道中的模型一致。
+ {
+ "llmModels": [ // 语言模型配置
+ {
+ "model": "ERNIE-Bot", // 这里的模型需要对应 One API 的模型
+ "name": "文心一言", // 对外展示的名称
+ "avatar": "/imgs/model/openai.svg", // 模型的logo
+ "maxContext": 16000, // 最大上下文
+ "maxResponse": 4000, // 最大回复
+ "quoteMaxToken": 13000, // 最大引用内容
+ "maxTemperature": 1.2, // 最大温度
+ "charsPointsPrice": 0,
+ "censor": false,
+ "vision": false, // 是否支持图片输入
+ "datasetProcess": true, // 是否设置为知识库处理模型
+ "usedInClassify": true, // 是否用于问题分类
+ "usedInExtractFields": true, // 是否用于字段提取
+ "usedInToolCall": true, // 是否用于工具调用
+ "usedInQueryExtension": true, // 是否用于问题优化
+ "toolChoice": true, // 是否支持工具选择
+ "functionCall": false, // 是否支持函数调用
+ "customCQPrompt": "", // 自定义文本分类提示词(不支持工具和函数调用的模型
+ "customExtractPrompt": "", // 自定义内容提取提示词
+ "defaultSystemChatPrompt": "", // 对话默认携带的系统提示词
+ "defaultConfig":{} // 请求API时,挟带一些默认配置(比如 GLM4 的 top_p)
+ }
+ ],
+ "vectorModels": [ // 向量模型配置
+ {
+ "model": "text-embedding-ada-002",
+ "name": "Embedding-2",
+ "avatar": "/imgs/model/openai.svg",
+ "charsPointsPrice": 0,
+ "defaultToken": 700,
+ "maxToken": 3000,
+ "weight": 100
+ },
+ ]
+}
+
Docker 版本
+ docker-compose down
+docker-compose up -d
+
Sealos 版本
直接找到 FastGPT 服务,点击重启即可。
这章介绍一些提供商接入 OneAPI 的教程,配置后不要忘记修改 FastGPT 配置文件。
千问目前已经兼容 GPT 格式,可以直接选择 OpenAI 类型来接入即可。如下图,选择类型为OpenAI
,代理填写阿里云的代理地址。
目前可以直接使用阿里云的语言模型和 text-embedding-v3
向量模型(实测已经归一化,可直接使用)
硅基流动 是一个专门提供开源模型调用平台,并拥有自己的加速引擎。模型覆盖面广,非常适合低成本来测试开源模型。接入教程:
OpenAI
类型,代理填写:https://api.siliconflow.cn
,密钥是第二步创建的密钥。由于 OneAPI 未内置 硅基流动 的模型名,可以通过自定义模型名称来填入,下面是获取模型名称的教程:
通过 SiliconCloud 体验开源模型
SiliconCloud(硅基流动) 是一个以提供开源模型调用为主的平台,并拥有自己的加速引擎。帮助用户低成本、快速的进行开源模型的测试和使用。实际体验下来,他们家模型的速度和稳定性都非常不错,并且种类丰富,覆盖语言、向量、重排、TTS、STT、绘图、视频生成模型,可以满足 FastGPT 中所有模型需求。
如果你想部分模型使用 SiliconCloud 的模型,可额外参考OneAPI接入硅基流动。
本文会介绍完全使用 SiliconCloud 模型来部署 FastGPT 的方案。
+ OPENAI_BASE_URL=https://api.siliconflow.cn/v1
+# 填写 SiliconCloud 控制台提供的 Api Key
+CHAT_API_KEY=sk-xxxxxx
+
我们选取 SiliconCloud 中的模型作为 FastGPT 配置。这里配置了 Qwen2.5 72b
的纯语言和视觉模型;选择 bge-m3
作为向量模型;选择 bge-reranker-v2-m3
作为重排模型。选择 fish-speech-1.5
作为语音模型;选择 SenseVoiceSmall
作为语音输入模型。
注意:ReRank 模型仍需配置一次 Api Key
+ {
+ "llmModels": [
+ {
+ "provider": "Other", // 模型提供商,主要用于分类展示,目前已经内置提供商包括:https://github.com/labring/FastGPT/blob/main/packages/global/core/ai/provider.ts, 可 pr 提供新的提供商,或直接填写 Other
+ "model": "Qwen/Qwen2.5-72B-Instruct", // 模型名(对应OneAPI中渠道的模型名)
+ "name": "Qwen2.5-72B-Instruct", // 模型别名
+ "maxContext": 32000, // 最大上下文
+ "maxResponse": 4000, // 最大回复
+ "quoteMaxToken": 30000, // 最大引用内容
+ "maxTemperature": 1, // 最大温度
+ "charsPointsPrice": 0, // n积分/1k token(商业版)
+ "censor": false, // 是否开启敏感校验(商业版)
+ "vision": false, // 是否支持图片输入
+ "datasetProcess": true, // 是否设置为文本理解模型(QA),务必保证至少有一个为true,否则知识库会报错
+ "usedInClassify": true, // 是否用于问题分类(务必保证至少有一个为true)
+ "usedInExtractFields": true, // 是否用于内容提取(务必保证至少有一个为true)
+ "usedInToolCall": true, // 是否用于工具调用(务必保证至少有一个为true)
+ "usedInQueryExtension": true, // 是否用于问题优化(务必保证至少有一个为true)
+ "toolChoice": true, // 是否支持工具选择(分类,内容提取,工具调用会用到。)
+ "functionCall": false, // 是否支持函数调用(分类,内容提取,工具调用会用到。会优先使用 toolChoice,如果为false,则使用 functionCall,如果仍为 false,则使用提示词模式)
+ "customCQPrompt": "", // 自定义文本分类提示词(不支持工具和函数调用的模型
+ "customExtractPrompt": "", // 自定义内容提取提示词
+ "defaultSystemChatPrompt": "", // 对话默认携带的系统提示词
+ "defaultConfig": {}, // 请求API时,挟带一些默认配置(比如 GLM4 的 top_p)
+ "fieldMap": {} // 字段映射(o1 模型需要把 max_tokens 映射为 max_completion_tokens)
+ },
+ {
+ "provider": "Other",
+ "model": "Qwen/Qwen2-VL-72B-Instruct",
+ "name": "Qwen2-VL-72B-Instruct",
+ "maxContext": 32000,
+ "maxResponse": 4000,
+ "quoteMaxToken": 30000,
+ "maxTemperature": 1,
+ "charsPointsPrice": 0,
+ "censor": false,
+ "vision": true,
+ "datasetProcess": false,
+ "usedInClassify": false,
+ "usedInExtractFields": false,
+ "usedInToolCall": false,
+ "usedInQueryExtension": false,
+ "toolChoice": false,
+ "functionCall": false,
+ "customCQPrompt": "",
+ "customExtractPrompt": "",
+ "defaultSystemChatPrompt": "",
+ "defaultConfig": {}
+ }
+ ],
+ "vectorModels": [
+ {
+ "provider": "Other",
+ "model": "Pro/BAAI/bge-m3",
+ "name": "Pro/BAAI/bge-m3",
+ "charsPointsPrice": 0,
+ "defaultToken": 512,
+ "maxToken": 5000,
+ "weight": 100
+ }
+ ],
+ "reRankModels": [
+ {
+ "model": "BAAI/bge-reranker-v2-m3", // 这里的model需要对应 siliconflow 的模型名
+ "name": "BAAI/bge-reranker-v2-m3",
+ "requestUrl": "https://api.siliconflow.cn/v1/rerank",
+ "requestAuth": "siliconflow 上申请的 key"
+ }
+ ],
+ "audioSpeechModels": [
+ {
+ "model": "fishaudio/fish-speech-1.5",
+ "name": "fish-speech-1.5",
+ "voices": [
+ {
+ "label": "fish-alex",
+ "value": "fishaudio/fish-speech-1.5:alex",
+ "bufferId": "fish-alex"
+ },
+ {
+ "label": "fish-anna",
+ "value": "fishaudio/fish-speech-1.5:anna",
+ "bufferId": "fish-anna"
+ },
+ {
+ "label": "fish-bella",
+ "value": "fishaudio/fish-speech-1.5:bella",
+ "bufferId": "fish-bella"
+ },
+ {
+ "label": "fish-benjamin",
+ "value": "fishaudio/fish-speech-1.5:benjamin",
+ "bufferId": "fish-benjamin"
+ },
+ {
+ "label": "fish-charles",
+ "value": "fishaudio/fish-speech-1.5:charles",
+ "bufferId": "fish-charles"
+ },
+ {
+ "label": "fish-claire",
+ "value": "fishaudio/fish-speech-1.5:claire",
+ "bufferId": "fish-claire"
+ },
+ {
+ "label": "fish-david",
+ "value": "fishaudio/fish-speech-1.5:david",
+ "bufferId": "fish-david"
+ },
+ {
+ "label": "fish-diana",
+ "value": "fishaudio/fish-speech-1.5:diana",
+ "bufferId": "fish-diana"
+ }
+ ]
+ }
+ ],
+ "whisperModel": {
+ "model": "FunAudioLLM/SenseVoiceSmall",
+ "name": "SenseVoiceSmall",
+ "charsPointsPrice": 0
+ }
+}
+
随便新建一个简易应用,选择对应模型,并开启图片上传后进行测试:
可以看到,72B 的模型,性能还是非常快的,这要是本地没几个 4090,不说配置环境,输出怕都要 30s 了。
新建一个知识库(由于只配置了一个向量模型,页面上不会展示向量模型选择)
导入本地文件,直接选择文件,然后一路下一步即可。79 个索引,大概花了 20s 的时间就完成了。现在我们去测试一下知识库问答。
首先回到我们刚创建的应用,选择知识库,调整一下参数后即可开始对话:
对话完成后,点击底部的引用,可以查看引用详情,同时可以看到具体的检索和重排得分:
继续在刚刚的应用中,左侧配置中找到语音播放,点击后可以从弹窗中选择语音模型,并进行试听:
继续在刚刚的应用中,左侧配置中找到语音输入,点击后可以从弹窗中开启语言输入
开启后,对话输入框中,会增加一个话筒的图标,点击可进行语音输入:
如果你想快速的体验开源模型或者快速的使用 FastGPT,不想在不同服务商申请各类 Api Key,那么可以选择 SiliconCloud 的模型先进行快速体验。
如果你决定未来私有化部署模型和 FastGPT,前期可通过 SiliconCloud 进行测试验证,后期再进行硬件采购,减少 POC 时间和成本。
FastGPT Api Key 使用与鉴权
FasGPT OpenAPI 接口允许你使用 Api Key 进行鉴权,从而操作 FastGPT 上的相关服务和资源,例如:调用应用对话接口、上传知识库数据、搜索测试等等。出于兼容性和安全考虑,并不是所有的接口都允许通过 Api Key 访问。
注意:BaseURL 不是接口地址,而是所有接口的根地址,直接请求 BaseURL 是没有用的。
FastGPT 的 API Key 有 2 类,一类是全局通用的 key (无法直接调用应用对话);一类是携带了 AppId 也就是有应用标记的 key (可直接调用应用对话)。
我们建议,仅操作应用或者对话的相关接口使用 应用特定key
,其他接口使用 通用key
。
通用key | 应用特定 key |
---|---|
OpenAPI 中,所有的接口都通过 Header.Authorization 进行鉴权。
+ baseUrl: "https://api.fastgpt.in/api"
+headers: {
+ Authorization: "Bearer {{apikey}}"
+}
+
发起应用对话示例
+ curl --location --request POST 'https://api.fastgpt.in/api/v1/chat/completions' \
+--header 'Authorization: Bearer fastgpt-xxxxxx' \
+--header 'Content-Type: application/json' \
+--data-raw '{
+ "chatId": "111",
+ "stream": false,
+ "detail": false,
+ "messages": [
+ {
+ "content": "导演是谁",
+ "role": "user"
+ }
+ ]
+}'
+
FastGPT OpenAPI 对话接口
该接口的 API Key 需使用应用特定的 key
,否则会报错。
有些包调用时,BaseUrl
需要添加v1
路径,有些不需要,如果出现404情况,可补充v1
重试。
对话接口兼容GPT
的接口!如果你的项目使用的是标准的GPT
官方接口,可以直接通过修改BaseUrl
和 Authorization
来访问 FastGpt 应用,不过需要注意下面几个规则:
传入的model
,temperature
等参数字段均无效,这些字段由编排决定,不会根据 API 参数改变。
不会返回实际消耗Token
值,如果需要,可以设置detail=true
,并手动计算 responseData
里的tokens
值。
如果工作流中包含交互节点,依然是调用该 API 接口,需要设置detail=true
,并可以从event=interactive
的数据中获取交互节点的配置信息。如果是stream=false
,则可以从 choice 中获取type=interactive
的元素,获取交互节点的选择信息。
当你调用一个带交互节点的工作流时,如果工作流遇到了交互节点,那么会直接返回,你可以得到下面的信息:
紧接着上一节,当你接收到交互节点信息后,可以根据这些数据进行 UI 渲染,引导用户输入或选择相关信息。然后需要再次发起对话,来继续工作流。调用的接口与仍是该接口,你需要按以下格式来发起请求:
插件的接口与对话接口一致,仅请求参数略有区别,有以下规定:
detail
模式。chatId
,因为插件只能运行一轮。messages
。variables
来代表插件的输入。pluginData
来获取插件输出。
+ curl --location --request POST 'http://localhost:3000/api/v1/chat/completions' \
+--header 'Authorization: Bearer test-xxxxx' \
+--header 'Content-Type: application/json' \
+--data-raw '{
+ "stream": false,
+ "chatId": "test",
+ "variables": {
+ "query":"你好" # 我的插件输入有一个参数,变量名叫 query
+ }
+}'
+
以下接口可使用任意API Key
调用。
4.8.12 以上版本才能使用
重要字段
仅会情况通过 API Key 创建的对话历史记录,不会清空在线使用、分享链接等其他来源的对话历史记录。
指的是某个 chatId 下的对话记录操作。
4.8.16 后新版接口
新版猜你想问,必须包含 appId 和 chatId 的参数才可以进行使用。会自动根据 chatId 去拉取最近 6 轮对话记录作为上下文来引导回答。
4.8.16 前旧版接口:
FastGPT OpenAPI 知识库接口
如何获取知识库ID(datasetId) | 如何获取文件集合ID(collection_id) |
---|---|
入参
参数 | 说明 | 必填 |
---|---|---|
datasetId | 知识库ID | ✅ |
parentId: | 父级ID,不填则默认为根目录 | |
trainingType | 训练模式。chunk: 按文本长度进行分割;qa: QA拆分;auto: 增强训练 | ✅ |
chunkSize | 预估块大小 | |
chunkSplitter | 自定义最高优先分割符号 | |
qaPrompt | qa拆分提示词 | |
tags | 集合标签(字符串数组) | |
createTime | 文件创建时间(Date / String) |
出参
传入一段文字,创建一个集合,会根据传入的文字进行分割。
传入一个网络链接,创建一个集合,会先去对应网页抓取内容,再抓取的文字进行分割。
传入一个文件,创建一个集合,会读取文件内容进行分割。目前支持:pdf, docx, md, txt, html, csv。
传入一个文件的 id,创建一个集合,会读取文件内容进行分割。目前支持:pdf, docx, md, txt, html, csv。
Data结构
字段 | 类型 | 说明 | 必填 |
---|---|---|---|
teamId | String | 团队ID | ✅ |
tmbId | String | 成员ID | ✅ |
datasetId | String | 知识库ID | ✅ |
collectionId | String | 集合ID | ✅ |
q | String | 主要数据 | ✅ |
a | String | 辅助数据 | ✖ |
fullTextToken | String | 分词 | ✖ |
indexes | Index[] | 向量索引 | ✅ |
updateTime | Date | 更新时间 | ✅ |
chunkIndex | Number | 分块下表 | ✖ |
Index结构
每组数据的自定义索引最多5个
字段 | 类型 | 说明 | 必填 |
---|---|---|---|
defaultIndex | Boolean | 是否为默认索引 | ✅ |
dataId | String | 关联的向量ID | ✅ |
text | String | 文本内容 | ✅ |
注意,每次最多推送 200 组数据。
FastGPT OpenAPI 文档
FastGPT 分享链接身份鉴权
在 FastGPT V4.6.4 中,我们修改了分享链接的数据读取方式,为每个用户生成一个 localId,用于标识用户,从云端拉取对话记录。但是这种方式仅能保障用户在同一设备同一浏览器中使用,如果切换设备或者清空浏览器缓存则会丢失这些记录。这种方式存在一定的风险,因此我们仅允许用户拉取近30天
的20条
记录。
分享链接身份鉴权设计的目的在于,将 FastGPT 的对话框快速、安全的接入到你现有的系统中,仅需 2 个接口即可实现。
免登录链接配置中,你可以选择填写身份验证
栏。这是一个POST
请求的根地址。在填写该地址后,分享链接的初始化、开始对话以及对话结束都会向该地址的特定接口发送一条请求。下面以host
来表示凭身份验证根地址
。服务器接口仅需返回是否校验成功即可,不需要返回其他数据,格式如下:
+ {
+ "success": true,
+ "message": "错误提示",
+ "msg": "同message, 错误提示",
+ "data": {
+ "uid": "用户唯一凭证"
+ }
+}
+
FastGPT
将会判断success
是否为true
决定是允许用户继续操作。message
与msg
是等同的,你可以选择返回其中一个,当success
不为true
时,将会提示这个错误。
uid
是用户的唯一凭证,将会用于拉取对话记录以及保存对话记录。可参考下方实践案例。
配置校验地址后,在每次分享链接使用时,都会向对应的地址发起校验和上报请求。
这里仅需配置根地址,无需具体到完整请求路径。
在分享链接的地址中,增加一个额外的参数: authToken。例如:
原始的链接:https://share.tryfastgpt.ai/chat/share?shareId=648aaf5ae121349a16d62192
完整链接: https://share.tryfastgpt.ai/chat/share?shareId=648aaf5ae121349a16d62192&authToken=userid12345
这个authToken
通常是你系统生成的用户唯一凭证(Token之类的)。FastGPT 会在鉴权接口的body
中携带 token={{authToken}} 的参数。
该接口无规定返回值。
响应值与chat 接口格式相同,仅多了一个token
。
重点关注:totalPoints
(总消耗AI积分),token
(Token消耗总数)
+ curl --location --request POST '{{host}}/shareAuth/finish' \
+--header 'Content-Type: application/json' \
+--data-raw '{
+ "token": "{{authToken}}",
+ "responseData": [
+ {
+ "moduleName": "core.module.template.Dataset search",
+ "moduleType": "datasetSearchNode",
+ "totalPoints": 1.5278,
+ "query": "导演是谁\n《铃芽之旅》的导演是谁?\n这部电影的导演是谁?\n谁是《铃芽之旅》的导演?",
+ "model": "Embedding-2(旧版,不推荐使用)",
+ "tokens": 1524,
+ "similarity": 0.83,
+ "limit": 400,
+ "searchMode": "embedding",
+ "searchUsingReRank": false,
+ "extensionModel": "FastAI-4k",
+ "extensionResult": "《铃芽之旅》的导演是谁?\n这部电影的导演是谁?\n谁是《铃芽之旅》的导演?",
+ "runningTime": 2.15
+ },
+ {
+ "moduleName": "AI 对话",
+ "moduleType": "chatNode",
+ "totalPoints": 0.593,
+ "model": "FastAI-4k",
+ "tokens": 593,
+ "query": "导演是谁",
+ "maxToken": 2000,
+ "quoteList": [
+ {
+ "id": "65bb346a53698398479a8854",
+ "q": "导演是谁?",
+ "a": "电影《铃芽之旅》的导演是新海诚。",
+ "chunkIndex": 0,
+ "datasetId": "65af9b947916ae0e47c834d2",
+ "collectionId": "65bb345c53698398479a868f",
+ "sourceName": "dataset - 2024-01-23T151114.198.csv",
+ "sourceId": "65bb345b53698398479a868d",
+ "score": [
+ {
+ "type": "embedding",
+ "value": 0.9377183318138123,
+ "index": 0
+ },
+ {
+ "type": "rrf",
+ "value": 0.06557377049180328,
+ "index": 0
+ }
+ ]
+ }
+ ],
+ "historyPreview": [
+ {
+ "obj": "Human",
+ "value": "使用 <Data></Data> 标记中的内容作为本次对话的参考:\n\n<Data>\n导演是谁?\n电影《铃芽之旅》的导演是新海诚。\n------\n电影《铃芽之旅》的编剧是谁?22\n新海诚是本片的编剧。\n------\n电影《铃芽之旅》的女主角是谁?\n电影的女主角是铃芽。\n------\n电影《铃芽之旅》的制作团队中有哪位著名人士?2\n川村元气是本片的制作团队成员之一。\n------\n你是谁?\n我是电影《铃芽之旅》助手\n------\n电影《铃芽之旅》男主角是谁?\n电影《铃芽之旅》男主角是宗像草太,由松村北斗配音。\n------\n电影《铃芽之旅》的作者新海诚写了一本小说,叫什么名字?\n小说名字叫《铃芽之旅》。\n------\n电影《铃芽之旅》的女主角是谁?\n电影《铃芽之旅》的女主角是岩户铃芽,由原菜乃华配音。\n------\n电影《铃芽之旅》的故事背景是什么?\n日本\n------\n谁担任电影《铃芽之旅》中岩户环的配音?\n深津绘里担任电影《铃芽之旅》中岩户环的配音。\n</Data>\n\n回答要求:\n- 如果你不清楚答案,你需要澄清。\n- 避免提及你是从 <Data></Data> 获取的知识。\n- 保持答案与 <Data></Data> 中描述的一致。\n- 使用 Markdown 语法优化回答格式。\n- 使用与问题相同的语言回答。\n\n问题:\"\"\"导演是谁\"\"\""
+ },
+ {
+ "obj": "AI",
+ "value": "电影《铃芽之旅》的导演是新海诚。"
+ }
+ ],
+ "contextTotalLen": 2,
+ "runningTime": 1.32
+ }
+ ]
+
+
+}'
+
responseData 完整字段说明:
+ type ResponseType = {
+ moduleType: FlowNodeTypeEnum; // 模块类型
+ moduleName: string; // 模块名
+ moduleLogo?: string; // logo
+ runningTime?: number; // 运行时间
+ query?: string; // 用户问题/检索词
+ textOutput?: string; // 文本输出
+
+ tokens?: number; // 上下文总Tokens
+ model?: string; // 使用到的模型
+ contextTotalLen?: number; // 上下文总长度
+ totalPoints?: number; // 总消耗AI积分
+
+ temperature?: number; // 温度
+ maxToken?: number; // 模型的最大token
+ quoteList?: SearchDataResponseItemType[]; // 引用列表
+ historyPreview?: ChatItemType[]; // 上下文预览(历史记录会被裁剪)
+
+ similarity?: number; // 最低相关度
+ limit?: number; // 引用上限token
+ searchMode?: `${DatasetSearchModeEnum}`; // 搜索模式
+ searchUsingReRank?: boolean; // 是否使用rerank
+ extensionModel?: string; // 问题扩展模型
+ extensionResult?: string; // 问题扩展结果
+ extensionTokens?: number; // 问题扩展总字符长度
+
+ cqList?: ClassifyQuestionAgentItemType[]; // 分类问题列表
+ cqResult?: string; // 分类问题结果
+
+ extractDescription?: string; // 内容提取描述
+ extractResult?: Record<string, any>; // 内容提取结果
+
+ params?: Record<string, any>; // HTTP模块params
+ body?: Record<string, any>; // HTTP模块body
+ headers?: Record<string, any>; // HTTP模块headers
+ httpResult?: Record<string, any>; // HTTP模块结果
+
+ pluginOutput?: Record<string, any>; // 插件输出
+ pluginDetail?: ChatHistoryItemResType[]; // 插件详情
+
+ isElseResult?: boolean; // 判断器结果
+}
+
我们以Laf作为服务器为例,简单展示这 3 个接口的使用方式。
我们随便复制3个地址中一个接口: https://d8dns0.laf.dev/shareAuth/finish
, 去除/shareAuth/finish
后填入身份校验
:https://d8dns0.laf.dev
源分享链接:https://share.tryfastgpt.ai/chat/share?shareId=64be36376a438af0311e599c
修改后:https://share.tryfastgpt.ai/chat/share?shareId=64be36376a438af0311e599c&authToken=fastgpt
authToken
不等于fastgpt
的链接会提示身份错误。这个鉴权方式通常是帮助你直接嵌入分享链接
到你的应用中,在你的应用打开分享链接前,应做authToken
的拼接后再打开。
除了对接已有系统的用户外,你还可以对接余额
功能,通过结果上报
接口扣除用户余额,通过对话前校验
接口检查用户的余额。
使用 Cloudflare Worker 实现中转
workers 配置文件
+ const TELEGRAPH_URL = 'https://api.openai.com';
+
+addEventListener('fetch', (event) => {
+ event.respondWith(handleRequest(event.request));
+});
+
+async function handleRequest(request) {
+ // 安全校验
+ if (request.headers.get('auth') !== 'auth_code') {
+ return new Response('UnAuthorization', { status: 403 });
+ }
+
+ const url = new URL(request.url);
+ url.host = TELEGRAPH_URL.replace(/^https?:\/\//, '');
+
+ const modifiedRequest = new Request(url.toString(), {
+ headers: request.headers,
+ method: request.method,
+ body: request.body,
+ redirect: 'follow'
+ });
+
+ const response = await fetch(modifiedRequest);
+ const modifiedResponse = new Response(response.body, response);
+
+ // 添加允许跨域访问的响应头
+ modifiedResponse.headers.set('Access-Control-Allow-Origin', '*');
+
+ return modifiedResponse;
+}
+
修改 FastGPT 的环境变量
务必别忘了填 v1!
+ OPENAI_BASE_URL=https://xxxxxx/v1
+OPENAI_BASE_URL_AUTH=auth_code
+
使用 HTTP 代理实现中转
如果你有代理工具(例如 Clash 或者 sing-box),也可以使用 HTTP 代理来访问 OpenAI。只需要添加以下两个环境变量即可:
+ AXIOS_PROXY_HOST=
+AXIOS_PROXY_PORT=
+
以 Clash 为例,建议指定 api.openai.com
走代理,其他请求都直连。示例配置如下:
+ mixed-port: 7890
+allow-lan: false
+bind-address: '*'
+mode: rule
+log-level: warning
+dns:
+ enable: true
+ ipv6: false
+ nameserver:
+ - 8.8.8.8
+ - 8.8.4.4
+ cache-size: 400
+proxies:
+ -
+proxy-groups:
+ - { name: '♻️ 自动选择', type: url-test, proxies: [香港V01×1.5], url: 'https://api.openai.com', interval: 3600}
+rules:
+ - 'DOMAIN-SUFFIX,api.openai.com,♻️ 自动选择'
+ - 'MATCH,DIRECT'
+
然后给 FastGPT 添加两个环境变量:
+ AXIOS_PROXY_HOST=127.0.0.1
+AXIOS_PROXY_PORT=7890
+
FastGPT 私有化部署代理方案
使用 Sealos 部署 Nginx 实现中转
打开 「应用管理」,点击「新建应用」:
务必开启外网访问,复制外网访问提供的地址。
复制下面这段配置文件,注意 server_name
后面的内容替换成第二步的外网访问地址。
+ user nginx;
+worker_processes auto;
+worker_rlimit_nofile 51200;
+
+events {
+ worker_connections 1024;
+}
+
+http {
+ resolver 8.8.8.8;
+ proxy_ssl_server_name on;
+
+ access_log off;
+ server_names_hash_bucket_size 512;
+ client_header_buffer_size 64k;
+ large_client_header_buffers 4 64k;
+ client_max_body_size 50M;
+
+ proxy_connect_timeout 240s;
+ proxy_read_timeout 240s;
+ proxy_buffer_size 128k;
+ proxy_buffers 4 256k;
+
+ server {
+ listen 80;
+ server_name tgohwtdlrmer.cloud.sealos.io; # 这个地方替换成 Sealos 提供的外网地址
+
+ location ~ /openai/(.*) {
+ proxy_pass https://api.openai.com/$1$is_args$args;
+ proxy_set_header Host api.openai.com;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ # 如果响应是流式的
+ proxy_set_header Connection '';
+ proxy_http_version 1.1;
+ chunked_transfer_encoding off;
+ proxy_buffering off;
+ proxy_cache off;
+ # 如果响应是一般的
+ proxy_buffer_size 128k;
+ proxy_buffers 4 256k;
+ proxy_busy_buffers_size 256k;
+ }
+ }
+}
+
点开高级配置。
点击「新增配置文件」。
文件名写: /etc/nginx/nginx.conf
。
文件值为刚刚复制的那段代码。
点击确认。
填写完毕后,点击右上角的「部署」,即可完成部署。
进入刚刚部署应用的详情,复制外网地址
注意:这是个 API 地址,点击打开是无效的。如需验证,可以访问:
*.cloud.sealos.io/openai/api
,如果提示Invalid URL (GET /api)
则代表成功。
修改环境变量(是 FastGPT 的环境变量,不是 Sealos 的):
+ OPENAI_BASE_URL=https://tgohwtdlrmer.cloud.sealos.io/openai/v1
+
Done!
使用 Sealos 一键部署 FastGPT
FastGPT 使用了 one-api 项目来管理模型池,其可以兼容 OpenAI 、Azure 、国内主流模型和本地模型等。
使用 Sealos 服务,无需采购服务器、无需域名,支持高并发 & 动态伸缩,并且数据库应用采用 kubeblocks 的数据库,在 IO 性能方面,远超于简单的 Docker 容器部署。可以根据需求,再下面两个区域选择部署。
新加披区的服务器在国外,可以直接访问 OpenAI,但国内用户需要梯子才可以正常访问新加坡区。国际区价格稍贵,点击下面按键即可部署👇
北京区服务提供商为火山云,国内用户可以稳定访问,但无法访问 OpenAI 等境外服务,价格约为新加坡区的 1/4。点击下面按键即可部署👇
由于需要部署数据库,部署完后需要等待 2~4 分钟才能正常访问。默认用了最低配置,首次访问时会有些慢。
根据提示,输入root_password
,和 openai
/oneapi
的地址和密钥。
点击部署后,会跳转到应用管理页面。可以点击fastgpt
主应用右侧的详情按键(名字为 fastgpt-xxxx), 如下图所示。
点击详情后,会跳转到 fastgpt 的部署管理页面,点击外网访问地址中的链接,即可打开 fastgpt 服务。
如需绑定自定义域名、修改部署参数,可以点击右上角变更,根据 sealos 的指引完成。
用户名:root
密码是刚刚一键部署时设置的root_password
在 Sealos 中,你可以打开应用管理
(App Launchpad)看到部署的 FastGPT,可以打开数据库
(Database)看到对应的数据库。
在应用管理
中,选中 FastGPT,点击变更,可以看到对应的环境变量和配置文件。
在 Sealos 上,FastGPT 一共运行了 1 个服务和 2 个数据库,如暂停和删除请注意数据库一同操作。(你可以白天启动,晚上暂停它们,省钱大法)
点击变更或重启会自动拉取镜像更新,请确保镜像tag
正确。建议不要使用latest
,改成固定版本号。
Sealos 采用按量计费的方式,也就是申请了多少 cpu、内存、磁盘,就按该申请量进行计费。具体的计费标准,可以打开sealos
控制面板中的费用中心
进行查看。
FastGPT 商业版共包含了2个应用(fastgpt, fastgpt-plus)和2个数据库,使用多 Api Key 时候需要安装 OneAPI(一个应用和一个数据库),总计3个应用和3个数据库。
点击右侧的详情,可以查看对应应用的详细信息。
升级脚本文档先看下文档,看下需要升级哪个版本。注意,不要跨版本升级!!!!!
例如,目前是4.5 版本,要升级到4.5.1,就先把镜像版本改成v4.5.1,执行一下升级脚本,等待完成后再继续升级。如果目标版本不需要执行初始化,则可以跳过。
升级步骤:
打开对应的应用,点击外网访问地址。
点击对应应用的变更->点击自定义域名->填写域名-> 操作域名 Cname -> 确认 -> 确认变。
打开 Sealos 的应用管理 -> 找到对应的应用 -> 变更 -> 往下拉到高级配置,里面有个配置文件 -> 新增或点击对应的配置文件可以进行编辑 -> 点击右上角确认变。
修改应用的环境变量,增加
+ SYSTEM_NAME=FastGPT
+SYSTEM_DESCRIPTION=
+SYSTEM_FAVICON=/favicon.ico
+HOME_URL=/app/list
+
SYSTEM_FAVICON 可以是一个网络地址
目前暂时无法 把浏览器上的logo替换。仅支持svg,待后续可视化做了后可以全部替换。 +新增一个挂载文件,文件名为:/app/projects/app/public/icon/logo.svg ,值为 svg 对应的值。
+ {
+ "license": "",
+ "system": {
+ "title": "" // 系统名称
+ }
+}
+
FastGPT 从旧版本升级到 V4.0 操作指南
如果您是从旧版本升级到 V4,由于新版 MongoDB 表变更比较大,需要按照本文档的说明执行一些初始化脚本。
需要连接上 MongoDB 数据库,执行两条命令:
+ db.models.renameCollection("apps")
+db.sharechats.renameCollection("outlinks")
+
注意:从旧版更新到 V4, MongoDB 会自动创建空表,你需要先手动删除这两个空表,再执行上面的操作。
依次执行下面 3 条命令,时间比较长,不成功可以重复执行(会跳过已经初始化的数据),直到所有数据更新完成。
+ db.chats.find({appId: {$exists: false}}).forEach(function(item){
+ db.chats.updateOne(
+ {
+ _id: item._id,
+ },
+ { "$set": {"appId":item.modelId}}
+ )
+})
+
+db.collections.find({appId: {$exists: false}}).forEach(function(item){
+ db.collections.updateOne(
+ {
+ _id: item._id,
+ },
+ { "$set": {"appId":item.modelId}}
+ )
+})
+
+db.outlinks.find({shareId: {$exists: false}}).forEach(function(item){
+ db.outlinks.updateOne(
+ {
+ _id: item._id,
+ },
+ { "$set": {"shareId":item._id.toString(),"appId":item.modelId}}
+ )
+})
+
部署新版项目,并发起 3 个 HTTP 请求(记得携带 headers.rootkey
,这个值是环境变量里的)
1 和 2 有可能会因为内存不足挂掉,可以重复执行。
FastGPT 从旧版本升级到 V4.1 操作指南
如果您是从旧版本升级到 V4.1,由于新版重新设置了对话存储结构,需要初始化原来的存储内容。
V4.1 优化了 PostgreSQL 和 MongoDB 的连接变量,只需要填 1 个 URL 即可:
注意:/fastgpt 和 /postgres 是指数据库名称,需要和旧版的变量对应。
+ # mongo 配置,不需要改. 如果连不上,可能需要去掉 ?authSource=admin
+- MONGODB_URI=mongodb://username:password@mongo:27017/fastgpt?authSource=admin
+# pg配置. 不需要改
+- PG_URL=postgresql://username:password@pg:5432/postgres
+
部署新版项目,并发起 1 个 HTTP 请求(记得携带 headers.rootkey
,这个值是环境变量里的)
FastGPT 从旧版本升级到 V4.2 操作指南
99.9%用户不影响,升级 4.2 主要是修改了配置文件中 QAModel 的格式。从原先的数组改成对象:
+ "QAModel": {
+ "model": "gpt-3.5-turbo-16k",
+ "name": "GPT35-16k",
+ "maxToken": 16000,
+ "price": 0
+}
+
改动目的是,我们认为不需要留有选择余地,选择一个最合适的模型去进行任务即可。
FastGPT 从旧版本升级到 V4.2.1 操作指南
私有部署,如果添加了配置文件,需要在配置文件中修改 VectorModels
字段。增加 defaultToken 和 maxToken,分别对应直接分段时的默认 token 数量和该模型支持的 token 上限 (通常不建议超过 3000)
+ "VectorModels": [
+ {
+ "model": "text-embedding-ada-002",
+ "name": "Embedding-2",
+ "price": 0,
+ "defaultToken": 500,
+ "maxToken": 3000
+ }
+]
+
改动目的是,我们认为不需要留有选择余地,选择一个最合适的模型去进行任务即可。
FastGPT 从旧版本升级到 V4.3 操作指南
发起 1 个 HTTP 请求 (记得携带 headers.rootkey
,这个值是环境变量里的)
+ curl --location --request POST 'https://{{host}}/api/admin/initv43' \
+--header 'rootkey: {{rootkey}}' \
+--header 'Content-Type: application/json'
+
会给 PG 数据库的 modeldata 表插入一个新列 file_id,用于存储文件 ID。
增加一个 FILE_TOKEN_KEY
环境变量,用于生成文件预览链接,过期时间为 30 分钟。
+ FILE_TOKEN_KEY=filetokenkey
+
FastGPT 从旧版本升级到 V4.4 操作指南
发起 1 个 HTTP 请求 (记得携带 headers.rootkey
,这个值是环境变量里的)
+ curl --location --request POST 'https://{{host}}/api/admin/initv44' \
+--header 'rootkey: {{rootkey}}' \
+--header 'Content-Type: application/json'
+
会给初始化 Mongo 的部分字段。
FastGPT 从旧版本升级到 V4.4.1 操作指南
发起 1 个 HTTP 请求(记得携带 headers.rootkey
,这个值是环境变量里的)
+ curl --location --request POST 'https://{{host}}/api/admin/initv441' \
+--header 'rootkey: {{rootkey}}' \
+--header 'Content-Type: application/json'
+
会给初始化 Mongo 的 dataset.files,将所有数据设置为可用。
FastGPT 从旧版本升级到 V4.4.2 操作指南
发起 1 个 HTTP 请求 (记得携带 headers.rootkey
,这个值是环境变量里的)
+ curl --location --request POST 'https://{{host}}/api/admin/initv442' \
+--header 'rootkey: {{rootkey}}' \
+--header 'Content-Type: application/json'
+
会给初始化 Mongo 的 Bill 表的索引,之前过期时间有误。
FastGPT V4.4.5 更新
发起 1 个 HTTP 请求(记得携带 headers.rootkey
,这个值是环境变量里的)
+ curl --location --request POST 'https://{{host}}/api/admin/initv445' \
+--header 'rootkey: {{rootkey}}' \
+--header 'Content-Type: application/json'
+
初始化了 variable 模块,将其合并到用户引导模块中。
FastGPT V4.4.7 更新(需执行升级脚本)
发起 1 个 HTTP 请求({{rootkey}} 替换成环境变量里的rootkey
,{{host}}替换成自己域名)
+ curl --location --request POST 'https://{{host}}/api/admin/initv447' \
+--header 'rootkey: {{rootkey}}' \
+--header 'Content-Type: application/json'
+
初始化 pg 索引以及将 file_id 中空对象转成 manual 对象。如果数据多,可能需要较长时间,可以通过日志查看进度。
FastGPT V4.5 更新
FastGPT V4.5 引入 PgVector0.5 版本的 HNSW 索引,极大的提高了知识库检索的速度,比起IVFFlat
索引大致有3~10倍的性能提升,可轻松实现百万数据毫秒级搜索。缺点在于构建索引的速度非常慢,4c16g 500w 组数据使用并行构建
大约花了 48 小时。具体参数配置可参考 PgVector官方
下面需要对数据库进行一些操作升级:
+ -- 升级插件名
+ALTER EXTENSION vector UPDATE;
+-- 插件是否升级成功,成功的话,vector插件版本为 0.5.0,旧版的为 0.4.1
+\dx
+
+-- 下面两个语句会设置 pg 在构建索引时可用的内存大小,需根据自身的数据库规格来动态配置,可配置为 1/4 的内存大小
+alter system set maintenance_work_mem = '2400MB';
+select pg_reload_conf();
+
+-- 重构数据库索引和排序
+REINDEX DATABASE postgres;
+
+-- 开始构建索引,该索引构建时间非常久,直接点击右上角的叉,退出 Terminal 即可
+CREATE INDEX CONCURRENTLY vector_index ON modeldata USING hnsw (vector vector_ip_ops) WITH (m = 16, ef_construction = 64);
+-- 可以再次点击一键链接,进入 Terminal,输入下方命令,如果看到 "vector_index" hnsw (vector vector_ip_ops) WITH (m='16', ef_construction='64') 则代表构建完成(注意,后面没有 INVALID)
+\d modeldata
+
下面的命令是基于给的 docker-compose 模板,如果数据库账号密码更换了,请自行调整。
docker-compose.yml
中pg的镜像版本,改成 ankane/pgvector:v0.5.0
或 registry.cn-hangzhou.aliyuncs.com/fastgpt/pgvector:v0.5.0
docker exec -it pg bash
psql 'postgresql://username:password@localhost:5432/postgres'
+ -- 升级插件名
+ALTER EXTENSION vector UPDATE;
+-- 插件是否升级成功,成功的话,vector插件版本为 0.5.0,旧版的为 0.4.2
+\dx
+
+-- 下面两个语句会设置 pg 在构建索引时可用的内存大小,需根据自身的数据库规格来动态配置,可配置为 1/4 的内存大小
+alter system set maintenance_work_mem = '2400MB';
+select pg_reload_conf();
+
+-- 重构数据库索引和排序
+REINDEX DATABASE postgres;
+ALTER DATABASE postgres REFRESH COLLATION VERSION;
+
+-- 开始构建索引,该索引构建时间非常久,直接关掉终端即可,不要使用 ctrl+c 关闭
+CREATE INDEX CONCURRENTLY vector_index ON modeldata USING hnsw (vector vector_ip_ops) WITH (m = 16, ef_construction = 64);
+-- 可以再次连接数据库,输入下方命令。如果看到 "vector_index" hnsw (vector vector_ip_ops) WITH (m='16', ef_construction='64') 则代表构建完成(注意,后面没有 INVALID)
+\d modeldata
+
config.json
文件 最新配置可参考: V45版本最新 config.json
FastGPT V4.5.1 更新
发起 1 个 HTTP 请求({{rootkey}} 替换成环境变量里的rootkey
,{{host}}替换成自己域名)
+ curl --location --request POST 'https://{{host}}/api/admin/initv451' \
+--header 'rootkey: {{rootkey}}' \
+--header 'Content-Type: application/json'
+
初始化内容:
该初始化接口可能速度很慢,返回超时不用管,注意看日志即可
FastGPT V4.6 更新
V4.6 版本加入了简单的团队功能,可以邀请其他用户进来管理资源。该版本升级后无法执行旧的升级脚本,且无法回退。
更新镜像至 latest 或者 v4.6 版本。商业版镜像更新至 V0.2.1
最新配置可参考:V46 版本最新 config.json,商业镜像配置文件也更新,参考最新的飞书文档。
发起 2 个 HTTP 请求 ({{rootkey}} 替换成环境变量里的 rootkey
,{{host}} 替换成自己域名)
该初始化接口可能速度很慢,返回超时不用管,注意看日志即可,需要注意的是,需确保 initv46 成功后,在执行 initv46-2
+ curl --location --request POST 'https://{{host}}/api/admin/initv46' \
+--header 'rootkey: {{rootkey}}' \
+--header 'Content-Type: application/json'
+
+ curl --location --request POST 'https://{{host}}/api/admin/initv46-2' \
+--header 'rootkey: {{rootkey}}' \
+--header 'Content-Type: application/json'
+
初始化内容: +1。创建默认团队 +2。初始化 Mongo 所有资源的团队字段 +3。初始化 Pg 的字段 +4。初始化 Mongo Data
旧的 4.6 版本由于缺少一个字段,导致文件导入时知识库数据无法显示,可执行下面的脚本:
https://xxxxx/api/admin/initv46-fix
+ curl --location --request POST 'https://{{host}}/api/admin/initv46-fix' \
+--header 'rootkey: {{rootkey}}' \
+--header 'Content-Type: application/json'
+
FastGPT V4.6 .1
FastGPT V4.6.2
发起 1 个 HTTP 请求 ({{rootkey}} 替换成环境变量里的 rootkey
,{{host}} 替换成自己域名)
+ curl --location --request POST 'https://{{host}}/api/admin/initv462' \
+--header 'rootkey: {{rootkey}}' \
+--header 'Content-Type: application/json'
+
初始化说明:
FastGPT V4.6.3
发起 1 个 HTTP 请求 ({{rootkey}} 替换成环境变量里的 rootkey
,{{host}} 替换成自己域名)
+ curl --location --request POST 'https://{{host}}/api/admin/initv463' \
+--header 'rootkey: {{rootkey}}' \
+--header 'Content-Type: application/json'
+
初始化说明:
FastGPT V4.6.4
发起 1 个 HTTP 请求 ({{rootkey}} 替换成环境变量里的 rootkey
,{{host}} 替换成自己域名)
+ curl --location --request POST 'https://{{host}}/api/admin/initv464' \
+--header 'rootkey: {{rootkey}}' \
+--header 'Content-Type: application/json'
+
初始化说明:
身份鉴权
地址,仅需3个接口
即可完全接入已有用户系统。具体参考分享链接身份鉴权FastGPT V4.6.5
由于 openai 已开始弃用 function call,改为 toolChoice。FastGPT 同步的修改了对于的配置和调用方式,需要对配置文件做一些修改:
functionCall
字段,改成toolChoice
即可。设置为true
的模型,会默认走 openai 的 tools 模式;未设置或设置为false
的,会走提示词生成模式。问题优化模型与内容提取模型使用同一组配置。
"ReRankModels": []
FastGPT V4.6.6
为了减少代码重复度,我们对配置文件做了一些修改:点击查看最新的配置文件
更新商业版镜像到 4.6.6 版本。
将旧版配置文件中的 SystemParams.pluginBaseUrl
放置到环境变量中:
PRO_URL=商业版镜像地址(此处不再需要以 /api 结尾),例如:
PRO_URL=http://fastgpt-plugin.ns-hsss5d.svc.cluster.local:3000
原本在配置文件中的 FeConfig
已被移除,可以直接打开新的商业版镜像外网地址进行配置。包括 FastGPT 的各个参数和模型都可以直接在商业版镜像中配置,无需再变更 config.json
文件。
FastGPT V4.6.7
发起 1 个 HTTP 请求 ({{rootkey}} 替换成环境变量里的 rootkey
,{{host}} 替换成自己域名)
+ curl --location --request POST 'https://{{host}}/api/admin/initv467' \
+--header 'rootkey: {{rootkey}}' \
+--header 'Content-Type: application/json'
+
初始化说明:
FastGPT V4.6.8更新说明
command
和entrypoint
+ mongo:
+ image: mongo:5.0.18
+ # image: registry.cn-hangzhou.aliyuncs.com/fastgpt/mongo:5.0.18 # 阿里云
+ container_name: mongo
+ ports:
+ - 27017:27017
+ networks:
+ - fastgpt
+ command: mongod --keyFile /data/mongodb.key --replSet rs0
+ environment:
+ # 这里密码注意要和以前的一致
+ - MONGO_INITDB_ROOT_USERNAME=username
+ - MONGO_INITDB_ROOT_PASSWORD=password
+ volumes:
+ - ./mongo/data:/data/db
+ entrypoint:
+ - bash
+ - -c
+ - |
+ openssl rand -base64 128 > /data/mongodb.key
+ chmod 400 /data/mongodb.key
+ chown 999:999 /data/mongodb.key
+ echo 'const isInited = rs.status().ok === 1
+ if(!isInited){
+ rs.initiate({
+ _id: "rs0",
+ members: [
+ { _id: 0, host: "mongo:27017" }
+ ]
+ })
+ }' > /data/initReplicaSet.js
+ # 启动MongoDB服务
+ exec docker-entrypoint.sh "$@" &
+
+ # 等待MongoDB服务启动
+ until mongo -u myusername -p mypassword --authenticationDatabase admin --eval "print('waited for connection')" > /dev/null 2>&1; do
+ echo "Waiting for MongoDB to start..."
+ sleep 2
+ done
+
+ # 执行初始化副本集的脚本
+ mongo -u myusername -p mypassword --authenticationDatabase admin /data/initReplicaSet.js
+
+ # 等待docker-entrypoint.sh脚本执行的MongoDB服务进程
+ wait $!
+
+ # 重启 Mongo
+docker-compose down
+docker-compose up -d
+
去除了重复的模型配置,LLM模型都合并到一个属性中:点击查看最新的配置文件
商业版用户需要执行一个初始化,格式化团队信息。
发起 1 个 HTTP 请求 ({{rootkey}} 替换成环境变量里的 rootkey
,{{host}} 替换成商业版域名)
+ curl --location --request POST 'https://{{host}}/api/init/v468' \
+--header 'rootkey: {{rootkey}}' \
+--header 'Content-Type: application/json'
+
会初始化计费系统,内部使用可把免费的存储拉大。
defaultConfig
传入默认的配置。ChatNextWeb
的流,更加丝滑。此外,之前提到的乱码、中断,刷新后又正常了,可能会修复)FastGPT V4.6.9更新说明
增加 oneapi 地址和令牌。
+ OPENAI_BASE_URL=http://oneapi:3000/v1
+CHAT_API_KEY=sk-fastgpt
+
从任意终端,发起 1 个 HTTP 请求。其中 {{rootkey}} 替换成环境变量里的 rootkey
;{{host}} 替换成自己域名
+ curl --location --request POST 'https://{{host}}/api/admin/initv469' \
+--header 'rootkey: {{rootkey}}' \
+--header 'Content-Type: application/json'
+
token
字段(总token数量)。FastGPT V4.7更新说明
增加一些 Boolean 值,用于决定不同功能块可以使用哪些模型,同时增加了模型的 logo:点击查看最新的配置文件
升级完镜像后。从任意终端,发起 1 个 HTTP 请求。其中 {{rootkey}} 替换成环境变量里的 rootkey
;{{host}} 替换成自己域名
+ curl --location --request POST 'https://{{host}}/api/admin/initv47' \
+--header 'rootkey: {{rootkey}}' \
+--header 'Content-Type: application/json'
+
脚本功能:
4.7对ReRank模型进行了格式变动,兼容 cohere 的格式,可以直接使用 cohere 提供的 API。如果是本地的 ReRank 模型,需要修改镜像为:registry.cn-hangzhou.aliyuncs.com/fastgpt/bge-rerank-base:v0.1
。
cohere的重排模型对中文不是很好,感觉不如 bge 的好用,接入教程如下:
+ {
+ "reRankModels": [
+ {
+ "model": "rerank-multilingual-v2.0", // 这里的 model 需要对应 cohere 的模型名
+ "name": "检索重排", // 随意
+ "requestUrl": "https://api.cohere.ai/v1/rerank",
+ "requestAuth": "Coherer上申请的key"
+ }
+ ]
+}
+
functionCall
设置为 true
, toolChoice
设置为 false
。如果 toolChoice
为 true,会走 tool 模式。FastGPT V4.7.1 更新说明
从任意终端,发起 1 个 HTTP 请求。其中 {{rootkey}} 替换成环境变量里的 rootkey
;{{host}} 替换成FastGPT的域名。
+ curl --location --request POST 'https://{{host}}/api/admin/clearInvalidData' \
+--header 'rootkey: {{rootkey}}' \
+--header 'Content-Type: application/json'
+
该请求会执行脏数据清理(清理无效的文件、清理无效的图片、清理无效的知识库集合、清理无效的向量)
增加了Laf环境配置:点击查看最新的配置文件
FastGPT V4.8 更新说明
FastGPT workflow V2上线,支持更加简洁的工作流模式。
由于工作流差异较大,不少地方需要手动重新构建。请依次重建插件和应用
简易尽快更新工作流,避免未来持续迭代后导致无法兼容。
给应用和插件增加了 version 的字段,用于标识是旧工作流还是新工作流。当你更新 4.8 后,保存和新建的工作流均为新版,旧版工作流会有一个重置的弹窗提示。并且,如果是通过 API 和 分享链接 调用的工作流,仍可以正常使用,直到你下次保存它们。
商业版用户如果配置了邮件验证码,需要在管理端 -> 项目配置 -> 登录配置 -> 邮箱登录配置 -> 修改 邮箱服务SMTP地址,之前只能配置别名,现在可以配置自定义的地址。下面是一组别名和实际地址关系:
qq: smtp.qq.com +gmail: smtp.gmail.com
FastGPT V4.8.1 更新说明
从任意终端,发起 1 个 HTTP 请求。其中 {{rootkey}} 替换成环境变量里的 rootkey
;{{host}} 替换成FastGPT的域名。
+ curl --location --request POST 'https://{{host}}/api/admin/initv481' \
+--header 'rootkey: {{rootkey}}' \
+--header 'Content-Type: application/json'
+
由于之前集合名不规范,该初始化会重置表名。请在初始化前,确保 dataset.trainings 表没有数据。 +最好更新该版本时,暂停所有进行中业务,再进行初始化,避免数据冲突。
从任意终端,发起 1 个 HTTP 请求。其中 {{rootkey}} 替换成环境变量里的 rootkey
;{{host}} 替换成FastGPT的域名。
+ curl --location --request POST 'https://{{host}}/api/admin/clearInvalidData' \
+--header 'rootkey: {{rootkey}}' \
+--header 'Content-Type: application/json'
+
初始化完后,可以执行这个命令。之前定时清理的定时器有些问题,部分数据没被清理,可以手动执行清理。
使用 Chat api 接口需要注意,增加了 event: updateVariables 事件,用于更新变量。
FastGPT V4.8.10 更新说明
fastgpt-pro
镜像,增加沙盒的环境变量:SANDBOX_URL=http://xxxxx:3000
fastgpt-pro
镜像和fastgpt
镜像增加环境变量,以便更好的存储系统日志:
+ LOG_LEVEL=debug
+STORE_LOG_LEVEL=warn
+
从任意终端,发起 1 个 HTTP 请求。其中 {{rootkey}} 替换成环境变量里的 rootkey
;{{host}} 替换成FastGPT 域名。
+ curl --location --request POST 'https://{{host}}/api/admin/initv4810' \
+--header 'rootkey: {{rootkey}}' \
+--header 'Content-Type: application/json'
+
完整内容请见:4.8.10 release
FastGPT V4.8.11 更新说明
如需增加 openai o1 模型,可添加如下配置:
+ {
+ "model": "o1-mini",
+ "name": "o1-mini",
+ "avatar": "/imgs/model/openai.svg",
+ "maxContext": 125000,
+ "maxResponse": 65000,
+ "quoteMaxToken": 120000,
+ "maxTemperature": 1.2,
+ "charsPointsPrice": 0,
+ "censor": false,
+ "vision": false,
+ "datasetProcess": true,
+ "usedInClassify": true,
+ "usedInExtractFields": true,
+ "usedInToolCall": true,
+ "usedInQueryExtension": true,
+ "toolChoice": false,
+ "functionCall": false,
+ "customCQPrompt": "",
+ "customExtractPrompt": "",
+ "defaultSystemChatPrompt": "",
+ "defaultConfig": {
+ "temperature": 1
+ }
+},
+{
+ "model": "o1-preview",
+ "name": "o1-preview",
+ "avatar": "/imgs/model/openai.svg",
+ "maxContext": 125000,
+ "maxResponse": 32000,
+ "quoteMaxToken": 120000,
+ "maxTemperature": 1.2,
+ "charsPointsPrice": 0,
+ "censor": false,
+ "vision": false,
+ "datasetProcess": true,
+ "usedInClassify": true,
+ "usedInExtractFields": true,
+ "usedInToolCall": true,
+ "usedInQueryExtension": true,
+ "toolChoice": false,
+ "functionCall": false,
+ "customCQPrompt": "",
+ "customExtractPrompt": "",
+ "defaultSystemChatPrompt": "",
+ "defaultConfig": {
+ "temperature": 1
+ }
+}
+
从任意终端,发起 1 个 HTTP 请求。其中 {{rootkey}} 替换成环境变量里的 rootkey
;{{host}} 替换成FastGPT 商业版域名。
+ curl --location --request POST 'https://{{host}}/api/admin/init/4811' \
+--header 'rootkey: {{rootkey}}' \
+--header 'Content-Type: application/json'
+
会初始化团队成员组。
defaultConfig
配置,覆盖 temperature
、max_tokens
和 stream
配置,o1 不支持 stream 模式。非流模式
,同时简易模式也可以选择工作流作为插件了,简易模式调用子应用时,都将强制使用非流模式。FastGPT V4.8.12 更新说明
从任意终端,发起 1 个 HTTP 请求。其中 {{rootkey}} 替换成环境变量里的 rootkey
;{{host}} 替换成FastGPT 管理端域名。
+ curl --location --request POST 'https://{{host}}/api/admin/init/4812' \
+--header 'rootkey: {{rootkey}}' \
+--header 'Content-Type: application/json'
+
会初始化应用和知识库的成员组数据。
由于 js int64 精度丢失问题,之前私有化使用 milvus 或者 zilliz 的用户,如果存在数据精度丢失的问题,需要重构 Milvus 数据。(可以查看 dataset_datas 表中,indexes 中的 dataId 是否末尾精度丢失)。使用 PG 的用户不需要操作。
从任意终端,发起 1 个 HTTP 请求。其中 {{rootkey}} 替换成环境变量里的 rootkey
;{{host}} 替换成FastGPT 主域名。
+ curl --location --request POST 'https://{{host}}/api/admin/resetMilvus' \
+--header 'rootkey: {{rootkey}}' \
+--header 'Content-Type: application/json'
+
FastGPT V4.8.13 更新说明
FE_DOMAIN=http://xx.com
,值为 fastgpt 前端访问地址,注意后面不要加/
。可以自动补齐相对文件地址的前缀。虽然依然兼容旧版的文件上传编排,但是未来两个版本内将会去除兼容代码,请尽快调整编排,以适应最新的文件上传逻辑。尤其是嵌套应用的文件传递,未来将不会自动传递,必须手动指定传递的文件。具体内容可参考: 文件上传变更
FastGPT V4.8.14 更新说明
milvus版本使用:v4.8.14-milvus-fix 镜像。
可以允许你配置用户加载对话时,自动触发一次工作流。可以用于一些 CRM 系统,可以快速的引导用户使用,无需等待用户主动触发。
FastGPT V4.8.15 更新说明
源码模式 | 预览模式 | 全屏模式 |
---|---|---|
从任意终端,发起 1 个 HTTP 请求。其中 {{rootkey}} 替换成环境变量里的 rootkey
;{{host}} 替换成FastGPT 域名。
+ curl --location --request POST 'https://{{host}}/api/admin/initv4815' \
+--header 'rootkey: {{rootkey}}' \
+--header 'Content-Type: application/json'
+
会重置应用定时执行的字段,把 null 去掉,减少索引大小。
从任意终端,发起 1 个 HTTP 请求。其中 {{rootkey}} 替换成环境变量里的 rootkey
;{{host}} 替换成fastgpt-pro域名。
+ curl --location --request POST 'https://{{host}}/api/admin/init/refreshFreeUser' \
+--header 'rootkey: {{rootkey}}' \
+--header 'Content-Type: application/json'
+
重新计算一次免费版用户的时长,之前有版本升级时没有重新计算时间,导致会误发通知。
FastGPT V4.8.16 更新说明
参考最新的配置文件,更新 config.json
或 admin 中模型文件配置。给 LLMModel 和 VectorModel 增加 provider
字段,以便进行模型分类。例如:
+ {
+ "provider": "OpenAI", // 这是新增的
+ "model": "gpt-4o",
+ "name": "gpt-4o",
+ "maxContext": 125000,
+ "maxResponse": 4000,
+ "quoteMaxToken": 120000,
+ "maxTemperature": 1.2,
+ "charsPointsPrice": 0,
+ "censor": false,
+ "vision": true,
+ "datasetProcess": true,
+ "usedInClassify": true,
+ "usedInExtractFields": true,
+ "usedInToolCall": true,
+ "usedInQueryExtension": true,
+ "toolChoice": true,
+ "functionCall": false,
+ "customCQPrompt": "",
+ "customExtractPrompt": "",
+ "defaultSystemChatPrompt": "",
+ "defaultConfig": {},
+ "fieldMap": {}
+}
+
FastGPT V4.8.17 更新说明
从任意终端,发起 1 个 HTTP 请求。其中 {{rootkey}} 替换成环境变量里的 rootkey
;{{host}} 替换成FastGPT 域名。
+ curl --location --request POST 'https://{{host}}/api/admin/initv4817' \
+--header 'rootkey: {{rootkey}}' \
+--header 'Content-Type: application/json'
+
会将用户绑定的 OpenAI 账号移动到团队中。
/api/v1/chat/completions 接口返回值调整,对话节点、工具节点等使用到模型的节点,将不再返回 tokens
字段,改为返回 inputTokens
和 outputTokens
字段,分别表示输入和输出的 Token 数量。
FastGPT V4.8.18 更新说明
从任意终端,发起 1 个 HTTP 请求。其中 {{rootkey}} 替换成环境变量里的 rootkey
;{{host}} 替换成FastGPT 域名。
+ curl --location --request POST 'https://{{host}}/api/admin/initv4818' \
+--header 'rootkey: {{rootkey}}' \
+--header 'Content-Type: application/json'
+
会迁移全文检索表,时间较长,迁移期间全文检索会失效,日志中会打印已经迁移的数据长度。
FastGPT V4.8.2 更新说明
+ SANDBOX_URL=内网地址
+
可以拉取最新 docker-compose.yml 文件参考
sandbox
SANDBOX_URL
FastGPT V4.8.3 更新说明
FastGPT V4.8.4 更新说明
从任意终端,发起 1 个 HTTP 请求。其中 {{rootkey}} 替换成环境变量里的 rootkey
;{{host}} 替换成FastGPT 商业版的域名。
+ curl --location --request POST 'https://{{host}}/api/admin/init/484' \
+--header 'rootkey: {{rootkey}}' \
+--header 'Content-Type: application/json'
+
FastGPT V4.8.5 更新说明
从任意终端,发起 1 个 HTTP 请求。其中 {{rootkey}} 替换成环境变量里的 rootkey
;{{host}} 替换成FastGPT 域名。
+ curl --location --request POST 'https://{{host}}/api/admin/initv485' \
+--header 'rootkey: {{rootkey}}' \
+--header 'Content-Type: application/json'
+
会把插件的数据表合并到应用中,插件表不会删除。
商业版用户执行额外的初始化
从任意终端,发起 1 个 HTTP 请求。其中 {{rootkey}} 替换成环境变量里的 rootkey
;{{host}} 替换成FastGPT 商业版的域名:
+ curl --location --request POST 'https://{{host}}/api/admin/init/485' \
+--header 'rootkey: {{rootkey}}' \
+--header 'Content-Type: application/json'
+
会重置知识库权限系统。
a
字段时,自动将q
作为补充索引。%
,且为转义时会导致页面崩溃FastGPT V4.8.6 更新说明
从任意终端,发起 1 个 HTTP 请求。其中 {{rootkey}} 替换成环境变量里的 rootkey
;{{host}} 替换成FastGPT 域名。
+ curl --location --request POST 'https://{{host}}/api/admin/initv486' \
+--header 'rootkey: {{rootkey}}' \
+--header 'Content-Type: application/json'
+
会初始化应用的继承权限
FastGPT V4.8.7 更新说明
FastGPT V4.8.8 更新说明
从任意终端,发起 1 个 HTTP 请求。其中 {{rootkey}} 替换成环境变量里的 rootkey
;{{host}} 替换成FastGPT 域名。
+ curl --location --request POST 'https://{{host}}/api/admin/initv488' \
+--header 'rootkey: {{rootkey}}' \
+--header 'Content-Type: application/json'
+
会初始化知识库的继承权限
FastGPT V4.8.9 更新说明
从任意终端,发起 1 个 HTTP 请求。其中 {{rootkey}} 替换成环境变量里的 rootkey
;{{host}} 替换成FastGPT 商业版域名。
+ curl --location --request POST 'https://{{host}}/api/admin/init/489' \
+--header 'rootkey: {{rootkey}}' \
+--header 'Content-Type: application/json'
+
会初始化多租户的通知方式,仅内部使用的,无需执行。
FastGPT 版本更新介绍及升级操作
FastGPT 升级说明
FastGPT 升级包括两个步骤:
git版
阿里云
镜像由镜像名和Tag
组成,例如: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.6.1 代表4.6.3
版本镜像,具体可以看 docker hub, github 仓库。
修改镜像 - 确认变更
如果要修改配置文件,可以拉到下面的配置文件
进行修改。
直接修改yml
文件中的image:
即可。随后执行:
+ docker-compose pull
+docker-compose up -d
+
镜像更新完后,可以查看文档中的版本介绍
,通常需要执行升级脚本的版本都会标明包含升级脚本
,打开对应的文档,参考说明执行升级脚本即可,大部分时候都是需要发送一个POST
请求。
数据表出现大幅度变更,无法通过设置默认值,或复杂度较高时,会通过升级脚本来更新部分数据表字段。 +严格按初始化步骤进行操作,不会造成旧数据丢失。但在初始化过程中,如果数据量大,需要初始化的时间较长,这段时间可能会造成服务无法正常使用。
{{}} 代表变量, {{host}}代表一个名为 host 的变量。指的是你服务器的域名或 IP。
Sealos 中,你可以在下图中找到你的域名:
从docker-compose.yml
中的environment
中获取,对应的是ROOT_KEY
的值。
sealos 中可以从上图左侧的环境变量中获取。
建议逐一版本升级,防止脏数据。例如,当前版本是4.4.7,需要升级到4.6。
逐一升级
FastGPT 常见应用使用问题,包括简易应用、工作流和插件
问题分类节点具有获取上下文信息的能力,当处理两个关联性较大的问题时,模型的判断准确性往往依赖于这两个问题之间的联系和模型的能力。例如,当用户先问“我该如何使用这个功能?”接着又询问“这个功能有什么限制?”时,模型借助上下文信息,就能够更精准地理解并响应。
但是,当连续问题之间的关联性较小,模型判断的准确度可能会受到限制。在这种情况下,我们可以引入全局变量的概念来记录分类结果。在后续的问题分类阶段,首先检查全局变量是否存有分类结果。如果有,那么直接沿用该结果;若没有,则让模型自行判断。
建议:构建批量运行脚本进行测试,评估问题分类的准确性。
发布后,后台生效。
在针对知识库的回答要求里有, 要给它配置提示词,不然他就是默认的,默认的里面就有该语法。
FastGPT 常见聊天框问题
应用需要点击发布后,聊天才会更新应用。
常见知识库使用问题
将文件另存为 UTF-8 编码格式。
FastGPT回复长度计算公式:
最大回复=min(配置的最大回复(内置的限制),最大上下文(输入和输出的总和)-历史记录)
18K模型->输入与输出的和
输出增多->输入减小
所以可以:
配置的最大回复:
FastGPT回复长度计算公式:
最大回复=min(配置的最大回复(内置的限制),最大上下文(输入和输出的总和)-历史记录)
18K模型->输入与输出的和
输出增多->输入减小
所以可以:
配置的最大回复:
是oneapi渠道的问题,可以换个模型用or换一家中转站
大概率是api-key填写了openapi,然后部署的服务器在国内,不能访问海外的api,可以使用中转或者反代的手段解决访问不到的问题
如何通过外部渠道与 FastGPT 集成,实现对多种平台的支持
提示词给引导,不要以markdown格式输出。图片需要二开 cow 实现图片链接截取并发送。
在应用的对话日志里可以查看。
钉钉 SSO 登录
登录 钉钉开放平台,创建一个应用。
点击进入创建好的应用后,点开安全设置
,配置出口 IP(服务器 IP),和重定向 URL。重定向 URL 填写逻辑:
{{fastgpt 域名}}/login/provider
点击进入创建好的应用后,点开权限设置
,开放两个权限: 个人手机号信息
和通讯录个人信息读权限
点击进入创建好的应用后,点开版本管理与发布
,随便创建一个新版本即可。
名字都是对应上,直接填写即可。
FastGPT AI 相关参数配置说明
在 FastGPT 的 AI 对话模块中,有一个 AI 高级配置,里面包含了 AI 模型的参数配置,本文详细介绍这些配置的含义。
旧版名字叫做:返回 AI 内容;新版改名:流响应。
这是一个开关,打开的时候,当 AI 对话模块运行时,会将其输出的内容返回到浏览器(API响应); +如果关闭,会强制使用非流模式调用模型,并且 AI 输出的内容不会返回到浏览器,但是生成的内容仍可以通过【AI回复】进行输出。你可以将【AI回复】连接到其他模块中进行二次使用。
代表模型最多容纳的文字数量。
支持函数调用的模型,在使用工具时更加准确。
越低回答越严谨,少废话(实测下来,感觉差别不大)
最大回复 token 数量。注意,是回复的Tokens!不是上下文 tokens。
通常,回复上限=min(模型允许的最大回复上限, 最大上下文-已用上下文)
所以,一般配置模型时,不会把最大上下文配置成模型实际最大上下文,而是预留预定空间给回答,例如 128k 模型,可以配置 max_context=115000
被放置在上下文数组的最前面,role 为 system,用于引导模型。
可以配置模型支持的记忆轮数,如果模型的超出上下文,系统会自动截断,尽可能保证不超模型上下文。
所以尽管配置 30 轮对话,实际运行时候,不一定会达到 30 轮。
进行知识库搜索后,你可以自定义组织检索结果构成的提示词,这个配置,仅工作流中 AI 对话节点可用。并且,只会在有引用知识库内容时才会生效。
想使用明白这两个变量,首先要了解传递传递给 AI 模型的消息格式。它是一个数组,FastGPT 中这个数组的组成形式为:
+ [
+ 内置提示词(config.json 配置,一般为空)
+ 系统提示词 (用户输入的提示词)
+ 历史记录
+ 问题(由引用提示词、引用模板和用户问题组成)
+]
+
Tips: 可以通过点击上下文按键查看完整的上下文组成,便于调试。
简易模式已移除该功能,仅在工作流中可配置,可点击工作流中AI对话节点
内,知识库引用旁边的setting icon
进行配置。随着模型的增强,这部分功能将逐步弱化。
引用模板和引用提示词通常是成对出现,引用提示词依赖引用模板。
FastGPT 知识库采用 QA 对(不一定都是问答格式,仅代表两个变量)的格式存储,在转义成字符串时候会根据引用模板来进行格式化。知识库包含多个可用变量: q, a, sourceId(数据的ID), index(第n个数据), source(数据的集合名、文件名),score(距离得分,0-1) 可以通过 {{q}} {{a}} {{sourceId}} {{index}} {{source}} {{score}} 按需引入。下面一个模板例子:
可以通过 知识库结构讲解 了解详细的知识库的结构。
+ {instruction:"{{q}}",output:"{{a}}",source:"{{source}}"}
+
搜索到的知识库,会自动将 q,a,source 替换成对应的内容。每条搜索到的内容,会通过 \n
隔开。例如:
+ {instruction:"电影《铃芽之旅》的导演是谁?",output:"电影《铃芽之旅》的导演是新海诚。",source:"手动输入"}
+{instruction:"本作的主人公是谁?",output:"本作的主人公是名叫铃芽的少女。",source:""}
+{instruction:"电影《铃芽之旅》男主角是谁?",output:"电影《铃芽之旅》男主角是宗像草太,由松村北斗配音。",source:""}
+{instruction:"电影《铃芽之旅》的编剧是谁?22",output:"新海诚是本片的编剧。",source:"手动输入"}
+
引用模板需要和引用提示词一起使用,提示词中可以写引用模板的格式说明以及对话的要求等。可以使用 {{quote}} 来使用 引用模板,使用 {{question}} 来引入问题。例如:
+ 你的背景知识:
+"""
+{{quote}}
+"""
+对话要求:
+1. 背景知识是最新的,其中 instruction 是相关介绍,output 是预期回答或补充。
+2. 使用背景知识回答问题。
+3. 背景知识无法回答问题时,你可以礼貌的的回答用户问题。
+我的问题是:"{{question}}"
+
转义后则为:
+ 你的背景知识:
+"""
+{instruction:"电影《铃芽之旅》的导演是谁?",output:"电影《铃芽之旅》的导演是新海诚。",source:"手动输入"}
+{instruction:"本作的主人公是谁?",output:"本作的主人公是名叫铃芽的少女。",source:""}
+{instruction:"电影《铃芽之旅》男主角是谁?",output:"电影《铃芽之旅》男主角是宗像草太,由松村北斗配音}
+"""
+对话要求:
+1. 背景知识是最新的,其中 instruction 是相关介绍,output 是预期回答或补充。
+2. 使用背景知识回答问题。
+3. 背景知识无法回答问题时,你可以礼貌的的回答用户问题。
+我的问题是:"{{question}}"
+
引用模板规定了搜索出来的内容如何组成一句话,其由 q,a,index,source 多个变量组成。
引用提示词由引用模板
和提示词
组成,提示词通常是对引用模板的一个描述,加上对模型的要求。
我们通过一组你是谁
的手动数据,对通用模板与问答模板的效果进行对比。此处特意打了个搞笑的答案,通用模板下 GPT35 就变得不那么听话了,而问答模板下 GPT35 依然能够回答正确。这是由于结构化的提示词,在大语言模型中具有更强的引导作用。
Tips: 建议根据不同的场景,每种知识库仅选择1类数据类型,这样有利于充分发挥提示词的作用。
通用模板配置及效果 | 问答模板配置及效果 |
---|---|
使用非严格模板,我们随便询问一个不在知识库中的内容,模型通常会根据其自身知识进行回答。
非严格模板效果 | 选择严格模板 | 严格模板效果 |
---|---|---|
instruction
和output
,清楚的告诉模型,output
是一个预期的答案。FastGPT 对话问题引导
你可以为你的应用提前预设一些问题,用户在输入时,会根据输入的内容,动态搜索这些问题作为提示,从而引导用户更快的进行提问。
你可以直接在 FastGPT 中配置词库,或者提供自定义词库接口。
需要保证这个接口可以被用户浏览器访问。
请求:
+ curl --location --request GET 'http://localhost:3000/api/core/chat/inputGuide/query?appId=663c75302caf8315b1c00194&searchKey=你'
+
其中 appId
为应用ID,searchKey
为搜索关键字,最多是50个字符。
响应
+ {
+ "code": 200,
+ "statusText": "",
+ "message": "",
+ "data": [
+ "是你",
+ "你是谁呀",
+ "你好好呀",
+ "你好呀",
+ "你是谁!",
+ "你好"
+ ]
+}
+
data是一个数组,包含了搜索到的问题,最多只需要返回5个问题。
参数说明:
FastGPT 知识库集合标签使用说明
知识库集合标签是 FastGPT 商业版特有功能。它允许你对知识库中的数据集合添加标签进行分类,更高效地管理知识库数据。
而进一步可以在问答中,搜索知识库时添加集合过滤,实现更精确的搜索。
在知识库详情页面,可以对标签进行管理,可执行的操作有
也可以利用标签对数据集合进行筛选
利用标签可以在知识库搜索时,通过填写「集合过滤」这一栏来实现更精确的搜索,具体的填写示例如下
+ {
+ "tags": {
+ "$and": ["标签 1","标签 2"],
+ "$or": ["有 $and 标签时,and 生效,or 不生效"]
+ },
+ "createTime": {
+ "$gte": "YYYY-MM-DD HH:mm 格式即可,集合的创建时间大于该时间",
+ "$lte": "YYYY-MM-DD HH:mm 格式即可,集合的创建时间小于该时间,可和 $gte 共同使用"
+ }
+}
+
在填写时有两个注意的点,
string
类型的标签名,也可以为 null
,而 null
代表着未设置标签的数据集合$and
和 $or
两种条件类型,在同时设置了 $and
和 $or
的情况下,只有 $and
会生效FastGPT 文件输入功能介绍
从 4.8.9 版本起,FastGPT 支持在简易模式
和工作流
中,配置用户上传文件、图片功能。下面先简单介绍下如何使用文件输入功能,最后是介绍下文件解析的工作原理。
简易模式打开文件上传后,会使用工具调用模式,也就是由模型自行决策,是否需要读取文件内容。
可以找到左侧文件上传的配置项,点击其右侧的开启
/关闭
按键,即可打开配置弹窗。
随后,你的调试对话框中,就会出现一个文件选择的 icon,可以点击文件选择 icon,选择你需要上传的文件。
工作模式
从 4.8.13 版本起,简易模式的文件读取将会强制解析文件并放入 system 提示词中,避免连续对话时,模型有时候不会主动调用读取文件的工具。
工作流中,可以在系统配置中,找到文件输入
配置项,点击其右侧的开启
/关闭
按键,即可打开配置弹窗。
在工作流中,使用文件的方式很多,最简单的就是类似下图中,直接通过工具调用接入文档解析,实现和简易模式一样的效果。
当然,你也可以在工作流中,对文档进行内容提取、内容分析等,然后将分析的结果传递给 HTTP 或者其他模块,从而实现文件处理的 SOP。
不同于图片识别,LLM 模型目前没有支持直接解析文档的能力,所有的文档“理解”都是通过文档转文字后拼接 prompt 实现。这里通过几个 FAQ 来解释文档解析的工作原理,理解文档解析的原理,可以更好的在工作流中使用文档解析功能。
FastGPT 的对话记录存储结构中,role=user 的消息,value 值会按以下结构存储:
+ type UserChatItemValueItemType = {
+ type: 'text' | 'file'
+ text?: {
+ content: string;
+ };
+ file?: {
+ type: 'img' | 'doc'
+ name?: string;
+ url: string;
+ };
+};
+
也就是说,上传的图片和文档,都会以 URL 的形式存储在库中,并不会存储解析后的文档内容
。
文档解析节点不会处理图片,图片链接会被过滤,图片识别请直接使用支持图片识别的 LLM 模型。
文档解析依赖文档解析节点,这个节点会接收一个array<string>
类型的输入,对应的是文件输入的 URL;输出的是一个string
,对应的是文档解析后的内容。
文档
类型的 URL,它是通过文件 URL 解析出来的文名件后缀
去判断的。如果你同时选择了文档和图片,图片会被忽略。按下列的模板,对多个文件进行拼接,即文件名+文件内容的形式组成一个字符串,不同文档之间通过分隔符:\n******\n
进行分割。
+ File: ${filename}
+<Content>
+${content}
+</Content>
+
在 AI 节点(AI对话/工具调用)中,新增了一个文档链接的输入,可以直接引用文档的地址,从而实现文档内容的引用。
它接收一个Array<string>
类型的输入,最终这些 url 会被解析,并进行提示词拼接,放置在 role=system 的消息中。提示词模板如下:
+ 将 <FilesContent></FilesContent> 中的内容作为本次对话的参考:
+<FilesContent>
+{{quote}}
+</FilesContent>
+
由于与 4.8.9 版本有些差异,尽管我们做了向下兼容,避免工作流立即不可用。但是请尽快的按新版本规则进行调整工作流,后续将会去除兼容性代码。
快速体验 FastGPT 基础功能
更多使用技巧,查看视屏教程
开始前,请准备一份测试电子文档,WORD,PDF,TXT,excel,markdown 都可以,比如公司休假制度,不涉密的销售说辞,产品知识等等。
这里使用 FastGPT 中文 README 文件为例。
首先我们需要创建一个知识库。
知识库创建完之后我们需要上传一点内容。
上传内容这里有四种模式:
这里,我们选择 QA 拆分,让 AI 自动生成问答,若问答质量不高,可以后期手动修改。
点击上传后我们需要等待数据处理完成,等到我们上传的文件状态为可用。
点击「应用」按钮来新建一个应用,这里有四个模板,我们选择「知识库 + 对话引导」。
应用创建后来再应用详情页找到「知识库」模块,把我们刚刚创建的知识库添加进去。
添加完知识库后记得点击「保存并预览」,这样我们的应用就和知识库关联起来了。
然后我们就可以愉快的开始聊天啦。
如何在FastGPT中通过Markdown嵌入HTML代码块,并提供全屏、源代码切换等交互功能
源码模式 | 预览模式 | 全屏模式 |
---|---|---|
尽管Markdown本身支持嵌入HTML标签,但由于安全问题,许多平台和环境对HTML的渲染进行了限制,特别是在渲染动态内容、交互式元素以及外部资源时。这些限制大大降低了用户在撰写和展示复杂文档时的灵活性,尤其是当需要嵌入外部HTML内容时。为了应对这一问题,我们通过使用 iframe
来嵌入和渲染HTML内容,并结合 sandbox
属性,保障了外部HTML的安全渲染。
该功能模块的主要目的是扩展FastGPT在Markdown渲染中的能力,支持嵌入和渲染HTML内容。由于是利用 Iframe 渲染,所以无法确认内容的高度,FastGPT 中会给 Iframe 设置一个固定高度来进行渲染。并且不支持 HTML 中执行 js 脚本。
本模块通过以下方式实现了HTML渲染和互动功能:
iframe
类型的代码块展示HTML内容。使用自定义的 IframeBlock
组件,结合 sandbox
属性来保障嵌入内容的安全性。sandbox
限制了外部HTML中的行为,如禁用脚本执行、限制表单提交等,确保HTML内容的安全性。通过辅助函数与渲染Markdown内容的部分结合,处理 iframe
嵌入的HTML内容。iframe
的 sandbox
属性和 referrerPolicy
来防止潜在的安全风险。sandbox
属性提供了细粒度的控制,允许特定的功能(如脚本、表单、弹出窗口等)在受限的环境中执行,以确保渲染的HTML内容不会对系统造成威胁。iframe
自适应父容器的宽度,同时保证 iframe
嵌入的内容能够适当显示。你只需要通过 Markdown 代码块格式,并标记语言为 html
即可。例如:
+ ```html
+<!DOCTYPE html>
+<html lang="zh-CN">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta http-equiv="X-UA-Compatible" content="ie=edge">
+ <title>欢迎使用FastGPT</title>
+ </head>
+ <body>
+ <nav>
+ <ul>
+ <li><a href="#home">首页</a></li>
+ <li><a href="#about">关于我们</a></li>
+ <li><a href="#contact">联系我们</a></li>
+ <li><a href="#gallery">图库</a></li>
+ </ul>
+ </nav>
+ </body>
+</html>
+
对话框组件,支持多种交互方式,提升用户在应用中的交互体验。
FastGPT 的功能和使用指南
FastGPT API 文件库功能介绍和使用方式
目前 FastGPT 支持本地文件导入,但是很多时候,用户自身已经有了一套文档库,如果把文件重复导入一遍,会造成二次存储,并且不方便管理。因为 FastGPT 提供了一个 API 文件库的概念,可以通过简单的 API 接口,去拉取已有的文档库,并且可以灵活配置是否导入。
API 文件库能够让用户轻松对接已有的文档库,只需要按照 FastGPT 的 API 文件库规范,提供相应文件接口,然后将服务接口的 baseURL 和 token 填入知识库创建参数中,就能直接在页面上拿到文件库的内容,并选择性导入
创建知识库时,选择 API 文件库类型,然后需要配置两个关键参数:文件服务接口的 baseURL 和用于身份验证的请求头信息。只要提供的接口规范符合 FastGPT 的要求,系统就能自动获取并展示完整的文件列表,可以根据需要选择性地将文件导入到知识库中。
你需要提供两个参数:
Authorization: Bearer <token>
接口响应格式:
+ type ResponseType = {
+ success: boolean;
+ message: string;
+ data: any;
+}
+
数据类型:
+ // 文件列表中,单项的文件类型
+type FileListItem = {
+ id: string;
+ parentId: string | null;
+ name: string;
+ type: 'file' | 'folder';
+ updateTime: Date;
+ createTime: Date;
+}
+
本节会详细介绍 FastGPT 知识库结构设计,理解其 QA 的存储格式和多向量映射,以便更好的构建知识库。同时会介绍每个搜索参数的功能。这篇介绍主要以使用为主,详细原理不多介绍。
FastGPT 采用了 RAG 中的 Embedding 方案构建知识库,要使用好 FastGPT 需要简单的理解Embedding
向量是如何工作的及其特点。
人类的文字、图片、视频等媒介是无法直接被计算机理解的,要想让计算机理解两段文字是否有相似性、相关性,通常需要将它们转成计算机可以理解的语言,向量是其中的一种方式。
向量可以简单理解为一个数字数组,两个向量之间可以通过数学公式得出一个距离
,距离越小代表两个向量的相似度越大。从而映射到文字、图片、视频等媒介上,可以用来判断两个媒介之间的相似度。向量搜索便是利用了这个原理。
而由于文字是有多种类型,并且拥有成千上万种组合方式,因此在转成向量进行相似度匹配时,很难保障其精确性。在向量方案构建的知识库中,通常使用topk
召回的方式,也就是查找前k
个最相似的内容,丢给大模型去做更进一步的语义判断
、逻辑推理
和归纳总结
,从而实现知识库问答。因此,在知识库问答中,向量搜索的环节是最为重要的。
影响向量搜索精度的因素非常多,主要包括:向量模型的质量、数据的质量(长度,完整性,多样性)、检索器的精度(速度与精度之间的取舍)。与数据质量对应的就是检索词的质量。
检索器的精度比较容易解决,向量模型的训练略复杂,因此数据和检索词质量优化成了一个重要的环节。
index
的内容,减少向量内容的长度:当index
的内容更少,更准确时,检索精度自然会提高。但与此同时,会牺牲一定的检索范围,适合答案较为严格的场景。index
的数量,可以为同一个chunk
内容增加多组index
。在 FastGPT 中,整个知识库由库、集合和数据 3 部分组成。集合可以简单理解为一个文件
。一个库
中可以包含多个集合
,一个集合
中可以包含多组数据
。最小的搜索单位是库
,也就是说,知识库搜索时,是对整个库
进行搜索,而集合仅是为了对数据进行分类管理,与搜索效果无关。(起码目前还是)
FastGPT 采用了PostgresSQL
的PG Vector
插件作为向量检索器,索引为HNSW
。且PostgresSQL
仅用于向量检索(该引擎可以替换成其它数据库),MongoDB
用于其他数据的存取。
在MongoDB
的dataset.datas
表中,会存储向量原数据的信息,同时有一个indexes
字段,会记录其对应的向量ID,这是一个数组,也就是说,一组数据可以对应多个向量。
在PostgresSQL
的表中,设置一个vector
字段用于存储向量。在检索时,会先召回向量,再根据向量的ID,去MongoDB
中寻找原数据内容,如果对应了同一组原数据,则进行合并,向量得分取最高得分。
在一组向量中,内容的长度和语义的丰富度通常是矛盾的,无法兼得。因此,FastGPT 采用了多向量映射的方式,将一组数据映射到多组向量中,从而保障数据的完整性和语义的丰富度。
你可以为一组较长的文本,添加多组向量,从而在检索时,只要其中一组向量被检索到,该数据也将被召回。
意味着,你可以通过标注数据块的方式,不断提高数据块的精度。
问题优化
实现指代消除和问题扩展,从而增加连续对话的检索能力以及语义丰富度。Concat query
来增加Rerank
连续对话的时,排序的准确性。RRF
合并方式,综合多个渠道的检索效果。Rerank
来二次排序,提高精度。语义检索是通过向量距离,计算用户问题与知识库内容的距离,从而得出“相似度”,当然这并不是语文上的相似度,而是数学上的。
优点:
缺点:
采用传统的全文检索方式。适合查找关键的主谓语等。
同时使用向量检索和全文检索,并通过 RRF 公式进行两个搜索结果合并,一般情况下搜索结果会更加丰富准确。
由于混合检索后的查找范围很大,并且无法直接进行相似度过滤,通常需要进行利用重排模型进行一次结果重新排序,并利用重排的得分进行过滤。
利用ReRank
模型对搜索结果进行重排,绝大多数情况下,可以有效提高搜索结果的准确率。不过,重排模型与问题的完整度(主谓语齐全)有一些关系,通常会先走问题优化后再进行搜索-重排。重排后可以得到一个0-1
的得分,代表着搜索内容与问题的相关度,该分数通常比向量的得分更加精确,可以根据得分进行过滤。
FastGPT 会使用 RRF
对重排结果、向量搜索结果、全文检索结果进行合并,得到最终的搜索结果。
每次搜索最多引用n
个tokens
的内容。
之所以不采用top k
,是发现在混合知识库(问答库、文档库)时,不同chunk
的长度差距很大,会导致top k
的结果不稳定,因此采用了tokens
的方式进行引用上限的控制。
一个0-1
的数值,会过滤掉一些低相关度的搜索结果。
该值仅在语义检索
或使用结果重排
时生效。
在 RAG 中,我们需要根据输入的问题去数据库里执行 embedding 搜索,查找相关的内容,从而查找到相似的内容(简称知识库搜索)。
在搜索的过程中,尤其是连续对话的搜索,我们通常会发现后续的问题难以搜索到合适的内容,其中一个原因是知识库搜索只会使用“当前”的问题去执行。看下面的例子:
用户在提问“第二点是什么”的时候,只会去知识库里查找“第二点是什么”,压根查不到内容。实际上需要查询的是“QA结构是什么”。因此我们需要引入一个【问题优化】模块,来对用户当前的问题进行补全,从而使得知识库搜索能够搜索到合适的内容。使用补全后效果如下:
在进行数据检索
前,会先让模型进行指代消除
与问题扩展
,一方面可以可以解决指代对象不明确问题,同时可以扩展问题的语义丰富度。你可以通过每次对话后的对话详情,查看补全的结果。
FastGPT 外部文件知识库功能介绍和使用方式
外部文件库是 FastGPT 商业版特有功能。它允许接入你现在的文件系统,无需将文件再导入一份到 FastGPT 中。
并且,阅读权限可以通过你的文件系统进行控制。
4.8.15 提供了新的知识库类型 - API 文件库,对外部文件知识库做了进一步的拓展
通过对接口进行简单的调整,就能使用 API 文件库代替外部文件知识库的功能
你可以直接将外部文件知识库中的外部预览地址,作为 API 文件库接口规范中获取文件阅读链接的接口返回
然后再以相同的 baseURL 实现获取文件列表和获取单个文件内容这两个接口
这样就能轻松地使用 API 文件库替代原有的外部文件知识库,更多详细的内容见 API 文件库的文档
知识库的基础原理、搜索方案、Web站点同步和外部文件知识库的使用方法。
FastGPT 飞书知识库功能介绍和使用方式
FastGPT v4.8.16 版本开始,商业版用户支持飞书知识库导入,用户可以通过配置飞书应用的 appId 和 appSecret,并选中一个文档空间的顶层文件夹来导入飞书知识库。目前处于测试阶段,部分交互有待优化。
由于飞书限制,无法直接获取所有文档内容,目前仅可以获取共享空间下文件目录的内容,无法获取个人空间和知识库里的内容。
打开 飞书开放平台,点击创建应用,选择自建应用,然后填写应用名称。
创建应用后,进入应用可以配置相关权限,这里需要增加两个权限:
可参考飞书教程: https://open.feishu.cn/document/server-docs/docs/drive-v1/faq#b02e5bfb
大致总结为:
如果你的目录已经给全员组增加权限了,则可以跳过上面步骤,直接获取 Folder Token。
可以页面路径上获取 Folder Token,注意不要把问号复制进来。
根据 3 和 5 获取到的 3 个参数,创建知识库,选择飞书文件库类型,然后填入对应的参数,点击创建。
本节详细介绍RAG模型的核心机制、应用场景及其在生成任务中的优势与局限性。
随着自然语言处理(NLP)技术的迅猛发展,生成式语言模型(如GPT、BART等)在多种文本生成任务中表现卓越,尤其在语言生成和上下文理解方面。然而,纯生成模型在处理事实类任务时存在一些固有的局限性。例如,由于这些模型依赖于固定的预训练数据,它们在回答需要最新或实时信息的问题时,可能会出现“编造”信息的现象,导致生成结果不准确或缺乏事实依据。此外,生成模型在面对长尾问题和复杂推理任务时,常因缺乏特定领域的外部知识支持而表现不佳,难以提供足够的深度和准确性。
与此同时,检索模型(Retriever)能够通过在海量文档中快速找到相关信息,解决事实查询的问题。然而,传统检索模型(如BM25)在面对模糊查询或跨域问题时,往往只能返回孤立的结果,无法生成连贯的自然语言回答。由于缺乏上下文推理能力,检索模型生成的答案通常不够连贯和完整。
为了解决这两类模型的不足,检索增强生成模型(Retrieval-Augmented Generation,RAG)应运而生。RAG通过结合生成模型和检索模型的优势,实时从外部知识库中获取相关信息,并将其融入生成任务中,确保生成的文本既具备上下文连贯性,又包含准确的知识。这种混合架构在智能问答、信息检索与推理、以及领域特定的内容生成等场景中表现尤为出色。
RAG是一种将信息检索与生成模型相结合的混合架构。首先,检索器从外部知识库或文档集中获取与用户查询相关的内容片段;然后,生成器基于这些检索到的内容生成自然语言输出,确保生成的内容既信息丰富,又具备高度的相关性和准确性。
RAG 模型由两个主要模块构成:检索器(Retriever)与生成器(Generator)。这两个模块相互配合,确保生成的文本既包含外部的相关知识,又具备自然流畅的语言表达。
检索器的主要任务是从一个外部知识库或文档集中获取与输入查询最相关的内容。在RAG中,常用的技术包括:
RAG中检索器的作用是为生成器提供一个上下文背景,使生成器能够基于这些检索到的文档片段生成更为相关的答案。
生成器负责生成最终的自然语言输出。在RAG系统中,常用的生成器包括:
生成器在接收来自检索器的文档片段后,会利用这些片段作为上下文,并结合输入的查询,生成相关且自然的文本回答。这确保了模型的生成结果不仅仅基于已有的知识,还能够结合外部最新的信息。
RAG模型的工作流程可以总结为以下几个步骤:
在RAG模型中,用户的查询首先被转化为向量表示,然后在知识库中执行向量检索。通常,检索器采用诸如BERT等预训练模型生成查询和文档片段的向量表示,并通过相似度计算(如余弦相似度)匹配最相关的文档片段。RAG的检索器不仅仅依赖简单的关键词匹配,而是采用语义级别的向量表示,从而在面对复杂问题或模糊查询时,能够更加准确地找到相关知识。这一步骤对于最终生成的回答至关重要,因为检索的效率和质量直接决定了生成器可利用的上下文信息 。
生成阶段是RAG模型的核心部分,生成器负责基于检索到的内容生成连贯且自然的文本回答。RAG中的生成器,如BART或GPT等模型,结合用户输入的查询和检索到的文档片段,生成更加精准且丰富的答案。与传统生成模型相比,RAG的生成器不仅能够生成语言流畅的回答,还可以根据外部知识库中的实际信息提供更具事实依据的内容,从而提高了生成的准确性 。
RAG模型在对话系统中能够有效支持多轮交互。每一轮的查询和生成结果会作为下一轮的输入,系统通过分析和学习用户的反馈,逐步优化后续查询的上下文。通过这种循环反馈机制,RAG能够更好地调整其检索和生成策略,使得在多轮对话中生成的答案越来越符合用户的期望。此外,多轮交互还增强了RAG在复杂对话场景中的适应性,使其能够处理跨多轮的知识整合和复杂推理 。
RAG(检索增强生成)模型通过结合检索器和生成器,实现了在多种任务中知识密集型内容生成的突破性进展。然而,尽管其具有较强的应用潜力和跨领域适应能力,但在实际应用中仍然面临着一些关键局限,限制了其在大规模系统中的部署和优化。以下是RAG模型的几个主要局限性:
RAG模型的性能很大程度上取决于检索器返回的文档质量。由于生成器主要依赖检索器提供的上下文信息,如果检索到的文档片段不相关、不准确,生成的文本可能出现偏差,甚至产生误导性的结果。尤其在多模糊查询或跨领域检索的情况下,检索器可能无法找到合适的片段,这将直接影响生成内容的连贯性和准确性。
RAG模型将检索和生成模块结合,尽管生成结果更加准确,但也大大增加了模型的计算复杂度。尤其在处理大规模数据集或长文本时,生成器需要处理来自多个文档片段的信息,导致生成时间明显增加,推理速度下降。对于实时问答系统或其他需要快速响应的应用场景,这种高计算复杂度是一个主要瓶颈。
RAG模型通常依赖于一个预先建立的外部知识库,该知识库可能包含文档、论文、法律条款等各类信息。然而,知识库内容的时效性和准确性直接影响到RAG生成结果的可信度。随着时间推移,知识库中的内容可能过时,导致生成的回答不能反映最新的信息。这对于需要实时信息的场景(如医疗、金融)尤其明显。
RAG模型结合了检索与生成模块,在生成内容的可控性和透明度上存在一定问题。特别是在复杂任务或多义性较强的用户输入情况下,生成器可能会基于不准确的文档片段生成错误的推理,导致生成的答案偏离实际问题。此外,由于RAG模型的“黑箱”特性,用户难以理解生成器如何利用检索到的文档信息,这在高敏感领域如法律或医疗中尤为突出,可能导致用户对生成内容产生不信任感。
RAG模型的整体性能依赖于知识库的准确性和检索的效率,因此在数据采集、内容分块、精准检索和回答生成等环节进行优化,是提升模型效果的关键。通过加强数据来源、改进内容管理、优化检索策略及提升回答生成的准确性,RAG模型能够更加适应复杂且动态的实际应用需求。
RAG模型的核心依赖在于知识库的数据质量和广度,知识库在某种程度上充当着“外部记忆”的角色。因此,高质量的知识库不仅应包含广泛领域的内容,更要确保数据来源的权威性、可靠性以及时效性。知识库的数据源应涵盖多种可信的渠道,例如科学文献数据库(如PubMed、IEEE Xplore)、权威新闻媒体、行业标准和报告等,这样才能提供足够的背景信息支持RAG在不同任务中的应用。此外,为了确保RAG模型能够提供最新的回答,知识库需要具备自动化更新的能力,以避免数据内容老旧,导致回答失准或缺乏现实参考。
RAG模型的数据分块与内容管理是优化检索与生成流程的关键。合理的分块策略能够帮助模型高效定位目标信息,并在回答生成时提供清晰的上下文支持。通常情况下,将数据按段落、章节或主题进行分块,不仅有助于检索效率的提升,还能避免冗余数据对生成内容造成干扰。尤其在复杂、长文本中,适当的分块策略可保证模型生成的答案具备连贯性、精确性,避免出现内容跳跃或上下文断裂的问题。
在RAG模型中,检索模块决定了生成答案的相关性和准确性。有效的检索策略可确保模型获取到最适合的上下文片段,使生成的回答更加精准且贴合查询需求。常用的混合检索策略(如BM25和DPR结合)能够在关键词匹配和语义检索方面实现优势互补:BM25适合高效地处理关键字匹配任务,而DPR在理解深层语义上表现更为优异。因此,合理选用检索策略有助于在不同任务场景下达到计算资源和检索精度的平衡,以高效提供相关上下文供生成器使用。
在RAG模型中,生成器负责基于检索模块提供的上下文,为用户查询生成自然语言答案。生成内容的准确性和逻辑性直接决定了用户的体验,因此优化生成器的表现至关重要。通过引入知识图谱等结构化信息,生成器能够更准确地理解和关联上下文,从而生成逻辑连贯、准确的回答。此外,生成器的生成逻辑可结合用户反馈持续优化,使回答风格和内容更加符合用户需求。
RAG模型已在多个领域得到广泛应用,主要包括:
RAG还可以应用于多模态生成场景,如图像、音频和3D内容生成。例如,跨模态应用如ReMoDiffuse和Make-An-Audio利用RAG技术实现不同数据形式的生成。此外,在企业决策支持中,RAG能够快速检索外部资源(如行业报告、市场数据),生成高质量的前瞻性报告,从而提升企业战略决策的能力。
本文档系统阐述了检索增强生成(RAG)模型的核心机制、优势与应用场景。通过结合生成模型与检索模型,RAG解决了传统生成模型在面对事实性任务时的“编造”问题和检索模型难以生成连贯自然语言输出的不足。RAG模型能够实时从外部知识库获取信息,使生成内容既包含准确的知识,又具备流畅的语言表达,适用于医疗、法律、智能问答系统等多个知识密集型领域。
在应用实践中,RAG模型虽然有着信息完整性、推理能力和跨领域适应性等显著优势,但也面临着数据质量、计算资源消耗和知识库更新等挑战。为进一步提升RAG的性能,提出了针对数据采集、内容分块、检索策略优化以及回答生成的全面改进措施,如引入知识图谱、优化用户反馈机制、实施高效去重算法等,以增强模型的适用性和效率。
RAG在智能问答、信息检索与文本生成等领域展现了出色的应用潜力,并在不断发展的技术支持下进一步拓展至多模态生成和企业决策支持等场景。通过引入混合检索技术、知识图谱以及动态反馈机制,RAG能够更加灵活地应对复杂的用户需求,生成具有事实支撑和逻辑连贯性的回答。未来,RAG将通过增强模型透明性与可控性,进一步提升在专业领域中的可信度和实用性,为智能信息检索与内容生成提供更广泛的应用空间。
FastGPT Web 站点同步功能介绍和使用方式
该功能目前仅向商业版用户开放。
Web 站点同步利用爬虫的技术,可以通过一个入口网站,自动捕获同域名
下的所有网站,目前最多支持200
个子页面。出于合规与安全角度,FastGPT 仅支持静态站点
的爬取,主要用于各个文档站点快速构建知识库。
Tips: 国内的媒体站点基本不可用,公众号、csdn、知乎等。可以通过终端发送curl
请求检测是否为静态站点,例如:
+ curl https://doc.tryfastgpt.ai/docs/intro/
+
好了, 现在点击开始同步,静等系统自动抓取网站信息即可。
选择器是 HTML CSS JS 的产物,你可以通过选择器来定位到你需要抓取的具体内容,而不是整个站点。使用方式为:
菜鸟教程 css 选择器,具体选择器的使用方式可以参考菜鸟教程。
上图中,我们选中了一个区域,对应的是div
标签,它有 data-prismjs-copy
, data-prismjs-copy-success
, data-prismjs-copy-error
三个属性,这里我们用到一个就够。所以选择器是:
+div[data-prismjs-copy]
除了属性选择器,常见的还有类和ID选择器。例如:
上图 class 里的是类名(可能包含多个类名,都是空格隔开的,选择一个即可),选择器可以为:.docs-content
在开头的演示中,我们对 FastGPT 文档是使用了多选择器的方式来选择,通过逗号隔开了两个选择器。
我们希望选中上图两个标签中的内容,此时就需要两组选择器。一组是:.docs-content .mb-0.d-flex
,含义是 docs-content
类下同时包含 mb-0
和d-flex
两个类的子元素;
另一组是.docs-content div[data-prismjs-copy]
,含义是docs-content
类下包含data-prismjs-copy
属性的div
元素。
把两组选择器用逗号隔开即可:.docs-content .mb-0.d-flex, .docs-content div[data-prismjs-copy]
FastGPT 语雀文件库功能介绍和使用方式
FastGPT v4.8.16 版本开始,商业版用户支持语雀文件库导入,用户可以通过配置语雀的 token 和 uid 来导入语雀文档库。目前处于测试阶段,部分交互有待优化。
在语雀首页 - 个人头像 - 设置,可找到对应参数。
参考下图获取 Token 和 User ID,注意给 Token 赋值权限:
获取 Token | 增加权限 | 获取 User ID |
---|---|---|
使用上一步获取的 token 和 uid,创建知识库,选择语雀文件库类型,然后填入对应的参数,点击创建。
创建完知识库后,点击添加文件
即可导入语雀的文档库,跟随引导即可。
语雀知识库支持定时同步功能,每天会不定时的扫描一次,如果文档有更新,则会进行同步,也可以进行手动同步。
FastGPT Bing 搜索插件配置步骤详解
搜索Bing Search v7,点击创建
https://portal.azure.com/#create/Microsoft.BingSearch
如何配置和使用 Doc2x 插件
FastGPT Google 搜索插件配置指南
https://programmablesearchengine.google.com/
我们连到Custom Search Engine control panel 建立Search Engine
取得搜索引擎的ID,即cx
https://developers.google.com/custom-search/v1/overview?hl=zh-cn
将搜索引擎ID填入cx字段,api key填入key字段
FastGPT 系统插件提交指南
如何向 FastGPT 社区提交系统插件
由于目前未采用按需安装的模式,合并进仓库的插件会全部展示给用户使用。
为了控制插件的质量以及避免数量过多带来的繁琐,并不是所有的插件都会被合并到开源仓库中,你可以提前 PR 与我们沟通插件的内容。
后续实现插件按需安装后,我们会允许更多的社区插件合入。
FastGPT 系统插件和用户工作台的插件效果是一致的,所以你需要提前了解“插件”的定义和功能。
在 FastGPT 中,插件是一种特殊的工作流,它允许你将一个工作流封装起来,并自定义入口参数和出口参数,类似于代码里的 “子函数”。
需要在 dev 环境下执行下面的操作。
选择基础模板即可。
系统插件配置以及自定义代码,都会在 packages/plugins 目录下。
+ {
+ "author": "填写你的名字",
+ "version": "当前系统版本号",
+ "name": "插件名",
+ "avatar": "插件头像,需要配成 icon 格式。直接把 logo 图在 pr 评论区提交即可,我们会帮你加入。",
+ "intro": " 插件的描述,这个描述会影响工具调用",
+ "showStatus": false, // 是否在对话过程展示状态
+ "weight": 10, // 排序权重,均默认 10
+
+ "isTool": true, // 是否作为工具调用节点
+ "templateType": "tools", // 都填写 tools 即可,由官方来分类
+
+ "workflow": { // 这个对象先不管,待会直接粘贴导出的工作流即可
+ "nodes": [],
+ "edges": []
+ }
+}
+
无需额外写代码的插件,直接放在 staticPluginList 内,需要在项目内额外写代码的,写在 packagePluginList 中。
完成工作流编排后,可以点击右上角的发布,并在其他工作流中引入进行测试(此时属于团队插件)。
鼠标放置在左上角插件的头像和名称上,会出现对于下拉框操作,可以导出工作流配置。
导出的配置,会自动到剪切板,可以直接到 template.json 文件中粘贴使用,替换步骤 2 中,workflow 的值。
刷新页面,打开系统插件,看其是否成功加载,并将其添加到工作流中使用。
如果你觉得你的插件需要提交到开源仓库,可以通过 PR 形式向我们提交。
这一章会介绍如何增加一些无法单纯通过编排实现的插件。因为可能需要用到网络请求或第三方包。
上一章提到,在插件的 template 目录下,还有一个 index.ts 文件,这个文件就是用来执行一些插件的代码的。你可以通过在 HTTP 节点中的 URL,填写插件的名字,即可触发该方法,下面以 duckduckgo/search 这个插件为例:
参考上面 3 张图片,当 HTTP 节点的 URL 为系统插件注册的名字时,该请求不会以 HTTP 形式发送,而是会请求到 index.ts 文件中的 main 方法。出入参则对应了 body 和自定义输出的字段名。
由于目前插件会默认插件输出均作为“工具调用”的结果,无法单独指定某些字段作为工具输出,所以,请避免插件的自定义输出携带大量说明字段。
FastGPT SearXNG 搜索插件配置指南
SearXNG是一款免费的互联网元搜索引擎,它汇总了来自各种搜索服务和数据库的结果。它不会跟踪或分析用户。用户可以自行部署它进行使用。本文介绍 Searxng 的部署以及接入 FastGPT 插件。
这里介绍在 Sealos 中部署 SearXNG 的方法。Docker 部署,可以直接参考 SearXNG 官方教程。
点击打开 Sealos 北京区,点击应用部署,并新建一个应用:
打开应用部署 | 点击新建应用 |
---|---|
把下面参数,填入配置中:
环境变量
填下面两个内容,主要是为了减小并发,不然内存占用非常大。
+ UWSGI_WORKERS=4
+UWSGI_THREADS=4
+
配置文件
新增一个配置文件,文件名:/etc/searx/settings.yml
+文件内容:
+ general:
+ debug: false
+ instance_name: "searxng"
+ privacypolicy_url: false
+ donation_url: false
+ contact_url: false
+ enable_metrics: true
+ open_metrics: ''
+
+brand:
+ new_issue_url: https://github.com/searxng/searxng/issues/new
+ docs_url: https://docs.searxng.org/
+ public_instances: https://searx.space
+ wiki_url: https://github.com/searxng/searxng/wiki
+ issue_url: https://github.com/searxng/searxng/issues
+
+search:
+ safe_search: 0
+ autocomplete: ""
+ autocomplete_min: 4
+ default_lang: "auto"
+ ban_time_on_fail: 5
+ max_ban_time_on_fail: 120
+ formats:
+ - html
+
+server:
+ port: 8080
+ bind_address: "0.0.0.0"
+ base_url: false
+ limiter: false
+ public_instance: false
+ secret_key: "example"
+ image_proxy: false
+ http_protocol_version: "1.0"
+ method: "POST"
+ default_http_headers:
+ X-Content-Type-Options: nosniff
+ X-Download-Options: noopen
+ X-Robots-Tag: noindex, nofollow
+ Referrer-Policy: no-referrer
+
+redis:
+ url: false
+
+ui:
+ static_path: ""
+ static_use_hash: false
+ templates_path: ""
+ default_theme: simple
+ default_locale: ""
+ query_in_title: false
+ infinite_scroll: false
+ center_alignment: false
+ theme_args:
+ simple_style: auto
+
+outgoing:
+ request_timeout: 30.0
+ max_request_timeout: 40.0
+ pool_connections: 200
+ pool_maxsize: 50
+ enable_http2: false
+ retries: 5
+
+engines:
+
+ - name: bing
+ engine: bing
+ shortcut: bi
+
+doi_resolvers:
+ oadoi.org: 'https://oadoi.org/'
+ doi.org: 'https://doi.org/'
+ doai.io: 'https://dissem.in/'
+ sci-hub.se: 'https://sci-hub.se/'
+ sci-hub.st: 'https://sci-hub.st/'
+ sci-hub.ru: 'https://sci-hub.ru/'
+
+default_doi_resolver: 'oadoi.org'
+
国内目前只有 Bing 引擎可以正常用,所以上面的配置只配置了 bing 引擎。如果在海外部署,可以使用Sealos 新加坡可用区,并配置其他搜索引擎,可以参考SearXNG 默认配置文件, 从里面复制一些 engine 配置。例如:
+ - name: duckduckgo
+ engine: duckduckgo
+ shortcut: ddg
+
+ - name: google
+ engine: google
+ shortcut: go
+
复制 Sealos 部署后提供的公网地址,填入 FastGPT 的 SearXNG 插件的 URL 中。
复制公网地址 | 填入 URL |
---|---|
+ {
+ "result": "[{\"title\":\"标题1\",\"link\":\"链接1\",\"snippet\":\"摘要1\"}, ...]"
+}
+
+ {
+ "result": "[]",
+ "error": {
+ "message": "No search results",
+ "code": 500
+ }
+}
+
+ - "缺少查询参数"
+- "缺少url"
+- "Failed to fetch data from Search XNG"
+
一般问题来源于参数缺失与服务部署,如有更多问题可在用户群提问。
FastGPT 使用 Gapier 快速导入Agent工具
FastGPT V4.7版本加入了工具调用,可以兼容 GPTs 的 Actions。这意味着,你可以直接导入兼容 GPTs 的 Agent 工具。
Gapier 是一个在线 GPTs Actions工具,提供了50多种现成工具,并且每天有免费额度进行测试,方便用户试用,官方地址为:https://gapier.com/。
现在,我们开始把 Gapier 的工具导入到 FastGPT 中。
Step1 | Step2 | Step3 |
---|---|---|
登录Gapier 复制相关参数 | ||
Step4 | Step5 | Step6 |
自定义请求头: Authorization 请求值: Bearer 复制的key |
创建完后,如果需要变更,无需重新创建,只需要修改对应参数即可,会自动做差值比较更新。
Step1 | Step2 | |
---|---|---|
Step3 | Step4 | |
Step1 | Step2 | |
---|---|---|
Step3 | Step4 | |
不同模型调用工具采用不同的方法,有些模型支持 toolChoice 和 functionCall 效果会更好。不支持这两种方式的模型通过提示词调用,但是效果不是很好,并且为了保证顺利调用,FastGPT内置的提示词,仅支持每次调用一个工具。
具体哪些模型支持 functionCall 可以官网查看(当然,也需要OneAPI支持),同时需要调整模型配置文件中的对应字段(详细看配置字段说明)。
线上版用户,可以在模型选择时,看到是否支持函数调用的标识。
快速了解 FastGPT 工作流和插件的使用
FastGPT 从 V4 版本开始采用新的交互方式来构建 AI 应用。使用了 Flow 节点编排(工作流)的方式来实现复杂工作流,提高可玩性和扩展性。但同时也提高了上手的门槛,有一定开发背景的用户使用起来会比较容易。
在程序中,节点可以理解为一个个 Function 或者接口。可以理解为它就是一个步骤。将多个节点一个个拼接起来,即可一步步的去实现最终的 AI 输出。
如下图,这是一个最简单的 AI 对话。它由用流程开始和 AI 对话节点组成。
执行流程如下:
从功能上,节点可以分为 2 类:
每个节点会包含 3 个核心部分:输入、输出和触发器。
FastGPT的工作流从【流程开始】节点开始执行,可以理解为从用户输入问题开始,没有固定的出口,是以节点运行结束作为出口,如果在一个轮调用中,所有节点都不再运行,则工作流结束。
下面我们来看下,工作流是如何运行的,以及每个节点何时被触发执行。
如上图所示节点会“被连接”也会“连接其他节点”,我们称“被连接”的那根线为前置线,“连接其他节点的线”为后置线。上图例子中【知识库搜索】模块左侧有一根前置线,右侧有一根后置线。而【AI对话】节点只有左侧一根前置线。
FastGPT工作流中的线有以下几种状态:
waiting
:被连接的节点等待执行。active
:被连接的节点可以执行。skip
:被连接的节点不需要执行跳过。节点执行的原则:
waiting
的,如果有则等待。active
如果有则执行。waiting
也没有 active
则认为此节点需要跳过。active
或skip
并且更改前置线状态为waiting
等待下一轮执行。让我们看一下上面例子的执行过程:
active
。active
开始执行,执行完毕后更改后置线状态为active
前置线状态为waiting
。active
开始执行,流程执行结束。HTTP
节点中进行合并,使用[Laf](https://laf.run/)
可以快速实现一个无服务器HTTP接口。FastGPT AI 对话模块介绍
可以通过 config.json 配置可选的对话模型,通过 one-api 来实现多模型接入。
点击AI模型后,可以配置模型的相关参数。
具体配置参数介绍可以参考: AI参数配置说明
FastGPT 内容提取模块介绍
从文本中提取结构化数据,通常是配合 HTTP 模块实现扩展。也可以做一些直接提取操作,例如:翻译。
顾名思义,给模型设置一个目标,需要提取哪些内容。
示例 1
你是实验室预约助手,从对话中提取出姓名,预约时间,实验室号。当前时间 {{cTime}}
示例 2
你是谷歌搜索助手,从对话中提取出搜索关键词
示例 3
将我的问题直接翻译成英文,不要回答问题
通常需要一些历史记录,才能更完整的提取用户问题。例如上图中需要提供姓名、时间和实验室名,用户可能一开始只给了时间和实验室名,没有提供自己的姓名。再经过一轮缺失提示后,用户输入了姓名,此时需要结合上一次的记录才能完整的提取出 3 个内容。
目标字段与提取的结果相对应,从上图可以看到,每增加一个字段,输出会增加一个对应的出口。
问题优化模块介绍和使用
在 RAG 中,我们需要根据输入的问题去数据库里执行 embedding 搜索,查找相关的内容,从而查找到相似的内容(简称知识库搜索)。
在搜索的过程中,尤其是连续对话的搜索,我们通常会发现后续的问题难以搜索到合适的内容,其中一个原因是知识库搜索只会使用“当前”的问题去执行。看下面的例子:
用户在提问“第二点是什么”的时候,只会去知识库里查找“第二点是什么”,压根查不到内容。实际上需要查询的是“QA结构是什么”。因此我们需要引入一个【问题优化】模块,来对用户当前的问题进行补全,从而使得知识库搜索能够搜索到合适的内容。使用补全后效果如下:
调用 AI 去对用户当前的问题进行补全。目前主要是补全“指代”词,使得检索词更加的完善可靠,从而增强上下文连续对话的知识库搜索能力。
遇到最大的难题在于:模型对于【补全】的概念可能不清晰,且对于长上下文往往无法准确的知道应该如何补全。
自定义反馈模块介绍
该模块为临时模块,后续会针对该模块进行更全面的设计。
自定义反馈模块,可以为你的对话增加一个反馈标记,从而方便在后台更好的分析对话的数据。
在调试模式下,不会记录反馈内容,而是直接提示: 自动反馈测试: 反馈内容
。
在对话模式(对话、分享窗口、带 chatId 的 API 调用)时,会将反馈内容记录到对话日志中。(会延迟60s记录)
自定义反馈模块的功能类似于程序开发的埋点
,便于你观测的对话中的数据。
FastGPT AI 知识库搜索模块介绍
知识库搜索具体参数说明,以及内部逻辑请移步:FastGPT知识库搜索方案
可以选择一个或多个相同向量模型的知识库,用于向量搜索。
以数组格式输出引用,长度可以为 0。意味着,即使没有搜索到内容,这个输出链路也会走通。
FastGPT 表单输入模块介绍
「表单输入」节点属于用户交互节点,当触发这个节点时,对话会进入“交互”状态,会记录工作流的状态,等用户完成交互后,继续向下执行工作流
比如上图中的例子,当触发表单输入节点时,对话框隐藏,对话进入“交互状态”
当用户填完必填的信息并点击提交后,节点能够收集用户填写的表单信息,传递到后续的节点中使用
能够精准收集需要的用户信息,再根据用户信息进行后续操作
FastGPT HTTP 模块介绍
HTTP 模块会向对应的地址发送一个 HTTP
请求,实际操作与 Postman 和 ApiFox 这类直流工具使用差不多。
{{}}
来引用变量。{{}}
来引用变量。全局变量
、系统变量
、前方节点输出
你可以将鼠标放置在请求参数
旁边的问号中,里面会提示你可用的变量。
不多描述,使用方法和Postman, ApiFox 基本一致。
可通过 {{key}} 来引入变量。例如:
key | value |
---|---|
appId | {{appId}} |
Authorization | Bearer {{token}} |
只有特定请求类型下会生效。
可以写一个自定义的 Json
,并通过 {{key}} 来引入变量。例如:
从图中可以看出,FastGPT可以添加多个返回值,这个返回值并不代表接口的返回值,而是代表如何解析接口返回值
,可以通过 JSON path
的语法,来提取
接口响应的值。
语法可以参考: https://github.com/JSONPath-Plus/JSONPath?tab=readme-ov-file
你可以配置对应的key
来从FastGPT 转化后的格式
获取需要的值,该规则遵守 JS 的对象取值规则。例如:
message
的内容,那么你可以配置message
的key
为message
,这样就可以获取到message
的内容。user的name
,则key
可以为:data.user.name
。key
可以为:data.list[1]
,然后输出类型选择字符串,则获自动获取到[ { "test": 22 } ]
的json
字符串。FastGPT v4.6.8 后,加入了出参格式化功能,主要以json
格式化成字符串
为主。如果你的输出类型选择了字符串
,则会将HTTP
对应key
的值,转成json
字符串进行输出。因此,未来你可以直接从HTTP
接口输出内容至文本加工
中,然后拼接适当的提示词,最终输入给AI对话
。
HTTP模块非常强大,你可以对接一些公开的API,来提高编排的功能。
如果你不想额外部署服务,可以使用 Laf 来快速开发上线接口,即写即发,无需部署。
下面是在 Laf 编写的 POST 请求示例:
+ import cloud from '@lafjs/cloud'
+const db = cloud.database()
+
+type RequestType = {
+ appId: string;
+ appointment: string;
+ action: 'post' | 'delete' | 'put' | 'get'
+}
+
+export default async function (ctx: FunctionContext) {
+ try {
+ // 从 body 中获取参数
+ const { appId, appointment, action } = ctx.body as RequestType
+
+ const parseBody = JSON.parse(appointment)
+ if (action === 'get') {
+ return await getRecord(parseBody)
+ }
+ if (action === 'post') {
+ return await createRecord(parseBody)
+ }
+ if (action === 'put') {
+ return await putRecord(parseBody)
+ }
+ if (action === 'delete') {
+ return await removeRecord(parseBody)
+ }
+
+
+ return {
+ response: "异常"
+ }
+ } catch (err) {
+ return {
+ response: "异常"
+ }
+ }
+}
+
通过 HTTP 模块你可以无限扩展,比如:
FastGPT 工作流节点设置和使用指南
FastGPT 知识库搜索引用合并模块介绍
将多个知识库搜索结果合并成一个结果进行输出,并会通过 RRF 进行重新排序(根据排名情况),并且支持最大 tokens 过滤。
AI对话只能接收一个知识库引用内容。因此,如果调用了多个知识库,无法直接引用所有知识库(如下图)
使用知识库搜索引用合并,可以把多个知识库的搜索结果合在一起。
FastGPT Laf 函数调用模块介绍
Laf 函数调用
模块可以调用 Laf 账号下的云函数,其工作原理与 HTTP 模块相同,有以下特殊特征:
要调用 Laf 云函数,首先需要绑定 Laf 账号和应用,并且在应用中创建云函数。
Laf 提供了 PAT(访问凭证) 来实现 Laf 平台外的快捷登录,可以访问 Laf 文档查看详细如何获取 PAT。
在获取到 PAT 后,我们可以进入 FastGPT 的账号页
或是在高级编排中的 Laf模块
对 Laf 账号进行绑定。Laf 账号是团队共享的,仅团队管理员可配置。
填入 PAT 验证后,选择需要绑定的应用(应用需要是 Running 状态),即可调用该应用下的云函数。
Laf 云函数拥有根据 interface 自动生成 OpenAPI 的能力,可以参照下面的代码编写云函数,以便自动生成 OpenAPI 文档。
Laf模块
可以根据 OpenAPI 文档,自动识别出入参,无需手动添加数据类型。如果不会写 TS,可忽略,手动在 FastGPT 中添加参数即可。
+ import cloud from '@lafjs/cloud'
+
+interface IRequestBody { // 自定义入参,FastGPT 传入的均为POST请求。
+ data1: string // 必填参数
+ data2?: string // 可选参数
+}
+
+interface RequestProps extends IRequestBody { // 完整入参,这个无需改动。
+ systemParams: { // 这是FastGPT默认会传递过来的参数
+ appId: string,
+ variables: string,
+ histories: string,
+ cTime: string,
+ chatId: string,
+ responseChatItemId: string
+ }
+}
+
+interface IResponse { // 响应内容
+ message: string // 必返回的参数
+ msg?: string; // 可选的返回参数
+}
+
+export default async function (ctx: FunctionContext): Promise<IResponse> {
+ const {
+ data1,
+ data2,
+ systemParams
+ }: RequestProps = ctx.body;
+
+ console.log({
+ data1,
+ data2,
+ systemParams
+ });
+
+ return {
+ message: 'ok',
+ msg: 'msg'
+ };
+}
+
当然,你也可以在 Laf 平台上选择 fastgpt_template,快速生成该函数模板。
具体操作可以是,进入 Laf 的函数页面,新建函数(注意 fastgpt 只会调用 post 请求的函数),然后复制上面的代码或者点击更多模板搜索“fastgpt”,使用下面的模板
在选择函数后,可以通过点击“同步参数”,自动同步云函数的参数到 FastGPT 中。当然也可以手动添加,手动修改后的参数不会被“同步参数”修改。
先在 laf 中调试函数,看是否正常调用。可以通过 console.log,打印入参,将入参放在 Laf 测试页面的 Body 中进行测试。
FastGPT 循环运行节点介绍和使用
【循环运行】节点是 FastGPT V4.8.11 版本新增的一个重要功能模块。它允许工作流对数组类型的输入数据进行迭代处理,每次处理数组中的一个元素,并自动执行后续节点,直到完成整个数组的处理。
这个节点的设计灵感来自编程语言中的循环结构,但以可视化的方式呈现。
在程序中,节点可以理解为一个个 Function 或者接口。可以理解为它就是一个步骤。将多个节点一个个拼接起来,即可一步步的去实现最终的 AI 输出。
【循环运行】节点本质上也是一个 Function,它的主要职责是自动化地重复执行特定的工作流程。
数组批量处理
自动迭代执行
与其他节点协同
【循环运行】节点的主要作用是通过自动化的方式扩展工作流的处理能力,使 FastGPT 能够更好地处理批量任务和复杂的数据处理流程。特别是在处理大规模数据或需要多轮迭代的场景下,循环运行节点能显著提升工作流的效率和自动化程度。
【循环运行】节点特别适合以下场景:
批量数据处理
数据流水线处理
递归或迭代任务
【循环运行】节点需要配置两个核心输入参数:
数组 (必填):接收一个数组类型的输入,可以是:
Array<string>
)Array<number>
)Array<boolean>
)Array<object>
)循环体 (必填):定义每次循环需要执行的节点流程,包含:
在循环体内部,可以添加任意类型的节点,如:
循环体结束节点配置:
假设我们有一个包含多个文本的数组,需要对每个文本进行 AI 处理。这是循环运行节点最基础也最常见的应用场景。
准备输入数组
使用【代码运行】节点创建测试数组:
+ const texts = [
+ "这是第一段文本",
+ "这是第二段文本",
+ "这是第三段文本"
+];
+return { textArray: texts };
+
配置循环运行节点
textArray
。请将这段文本翻译成英文
。在处理长文本翻译时,我们经常会遇到以下挑战:
【循环运行】节点可以很好地解决这些问题。
文本预处理与分段
使用【代码运行】节点进行文本分段,代码如下:
+ const MAX_HEADING_LENGTH = 7; // 最大标题长度
+const MAX_HEADING_CONTENT_LENGTH = 200; // 最大标题内容长度
+const MAX_HEADING_UNDERLINE_LENGTH = 200; // 最大标题下划线长度
+const MAX_HTML_HEADING_ATTRIBUTES_LENGTH = 100; // 最大HTML标题属性长度
+const MAX_LIST_ITEM_LENGTH = 200; // 最大列表项长度
+const MAX_NESTED_LIST_ITEMS = 6; // 最大嵌套列表项数
+const MAX_LIST_INDENT_SPACES = 7; // 最大列表缩进空格数
+const MAX_BLOCKQUOTE_LINE_LENGTH = 200; // 最大块引用行长度
+const MAX_BLOCKQUOTE_LINES = 15; // 最大块引用行数
+const MAX_CODE_BLOCK_LENGTH = 1500; // 最大代码块长度
+const MAX_CODE_LANGUAGE_LENGTH = 20; // 最大代码语言长度
+const MAX_INDENTED_CODE_LINES = 20; // 最大缩进代码行数
+const MAX_TABLE_CELL_LENGTH = 200; // 最大表格单元格长度
+const MAX_TABLE_ROWS = 20; // 最大表格行数
+const MAX_HTML_TABLE_LENGTH = 2000; // 最大HTML表格长度
+const MIN_HORIZONTAL_RULE_LENGTH = 3; // 最小水平分隔线长度
+const MAX_SENTENCE_LENGTH = 400; // 最大句子长度
+const MAX_QUOTED_TEXT_LENGTH = 300; // 最大引用文本长度
+const MAX_PARENTHETICAL_CONTENT_LENGTH = 200; // 最大括号内容长度
+const MAX_NESTED_PARENTHESES = 5; // 最大嵌套括号数
+const MAX_MATH_INLINE_LENGTH = 100; // 最大行内数学公式长度
+const MAX_MATH_BLOCK_LENGTH = 500; // 最大数学公式块长度
+const MAX_PARAGRAPH_LENGTH = 1000; // 最大段落长度
+const MAX_STANDALONE_LINE_LENGTH = 800; // 最大独立行长度
+const MAX_HTML_TAG_ATTRIBUTES_LENGTH = 100; // 最大HTML标签属性长度
+const MAX_HTML_TAG_CONTENT_LENGTH = 1000; // 最大HTML标签内容长度
+const LOOKAHEAD_RANGE = 100; // 向前查找句子边界的字符数
+
+const AVOID_AT_START = `[\\s\\]})>,']`; // 避免在开头匹配的字符
+const PUNCTUATION = `[.!?…]|\\.{3}|[\\u2026\\u2047-\\u2049]|[\\p{Emoji_Presentation}\\p{Extended_Pictographic}]`; // 标点符号
+const QUOTE_END = `(?:'(?=\`)|''(?=\`\`))`; // 引号结束
+const SENTENCE_END = `(?:${PUNCTUATION}(?<!${AVOID_AT_START}(?=${PUNCTUATION}))|${QUOTE_END})(?=\\S|$)`; // 句子结束
+const SENTENCE_BOUNDARY = `(?:${SENTENCE_END}|(?=[\\r\\n]|$))`; // 句子边界
+const LOOKAHEAD_PATTERN = `(?:(?!${SENTENCE_END}).){1,${LOOKAHEAD_RANGE}}${SENTENCE_END}`; // 向前查找句子结束的模式
+const NOT_PUNCTUATION_SPACE = `(?!${PUNCTUATION}\\s)`; // 非标点符号空格
+const SENTENCE_PATTERN = `${NOT_PUNCTUATION_SPACE}(?:[^\\r\\n]{1,{MAX_LENGTH}}${SENTENCE_BOUNDARY}|[^\\r\\n]{1,{MAX_LENGTH}}(?=${PUNCTUATION}|$ {QUOTE_END})(?:${LOOKAHEAD_PATTERN})?)${AVOID_AT_START}*`; // 句子模式
+
+const regex = new RegExp(
+ "(" +
+ // 1. Headings (Setext-style, Markdown, and HTML-style, with length constraints)
+ `(?:^(?:[#*=-]{1,${MAX_HEADING_LENGTH}}|\\w[^\\r\\n]{0,${MAX_HEADING_CONTENT_LENGTH}}\\r?\\n[-=]{2,${MAX_HEADING_UNDERLINE_LENGTH}}|<h[1-6][^>] {0,${MAX_HTML_HEADING_ATTRIBUTES_LENGTH}}>)[^\\r\\n]{1,${MAX_HEADING_CONTENT_LENGTH}}(?:</h[1-6]>)?(?:\\r?\\n|$))` +
+ "|" +
+ // New pattern for citations
+ `(?:\\[[0-9]+\\][^\\r\\n]{1,${MAX_STANDALONE_LINE_LENGTH}})` +
+ "|" +
+ // 2. List items (bulleted, numbered, lettered, or task lists, including nested, up to three levels, with length constraints)
+ `(?:(?:^|\\r?\\n)[ \\t]{0,3}(?:[-*+•]|\\d{1,3}\\.\\w\\.|\\[[ xX]\\])[ \\t]+${SENTENCE_PATTERN.replace(/{MAX_LENGTH}/g, String (MAX_LIST_ITEM_LENGTH))}` +
+ `(?:(?:\\r?\\n[ \\t]{2,5}(?:[-*+•]|\\d{1,3}\\.\\w\\.|\\[[ xX]\\])[ \\t]+${SENTENCE_PATTERN.replace(/{MAX_LENGTH}/g, String (MAX_LIST_ITEM_LENGTH))}){0,${MAX_NESTED_LIST_ITEMS}}` +
+ `(?:\\r?\\n[ \\t]{4,${MAX_LIST_INDENT_SPACES}}(?:[-*+•]|\\d{1,3}\\.\\w\\.|\\[[ xX]\\])[ \\t]+${SENTENCE_PATTERN.replace(/{MAX_LENGTH}/g, String (MAX_LIST_ITEM_LENGTH))}){0,${MAX_NESTED_LIST_ITEMS}})?)` +
+ "|" +
+ // 3. Block quotes (including nested quotes and citations, up to three levels, with length constraints)
+ `(?:(?:^>(?:>|\\s{2,}){0,2}${SENTENCE_PATTERN.replace(/{MAX_LENGTH}/g, String(MAX_BLOCKQUOTE_LINE_LENGTH))}\\r?\\n?){1,$ {MAX_BLOCKQUOTE_LINES}})` +
+ "|" +
+ // 4. Code blocks (fenced, indented, or HTML pre/code tags, with length constraints)
+ `(?:(?:^|\\r?\\n)(?:\`\`\`|~~~)(?:\\w{0,${MAX_CODE_LANGUAGE_LENGTH}})?\\r?\\n[\\s\\S]{0,${MAX_CODE_BLOCK_LENGTH}}?(?:\`\`\`|~~~)\\r?\\n?` +
+ `|(?:(?:^|\\r?\\n)(?: {4}|\\t)[^\\r\\n]{0,${MAX_LIST_ITEM_LENGTH}}(?:\\r?\\n(?: {4}|\\t)[^\\r\\n]{0,${MAX_LIST_ITEM_LENGTH}}){0,$ {MAX_INDENTED_CODE_LINES}}\\r?\\n?)` +
+ `|(?:<pre>(?:<code>)?[\\s\\S]{0,${MAX_CODE_BLOCK_LENGTH}}?(?:</code>)?</pre>))` +
+ "|" +
+ // 5. Tables (Markdown, grid tables, and HTML tables, with length constraints)
+ `(?:(?:^|\\r?\\n)(?:\\|[^\\r\\n]{0,${MAX_TABLE_CELL_LENGTH}}\\|(?:\\r?\\n\\|[-:]{1,${MAX_TABLE_CELL_LENGTH}}\\|){0,1}(?:\\r?\\n\\|[^\\r\\n]{0,$ {MAX_TABLE_CELL_LENGTH}}\\|){0,${MAX_TABLE_ROWS}}` +
+ `|<table>[\\s\\S]{0,${MAX_HTML_TABLE_LENGTH}}?</table>))` +
+ "|" +
+ // 6. Horizontal rules (Markdown and HTML hr tag)
+ `(?:^(?:[-*_]){${MIN_HORIZONTAL_RULE_LENGTH},}\\s*$|<hr\\s*/?>)` +
+ "|" +
+ // 10. Standalone lines or phrases (including single-line blocks and HTML elements, with length constraints)
+ `(?!${AVOID_AT_START})(?:^(?:<[a-zA-Z][^>]{0,${MAX_HTML_TAG_ATTRIBUTES_LENGTH}}>)?${SENTENCE_PATTERN.replace(/{MAX_LENGTH}/g, String (MAX_STANDALONE_LINE_LENGTH))}(?:</[a-zA-Z]+>)?(?:\\r?\\n|$))` +
+ "|" +
+ // 7. Sentences or phrases ending with punctuation (including ellipsis and Unicode punctuation)
+ `(?!${AVOID_AT_START})${SENTENCE_PATTERN.replace(/{MAX_LENGTH}/g, String(MAX_SENTENCE_LENGTH))}` +
+ "|" +
+ // 8. Quoted text, parenthetical phrases, or bracketed content (with length constraints)
+ "(?:" +
+ `(?<!\\w)\"\"\"[^\"]{0,${MAX_QUOTED_TEXT_LENGTH}}\"\"\"(?!\\w)` +
+ `|(?<!\\w)(?:['\"\`'"])[^\\r\\n]{0,${MAX_QUOTED_TEXT_LENGTH}}\\1(?!\\w)` +
+ `|(?<!\\w)\`[^\\r\\n]{0,${MAX_QUOTED_TEXT_LENGTH}}'(?!\\w)` +
+ `|(?<!\\w)\`\`[^\\r\\n]{0,${MAX_QUOTED_TEXT_LENGTH}}''(?!\\w)` +
+ `|\\([^\\r\\n()]{0,${MAX_PARENTHETICAL_CONTENT_LENGTH}}(?:\\([^\\r\\n()]{0,${MAX_PARENTHETICAL_CONTENT_LENGTH}}\\)[^\\r\\n()]{0,$ {MAX_PARENTHETICAL_CONTENT_LENGTH}}){0,${MAX_NESTED_PARENTHESES}}\\)` +
+ `|\\[[^\\r\\n\\[\\]]{0,${MAX_PARENTHETICAL_CONTENT_LENGTH}}(?:\\[[^\\r\\n\\[\\]]{0,${MAX_PARENTHETICAL_CONTENT_LENGTH}}\\][^\\r\\n\\[\\]]{0,$ {MAX_PARENTHETICAL_CONTENT_LENGTH}}){0,${MAX_NESTED_PARENTHESES}}\\]` +
+ `|\\$[^\\r\\n$]{0,${MAX_MATH_INLINE_LENGTH}}\\$` +
+ `|\`[^\`\\r\\n]{0,${MAX_MATH_INLINE_LENGTH}}\`` +
+ ")" +
+ "|" +
+ // 9. Paragraphs (with length constraints)
+ `(?!${AVOID_AT_START})(?:(?:^|\\r?\\n\\r?\\n)(?:<p>)?${SENTENCE_PATTERN.replace(/{MAX_LENGTH}/g, String(MAX_PARAGRAPH_LENGTH))}(?:</p>)?(?=\\r? \\n\\r?\\n|$))` +
+ "|" +
+ // 11. HTML-like tags and their content (including self-closing tags and attributes, with length constraints)
+ `(?:<[a-zA-Z][^>]{0,${MAX_HTML_TAG_ATTRIBUTES_LENGTH}}(?:>[\\s\\S]{0,${MAX_HTML_TAG_CONTENT_LENGTH}}?</[a-zA-Z]+>|\\s*/>))` +
+ "|" +
+ // 12. LaTeX-style math expressions (inline and block, with length constraints)
+ `(?:(?:\\$\\$[\\s\\S]{0,${MAX_MATH_BLOCK_LENGTH}}?\\$\\$)|(?:\\$[^\\$\\r\\n]{0,${MAX_MATH_INLINE_LENGTH}}\\$))` +
+ "|" +
+ // 14. Fallback for any remaining content (with length constraints)
+ `(?!${AVOID_AT_START})${SENTENCE_PATTERN.replace(/{MAX_LENGTH}/g, String(MAX_STANDALONE_LINE_LENGTH))}` +
+ ")",
+ "gmu"
+);
+
+function main({text}){
+ const chunks = [];
+ let currentChunk = '';
+ const tokens = countToken(text)
+
+ const matches = text.match(regex);
+ if (matches) {
+ matches.forEach((match) => {
+ if (currentChunk.length + match.length <= 1000) {
+ currentChunk += match;
+ } else {
+ if (currentChunk) {
+ chunks.push(currentChunk);
+ }
+ currentChunk = match;
+ }
+ });
+ if (currentChunk) {
+ chunks.push(currentChunk);
+ }
+ }
+
+ return {chunks, tokens};
+}
+
这里我们用到了 Jina AI 开源的一个强大的正则表达式,它能利用所有可能的边界线索和启发式方法来精确切分文本。
配置循环运行节点
chunks
。result
。FastGPT 问题分类模块介绍
可以将用户的问题进行分类,分类后执行不同操作。在一些较模糊的场景中,分类效果不是很明显。
被放置在对话最前面,可用于补充说明分类内容的定义。例如问题会被分为:
由于 Laf 不是一个明确的东西,需要给它一个定义,此时提示词里可以填入 Laf 的定义:
+ Laf 是云开发平台,可以快速的开发应用
+Laf 是一个开源的 BaaS 开发平台(Backend as a Service)
+Laf 是一个开箱即用的 serverless 开发平台
+Laf 是一个集「函数计算」、「数据库」、「对象存储」等于一身的一站式开发平台
+Laf 可以是开源版的腾讯云开发、开源版的 Google Firebase、开源版的 UniCloud
+
适当增加一些聊天记录,可以联系上下文进行分类。
用户输入的内容。
依然以这 3 个分类为例,可以看到最终组成的 Function。其中返回值由系统随机生成,不需要关心。
+ const agentFunction = {
+ name: agentFunName,
+ description: '判断用户问题的类型属于哪方面,返回对应的枚举字段',
+ parameters: {
+ type: 'object',
+ properties: {
+ type: {
+ type: 'string',
+ description: `打招呼,返回: abc;Laf 常见问题,返回:vvv;其他问题,返回:aaa`
+ enum: ["abc","vvv","aaa"]
+ }
+ },
+ required: ['type']
+ }
+};
+
上面的 Function 必然会返回 type = abc,vvv,aaa
其中一个值,从而实现分类判断。
FastGPT 指定回复模块介绍
指定回复模块通常用户特殊状态回复,回复内容有两种:
FastGPT 代码运行节点介绍
可用于执行一段简单的 js 代码,用于进行一些复杂的数据处理。代码运行在沙盒中,无法进行网络请求、dom和异步操作。如需复杂操作,需外挂 HTTP 实现。
注意事项
fastgpt-sandbox
镜像,并配置SANDBOX_URL
环境变量。可在自定义输入中添加代码运行需要的变量,在代码的 main 函数中,可解构出相同名字的变量。
如上图,自定义输入中有 data1 和 data2 两个变量,main 函数中可以解构出相同名字的变量。
务必返回一个 object 对象
自定义输出中,可以添加变量名来获取 object 对应 key 下的值。例如上图中,返回了一个对象:
+ {
+ result: data1,
+ data2
+}
+
他有 2 个 key:result和 data2(js 缩写,key=data2,value=data2)。这时候自定义输出中就可以添加 2 个变量来获取对应 key 下的 value。
延迟 1 秒后返回
+ async function main({data1, data2}){
+ await delay(1000)
+ return {
+ result: "111"
+ }
+}
+
+ function main({input}){
+ return {
+ result: countToken(input)
+ }
+}
+
可用于将 SVG 图片转换为 base64 格式展示。
+ function main({input}){
+
+ return {
+ /*
+ param1: input 需要转换的字符串
+ param2: base64 prefix 前缀
+ */
+ result: strToBase64(input,'data:image/svg+xml;base64,')
+ }
+}
+
与 node 中 crypto 的 createHmac 方法一致。
+ function main({secret}){
+ const {sign,timestamp} = createHmac('sha256',secret)
+
+ return {
+ sign,timestamp
+ }
+}
+
FastGPT 判断器模块介绍
对任意变量进行IF
判断,若满足条件则执行IF
分支,不满足条件执行ELSE
分支。
上述例子中若「知识库引用」变量的长度等于0则执行IF
分支,否则执行ELSE
分支。
支持增加更多的判断条件和分支,同编程语言中的IF
语句逻辑相同。
适用场景有:让大模型做判断后输出固定内容,根据大模型回复内容判断是否触发后续模块。
FastGPT 工具调用模块介绍
工具可以是一个系统模块,例如:AI对话、知识库搜索、HTTP模块等。也可以是一个插件。
工具调用可以让 LLM 更动态的决策流程,而不都是固定的流程。(当然,缺点就是费tokens)
要了解工具如何运行的,首先需要知道它的运行条件。
参数介绍
和是否必须
。结合工具的介绍、参数介绍和参数是否必须,LLM会决定是否调用这个工具。有以下几种情况:
在支持函数调用
的模型中,可以一次性调用多个工具,调用逻辑如下:
高级编排中,拖动工具调用的连接点,可用的工具头部会出现一个菱形,可以将它与工具调用模块底部的菱形相连接。
被连接的工具,会自动分离工具输入与普通的输入,并且可以编辑介绍
,可以通过调整介绍,使得该工具调用时机更加精确。
关于工具调用,如何调试仍然是一个玄学,所以建议,不要一次性增加太多工具,选择少量工具调优后再进一步尝试。
默认情况下,工具调用节点,在决定调用工具后,会将工具运行的结果,返回给AI,让 AI 对工具运行的结果进行总结输出。有时候,如果你不需要 AI 进行进一步的总结输出,可以使用该节点,将其接入对于工具流程的末尾。
如下图,在执行知识库搜索后,发送给了 HTTP 请求,搜索将不会返回搜索的结果给工具调用进行 AI 总结。
当您使用了工具调用节点,同时就会出现工具调用终止节点和自定义变量节点,能够进一步提升工具调用的使用体验。
工具调用终止可用于结束本次调用,即可以接在某个工具后面,当工作流执行到这个节点时,便会强制结束本次工具调用,不再调用其他工具,也不会再调用 AI 针对工具调用结果回答问题。
自定义变量可以扩展工具的变量输入,即对于一些未被视作工具参数或无法工具调用的节点,可以自定义工具变量,填上对应的参数描述,那么工具调用便会相对应的调用这个节点,进而调用其之后的工作流。
FastGPT 用户选择模块的使用说明
「用户选择」节点属于用户交互节点,当触发这个节点时,对话会进入“交互”状态,会记录工作流的状态,等用户完成交互后,继续向下执行工作流
比如上图中的例子,当触发用户选择节点时,对话框隐藏,对话进入“交互状态”
当用户做出选择时,节点会判断用户的选择,执行“是”的分支
基础的用法为提出需要用户做抉择的问题,然后根据用户的反馈设计不同的工作流流程
FastGPT 变量更新模块介绍
最基础的使用场景为
FastGPT 官方文档
FastGPT 的能力与优势
FastGPT 是一个基于 LLM 大语言模型的知识库问答系统,提供开箱即用的数据处理、模型调用等能力。同时可以通过 Flow 可视化进行工作流编排,从而实现复杂的问答场景!
FastGPT 在线使用:https://tryfastgpt.ai
通过导入文档或已有问答对进行训练,让 AI 模型能根据你的文档以交互式对话方式回答问题。
FastGPT 采用直观的可视化界面设计,为各种应用场景提供了丰富实用的功能。通过简洁易懂的操作步骤,可以轻松完成 AI 客服的创建和训练流程。
提供手动输入、直接分段、LLM 自动处理和 CSV 等多种数据导入途径,其中“直接分段”支持通过 PDF、WORD、Markdown 和 CSV 文档内容作为上下文。FastGPT 会自动对文本数据进行预处理、向量化和 QA 分割,节省手动训练时间,提升效能。
基于 Flow 模块的工作流编排,可以帮助你设计更加复杂的问答流程。例如查询数据库、查询库存、预约实验室等。
FastGPT 对外的 API 接口对齐了 OpenAI 官方接口,可以直接接入现有的 GPT 应用,也可以轻松集成到企业微信、公众号、飞书等平台。
项目开源
FastGPT 遵循附加条件 Apache License 2.0 开源协议,你可以 Fork 之后进行二次开发和发布。FastGPT 社区版将保留核心功能,商业版仅在社区版基础上使用 API 的形式进行扩展,不影响学习使用。
独特的 QA 结构
针对客服问答场景设计的 QA 结构,提高在大量数据场景中的问答准确性。
可视化工作流
通过 Flow 模块展示了从问题输入到模型输出的完整流程,便于调试和设计复杂流程。
无限扩展
基于 API 进行扩展,无需修改 FastGPT 源码,也可快速接入现有的程序中。
便于调试
提供搜索测试、引用修改、完整对话预览等多种调试途径。
支持多种模型
支持 GPT、Claude、文心一言等多种 LLM 模型,未来也将支持自定义的向量模型。
FastGPT 商业版相关说明
FastGPT 商业版是基于 FastGPT 开源版的增强版本,增加了一些独有的功能。只需安装一个商业版镜像,并在开源版基础上填写对应的内网地址,即可快速使用商业版。
开源版 | 商业版 | 线上版 | |
---|---|---|---|
应用管理与高级编排 | ✅ | ✅ | ✅ |
文档知识库 | ✅ | ✅ | ✅ |
外部使用 | ✅ | ✅ | ✅ |
API 知识库 | ✅ | ✅ | ✅ |
最大应用数量 | 500 | 无限制 | 由付费套餐决定 |
最大知识库数量(单个知识库内容无限制) | 30 | 无限制 | 由付费套餐决定 |
自定义版权信息 | ❌ | ✅ | 设计中 |
多租户与支付 | ❌ | ✅ | ✅ |
团队空间 & 权限 | ❌ | ✅ | ✅ |
应用发布安全配置 | ❌ | ✅ | ✅ |
内容审核 | ❌ | ✅ | ✅ |
web站点同步 | ❌ | ✅ | ✅ |
主流文档库接入(目前支持:语雀、飞书) | ❌ | ✅ | ✅ |
增强训练模式 | ❌ | ✅ | ✅ |
第三方应用快速接入(飞书、公众号) | ❌ | ✅ | ✅ |
管理后台 | ❌ | ✅ | 不需要 |
SSO 登录(可自定义,也可使用内置:Github、公众号、钉钉、谷歌等) | ❌ | ✅ | 不需要 |
图片知识库 | ❌ | 设计中 | 设计中 |
对话日志运营分析 | ❌ | 设计中 | 设计中 |
完整商业授权 | ❌ | ✅ | ✅ |
FastGPT 商业版软件根据不同的部署方式,分为 3 类收费模式。下面列举各种部署方式一些常规内容,如仍有问题,可联系咨询
共有服务
特有服务
部署方式 | 特有服务 | 上线时长 | 标品价格 |
---|---|---|---|
Sealos全托管 | 1. 有效期内免费升级。 2. 免运维服务&数据库。 | 半天 | 6000元起/月(3个月起) 或 60000元起/年 |
自有服务器部署 | 1. 6个版本免费升级支持。 | 14天内 | 具体价格可联系咨询 |
6个版本的升级服务不是指只能用 6 个版本,而是指依赖 FastGPT 团队提供的升级服务。大部分时候,建议自行升级,也不麻烦。
全托管版本适合技术人员紧缺的团队,仅需关注业务推动,无需关心服务是否正常运行。
自有服务器部署版可以完全部署在自己服务器中。
单机版适合中小团队对内提供服务,需要自己维护数据库备份等。
高可用版适合对外提供在线服务,包含可视化监控、多副本、负载均衡、数据库自动备份等生产环境的基础设施。
请填写咨询问卷,我们会尽快与您联系。
根据需求,定制实现某个需求的编排功能,最终会交付一个应用编排。可根据实际情况商讨。
2000 ~ 3000元/人/天
大部分更新升级,重新拉镜像,然后执行一下初始化脚本就可以了,不需要执行额外操作。
跨版本更新或复杂更新可参考文档自行更新;或付费支持,标准与技术服务费一致。
完整版应用 = 开源版镜像 + 商业版镜像
我们会提供一个商业版镜像给你使用,该镜像需要一个 License 启动。
可以修改开源版部分代码,不支持修改商业版镜像。完整版本=开源版+商业版镜像,所以是可以修改部分内容的。但是如果二开了,后续则需要自己进行代码合并升级。
Sealos 云服务属于按量计费,下面是它的价格表:
使用 HTTP 模块绘制图片
先来看下官方接口的参数和响应值:
Body
+ {
+ "model": "dall-e-3",
+ "prompt": "A cute baby sea otter",
+ "n": 1,
+ "size": "1024x1024"
+}
+
Response
+ {
+ "created": 1589478378,
+ "data": [
+ {
+ "url": "https://..."
+ },
+ {
+ "url": "https://..."
+ }
+ ]
+}
+
【HTTP 请求】模块
调用 Dalle3 接口,获取图片的 URL。【文本加工】模块
来构建 Markdown
的图片格式。【指定回复】模块
来直接输出图片链接。请求参数直接复制 Dalle3 接口的即可,并求改 prompt 为变量。需要增加一个 Headers.Authorization
。
Body:
+ {
+ "model": "dall-e-3",
+ "prompt": "{{prompt}}",
+ "n": 1,
+ "size": "1024x1024"
+}
+
Headers:
Authorization: Bearer sk-xxx
Response:
响应值需要根据 Dalle3 接口的返回值进行获取,我们只绘制了1张图片,所以只需要取第一张图片的 URL 即可。给 HTTP 模块增加一个自定义输出 data[0].url
。
在 Markdown
语法中 ![图片描述](图片链接)
表示插入图片,图片链接由【HTTP 请求】模块输出。
因此可以增加一个输入来接收 【HTTP 请求】模块
的图片链接输出,并在 【文本加工】模块 - 文本
中通过变量来引用图片链接,从而得到一个完整的 Markdown
图片格式。
指定回复可以直接输出传入的内容到客户端,因此可以直接输出加工好的 Markdown
图片格式即可。
{
+ "nodes": [
+ {
+ "nodeId": "userGuide",
+ "name": "系统配置",
+ "intro": "可以配置应用的系统参数",
+ "avatar": "/imgs/workflow/userGuide.png",
+ "flowNodeType": "userGuide",
+ "position": {
+ "x": 531.2422736065552,
+ "y": -486.7611729549753
+ },
+ "inputs": [
+ {
+ "key": "welcomeText",
+ "renderTypeList": [
+ "hidden"
+ ],
+ "valueType": "string",
+ "label": "core.app.Welcome Text",
+ "value": ""
+ },
+ {
+ "key": "variables",
+ "renderTypeList": [
+ "hidden"
+ ],
+ "valueType": "any",
+ "label": "core.app.Chat Variable",
+ "value": []
+ },
+ {
+ "key": "questionGuide",
+ "valueType": "boolean",
+ "renderTypeList": [
+ "hidden"
+ ],
+ "label": "core.app.Question Guide",
+ "value": false
+ },
+ {
+ "key": "tts",
+ "renderTypeList": [
+ "hidden"
+ ],
+ "valueType": "any",
+ "label": "",
+ "value": {
+ "type": "web"
+ }
+ },
+ {
+ "key": "whisper",
+ "renderTypeList": [
+ "hidden"
+ ],
+ "valueType": "any",
+ "label": "",
+ "value": {
+ "open": false,
+ "autoSend": false,
+ "autoTTSResponse": false
+ }
+ },
+ {
+ "key": "scheduleTrigger",
+ "renderTypeList": [
+ "hidden"
+ ],
+ "valueType": "any",
+ "label": "",
+ "value": null
+ }
+ ],
+ "outputs": []
+ },
+ {
+ "nodeId": "448745",
+ "name": "流程开始",
+ "intro": "",
+ "avatar": "/imgs/workflow/userChatInput.svg",
+ "flowNodeType": "workflowStart",
+ "position": {
+ "x": 532.1275542407774,
+ "y": 46.03775600322817
+ },
+ "inputs": [
+ {
+ "key": "userChatInput",
+ "renderTypeList": [
+ "reference",
+ "textarea"
+ ],
+ "valueType": "string",
+ "label": "用户问题",
+ "required": true,
+ "toolDescription": "用户问题"
+ }
+ ],
+ "outputs": [
+ {
+ "id": "userChatInput",
+ "key": "userChatInput",
+ "label": "core.module.input.label.user question",
+ "valueType": "string",
+ "type": "static"
+ }
+ ]
+ },
+ {
+ "nodeId": "tMyUnRL5jIrC",
+ "name": "HTTP 请求",
+ "intro": "可以发出一个 HTTP 请求,实现更为复杂的操作(联网搜索、数据库查询等)",
+ "avatar": "/imgs/workflow/http.png",
+ "flowNodeType": "httpRequest468",
+ "showStatus": true,
+ "position": {
+ "x": 921.2377506442713,
+ "y": -483.94114977914256
+ },
+ "inputs": [
+ {
+ "key": "system_addInputParam",
+ "renderTypeList": [
+ "addInputParam"
+ ],
+ "valueType": "dynamic",
+ "label": "",
+ "required": false,
+ "description": "core.module.input.description.HTTP Dynamic Input",
+ "editField": {
+ "key": true,
+ "valueType": true
+ }
+ },
+ {
+ "key": "prompt",
+ "valueType": "string",
+ "label": "prompt",
+ "renderTypeList": [
+ "reference"
+ ],
+ "description": "",
+ "canEdit": true,
+ "editField": {
+ "key": true,
+ "valueType": true
+ },
+ "value": [
+ "448745",
+ "userChatInput"
+ ]
+ },
+ {
+ "key": "system_httpMethod",
+ "renderTypeList": [
+ "custom"
+ ],
+ "valueType": "string",
+ "label": "",
+ "value": "POST",
+ "required": 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,
+ "value": "https://api.openai.com/v1/images/generations"
+ },
+ {
+ "key": "system_httpHeader",
+ "renderTypeList": [
+ "custom"
+ ],
+ "valueType": "any",
+ "value": [
+ {
+ "key": "Authorization",
+ "type": "string",
+ "value": "Bearer "
+ }
+ ],
+ "label": "",
+ "description": "core.module.input.description.Http Request Header",
+ "placeholder": "core.module.input.description.Http Request Header",
+ "required": false
+ },
+ {
+ "key": "system_httpParams",
+ "renderTypeList": [
+ "hidden"
+ ],
+ "valueType": "any",
+ "value": [],
+ "label": "",
+ "required": false
+ },
+ {
+ "key": "system_httpJsonBody",
+ "renderTypeList": [
+ "hidden"
+ ],
+ "valueType": "any",
+ "value": "{\n \"model\": \"dall-e-3\",\n \"prompt\": \"{{prompt}}\",\n \"n\": 1,\n \"size\": \"1024x1024\"\n}",
+ "label": "",
+ "required": false
+ }
+ ],
+ "outputs": [
+ {
+ "id": "system_addOutputParam",
+ "key": "system_addOutputParam",
+ "type": "dynamic",
+ "valueType": "dynamic",
+ "label": "",
+ "editField": {
+ "key": true,
+ "valueType": true
+ }
+ },
+ {
+ "id": "httpRawResponse",
+ "key": "httpRawResponse",
+ "label": "原始响应",
+ "description": "HTTP请求的原始响应。只能接受字符串或JSON类型响应数据。",
+ "valueType": "any",
+ "type": "static"
+ },
+ {
+ "id": "DeKGGioBwaMf",
+ "type": "dynamic",
+ "key": "data[0].url",
+ "valueType": "string",
+ "label": "data[0].url"
+ }
+ ]
+ },
+ {
+ "nodeId": "CO3POL8svbbi",
+ "name": "文本加工",
+ "intro": "可对固定或传入的文本进行加工后输出,非字符串类型数据最终会转成字符串类型。",
+ "avatar": "/imgs/workflow/textEditor.svg",
+ "flowNodeType": "pluginModule",
+ "showStatus": false,
+ "position": {
+ "x": 1417.5940290051137,
+ "y": -478.81889618104356
+ },
+ "inputs": [
+ {
+ "key": "system_addInputParam",
+ "valueType": "dynamic",
+ "label": "动态外部数据",
+ "renderTypeList": [
+ "addInputParam"
+ ],
+ "required": false,
+ "description": "",
+ "canEdit": false,
+ "value": "",
+ "editField": {
+ "key": true
+ },
+ "dynamicParamDefaultValue": {
+ "inputType": "reference",
+ "valueType": "string",
+ "required": true
+ }
+ },
+ {
+ "key": "url",
+ "valueType": "string",
+ "label": "url",
+ "renderTypeList": [
+ "reference"
+ ],
+ "required": true,
+ "description": "",
+ "canEdit": true,
+ "editField": {
+ "key": true
+ },
+ "value": [
+ "tMyUnRL5jIrC",
+ "DeKGGioBwaMf"
+ ]
+ },
+ {
+ "key": "文本",
+ "valueType": "string",
+ "label": "文本",
+ "renderTypeList": [
+ "textarea"
+ ],
+ "required": true,
+ "description": "",
+ "canEdit": false,
+ "value": "![]({{url}})",
+ "editField": {
+ "key": true
+ },
+ "maxLength": "",
+ "dynamicParamDefaultValue": {
+ "inputType": "reference",
+ "valueType": "string",
+ "required": true
+ }
+ }
+ ],
+ "outputs": [
+ {
+ "id": "text",
+ "type": "static",
+ "key": "text",
+ "valueType": "string",
+ "label": "text",
+ "description": ""
+ }
+ ],
+ "pluginId": "community-textEditor"
+ },
+ {
+ "nodeId": "7mapnCgHfKW6",
+ "name": "指定回复",
+ "intro": "该模块可以直接回复一段指定的内容。常用于引导、提示。非字符串内容传入时,会转成字符串进行输出。",
+ "avatar": "/imgs/workflow/reply.png",
+ "flowNodeType": "answerNode",
+ "position": {
+ "x": 1922.5628399315042,
+ "y": -471.67391598231796
+ },
+ "inputs": [
+ {
+ "key": "text",
+ "renderTypeList": [
+ "textarea",
+ "reference"
+ ],
+ "valueType": "string",
+ "label": "core.module.input.label.Response content",
+ "description": "core.module.input.description.Response content",
+ "placeholder": "core.module.input.description.Response content",
+ "selectedTypeIndex": 1,
+ "value": [
+ "CO3POL8svbbi",
+ "text"
+ ]
+ }
+ ],
+ "outputs": []
+ }
+ ],
+ "edges": [
+ {
+ "source": "448745",
+ "target": "tMyUnRL5jIrC",
+ "sourceHandle": "448745-source-right",
+ "targetHandle": "tMyUnRL5jIrC-target-left"
+ },
+ {
+ "source": "tMyUnRL5jIrC",
+ "target": "CO3POL8svbbi",
+ "sourceHandle": "tMyUnRL5jIrC-source-right",
+ "targetHandle": "CO3POL8svbbi-target-left"
+ },
+ {
+ "source": "CO3POL8svbbi",
+ "target": "7mapnCgHfKW6",
+ "sourceHandle": "CO3POL8svbbi-source-right",
+ "targetHandle": "7mapnCgHfKW6-target-left"
+ }
+ ]
+}
+
使用 FastGPT 创建一个用于英语作文纠错的机器人,帮助用户检测并纠正语言错误
FastGPT 提供了一种基于 LLM Model 搭建应用的简便方式。
本文通过搭建一个英语作文纠错机器人,介绍一下如何使用 工作流
可以从 多轮翻译机器人 开始创建。
多轮翻译机器人是 @米开朗基杨 同学创建的,同样也是一个值得学习的工作流。
我们期望让大模型处理文字,返回一个结构化的数据,由我们自己处理。
提示词 是最重要的一个参数,这里提供的提示词仅供参考:
+ ## 角色
+资深英语写作专家
+
+## 任务
+对输入的原文进行分析。 找出其中的各种错误, 包括但不限于单词拼写错误、 语法错误等。
+注意: 忽略标点符号前后空格的问题。
+注意: 对于存在错误的句子, 提出修改建议是指指出这个句子中的具体部分, 然后提出将这一个部分修改替换为什么。
+
+## 输出格式
+不要使用 Markdown 语法, 输入 JSON 格式的内容。
+输出的"reason"的内容使用中文。
+直接输出一个列表, 其成员为一个相同类型的对象, 定义如下
+您正在找回 FastGPT 账号
+```
+{
+“raw”: string; // 表示原文
+“reason”: string; // 表示原因
+“suggestion”: string; // 修改建议
+}
+```
+
可以在模型选择的窗口中设置禁用 AI 回复。
这样就看不到输出的 json 格式的内容了。
上面的大模型输出了一个 json,这里要进行数据处理。数据处理可以使用代码执行组件。
+ function main({data}){
+ const array = JSON.parse(data)
+ return {
+ content: array.map(
+ (item, index) => {
+ return `
+## 分析${index+1}
+- **错误**: ${item.raw}
+- **分析**: ${item.reason}
+- **修改建议**: ${item.suggestion}
+`
+ }
+ ).join('')
+ }
+}
+
上面的代码将 JSON 解析为 Object, 然后拼接成一串 Markdown 语法的字符串。
FastGPT 的指定回复组件可以将 Markdown 解析为 Html 返回。
可以使用发布渠道进行发布。
可以选择通过 URL 访问,或者是直接嵌入你的网页中。
利用工具调用模块,发送一个飞书webhook通知
该文章展示如何发送一个简单的飞书webhook通知,以此类推,发送其他类型的通知也可以这么操作。
复制下面配置,点击「高级编排」右上角的导入按键,导入该配置,导入后将飞书提供的接口地址复制到「HTTP 模块」。
{
+ "nodes": [
+ {
+ "nodeId": "userGuide",
+ "name": "系统配置",
+ "intro": "可以配置应用的系统参数",
+ "avatar": "/imgs/workflow/userGuide.png",
+ "flowNodeType": "userGuide",
+ "position": {
+ "x": 303.41163758039283,
+ "y": -552.297639861266
+ },
+ "version": "481",
+ "inputs": [],
+ "outputs": []
+ },
+ {
+ "nodeId": "workflowStartNodeId",
+ "name": "流程开始",
+ "intro": "",
+ "avatar": "/imgs/workflow/userChatInput.svg",
+ "flowNodeType": "workflowStart",
+ "position": {
+ "x": 529.3935295017156,
+ "y": 197.114018410347
+ },
+ "version": "481",
+ "inputs": [
+ {
+ "key": "userChatInput",
+ "renderTypeList": [
+ "reference",
+ "textarea"
+ ],
+ "valueType": "string",
+ "label": "用户问题",
+ "required": true,
+ "toolDescription": "用户问题"
+ }
+ ],
+ "outputs": [
+ {
+ "id": "userChatInput",
+ "key": "userChatInput",
+ "label": "core.module.input.label.user question",
+ "valueType": "string",
+ "type": "static"
+ }
+ ]
+ },
+ {
+ "nodeId": "u6IAOEssxoZT",
+ "name": "工具调用",
+ "intro": "通过AI模型自动选择一个或多个功能块进行调用,也可以对插件进行调用。",
+ "avatar": "/imgs/workflow/tool.svg",
+ "flowNodeType": "tools",
+ "showStatus": true,
+ "position": {
+ "x": 1003.146243538873,
+ "y": 48.52327869406625
+ },
+ "version": "481",
+ "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"
+ },
+ {
+ "key": "history",
+ "renderTypeList": [
+ "numberInput",
+ "reference"
+ ],
+ "valueType": "chatHistory",
+ "label": "core.module.input.label.chat history",
+ "description": "最多携带多少轮对话记录",
+ "required": true,
+ "min": 0,
+ "max": 50,
+ "value": 6
+ },
+ {
+ "key": "userChatInput",
+ "renderTypeList": [
+ "reference",
+ "textarea"
+ ],
+ "valueType": "string",
+ "label": "用户问题",
+ "required": true,
+ "value": [
+ "workflowStartNodeId",
+ "userChatInput"
+ ]
+ }
+ ],
+ "outputs": [
+ {
+ "id": "answerText",
+ "key": "answerText",
+ "label": "core.module.output.label.Ai response content",
+ "description": "core.module.output.description.Ai response content",
+ "valueType": "string",
+ "type": "static"
+ }
+ ]
+ },
+ {
+ "nodeId": "fvY5hb0K646V",
+ "name": "工具调用终止",
+ "intro": "该模块需配置工具调用使用。当该模块被执行时,本次工具调用将会强制结束,并且不再调用AI针对工具调用结果回答问题。",
+ "avatar": "/imgs/workflow/toolStop.svg",
+ "flowNodeType": "stopTool",
+ "position": {
+ "x": 2367.838362362707,
+ "y": 732.355988936165
+ },
+ "version": "481",
+ "inputs": [],
+ "outputs": []
+ },
+ {
+ "nodeId": "x9rN2a4WnZmt",
+ "name": "HTTP 请求",
+ "intro": "向飞书发送一个webhooks通知信息。",
+ "avatar": "/imgs/workflow/http.png",
+ "flowNodeType": "httpRequest468",
+ "showStatus": true,
+ "position": {
+ "x": 1623.9214305901633,
+ "y": 22.777089001645862
+ },
+ "version": "486",
+ "inputs": [
+ {
+ "key": "system_addInputParam",
+ "renderTypeList": [
+ "addInputParam"
+ ],
+ "valueType": "dynamic",
+ "label": "",
+ "required": false,
+ "description": "core.module.input.description.HTTP Dynamic Input",
+ "editField": {
+ "key": true,
+ "valueType": true
+ }
+ },
+ {
+ "valueType": "string",
+ "renderTypeList": [
+ "reference"
+ ],
+ "key": "text",
+ "label": "text",
+ "toolDescription": "发送的消息",
+ "required": true,
+ "canEdit": true,
+ "editField": {
+ "key": true,
+ "description": true
+ }
+ },
+ {
+ "key": "system_httpMethod",
+ "renderTypeList": [
+ "custom"
+ ],
+ "valueType": "string",
+ "label": "",
+ "value": "POST",
+ "required": 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,
+ "value": ""
+ },
+ {
+ "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
+ },
+ {
+ "key": "system_httpParams",
+ "renderTypeList": [
+ "hidden"
+ ],
+ "valueType": "any",
+ "value": [],
+ "label": "",
+ "required": false
+ },
+ {
+ "key": "system_httpJsonBody",
+ "renderTypeList": [
+ "hidden"
+ ],
+ "valueType": "any",
+ "value": "{\r\n \"msg_type\": \"text\",\r\n \"content\": {\r\n \"text\": \"{{text}}\"\r\n }\r\n}",
+ "label": "",
+ "required": false
+ }
+ ],
+ "outputs": [
+ {
+ "id": "system_addOutputParam",
+ "key": "system_addOutputParam",
+ "type": "dynamic",
+ "valueType": "dynamic",
+ "label": "",
+ "editField": {
+ "key": true,
+ "valueType": true
+ }
+ },
+ {
+ "id": "error",
+ "key": "error",
+ "label": "请求错误",
+ "description": "HTTP请求错误信息,成功时返回空",
+ "valueType": "object",
+ "type": "static"
+ },
+ {
+ "id": "httpRawResponse",
+ "key": "httpRawResponse",
+ "label": "原始响应",
+ "required": true,
+ "description": "HTTP请求的原始响应。只能接受字符串或JSON类型响应数据。",
+ "valueType": "any",
+ "type": "static"
+ }
+ ]
+ },
+ {
+ "nodeId": "aGHGqH2oUupj",
+ "name": "指定回复",
+ "intro": "该模块可以直接回复一段指定的内容。常用于引导、提示。非字符串内容传入时,会转成字符串进行输出。",
+ "avatar": "/imgs/workflow/reply.png",
+ "flowNodeType": "answerNode",
+ "position": {
+ "x": 2350.7077940158674,
+ "y": 107.32448732713493
+ },
+ "version": "481",
+ "inputs": [
+ {
+ "key": "text",
+ "renderTypeList": [
+ "textarea",
+ "reference"
+ ],
+ "valueType": "any",
+ "required": true,
+ "label": "core.module.input.label.Response content",
+ "description": "core.module.input.description.Response content",
+ "placeholder": "core.module.input.description.Response content",
+ "value": "嘻嘻,发送成功"
+ }
+ ],
+ "outputs": []
+ }
+ ],
+ "edges": [
+ {
+ "source": "workflowStartNodeId",
+ "target": "u6IAOEssxoZT",
+ "sourceHandle": "workflowStartNodeId-source-right",
+ "targetHandle": "u6IAOEssxoZT-target-left"
+ },
+ {
+ "source": "u6IAOEssxoZT",
+ "target": "x9rN2a4WnZmt",
+ "sourceHandle": "selectedTools",
+ "targetHandle": "selectedTools"
+ },
+ {
+ "source": "x9rN2a4WnZmt",
+ "target": "fvY5hb0K646V",
+ "sourceHandle": "x9rN2a4WnZmt-source-right",
+ "targetHandle": "fvY5hb0K646V-target-left"
+ },
+ {
+ "source": "x9rN2a4WnZmt",
+ "target": "aGHGqH2oUupj",
+ "sourceHandle": "x9rN2a4WnZmt-source-right",
+ "targetHandle": "aGHGqH2oUupj-target-left"
+ }
+ ],
+ "chatConfig": {
+ "variables": [
+ {
+ "id": "txq1ca",
+ "key": "test",
+ "label": "测试",
+ "type": "custom",
+ "required": true,
+ "maxLen": 50,
+ "enums": [
+ {
+ "value": ""
+ }
+ ]
+ }
+ ],
+ "questionGuide": false,
+ "scheduledTriggerConfig": {
+ "cronString": "",
+ "timezone": "Asia/Shanghai",
+ "defaultPrompt": ""
+ },
+ "_id": "66715d4bf577287d39e35ecf"
+ }
+}
+
利用指定回复,创建固定的开头和结尾
如上图,可以通过指定回复编排一个固定的开头和结尾内容。
复制下面配置,点击「高级编排」右上角的导入按键,导入该配置。
{
+ "nodes": [
+ {
+ "nodeId": "7z5g5h",
+ "name": "流程开始",
+ "intro": "",
+ "avatar": "/imgs/workflow/userChatInput.svg",
+ "flowNodeType": "workflowStart",
+ "position": {
+ "x": -269.50851681351924,
+ "y": 1657.6123698022448
+ },
+ "inputs": [
+ {
+ "key": "userChatInput",
+ "renderTypeList": [
+ "reference",
+ "textarea"
+ ],
+ "valueType": "string",
+ "label": "问题输入",
+ "required": true,
+ "toolDescription": "用户问题",
+ "type": "systemInput",
+ "showTargetInApp": false,
+ "showTargetInPlugin": false,
+ "connected": false,
+ "selectedTypeIndex": 0,
+ "value": [
+ "7z5g5h",
+ "userChatInput"
+ ]
+ }
+ ],
+ "outputs": [
+ {
+ "id": "userChatInput",
+ "type": "static",
+ "key": "userChatInput",
+ "valueType": "string",
+ "label": "core.module.input.label.user question"
+ }
+ ]
+ },
+ {
+ "nodeId": "nlfwkc",
+ "name": "AI 对话",
+ "intro": "AI 大模型对话",
+ "avatar": "/imgs/workflow/AI.png",
+ "flowNodeType": "chatNode",
+ "showStatus": true,
+ "position": {
+ "x": 907.2058332478431,
+ "y": 1348.9992737142143
+ },
+ "inputs": [
+ {
+ "key": "model",
+ "renderTypeList": [
+ "settingLLMModel",
+ "reference"
+ ],
+ "label": "core.module.input.label.aiModel",
+ "valueType": "string",
+ "type": "selectLLMModel",
+ "required": true,
+ "showTargetInApp": false,
+ "showTargetInPlugin": false,
+ "value": "gpt-3.5-turbo",
+ "connected": false,
+ "selectedTypeIndex": 0
+ },
+ {
+ "key": "temperature",
+ "renderTypeList": [
+ "hidden"
+ ],
+ "label": "",
+ "value": 0,
+ "valueType": "number",
+ "min": 0,
+ "max": 10,
+ "step": 1,
+ "type": "hidden",
+ "showTargetInApp": false,
+ "showTargetInPlugin": false,
+ "connected": false,
+ "selectedTypeIndex": 0
+ },
+ {
+ "key": "maxToken",
+ "renderTypeList": [
+ "hidden"
+ ],
+ "label": "",
+ "value": 2000,
+ "valueType": "number",
+ "min": 100,
+ "max": 4000,
+ "step": 50,
+ "type": "hidden",
+ "showTargetInApp": false,
+ "showTargetInPlugin": false,
+ "connected": false,
+ "selectedTypeIndex": 0
+ },
+ {
+ "key": "isResponseAnswerText",
+ "renderTypeList": [
+ "hidden"
+ ],
+ "label": "",
+ "value": true,
+ "valueType": "boolean",
+ "type": "hidden",
+ "showTargetInApp": false,
+ "showTargetInPlugin": false,
+ "connected": false,
+ "selectedTypeIndex": 0
+ },
+ {
+ "key": "quoteTemplate",
+ "renderTypeList": [
+ "hidden"
+ ],
+ "label": "",
+ "valueType": "string",
+ "type": "hidden",
+ "showTargetInApp": false,
+ "showTargetInPlugin": false,
+ "connected": false,
+ "selectedTypeIndex": 0
+ },
+ {
+ "key": "quotePrompt",
+ "renderTypeList": [
+ "hidden"
+ ],
+ "label": "",
+ "valueType": "string",
+ "type": "hidden",
+ "showTargetInApp": false,
+ "showTargetInPlugin": false,
+ "connected": false,
+ "selectedTypeIndex": 0
+ },
+ {
+ "key": "systemPrompt",
+ "renderTypeList": [
+ "textarea",
+ "reference"
+ ],
+ "max": 300,
+ "valueType": "string",
+ "label": "core.ai.Prompt",
+ "description": "core.app.tip.chatNodeSystemPromptTip",
+ "placeholder": "core.app.tip.chatNodeSystemPromptTip",
+ "type": "textarea",
+ "showTargetInApp": true,
+ "showTargetInPlugin": true,
+ "value": "",
+ "connected": false,
+ "selectedTypeIndex": 0
+ },
+ {
+ "key": "history",
+ "renderTypeList": [
+ "numberInput",
+ "reference"
+ ],
+ "valueType": "chatHistory",
+ "label": "core.module.input.label.chat history",
+ "required": true,
+ "min": 0,
+ "max": 30,
+ "value": 6,
+ "type": "numberInput",
+ "showTargetInApp": true,
+ "showTargetInPlugin": true,
+ "connected": false,
+ "selectedTypeIndex": 0
+ },
+ {
+ "key": "userChatInput",
+ "renderTypeList": [
+ "reference",
+ "textarea"
+ ],
+ "valueType": "string",
+ "label": "问题输入",
+ "required": true,
+ "toolDescription": "用户问题",
+ "type": "custom",
+ "showTargetInApp": true,
+ "showTargetInPlugin": true,
+ "connected": true,
+ "selectedTypeIndex": 0,
+ "value": [
+ "7z5g5h",
+ "userChatInput"
+ ]
+ },
+ {
+ "key": "quoteQA",
+ "renderTypeList": [
+ "settingDatasetQuotePrompt"
+ ],
+ "label": "",
+ "debugLabel": "知识库引用",
+ "description": "core.module.Dataset quote.Input description",
+ "valueType": "datasetQuote",
+ "type": "target",
+ "showTargetInApp": true,
+ "showTargetInPlugin": true,
+ "connected": true,
+ "selectedTypeIndex": 0,
+ "value": [
+ "fljhzy",
+ "quoteQA"
+ ]
+ }
+ ],
+ "outputs": [
+ {
+ "id": "answerText",
+ "type": "static",
+ "key": "answerText",
+ "valueType": "string",
+ "label": "core.module.output.label.Ai response content",
+ "description": "core.module.output.description.Ai response content"
+ },
+ {
+ "id": "history",
+ "type": "static",
+ "key": "history",
+ "valueType": "chatHistory",
+ "label": "core.module.output.label.New context",
+ "description": "core.module.output.description.New context"
+ }
+ ]
+ },
+ {
+ "nodeId": "q9equb",
+ "name": "core.module.template.App system setting",
+ "intro": "可以配置应用的系统参数。",
+ "avatar": "/imgs/workflow/userGuide.png",
+ "flowNodeType": "userGuide",
+ "position": {
+ "x": -275.92529567956024,
+ "y": 1094.1001488133452
+ },
+ "inputs": [
+ {
+ "key": "welcomeText",
+ "renderTypeList": [
+ "hidden"
+ ],
+ "valueType": "string",
+ "label": "core.app.Welcome Text",
+ "type": "hidden",
+ "showTargetInApp": false,
+ "showTargetInPlugin": false,
+ "value": "你好,我是电影《星际穿越》 AI 助手,有什么可以帮助你的?\n[导演是谁]\n[剧情介绍]\n[票房分析]",
+ "connected": false,
+ "selectedTypeIndex": 0
+ },
+ {
+ "key": "variables",
+ "renderTypeList": [
+ "hidden"
+ ],
+ "valueType": "any",
+ "label": "core.module.Variable",
+ "value": [],
+ "type": "hidden",
+ "showTargetInApp": false,
+ "showTargetInPlugin": false,
+ "connected": false,
+ "selectedTypeIndex": 0
+ },
+ {
+ "key": "questionGuide",
+ "valueType": "boolean",
+ "renderTypeList": [
+ "hidden"
+ ],
+ "label": "",
+ "type": "switch",
+ "showTargetInApp": false,
+ "showTargetInPlugin": false,
+ "connected": false,
+ "selectedTypeIndex": 0
+ },
+ {
+ "key": "tts",
+ "renderTypeList": [
+ "hidden"
+ ],
+ "valueType": "any",
+ "label": "",
+ "type": "hidden",
+ "showTargetInApp": false,
+ "showTargetInPlugin": false,
+ "connected": false,
+ "selectedTypeIndex": 0
+ },
+ {
+ "key": "whisper",
+ "renderTypeList": [
+ "hidden"
+ ],
+ "valueType": "any",
+ "label": ""
+ },
+ {
+ "key": "scheduleTrigger",
+ "renderTypeList": [
+ "hidden"
+ ],
+ "valueType": "any",
+ "label": "",
+ "value": null
+ }
+ ],
+ "outputs": []
+ },
+ {
+ "nodeId": "tc90wz",
+ "name": "指定回复",
+ "intro": "该模块可以直接回复一段指定的内容。常用于引导、提示。非字符串内容传入时,会转成字符串进行输出。",
+ "avatar": "/imgs/workflow/reply.png",
+ "flowNodeType": "answerNode",
+ "position": {
+ "x": 159.49274056478237,
+ "y": 1621.4635230667668
+ },
+ "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,
+ "value": "这是开头\\n",
+ "connected": false,
+ "selectedTypeIndex": 0
+ }
+ ],
+ "outputs": []
+ },
+ {
+ "nodeId": "U5T3dMVY4wj7",
+ "name": "指定回复",
+ "intro": "该模块可以直接回复一段指定的内容。常用于引导、提示。非字符串内容传入时,会转成字符串进行输出。",
+ "avatar": "/imgs/workflow/reply.png",
+ "flowNodeType": "answerNode",
+ "position": {
+ "x": 1467.0625486167608,
+ "y": 1597.346243737531
+ },
+ "inputs": [
+ {
+ "key": "text",
+ "renderTypeList": [
+ "textarea",
+ "reference"
+ ],
+ "valueType": "string",
+ "label": "core.module.input.label.Response content",
+ "description": "core.module.input.description.Response content",
+ "placeholder": "core.module.input.description.Response content",
+ "value": "这是结尾"
+ }
+ ],
+ "outputs": []
+ }
+ ],
+ "edges": [
+ {
+ "source": "7z5g5h",
+ "target": "tc90wz",
+ "sourceHandle": "7z5g5h-source-right",
+ "targetHandle": "tc90wz-target-left"
+ },
+ {
+ "source": "tc90wz",
+ "target": "nlfwkc",
+ "sourceHandle": "tc90wz-source-right",
+ "targetHandle": "nlfwkc-target-left"
+ },
+ {
+ "source": "nlfwkc",
+ "target": "U5T3dMVY4wj7",
+ "sourceHandle": "nlfwkc-source-right",
+ "targetHandle": "U5T3dMVY4wj7-target-left"
+ }
+ ]
+}
+
将 FastGPT 接入谷歌搜索
工具调用模式 + | 工具调用模式 + |
非工具调用模式 + | 非工具调用模式 + |
如上图,利用「HTTP请求」模块,你可以外接一个搜索引擎作为 AI 回复的参考资料。这里以调用 Google Search API 为例。注意:本文主要是为了介绍 「HTTP请求」模块,具体的搜索效果需要依赖提示词和搜索引擎,尤其是【搜索引擎】,简单的搜索引擎无法获取更详细的内容,这部分可能需要更多的调试。
参考这篇文章,每天可以免费使用 100 次。
这里用 Laf 快速实现一个接口,即写即发布,无需部署。务必打开 POST 请求方式。
import cloud from '@lafjs/cloud'
+
+const googleSearchKey = "xxx"
+const googleCxId = "3740cxxx"
+const baseurl = "https://www.googleapis.com/customsearch/v1"
+
+type RequestType = {
+ searchKey: string
+}
+
+export default async function (ctx: FunctionContext) {
+ const { searchKey } = ctx.body as RequestType
+ console.log(ctx.body)
+ if (!searchKey) {
+ return {
+ prompt: ""
+ }
+ }
+
+ try {
+ const { data } = await cloud.fetch.get(baseurl, {
+ params: {
+ q: searchKey,
+ cx: googleCxId,
+ key: googleSearchKey,
+ c2coff: 1,
+ start: 1,
+ end: 20,
+ dateRestrict: 'm[1]',
+ }
+ })
+ const result = data.items.map((item) => item.snippet).join('\n');
+
+ return { prompt: result }
+ } catch (err) {
+ console.log(err)
+ ctx.response.status(500)
+ return {
+ message: "异常"
+ }
+ }
+}
+
利用工具模块,则无需多余的操作,直接由模型决定是否调用谷歌搜索,并生成检索词即可。
复制下面配置,进入「高级编排」,在右上角的 “…” 中选择「导入配置」,导入后修改「HTTP 请求」模块 - 请求地址 的值。
{
+ "nodes": [
+ {
+ "nodeId": "userGuide",
+ "name": "系统配置",
+ "intro": "可以配置应用的系统参数",
+ "avatar": "/imgs/workflow/userGuide.png",
+ "flowNodeType": "userGuide",
+ "position": {
+ "x": 262.2732338817093,
+ "y": -476.00241136598146
+ },
+ "inputs": [
+ {
+ "key": "welcomeText",
+ "renderTypeList": [
+ "hidden"
+ ],
+ "valueType": "string",
+ "label": "core.app.Welcome Text",
+ "value": ""
+ },
+ {
+ "key": "variables",
+ "renderTypeList": [
+ "hidden"
+ ],
+ "valueType": "any",
+ "label": "core.app.Chat Variable",
+ "value": []
+ },
+ {
+ "key": "questionGuide",
+ "valueType": "boolean",
+ "renderTypeList": [
+ "hidden"
+ ],
+ "label": "core.app.Question Guide",
+ "value": false
+ },
+ {
+ "key": "tts",
+ "renderTypeList": [
+ "hidden"
+ ],
+ "valueType": "any",
+ "label": "",
+ "value": {
+ "type": "web"
+ }
+ },
+ {
+ "key": "whisper",
+ "renderTypeList": [
+ "hidden"
+ ],
+ "valueType": "any",
+ "label": "",
+ "value": {
+ "open": false,
+ "autoSend": false,
+ "autoTTSResponse": false
+ }
+ },
+ {
+ "key": "scheduleTrigger",
+ "renderTypeList": [
+ "hidden"
+ ],
+ "valueType": "any",
+ "label": "",
+ "value": null
+ }
+ ],
+ "outputs": []
+ },
+ {
+ "nodeId": "448745",
+ "name": "流程开始",
+ "intro": "",
+ "avatar": "/imgs/workflow/userChatInput.svg",
+ "flowNodeType": "workflowStart",
+ "position": {
+ "x": 295.8944548701009,
+ "y": 110.81336038514848
+ },
+ "inputs": [
+ {
+ "key": "userChatInput",
+ "renderTypeList": [
+ "reference",
+ "textarea"
+ ],
+ "valueType": "string",
+ "label": "用户问题",
+ "required": true,
+ "toolDescription": "用户问题"
+ }
+ ],
+ "outputs": [
+ {
+ "id": "userChatInput",
+ "key": "userChatInput",
+ "label": "core.module.input.label.user question",
+ "valueType": "string",
+ "type": "static"
+ }
+ ]
+ },
+ {
+ "nodeId": "NOgbnBzUwDgT",
+ "name": "工具调用",
+ "intro": "通过AI模型自动选择一个或多个功能块进行调用,也可以对插件进行调用。",
+ "avatar": "/imgs/workflow/tool.svg",
+ "flowNodeType": "tools",
+ "showStatus": true,
+ "position": {
+ "x": 1028.8358722416106,
+ "y": -500.8755882990822
+ },
+ "inputs": [
+ {
+ "key": "model",
+ "renderTypeList": [
+ "settingLLMModel",
+ "reference"
+ ],
+ "label": "core.module.input.label.aiModel",
+ "valueType": "string",
+ "llmModelType": "all",
+ "value": "FastAI-plus"
+ },
+ {
+ "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": "你是谷歌搜索机器人,根据当前问题和对话记录生成搜索词。你需要自行判断是否需要进行网络实时查询:\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": [
+ "448745",
+ "userChatInput"
+ ]
+ }
+ ],
+ "outputs": []
+ },
+ {
+ "nodeId": "GMELVPxHfpg5",
+ "name": "HTTP 请求",
+ "intro": "调用谷歌搜索,查询相关内容",
+ "avatar": "/imgs/workflow/http.png",
+ "flowNodeType": "httpRequest468",
+ "showStatus": true,
+ "position": {
+ "x": 1013.2159795348916,
+ "y": 210.8685573380423
+ },
+ "inputs": [
+ {
+ "key": "system_addInputParam",
+ "renderTypeList": [
+ "addInputParam"
+ ],
+ "valueType": "dynamic",
+ "label": "",
+ "required": false,
+ "description": "core.module.input.description.HTTP Dynamic Input",
+ "editField": {
+ "key": true,
+ "valueType": true
+ }
+ },
+ {
+ "valueType": "string",
+ "renderTypeList": [
+ "reference"
+ ],
+ "key": "query",
+ "label": "query",
+ "toolDescription": "谷歌搜索检索词",
+ "required": true,
+ "canEdit": true,
+ "editField": {
+ "key": true,
+ "description": true
+ }
+ },
+ {
+ "key": "system_httpMethod",
+ "renderTypeList": [
+ "custom"
+ ],
+ "valueType": "string",
+ "label": "",
+ "value": "POST",
+ "required": 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,
+ "value": "https://xxxxxx.laf.dev/google_search"
+ },
+ {
+ "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
+ },
+ {
+ "key": "system_httpParams",
+ "renderTypeList": [
+ "hidden"
+ ],
+ "valueType": "any",
+ "value": [],
+ "label": "",
+ "required": false
+ },
+ {
+ "key": "system_httpJsonBody",
+ "renderTypeList": [
+ "hidden"
+ ],
+ "valueType": "any",
+ "value": "{\n \"searchKey\": \"{{query}}\"\n}",
+ "label": "",
+ "required": false
+ }
+ ],
+ "outputs": [
+ {
+ "id": "system_addOutputParam",
+ "key": "system_addOutputParam",
+ "type": "dynamic",
+ "valueType": "dynamic",
+ "label": "",
+ "editField": {
+ "key": true,
+ "valueType": true
+ }
+ },
+ {
+ "id": "httpRawResponse",
+ "key": "httpRawResponse",
+ "label": "原始响应",
+ "description": "HTTP请求的原始响应。只能接受字符串或JSON类型响应数据。",
+ "valueType": "any",
+ "type": "static"
+ },
+ {
+ "id": "M5YmxaYe8em1",
+ "type": "dynamic",
+ "key": "prompt",
+ "valueType": "string",
+ "label": "prompt"
+ }
+ ]
+ }
+ ],
+ "edges": [
+ {
+ "source": "448745",
+ "target": "NOgbnBzUwDgT",
+ "sourceHandle": "448745-source-right",
+ "targetHandle": "NOgbnBzUwDgT-target-left"
+ },
+ {
+ "source": "NOgbnBzUwDgT",
+ "target": "GMELVPxHfpg5",
+ "sourceHandle": "selectedTools",
+ "targetHandle": "selectedTools"
+ }
+ ]
+}
+
复制下面配置,进入「高级编排」,在右上角的 “…” 中选择「导入配置」,导入后修改「HTTP 请求」模块 - 请求地址 的值。
{
+ "nodes": [
+ {
+ "nodeId": "userGuide",
+ "name": "系统配置",
+ "intro": "可以配置应用的系统参数",
+ "avatar": "/imgs/workflow/userGuide.png",
+ "flowNodeType": "userGuide",
+ "position": {
+ "x": 126.6166221945532,
+ "y": -456.00079128406236
+ },
+ "inputs": [
+ {
+ "key": "welcomeText",
+ "renderTypeList": [
+ "hidden"
+ ],
+ "valueType": "string",
+ "label": "core.app.Welcome Text",
+ "value": ""
+ },
+ {
+ "key": "variables",
+ "renderTypeList": [
+ "hidden"
+ ],
+ "valueType": "any",
+ "label": "core.app.Chat Variable",
+ "value": []
+ },
+ {
+ "key": "questionGuide",
+ "valueType": "boolean",
+ "renderTypeList": [
+ "hidden"
+ ],
+ "label": "core.app.Question Guide",
+ "value": false
+ },
+ {
+ "key": "tts",
+ "renderTypeList": [
+ "hidden"
+ ],
+ "valueType": "any",
+ "label": "",
+ "value": {
+ "type": "web"
+ }
+ },
+ {
+ "key": "whisper",
+ "renderTypeList": [
+ "hidden"
+ ],
+ "valueType": "any",
+ "label": "",
+ "value": {
+ "open": false,
+ "autoSend": false,
+ "autoTTSResponse": false
+ }
+ },
+ {
+ "key": "scheduleTrigger",
+ "renderTypeList": [
+ "hidden"
+ ],
+ "valueType": "any",
+ "label": "",
+ "value": null
+ }
+ ],
+ "outputs": []
+ },
+ {
+ "nodeId": "448745",
+ "name": "流程开始",
+ "intro": "",
+ "avatar": "/imgs/workflow/userChatInput.svg",
+ "flowNodeType": "workflowStart",
+ "position": {
+ "x": 189.99351048246606,
+ "y": 50.36949968375285
+ },
+ "inputs": [
+ {
+ "key": "userChatInput",
+ "renderTypeList": [
+ "reference",
+ "textarea"
+ ],
+ "valueType": "string",
+ "label": "用户问题",
+ "required": true,
+ "toolDescription": "用户问题"
+ }
+ ],
+ "outputs": [
+ {
+ "id": "userChatInput",
+ "key": "userChatInput",
+ "label": "core.module.input.label.user question",
+ "valueType": "string",
+ "type": "static"
+ }
+ ]
+ },
+ {
+ "nodeId": "TWD5BAqIIFaj",
+ "name": "判断器",
+ "intro": "根据一定的条件,执行不同的分支。",
+ "avatar": "/imgs/workflow/ifElse.svg",
+ "flowNodeType": "ifElseNode",
+ "showStatus": true,
+ "position": {
+ "x": 1187.4821088468154,
+ "y": -143.83989103517257
+ },
+ "inputs": [
+ {
+ "key": "condition",
+ "valueType": "string",
+ "label": "",
+ "renderTypeList": [
+ "hidden"
+ ],
+ "required": false,
+ "value": "And"
+ },
+ {
+ "key": "ifElseList",
+ "renderTypeList": [
+ "hidden"
+ ],
+ "valueType": "any",
+ "label": "",
+ "value": [
+ {
+ "variable": [
+ "lG52GzzMm65z",
+ "6yF19MRD3nuB"
+ ],
+ "condition": "isEmpty",
+ "value": ""
+ }
+ ]
+ }
+ ],
+ "outputs": [
+ {
+ "id": "IF",
+ "key": "IF",
+ "label": "IF",
+ "valueType": "any",
+ "type": "source"
+ },
+ {
+ "id": "ELSE",
+ "key": "ELSE",
+ "label": "ELSE",
+ "valueType": "any",
+ "type": "source"
+ }
+ ]
+ },
+ {
+ "nodeId": "1ljV0oTq4zeC",
+ "name": "HTTP 请求",
+ "intro": "可以发出一个 HTTP 请求,实现更为复杂的操作(联网搜索、数据库查询等)",
+ "avatar": "/imgs/workflow/http.png",
+ "flowNodeType": "httpRequest468",
+ "showStatus": true,
+ "position": {
+ "x": 1992.0328696814468,
+ "y": 127.08080019458595
+ },
+ "inputs": [
+ {
+ "key": "DYNAMIC_INPUT_KEY",
+ "renderTypeList": [
+ "addInputParam"
+ ],
+ "valueType": "dynamic",
+ "label": "",
+ "required": false,
+ "description": "core.module.input.description.HTTP Dynamic Input",
+ "editField": {
+ "key": true,
+ "valueType": true
+ }
+ },
+ {
+ "key": "searchKey",
+ "valueType": "string",
+ "label": "searchKey",
+ "renderTypeList": [
+ "reference"
+ ],
+ "description": "",
+ "canEdit": true,
+ "editField": {
+ "key": true,
+ "valueType": true
+ },
+ "value": [
+ "lG52GzzMm65z",
+ "6yF19MRD3nuB"
+ ]
+ },
+ {
+ "key": "system_httpMethod",
+ "renderTypeList": [
+ "custom"
+ ],
+ "valueType": "string",
+ "label": "",
+ "value": "POST",
+ "required": 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,
+ "value": "https://xxxxxx.laf.dev/google_search"
+ },
+ {
+ "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
+ },
+ {
+ "key": "system_httpParams",
+ "renderTypeList": [
+ "hidden"
+ ],
+ "valueType": "any",
+ "value": [],
+ "label": "",
+ "required": false
+ },
+ {
+ "key": "system_httpJsonBody",
+ "renderTypeList": [
+ "hidden"
+ ],
+ "valueType": "any",
+ "value": "{\n \"searchKey\": \"{{searchKey}}\"\n}",
+ "label": "",
+ "required": false
+ },
+ {
+ "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",
+ "key": "system_addOutputParam",
+ "type": "dynamic",
+ "valueType": "dynamic",
+ "label": "",
+ "editField": {
+ "key": true,
+ "valueType": true
+ }
+ },
+ {
+ "id": "httpRawResponse",
+ "key": "httpRawResponse",
+ "label": "原始响应",
+ "description": "HTTP请求的原始响应。只能接受字符串或JSON类型响应数据。",
+ "valueType": "any",
+ "type": "static"
+ },
+ {
+ "id": "yw0oz9XWFXYf",
+ "type": "dynamic",
+ "key": "prompt",
+ "valueType": "string",
+ "label": "prompt"
+ }
+ ]
+ },
+ {
+ "nodeId": "Nc6hBdb3l9Pe",
+ "name": "AI 对话",
+ "intro": "AI 大模型对话",
+ "avatar": "/imgs/workflow/AI.png",
+ "flowNodeType": "chatNode",
+ "showStatus": true,
+ "position": {
+ "x": 1982.442841318768,
+ "y": -664.9716343803625
+ },
+ "inputs": [
+ {
+ "key": "model",
+ "renderTypeList": [
+ "settingLLMModel",
+ "reference"
+ ],
+ "label": "core.module.input.label.aiModel",
+ "valueType": "string",
+ "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": "isResponseAnswerText",
+ "renderTypeList": [
+ "hidden"
+ ],
+ "label": "",
+ "value": true,
+ "valueType": "boolean"
+ },
+ {
+ "key": "quoteTemplate",
+ "renderTypeList": [
+ "hidden"
+ ],
+ "label": "",
+ "valueType": "string"
+ },
+ {
+ "key": "quotePrompt",
+ "renderTypeList": [
+ "hidden"
+ ],
+ "label": "",
+ "valueType": "string"
+ },
+ {
+ "key": "systemPrompt",
+ "renderTypeList": [
+ "textarea",
+ "reference"
+ ],
+ "max": 3000,
+ "valueType": "string",
+ "label": "core.ai.Prompt",
+ "description": "core.app.tip.chatNodeSystemPromptTip",
+ "placeholder": "core.app.tip.chatNodeSystemPromptTip",
+ "selectedTypeIndex": 1,
+ "value": [
+ "1ljV0oTq4zeC",
+ "httpRawResponse"
+ ]
+ },
+ {
+ "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,
+ "toolDescription": "用户问题",
+ "value": [
+ "448745",
+ "userChatInput"
+ ]
+ },
+ {
+ "key": "quoteQA",
+ "renderTypeList": [
+ "settingDatasetQuotePrompt"
+ ],
+ "label": "",
+ "debugLabel": "知识库引用",
+ "description": "",
+ "valueType": "datasetQuote"
+ }
+ ],
+ "outputs": [
+ {
+ "id": "history",
+ "key": "history",
+ "label": "core.module.output.label.New context",
+ "description": "core.module.output.description.New context",
+ "valueType": "chatHistory",
+ "type": "static"
+ },
+ {
+ "id": "answerText",
+ "key": "answerText",
+ "label": "core.module.output.label.Ai response content",
+ "description": "core.module.output.description.Ai response content",
+ "valueType": "string",
+ "type": "static"
+ }
+ ]
+ },
+ {
+ "nodeId": "FYLw1BokYUad",
+ "name": "文本加工",
+ "intro": "可对固定或传入的文本进行加工后输出,非字符串类型数据最终会转成字符串类型。",
+ "avatar": "/imgs/workflow/textEditor.svg",
+ "flowNodeType": "pluginModule",
+ "showStatus": false,
+ "position": {
+ "x": 2479.5913201989906,
+ "y": 288.52613614690904
+ },
+ "inputs": [
+ {
+ "key": "system_addInputParam",
+ "valueType": "dynamic",
+ "label": "动态外部数据",
+ "renderTypeList": [
+ "addInputParam"
+ ],
+ "required": false,
+ "description": "",
+ "canEdit": false,
+ "value": "",
+ "editField": {
+ "key": true
+ },
+ "dynamicParamDefaultValue": {
+ "inputType": "reference",
+ "valueType": "string",
+ "required": true
+ }
+ },
+ {
+ "key": "q",
+ "valueType": "string",
+ "label": "q",
+ "renderTypeList": [
+ "reference"
+ ],
+ "required": true,
+ "description": "",
+ "canEdit": true,
+ "editField": {
+ "key": true
+ },
+ "value": [
+ "448745",
+ "userChatInput"
+ ]
+ },
+ {
+ "key": "response",
+ "valueType": "string",
+ "label": "response",
+ "renderTypeList": [
+ "reference"
+ ],
+ "required": true,
+ "description": "",
+ "canEdit": true,
+ "editField": {
+ "key": true
+ },
+ "value": [
+ "1ljV0oTq4zeC",
+ "yw0oz9XWFXYf"
+ ]
+ },
+ {
+ "key": "文本",
+ "valueType": "string",
+ "label": "文本",
+ "renderTypeList": [
+ "textarea"
+ ],
+ "required": true,
+ "description": "",
+ "canEdit": false,
+ "value": "请使用下面<data> </data>中的数据作为本次对话的参考。请直接输出答案,不要提及你是从<data> </data>中获取的知识。\n\n当前时间:{{cTime}}\n\n<data>\n{{response}}\n</data>\n\n我的问题:\"{{q}}\"",
+ "editField": {
+ "key": true
+ },
+ "maxLength": "",
+ "dynamicParamDefaultValue": {
+ "inputType": "reference",
+ "valueType": "string",
+ "required": true
+ }
+ }
+ ],
+ "outputs": [
+ {
+ "id": "text",
+ "type": "static",
+ "key": "text",
+ "valueType": "string",
+ "label": "text",
+ "description": ""
+ }
+ ],
+ "pluginId": "community-textEditor"
+ },
+ {
+ "nodeId": "EX0g9oK3sCOC",
+ "name": "AI 对话",
+ "intro": "AI 大模型对话",
+ "avatar": "/imgs/workflow/AI.png",
+ "flowNodeType": "chatNode",
+ "showStatus": true,
+ "position": {
+ "x": 3199.17223136331,
+ "y": -100.06379812849427
+ },
+ "inputs": [
+ {
+ "key": "model",
+ "renderTypeList": [
+ "settingLLMModel",
+ "reference"
+ ],
+ "label": "core.module.input.label.aiModel",
+ "valueType": "string",
+ "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": "isResponseAnswerText",
+ "renderTypeList": [
+ "hidden"
+ ],
+ "label": "",
+ "value": true,
+ "valueType": "boolean"
+ },
+ {
+ "key": "quoteTemplate",
+ "renderTypeList": [
+ "hidden"
+ ],
+ "label": "",
+ "valueType": "string"
+ },
+ {
+ "key": "quotePrompt",
+ "renderTypeList": [
+ "hidden"
+ ],
+ "label": "",
+ "valueType": "string"
+ },
+ {
+ "key": "systemPrompt",
+ "renderTypeList": [
+ "textarea",
+ "reference"
+ ],
+ "max": 3000,
+ "valueType": "string",
+ "label": "core.ai.Prompt",
+ "description": "core.app.tip.chatNodeSystemPromptTip",
+ "placeholder": "core.app.tip.chatNodeSystemPromptTip"
+ },
+ {
+ "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,
+ "toolDescription": "用户问题",
+ "value": [
+ "FYLw1BokYUad",
+ "text"
+ ]
+ },
+ {
+ "key": "quoteQA",
+ "renderTypeList": [
+ "settingDatasetQuotePrompt"
+ ],
+ "label": "",
+ "debugLabel": "知识库引用",
+ "description": "",
+ "valueType": "datasetQuote"
+ }
+ ],
+ "outputs": [
+ {
+ "id": "history",
+ "key": "history",
+ "label": "core.module.output.label.New context",
+ "description": "core.module.output.description.New context",
+ "valueType": "chatHistory",
+ "type": "static"
+ },
+ {
+ "id": "answerText",
+ "key": "answerText",
+ "label": "core.module.output.label.Ai response content",
+ "description": "core.module.output.description.Ai response content",
+ "valueType": "string",
+ "type": "static"
+ }
+ ]
+ },
+ {
+ "nodeId": "lG52GzzMm65z",
+ "name": "文本内容提取",
+ "intro": "可从文本中提取指定的数据,例如:sql语句、搜索关键词、代码等",
+ "avatar": "/imgs/workflow/extract.png",
+ "flowNodeType": "contentExtract",
+ "showStatus": true,
+ "position": {
+ "x": 535.331344778598,
+ "y": -437.1382636373696
+ },
+ "inputs": [
+ {
+ "key": "model",
+ "renderTypeList": [
+ "selectLLMModel",
+ "reference"
+ ],
+ "label": "core.module.input.label.aiModel",
+ "required": true,
+ "valueType": "string",
+ "llmModelType": "extractFields",
+ "value": "gpt-3.5-turbo"
+ },
+ {
+ "key": "description",
+ "renderTypeList": [
+ "textarea",
+ "reference"
+ ],
+ "valueType": "string",
+ "label": "提取要求描述",
+ "description": "给AI一些对应的背景知识或要求描述,引导AI更好的完成任务。\n该输入框可使用全局变量。",
+ "placeholder": "例如: \n1. 当前时间为: {{cTime}}。你是一个实验室预约助手,你的任务是帮助用户预约实验室,从文本中获取对应的预约信息。\n2. 你是谷歌搜索助手,需要从文本中提取出合适的搜索词。",
+ "value": "你是谷歌搜索机器人,根据当前问题和对话记录生成搜索词。你需要自行判断是否需要进行网络实时查询:\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": "content",
+ "renderTypeList": [
+ "reference",
+ "textarea"
+ ],
+ "label": "需要提取的文本",
+ "required": true,
+ "valueType": "string",
+ "toolDescription": "需要检索的内容",
+ "value": [
+ "448745",
+ "userChatInput"
+ ]
+ },
+ {
+ "key": "extractKeys",
+ "renderTypeList": [
+ "custom"
+ ],
+ "label": "",
+ "valueType": "any",
+ "description": "由 '描述' 和 'key' 组成一个目标字段,可提取多个目标字段",
+ "value": [
+ {
+ "required": false,
+ "defaultValue": "",
+ "desc": "搜索词",
+ "key": "searchKey",
+ "enum": ""
+ }
+ ]
+ }
+ ],
+ "outputs": [
+ {
+ "id": "fields",
+ "key": "fields",
+ "label": "完整提取结果",
+ "description": "一个 JSON 字符串,例如:{\"name:\":\"YY\",\"Time\":\"2023/7/2 18:00\"}",
+ "valueType": "string",
+ "type": "static"
+ },
+ {
+ "id": "6yF19MRD3nuB",
+ "key": "searchKey",
+ "label": "提取结果-搜索词",
+ "valueType": "string",
+ "type": "static"
+ }
+ ]
+ }
+ ],
+ "edges": [
+ {
+ "source": "TWD5BAqIIFaj",
+ "target": "Nc6hBdb3l9Pe",
+ "sourceHandle": "TWD5BAqIIFaj-source-IF",
+ "targetHandle": "Nc6hBdb3l9Pe-target-left"
+ },
+ {
+ "source": "1ljV0oTq4zeC",
+ "target": "FYLw1BokYUad",
+ "sourceHandle": "1ljV0oTq4zeC-source-right",
+ "targetHandle": "FYLw1BokYUad-target-left"
+ },
+ {
+ "source": "FYLw1BokYUad",
+ "target": "EX0g9oK3sCOC",
+ "sourceHandle": "FYLw1BokYUad-source-right",
+ "targetHandle": "EX0g9oK3sCOC-target-left"
+ },
+ {
+ "source": "448745",
+ "target": "lG52GzzMm65z",
+ "sourceHandle": "448745-source-right",
+ "targetHandle": "lG52GzzMm65z-target-left"
+ },
+ {
+ "source": "lG52GzzMm65z",
+ "target": "TWD5BAqIIFaj",
+ "sourceHandle": "lG52GzzMm65z-source-right",
+ "targetHandle": "TWD5BAqIIFaj-target-left"
+ },
+ {
+ "source": "TWD5BAqIIFaj",
+ "target": "1ljV0oTq4zeC",
+ "sourceHandle": "TWD5BAqIIFaj-source-ELSE",
+ "targetHandle": "1ljV0oTq4zeC-target-left"
+ }
+ ]
+}
+
FastGPT 应用场景及功能实现的搭建案例
展示高级编排操作数据库的能力
本示例演示了利用工具调用,自动选择调用知识库搜索实验室相关内容,或调用 HTTP 模块实现数据库的 CRUD 操作。
以一个实验室预约为例,用户可以通过对话系统预约、取消、修改预约和查询预约记录。
通过设计一个全局变量,让用户输入姓名,模拟用户身份信息。实际使用过程中,通常是直接通过嵌入 Token 来标记用户身份。
背景知识中,引导模型调用工具去执行不通的操作。
Tips: 这里需要增加适当的上下文,方便模型结合历史纪录进行判断和决策~
HTTP模块中,需要设置 3 个工具参数:
可直接复制,导入到 FastGPT 中。
{
+ "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"
+ }
+ ]
+}
+
可以在 Laf 中快速构建 HTTP 接口。
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}
+ ` }
+}
+
如何使用 FastGPT 构建一个多轮翻译机器人,实现连续的对话翻译功能
吴恩达老师提出了一种反思翻译的大语言模型(LLM)翻译工作流程——GitHub - andrewyng/translation-agent,具体工作流程如下:
source_language
翻译到 target_language
;这个翻译流程应该是目前比较新的一种翻译方式,利用 LLM 对自己的翻译结果进行改进来获得较好的翻译效果
项目中展示了可以利用对长文本进行分片,然后分别进行反思翻译处理,以突破 LLM 对 tokens 数量的限制,真正实现长文本一键高效率高质量翻译。
项目还通过给大模型限定国家地区,已实现更精确的翻译,如美式英语、英式英语之分;同时提出一些可能能带来更好效果的优化,如对于一些 LLM 未曾训练到的术语(或有多种翻译方式的术语)建立术语表,进一步提升翻译的精确度等等
而这一切都能通过 Fastgpt 工作流轻松实现,本文将手把手教你如何复刻吴恩达老师的 translation-agent
先从简单的开始,即不超出 LLM tokens 数量限制的单文本块翻译
第一步先让 LLM 对源文本块进行初始翻译(翻译的提示词在源项目中都有)
通过文本拼接
模块引用 源语言、目标语言、源文本这三个参数,生成提示词,传给 LLM,让它给出第一版的翻译
然后让 LLM 对第一步生成的初始翻译给出修改建议,称之为 反思
这时的提示词接收 5 个参数,源文本、初始翻译、源语言、目标语言 以及限定词地区国家,这样 LLM 会对前面生成的翻译提出相当多的修改建议,为后续的提升翻译作准备
在前文生成了初始翻译以及相应的反思后,将这二者输入给第三次 LLM 翻译,这样我们就能获得一个比较高质量的翻译结果
完整的工作流如下
由于考虑之后对这个反思翻译的复用,所以创建了一个插件,那么在下面我直接调用这个插件就能使用反思翻译,效果如下
随机挑选了一段哈利波特的文段
可以看到反思翻译后的效果还是好上不少的,其中反思的输出如下
在掌握了对短文本块的反思翻译后,我们能轻松的通过分片和循环,实现对长文本也即多文本块的反思翻译
整体的逻辑是,首先对传入文本的 tokens数量做判断,如果不超过设置的 tokens 限制,那么直接调用单文本块反思翻译,如果超过设置的 tokens限制,那么切割为合理的大小,再分别进行对应的反思翻译处理
首先,我使用了 Laf函数 模块来实现对输入文本的 tokens 的计算
laf函数的使用相当简单,即开即用,只需要在 laf 创建个应用,然后安装 tiktoken 依赖,导入如下代码即可
+ const { Tiktoken } = require("tiktoken/lite");
+const cl100k_base = require("tiktoken/encoders/cl100k_base.json");
+
+interface IRequestBody {
+ str: string
+}
+
+interface RequestProps extends IRequestBody {
+ systemParams: {
+ appId: string,
+ variables: string,
+ histories: string,
+ cTime: string,
+ chatId: string,
+ responseChatItemId: string
+ }
+}
+
+interface IResponse {
+ message: string;
+ tokens: number;
+}
+
+export default async function (ctx: FunctionContext): Promise<IResponse> {
+ const { str = "" }: RequestProps = ctx.body
+
+ const encoding = new Tiktoken(
+ cl100k_base.bpe_ranks,
+ cl100k_base.special_tokens,
+ cl100k_base.pat_str
+ );
+ const tokens = encoding.encode(str);
+ encoding.free();
+
+ return {
+ message: 'ok',
+ tokens: tokens.length
+ };
+}
+
再回到 Fastgpt,点击“同步参数”,再连线将源文本传入,即可计算 tokens 数量
由于不涉及第三方包,只是一些数据处理,所以直接使用 代码运行 模块处理即可
+ function main({tokenCount, tokenLimit}){
+ const numChunks = Math.ceil(tokenCount / tokenLimit);
+ let chunkSize = Math.floor(tokenCount / numChunks);
+
+ const remainingTokens = tokenCount % tokenLimit;
+ if (remainingTokens > 0) {
+ chunkSize += Math.floor(remainingTokens / numChunks);
+ }
+
+ return {chunkSize};
+}
+
通过上面的代码,我们就能算出不超过 token限制的合理单文本块大小是多少了
通过单文本块大小和源文本,我们再编写一个函数调用 langchain 的 textsplitters 包来实现文本分片,具体代码如下
+ import cloud from '@lafjs/cloud'
+import { TokenTextSplitter } from "@langchain/textsplitters";
+
+interface IRequestBody {
+ text: string
+ chunkSize: number
+}
+
+interface RequestProps extends IRequestBody {
+ systemParams: {
+ appId: string,
+ variables: string,
+ histories: string,
+ cTime: string,
+ chatId: string,
+ responseChatItemId: string
+ }
+}
+
+interface IResponse {
+ output: string[];
+}
+
+export default async function (ctx: FunctionContext): Promise<IResponse>{
+ const { text = '', chunkSize=1000 }: RequestProps = ctx.body;
+
+ const splitter = new TokenTextSplitter({
+ encodingName:"gpt2",
+ chunkSize: Number(chunkSize),
+ chunkOverlap: 0,
+ });
+
+ const output = await splitter.splitText(text);
+
+ return {
+ output
+ }
+}
+
这样我们就获得了切分好的文本,接下去的操作就类似单文本块反思翻译
这里应该还是不能直接调用前面的单文本块反思翻译,因为提示词中会涉及一些上下文的处理(或者可以修改下前面写好的插件,多传点参数进去)
详细的和前面类似,就是提示词进行一些替换,以及需要做一些很简单的数据处理,整体效果如下
长文反思翻译比较关键的一个部分,就是对多个文本块进行循环反思翻译
Fastgpt 提供了工作流线路可以返回去执行的功能,所以我们可以写一个很简单的判断函数,来判断结束或是接着执行
也就是通过判断当前处理的这个文本块,是否是最后一个文本块,从而判断是否需要继续执行,就这样,我们实现了长文反思翻译的效果
完整工作流如下
首先输入全局设置
然后输入需要翻译的文本,这里我选择了一章哈利波特的英文原文来做翻译,其文本长度通过 openai 对 tokens 数量的判断如下
实际运行效果如下
可以看到还是能满足阅读需求的
在源项目中,给 AI 的系统提示词还是比较的简略的,我们可以通过比较完善的提示词,来督促 LLM 返回更合适的翻译,进一步提升翻译的质量
比如初始翻译中,
+ # Role: 资深翻译专家
+
+## Background:
+你是一位经验丰富的翻译专家,精通{{source_lang}}和{{target_lang}}互译,尤其擅长将{{source_lang}}文章译成流畅易懂的{{target_lang}}。你曾多次带领团队完成大型翻译项目,译文广受好评。
+
+## Attention:
+- 翻译过程中要始终坚持"信、达、雅"的原则,但"达"尤为重要
+- 译文要符合{{target_lang}}的表达习惯,通俗易懂,连贯流畅
+- 避免使用过于文绉绉的表达和晦涩难懂的典故引用
+
+## Constraints:
+- 必须严格遵循四轮翻译流程:直译、意译、校审、定稿
+- 译文要忠实原文,准确无误,不能遗漏或曲解原意
+
+## Goals:
+- 通过四轮翻译流程,将{{source_lang}}原文译成高质量的{{target_lang}}译文
+- 译文要准确传达原文意思,语言表达力求浅显易懂,朗朗上口
+- 适度使用一些熟语俗语、流行网络用语等,增强译文的亲和力
+- 在直译的基础上,提供至少2个不同风格的意译版本供选择
+
+## Skills:
+- 精通{{source_lang}} {{target_lang}}两种语言,具有扎实的语言功底和丰富的翻译经验
+- 擅长将{{source_lang}}表达习惯转换为地道自然的{{target_lang}}
+- 对当代{{target_lang}}语言的发展变化有敏锐洞察,善于把握语言流行趋势
+
+## Workflow:
+1. 第一轮直译:逐字逐句忠实原文,不遗漏任何信息
+2. 第二轮意译:在直译的基础上用通俗流畅的{{target_lang}}意译原文,至少提供2个不同风格的版本
+3. 第三轮校审:仔细审视译文,消除偏差和欠缺,使译文更加地道易懂
+4. 第四轮定稿:择优选取,反复修改润色,最终定稿出一个简洁畅达、符合大众阅读习惯的译文
+
+## OutputFormat:
+- 只需要输出第四轮定稿的回答
+
+## Suggestions:
+- 直译时力求忠实原文,但不要过于拘泥逐字逐句
+- 意译时在准确表达原意的基础上,用最朴实无华的{{target_lang}}来表达
+- 校审环节重点关注译文是否符合{{target_lang}}表达习惯,是否通俗易懂
+- 定稿时适度采用一些熟语谚语、网络流行语等,使译文更接地气- 善于利用{{target_lang}}的灵活性,用不同的表述方式展现同一内容,提高译文的可读性
+
从而返回更准确更高质量的初始翻译,后续的反思和提升翻译也可以修改更准确的提示词,如下
然后再让我们来看看运行效果
给了和之前相同的一段文本进行测试,测试效果还是比较显著的,就比如红框部分,之前的翻译如下
从“让你的猫头鹰给我写信”这样有失偏颇的翻译,变成“给我写信,你的猫头鹰会知道怎么找到我”这样较为准确的翻译
比如限定词调优,源项目中已经做了示范,就是加上国家地区这个限定词,实测确实会有不少提升
出于 LLM 的卓越能力,我们能够通过设置不同的prompt来获取不同的翻译结果,也就是可以很轻松地通过设置特殊的限定词,来实现特定的,更精确的翻译
而对于一些超出 LLM 理解的术语等,也可以利用 Fastgpt 的知识库功能进行相应扩展,进一步完善翻译机器人的功能
指南:如何向 FastGPT 提交应用模板
目前合并进仓库的应用模板,会在「模板市场」中全部展示给用户。
为了控制模板的质量以及避免数量过多带来的繁琐,并不是所有的模板都会被合并到开源仓库中,你可以提前 PR 与我们沟通模板的内容。
预估最后总体的数量不会很多,控制在 50 个左右,一半来自 FastGPT Team,一半来自社区用户。
需要在 dev 环境下执行下面的操作。
可参照 FastGPT|快速开始本地开发
创建空白工作流即可。
应用模板配置以及相关资源,都会在 packages/templates/src 目录下。
+ {
+ "name": "模板名",
+ "intro": "模板描述,会展示在模板市场的展示页",
+ "author": "填写你的名字",
+ "avatar": "模板头像,可以将图片文件放在同一个文件夹中,然后填写相应路径",
+
+ "tags": ["模板标签"], // writing(文本创作),image-generation(图片生成),web-search(联网搜索),
+ // roleplay(角色扮演), office-services(办公服务) 暂时分为 5 类,从中选择相应的标签
+
+ "type": "模板类别", // simple(简易应用), advanced(工作流), plugin(插件)
+
+ "workflow": { // 这个对象先不管,待会直接粘贴导出的工作流即可
+ "nodes": [],
+ "edges": [],
+ "chatConfig": {}
+ }
+}
+
完成应用编排后,可以点击右上角的发布。
鼠标放置在左上角应用的头像和名称上,会出现对于下拉框操作,可以导出工作流配置。
导出的配置,会自动复制到剪切板,可以直接到 template.json 文件中粘贴使用,替换步骤 2 中,workflow 的值。
刷新页面,打开模板市场,看其是否成功加载,并点击「使用」测试其功能。
如果你觉得你的模板需要提交到开源仓库,可以通过 PR 形式向我们提交。
利用 AI 自我反思提升翻译质量,同时循环迭代执行 AI 工作流来突破 LLM tokens 限制,实现一个高效的长字幕翻译机器人。
直接使用 LLM 来翻译长字幕会遇到很多难点,这些难点也正是直接使用 AI 无法有效处理的问题:
Tokens 限制:这是最明显的障碍。大语言模型 (LLM) 通常有输出 tokens 的限制,这意味着对于长文本,如果不使用特殊的工作流,可能需要手动将文本分段,逐段输入 AI 进行翻译,然后再手动拼接结果。这个过程不仅繁琐,还容易出错。
字幕格式的保持:对于字幕来说,时间轴信息至关重要。然而,AI 模型有时会产生 “幻觉”,即无中生有地修改或生成不存在的信息。在字幕翻译中,这可能导致 AI 错误地修改时间轴,使字幕与音频不同步。
翻译质量:简单的机器翻译往往无法满足观众的需求。即使是大语言模型,单轮翻译的质量也常常不尽如人意。对于字幕来说,翻译质量直接影响观看体验,糟糕的翻译会严重影响观众的沉浸感。
本案例将展示如何利用 FastGPT 工作流代码结合 LLM 来有效解决这些问题。我们的方法不仅能克服技术限制,还能显著提升翻译质量。
工作流的一大优势在于可以结合额外的操作,使 AI 能更精准地处理信息。在字幕翻译中,我们可以先分离 SRT 字幕文件的各个组成部分,然后只让 LLM 翻译文本部分。这种方法既节约了 token 使用,又确保了时间轴信息不被误改。
具体实现如下:
这种预处理步骤大大提高了整个翻译过程的效率和准确性。
为了进一步优化翻译过程,我们需要将提取出的文本信息重新组织。这一步的目的是将文本分割成适合 LLM 处理的大小,同时保持上下文的连贯性。
在本例中,我们采用以下策略:
这种切分方法既考虑了 AI 模型的能力限制,又保证了翻译的连贯性。通过保持适当的上下文,我们可以得到更加准确和自然的翻译结果。
在这一步,我们构建了最终输入给 LLM 的原文本。这个步骤的关键在于如何在控制 tokens 数量的同时,为 AI 提供足够的上下文信息。我们采用了以下策略:
这种格式化方法使得 AI 能在理解全局的基础上,专注于翻译特定部分,从而提高翻译的准确性和连贯性。
这是整个过程中最关键的一步。我们利用 LLM 的强大能力来实现高质量翻译。在这一步中,我们将之前提到的 “初始翻译 -> 反思 -> 提升翻译” 的过程整合到了同一个提示词中。
这个过程包括以下几个阶段:
第一轮直译:要求 AI 严格按照
第二轮意译:允许 AI 自主发挥,对第一轮的结果进行修改和优化。
第三轮反思:AI 对自己的翻译进行评价,从多个角度提出改进建议。
最后一轮修改:根据反思阶段的建议,AI 对翻译进行最后的调整和优化。
这种多轮翻译和反思的方法显著提高了翻译质量。它不仅能捕捉原文的准确含义,还能使翻译更加流畅自然。
值得注意的是,这种方法的效果与直接分步执行相当,但工作流更加简洁高效。
完成翻译后,我们需要将所有信息重新组合成完整的字幕文件。这一步骤包括:
这个过程不仅提高了效率,还最大限度地减少了人为错误的可能性。
为了处理整个长字幕文件,我们需要一个循环执行机制。这是通过一个简单但有效的判断模块实现的:
这种循环机制确保了整个长字幕文件能被完整处理,无论字幕有多长。
为了验证这个方法的有效性,我们选取了一段《权力的游戏》的英文字幕,将其翻译成简体中文。可以看出我们的方法不仅能准确翻译内容,还能保持字幕的格式和时间轴信息。
本工作流完整配置如下,可直接复制,导入到 FastGPT 中。
{
+ "nodes": [
+ {
+ "nodeId": "userGuide",
+ "name": "系统配置",
+ "intro": "可以配置应用的系统参数",
+ "avatar": "core/workflow/template/systemConfig",
+ "flowNodeType": "userGuide",
+ "position": {
+ "x": -1453.0815298642474,
+ "y": 269.10239463914263
+ },
+ "version": "481",
+ "inputs": [
+ {
+ "key": "welcomeText",
+ "renderTypeList": [
+ "hidden"
+ ],
+ "valueType": "string",
+ "label": "core.app.Welcome Text",
+ "value": ""
+ },
+ {
+ "key": "variables",
+ "renderTypeList": [
+ "hidden"
+ ],
+ "valueType": "any",
+ "label": "core.app.Chat Variable",
+ "value": []
+ },
+ {
+ "key": "questionGuide",
+ "valueType": "boolean",
+ "renderTypeList": [
+ "hidden"
+ ],
+ "label": "core.app.Question Guide",
+ "value": false
+ },
+ {
+ "key": "tts",
+ "renderTypeList": [
+ "hidden"
+ ],
+ "valueType": "any",
+ "label": "",
+ "value": {
+ "type": "web"
+ }
+ },
+ {
+ "key": "whisper",
+ "renderTypeList": [
+ "hidden"
+ ],
+ "valueType": "any",
+ "label": "",
+ "value": {
+ "open": false,
+ "autoSend": false,
+ "autoTTSResponse": false
+ }
+ },
+ {
+ "key": "scheduleTrigger",
+ "renderTypeList": [
+ "hidden"
+ ],
+ "valueType": "any",
+ "label": "",
+ "value": null
+ }
+ ],
+ "outputs": []
+ },
+ {
+ "nodeId": "448745",
+ "name": "流程开始",
+ "intro": "",
+ "avatar": "core/workflow/template/workflowStart",
+ "flowNodeType": "workflowStart",
+ "position": {
+ "x": -1458.2511936623089,
+ "y": 1218.2790943636066
+ },
+ "version": "481",
+ "inputs": [
+ {
+ "key": "userChatInput",
+ "renderTypeList": [
+ "reference",
+ "textarea"
+ ],
+ "valueType": "string",
+ "label": "用户问题",
+ "required": true,
+ "toolDescription": "用户问题"
+ }
+ ],
+ "outputs": [
+ {
+ "id": "userChatInput",
+ "key": "userChatInput",
+ "label": "core.module.input.label.user question",
+ "type": "static",
+ "valueType": "string"
+ }
+ ]
+ },
+ {
+ "nodeId": "yjFO3YcM7KG2",
+ "name": "LLM 翻译",
+ "intro": "AI 大模型对话",
+ "avatar": "core/workflow/template/aiChat",
+ "flowNodeType": "chatNode",
+ "showStatus": true,
+ "position": {
+ "x": 2569.420973631976,
+ "y": 909.4127366971411
+ },
+ "version": "481",
+ "inputs": [
+ {
+ "key": "model",
+ "renderTypeList": [
+ "settingLLMModel",
+ "reference"
+ ],
+ "label": "core.module.input.label.aiModel",
+ "valueType": "string",
+ "selectedTypeIndex": 0,
+ "value": "claude-3-5-sonnet-20240620"
+ },
+ {
+ "key": "temperature",
+ "renderTypeList": [
+ "hidden"
+ ],
+ "label": "",
+ "value": 3,
+ "valueType": "number",
+ "min": 0,
+ "max": 10,
+ "step": 1
+ },
+ {
+ "key": "maxToken",
+ "renderTypeList": [
+ "hidden"
+ ],
+ "label": "",
+ "value": 4000,
+ "valueType": "number",
+ "min": 100,
+ "max": 4000,
+ "step": 50
+ },
+ {
+ "key": "isResponseAnswerText",
+ "renderTypeList": [
+ "hidden"
+ ],
+ "label": "",
+ "value": false,
+ "valueType": "boolean"
+ },
+ {
+ "key": "quoteTemplate",
+ "renderTypeList": [
+ "hidden"
+ ],
+ "label": "",
+ "valueType": "string"
+ },
+ {
+ "key": "quotePrompt",
+ "renderTypeList": [
+ "hidden"
+ ],
+ "label": "",
+ "valueType": "string"
+ },
+ {
+ "key": "systemPrompt",
+ "renderTypeList": [
+ "textarea",
+ "reference"
+ ],
+ "max": 3000,
+ "valueType": "string",
+ "label": "core.ai.Prompt",
+ "description": "core.app.tip.chatNodeSystemPromptTip",
+ "placeholder": "core.app.tip.chatNodeSystemPromptTip",
+ "value": "# Role: 资深字幕翻译专家\n\n## Background:\n你是一位经验丰富的{{source_lang}}和{{target_lang}}字幕翻译专家,精通{{source_lang}}和{{target_lang}}互译,尤其擅长将{{source_lang}}字幕译成流畅易懂的{{target_lang}}字幕。你曾多次带领团队完成大型商业电影的字幕翻译项目,所翻译的字幕广受好评。\n\n## Attention:\n- 翻译过程中要始终坚持\"信、达、雅\"的原则,但\"达\"尤为重要\n- 翻译的字幕要符合{{target_lang}}的表达习惯,通俗易懂,连贯流畅\n- 避免使用过于文绉绉的表达和晦涩难懂的典故引用 \n- 诗词歌词等内容需按原文换行和节奏分行,不破坏原排列格式 \n- 翻译对象是字幕,请进入整段文本的语境中对需要翻译的文本段进行翻译\n- <T>是标识每一帧字幕的标签,请严格按照<T>对文本的分割逐帧翻译,每一帧字幕末尾不要加 \\n 回车标识,且第一帧字幕开头不需要加<T>标识\n\n## Constraints:\n- 必须严格遵循四轮翻译流程:直译、意译、反思、提升\n- 译文要忠实原文,准确无误,不能遗漏或曲解原意\n- 最终译文使用Markdown的代码块呈现,但是不用输出markdown这个单词\n- <T>是标识每一帧字幕的标签,请严格按照<T>对文本的分割逐帧翻译,每一帧字幕末尾不要加 \\n 回车标识,且第一帧字幕开头不需要加<T>标识\n\n## Goals:\n- 通过四轮翻译流程,将{{source_lang}}字幕译成高质量的{{target_lang}}字幕\n- 翻译的字幕要准确传达原字幕意思,语言表达力求浅显易懂,朗朗上口 \n\n## Workflow:\n1. 第一轮直译:严格按照<T>逐句翻译,不遗漏任何信息\n2. 第二轮意译:在直译的基础上用通俗流畅的{{target_lang}}意译原文,逐句翻译,保留<T>标识标签\n3. 第三轮反思:仔细审视译文,分点列出一份建设性的批评和有用的建议清单以改进翻译,对每一句话提出建议,从以下四个角度展开\n (i) 准确性(纠正添加、误译、遗漏或未翻译的文本错误),\n (ii) 流畅性(应用{{target_lang}}的语法、拼写和标点规则,并确保没有不必要的重复),\n (iii) 风格(确保翻译反映源文本的风格并考虑其文化背景),\n (iv) 术语(确保术语使用一致且反映源文本所在领域,注意确保使用{{target_lang}}中的等效习语)\n4. 第四轮提升:严格遵循第三轮提出的建议对翻译修改,定稿出一个简洁畅达、符合大众观影习惯的字幕译文,保留<T>标识标签\n\n## OutputFormat:\n- 每一轮前用【思考】说明该轮要点\n- 第一轮和第二轮翻译后用【翻译】呈现译文\n- 第三轮输出建议清单,分点列出,在每一点前用*xxx*标识这条建议对应的要点,如*风格*;建议前用【思考】说明该轮要点,建议后用【建议】呈现建议\n- 第四轮在\\`\\`\\`代码块中展示最终{{target_lang}}字幕文件内容,如\\`\\`\\`xxx\\`\\`\\`\n\n## Suggestions:\n- 直译时力求忠实原文,但注意控制每帧字幕的字数,必要时进行精简压缩\n- 意译时在准确表达原意的基础上,用最朴实无华的{{target_lang}}来表达\n- 反思环节重点关注译文是否符合{{target_lang}}表达习惯,是否通俗易懂,是否准确流畅,是否术语一致\n- 提升环节采用反思环节的建议对意译环节的翻译进行修改,适度采用一些口语化的表达、网络流行语等,增强字幕的亲和力\n- 注意<T>是很重要的标识标签,请确保标签能在正确位置输出"
+ },
+ {
+ "key": "history",
+ "renderTypeList": [
+ "numberInput",
+ "reference"
+ ],
+ "valueType": "chatHistory",
+ "label": "core.module.input.label.chat history",
+ "description": "最多携带多少轮对话记录",
+ "required": true,
+ "min": 0,
+ "max": 50,
+ "value": 6
+ },
+ {
+ "key": "userChatInput",
+ "renderTypeList": [
+ "reference",
+ "textarea"
+ ],
+ "valueType": "string",
+ "label": "用户问题",
+ "required": true,
+ "toolDescription": "用户问题",
+ "value": [
+ "bxz97Vg4Omux",
+ "system_text"
+ ]
+ },
+ {
+ "key": "quoteQA",
+ "renderTypeList": [
+ "settingDatasetQuotePrompt"
+ ],
+ "label": "",
+ "debugLabel": "知识库引用",
+ "description": "",
+ "valueType": "datasetQuote"
+ }
+ ],
+ "outputs": [
+ {
+ "id": "history",
+ "key": "history",
+ "required": true,
+ "label": "core.module.output.label.New context",
+ "description": "core.module.output.description.New context",
+ "valueType": "chatHistory",
+ "type": "static"
+ },
+ {
+ "id": "answerText",
+ "key": "answerText",
+ "required": true,
+ "label": "core.module.output.label.Ai response content",
+ "description": "core.module.output.description.Ai response content",
+ "valueType": "string",
+ "type": "static"
+ }
+ ]
+ },
+ {
+ "nodeId": "bxz97Vg4Omux",
+ "name": "LLM 翻译提示词",
+ "intro": "可对固定或传入的文本进行加工后输出,非字符串类型数据最终会转成字符串类型。",
+ "avatar": "core/workflow/template/textConcat",
+ "flowNodeType": "textEditor",
+ "position": {
+ "x": 1893.11421220213,
+ "y": 1065.1299598362698
+ },
+ "version": "486",
+ "inputs": [
+ {
+ "key": "system_addInputParam",
+ "renderTypeList": [
+ "addInputParam"
+ ],
+ "valueType": "dynamic",
+ "label": "",
+ "required": false,
+ "description": "可以引用其他节点的输出,作为文本拼接的变量,通过 {{字段名}} 来引用变量",
+ "customInputConfig": {
+ "selectValueTypeList": [
+ "string",
+ "number",
+ "boolean",
+ "object",
+ "arrayString",
+ "arrayNumber",
+ "arrayBoolean",
+ "arrayObject",
+ "any",
+ "chatHistory",
+ "datasetQuote",
+ "dynamic",
+ "selectApp",
+ "selectDataset"
+ ],
+ "showDescription": false,
+ "showDefaultValue": false
+ }
+ },
+ {
+ "key": "system_textareaInput",
+ "renderTypeList": [
+ "textarea"
+ ],
+ "valueType": "string",
+ "required": true,
+ "label": "拼接文本",
+ "placeholder": "可通过 {{字段名}} 来引用变量",
+ "value": "你的任务是将文本从{{source_lang}}翻译成{{target_lang}}\n\n源文本如下,由XML标签<SOURCE_TEXT>和</SOURCE_TEXT>分隔:\n\n<SOURCE_TEXT>\n\n{{tagged_text}}\n\n</SOURCE_TEXT>\n\n仅翻译源文本中由<TRANSLATE_THIS>和</TRANSLATE_THIS>分隔的部分,将其余的源文本作为上下文\n\n重申一下,你应该只翻译文本的这一部分,这里再次显示在<TRANSLATE_THIS>和</TRANSLATE_THIS>之间:\n\n<TRANSLATE_THIS>\n\n{{chunk_to_translate}}\n\n</TRANSLATE_THIS>"
+ },
+ {
+ "renderTypeList": [
+ "reference"
+ ],
+ "valueType": "string",
+ "canEdit": true,
+ "key": "tagged_text",
+ "label": "tagged_text",
+ "customInputConfig": {
+ "selectValueTypeList": [
+ "string",
+ "number",
+ "boolean",
+ "object",
+ "arrayString",
+ "arrayNumber",
+ "arrayBoolean",
+ "arrayObject",
+ "any",
+ "chatHistory",
+ "datasetQuote",
+ "dynamic",
+ "selectApp",
+ "selectDataset"
+ ],
+ "showDescription": false,
+ "showDefaultValue": false
+ },
+ "required": true,
+ "value": [
+ "quYZgsW32ApA",
+ "xhXu6sdEWBnF"
+ ]
+ },
+ {
+ "renderTypeList": [
+ "reference"
+ ],
+ "valueType": "string",
+ "canEdit": true,
+ "key": "chunk_to_translate",
+ "label": "chunk_to_translate",
+ "customInputConfig": {
+ "selectValueTypeList": [
+ "string",
+ "number",
+ "boolean",
+ "object",
+ "arrayString",
+ "arrayNumber",
+ "arrayBoolean",
+ "arrayObject",
+ "any",
+ "chatHistory",
+ "datasetQuote",
+ "dynamic",
+ "selectApp",
+ "selectDataset"
+ ],
+ "showDescription": false,
+ "showDefaultValue": false
+ },
+ "required": true,
+ "value": [
+ "quYZgsW32ApA",
+ "eCp73lztAEGK"
+ ]
+ }
+ ],
+ "outputs": [
+ {
+ "id": "system_text",
+ "key": "system_text",
+ "label": "拼接结果",
+ "type": "static",
+ "valueType": "string"
+ }
+ ]
+ },
+ {
+ "nodeId": "w4heEpNflz59",
+ "name": "判断是否执行结束",
+ "intro": "根据一定的条件,执行不同的分支。",
+ "avatar": "core/workflow/template/ifelse",
+ "flowNodeType": "ifElseNode",
+ "showStatus": true,
+ "position": {
+ "x": 5625.495682697096,
+ "y": 1199.9313115831496
+ },
+ "version": "481",
+ "inputs": [
+ {
+ "key": "ifElseList",
+ "renderTypeList": [
+ "hidden"
+ ],
+ "valueType": "any",
+ "label": "",
+ "value": [
+ {
+ "condition": "AND",
+ "list": [
+ {
+ "variable": [
+ "a2lqxASWi1vb",
+ "nmBmGaARbKkl"
+ ],
+ "condition": "equalTo",
+ "value": "true"
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "outputs": [
+ {
+ "id": "ifElseResult",
+ "key": "ifElseResult",
+ "label": "判断结果",
+ "valueType": "string",
+ "type": "static"
+ }
+ ]
+ },
+ {
+ "nodeId": "a2lqxASWi1vb",
+ "name": "判断是否执行结束",
+ "intro": "执行一段简单的脚本代码,通常用于进行复杂的数据处理。",
+ "avatar": "core/workflow/template/codeRun",
+ "flowNodeType": "code",
+ "showStatus": true,
+ "position": {
+ "x": 5099.256084679105,
+ "y": 1102.1518590433243
+ },
+ "version": "482",
+ "inputs": [
+ {
+ "key": "system_addInputParam",
+ "renderTypeList": [
+ "addInputParam"
+ ],
+ "valueType": "dynamic",
+ "label": "",
+ "required": false,
+ "description": "这些变量会作为代码的运行的输入参数",
+ "customInputConfig": {
+ "selectValueTypeList": [
+ "string",
+ "number",
+ "boolean",
+ "object",
+ "arrayString",
+ "arrayNumber",
+ "arrayBoolean",
+ "arrayObject",
+ "any",
+ "chatHistory",
+ "datasetQuote",
+ "dynamic",
+ "selectApp",
+ "selectDataset"
+ ],
+ "showDescription": false,
+ "showDefaultValue": true
+ }
+ },
+ {
+ "key": "codeType",
+ "renderTypeList": [
+ "hidden"
+ ],
+ "label": "",
+ "value": "js"
+ },
+ {
+ "key": "code",
+ "renderTypeList": [
+ "custom"
+ ],
+ "label": "",
+ "value": "function main({chunks, currentChunk}){\n const findIndex = chunks.findIndex((item) => item === currentChunk)\n\n return {\n isEnd: chunks.length-1 === findIndex,\n i: findIndex + 1,\n }\n}"
+ },
+ {
+ "renderTypeList": [
+ "reference"
+ ],
+ "valueType": "arrayString",
+ "canEdit": true,
+ "key": "chunks",
+ "label": "chunks",
+ "customInputConfig": {
+ "selectValueTypeList": [
+ "string",
+ "number",
+ "boolean",
+ "object",
+ "arrayString",
+ "arrayNumber",
+ "arrayBoolean",
+ "arrayObject",
+ "any",
+ "chatHistory",
+ "datasetQuote",
+ "dynamic",
+ "selectApp",
+ "selectDataset"
+ ],
+ "showDescription": false,
+ "showDefaultValue": true
+ },
+ "required": true,
+ "value": [
+ "y3WEYOQ09CGC",
+ "qLUQfhG0ILRX"
+ ]
+ },
+ {
+ "renderTypeList": [
+ "reference"
+ ],
+ "valueType": "string",
+ "canEdit": true,
+ "key": "currentChunk",
+ "label": "currentChunk",
+ "customInputConfig": {
+ "selectValueTypeList": [
+ "string",
+ "number",
+ "boolean",
+ "object",
+ "arrayString",
+ "arrayNumber",
+ "arrayBoolean",
+ "arrayObject",
+ "any",
+ "chatHistory",
+ "datasetQuote",
+ "dynamic",
+ "selectApp",
+ "selectDataset"
+ ],
+ "showDescription": false,
+ "showDefaultValue": true
+ },
+ "required": true,
+ "value": [
+ "quYZgsW32ApA",
+ "eCp73lztAEGK"
+ ]
+ }
+ ],
+ "outputs": [
+ {
+ "id": "system_rawResponse",
+ "key": "system_rawResponse",
+ "label": "完整响应数据",
+ "valueType": "object",
+ "type": "static"
+ },
+ {
+ "id": "error",
+ "key": "error",
+ "label": "运行错误",
+ "description": "代码运行错误信息,成功时返回空",
+ "valueType": "object",
+ "type": "static"
+ },
+ {
+ "id": "system_addOutputParam",
+ "key": "system_addOutputParam",
+ "type": "dynamic",
+ "valueType": "dynamic",
+ "label": "",
+ "customFieldConfig": {
+ "selectValueTypeList": [
+ "string",
+ "number",
+ "boolean",
+ "object",
+ "arrayString",
+ "arrayNumber",
+ "arrayBoolean",
+ "arrayObject",
+ "any",
+ "chatHistory",
+ "datasetQuote",
+ "dynamic",
+ "selectApp",
+ "selectDataset"
+ ],
+ "showDescription": false,
+ "showDefaultValue": false
+ },
+ "description": "将代码中 return 的对象作为输出,传递给后续的节点。变量名需要对应 return 的 key"
+ },
+ {
+ "id": "nmBmGaARbKkl",
+ "valueType": "boolean",
+ "type": "dynamic",
+ "key": "isEnd",
+ "label": "isEnd"
+ },
+ {
+ "id": "nqB98uKpq6Ig",
+ "valueType": "number",
+ "type": "dynamic",
+ "key": "i",
+ "label": "i"
+ }
+ ]
+ },
+ {
+ "nodeId": "quYZgsW32ApA",
+ "name": "格式化源文本块",
+ "intro": "执行一段简单的脚本代码,通常用于进行复杂的数据处理。",
+ "avatar": "core/workflow/template/codeRun",
+ "flowNodeType": "code",
+ "showStatus": true,
+ "position": {
+ "x": 1251.2839737092052,
+ "y": 991.619268503857
+ },
+ "version": "482",
+ "inputs": [
+ {
+ "key": "system_addInputParam",
+ "renderTypeList": [
+ "addInputParam"
+ ],
+ "valueType": "dynamic",
+ "label": "",
+ "required": false,
+ "description": "这些变量会作为代码的运行的输入参数",
+ "customInputConfig": {
+ "selectValueTypeList": [
+ "string",
+ "number",
+ "boolean",
+ "object",
+ "arrayString",
+ "arrayNumber",
+ "arrayBoolean",
+ "arrayObject",
+ "any",
+ "chatHistory",
+ "datasetQuote",
+ "dynamic",
+ "selectApp",
+ "selectDataset"
+ ],
+ "showDescription": false,
+ "showDefaultValue": true
+ }
+ },
+ {
+ "key": "codeType",
+ "renderTypeList": [
+ "hidden"
+ ],
+ "label": "",
+ "value": "js"
+ },
+ {
+ "key": "code",
+ "renderTypeList": [
+ "custom"
+ ],
+ "label": "",
+ "value": "function main({source_text_chunks, i=0}){\n let before = source_text_chunks.slice(0, i).join(\"\");\n let current = \" <TRANSLATE_THIS>\" + source_text_chunks[i] + \"</TRANSLATE_THIS>\";\n let after = source_text_chunks.slice(i + 1).join(\"\");\n let tagged_text = before + current + after;\n\n return {\n tagged_text,\n chunk_to_translate: source_text_chunks[i],\n }\n}"
+ },
+ {
+ "renderTypeList": [
+ "reference"
+ ],
+ "valueType": "number",
+ "canEdit": true,
+ "key": "i",
+ "label": "i",
+ "customInputConfig": {
+ "selectValueTypeList": [
+ "string",
+ "number",
+ "boolean",
+ "object",
+ "arrayString",
+ "arrayNumber",
+ "arrayBoolean",
+ "arrayObject",
+ "any",
+ "chatHistory",
+ "datasetQuote",
+ "dynamic",
+ "selectApp",
+ "selectDataset"
+ ],
+ "showDescription": false,
+ "showDefaultValue": true
+ },
+ "required": true,
+ "value": [
+ "a2lqxASWi1vb",
+ "nqB98uKpq6Ig"
+ ]
+ },
+ {
+ "renderTypeList": [
+ "reference"
+ ],
+ "valueType": "arrayString",
+ "canEdit": true,
+ "key": "source_text_chunks",
+ "label": "source_text_chunks",
+ "customInputConfig": {
+ "selectValueTypeList": [
+ "string",
+ "number",
+ "boolean",
+ "object",
+ "arrayString",
+ "arrayNumber",
+ "arrayBoolean",
+ "arrayObject",
+ "any",
+ "chatHistory",
+ "datasetQuote",
+ "dynamic",
+ "selectApp",
+ "selectDataset"
+ ],
+ "showDescription": false,
+ "showDefaultValue": true
+ },
+ "required": true,
+ "value": [
+ "y3WEYOQ09CGC",
+ "qLUQfhG0ILRX"
+ ]
+ }
+ ],
+ "outputs": [
+ {
+ "id": "system_rawResponse",
+ "key": "system_rawResponse",
+ "label": "完整响应数据",
+ "valueType": "object",
+ "type": "static"
+ },
+ {
+ "id": "error",
+ "key": "error",
+ "label": "运行错误",
+ "description": "代码运行错误信息,成功时返回空",
+ "valueType": "object",
+ "type": "static"
+ },
+ {
+ "id": "system_addOutputParam",
+ "key": "system_addOutputParam",
+ "type": "dynamic",
+ "valueType": "dynamic",
+ "label": "",
+ "customFieldConfig": {
+ "selectValueTypeList": [
+ "string",
+ "number",
+ "boolean",
+ "object",
+ "arrayString",
+ "arrayNumber",
+ "arrayBoolean",
+ "arrayObject",
+ "any",
+ "chatHistory",
+ "datasetQuote",
+ "dynamic",
+ "selectApp",
+ "selectDataset"
+ ],
+ "showDescription": false,
+ "showDefaultValue": false
+ },
+ "description": "将代码中 return 的对象作为输出,传递给后续的节点。变量名需要对应 return 的 key"
+ },
+ {
+ "id": "xhXu6sdEWBnF",
+ "valueType": "string",
+ "type": "dynamic",
+ "key": "tagged_text",
+ "label": "tagged_text"
+ },
+ {
+ "id": "eCp73lztAEGK",
+ "valueType": "string",
+ "type": "dynamic",
+ "key": "chunk_to_translate",
+ "label": "chunk_to_translate"
+ }
+ ]
+ },
+ {
+ "nodeId": "izsNX8FXGD1t",
+ "name": "指定回复",
+ "intro": "该模块可以直接回复一段指定的内容。常用于引导、提示。非字符串内容传入时,会转成字符串进行输出。",
+ "avatar": "core/workflow/template/reply",
+ "flowNodeType": "answerNode",
+ "position": {
+ "x": 6399.439691374053,
+ "y": 1204.4024103331792
+ },
+ "version": "481",
+ "inputs": [
+ {
+ "key": "text",
+ "renderTypeList": [
+ "textarea",
+ "reference"
+ ],
+ "valueType": "any",
+ "required": true,
+ "label": "core.module.input.label.Response content",
+ "description": "core.module.input.description.Response content",
+ "placeholder": "core.module.input.description.Response content",
+ "value": "\n\n*** 字幕反思翻译完成!***"
+ }
+ ],
+ "outputs": []
+ },
+ {
+ "nodeId": "vlNHndpNuFXB",
+ "name": "取出 LLM 翻译第四轮文本",
+ "intro": "执行一段简单的脚本代码,通常用于进行复杂的数据处理。",
+ "avatar": "core/workflow/template/codeRun",
+ "flowNodeType": "code",
+ "showStatus": true,
+ "position": {
+ "x": 3284.6375352131763,
+ "y": 950.1100995985583
+ },
+ "version": "482",
+ "inputs": [
+ {
+ "key": "system_addInputParam",
+ "renderTypeList": [
+ "addInputParam"
+ ],
+ "valueType": "dynamic",
+ "label": "",
+ "required": false,
+ "description": "这些变量会作为代码的运行的输入参数",
+ "editField": {
+ "key": true,
+ "valueType": true
+ },
+ "customInputConfig": {
+ "selectValueTypeList": [
+ "string",
+ "number",
+ "boolean",
+ "object",
+ "arrayString",
+ "arrayNumber",
+ "arrayBoolean",
+ "arrayObject",
+ "any",
+ "chatHistory",
+ "datasetQuote",
+ "dynamic",
+ "selectApp",
+ "selectDataset"
+ ],
+ "showDescription": false,
+ "showDefaultValue": true
+ }
+ },
+ {
+ "key": "codeType",
+ "renderTypeList": [
+ "hidden"
+ ],
+ "label": "",
+ "value": "js"
+ },
+ {
+ "key": "code",
+ "renderTypeList": [
+ "custom"
+ ],
+ "label": "",
+ "value": "function main({data1}){\n const result = data1.split(\"```\").filter(item => !!item.trim())\n\n if(result[result.length-1]) {\n return {\n result: result[result.length-1].trim() \n }\n }\n\n return {\n result: '未截取到翻译内容'\n }\n}"
+ },
+ {
+ "key": "data1",
+ "valueType": "string",
+ "label": "data1",
+ "renderTypeList": [
+ "reference"
+ ],
+ "description": "",
+ "canEdit": true,
+ "editField": {
+ "key": true,
+ "valueType": true
+ },
+ "value": [
+ "yjFO3YcM7KG2",
+ "answerText"
+ ],
+ "customInputConfig": {
+ "selectValueTypeList": [
+ "string",
+ "number",
+ "boolean",
+ "object",
+ "arrayString",
+ "arrayNumber",
+ "arrayBoolean",
+ "arrayObject",
+ "any",
+ "chatHistory",
+ "datasetQuote",
+ "dynamic",
+ "selectApp",
+ "selectDataset"
+ ],
+ "showDescription": false,
+ "showDefaultValue": true
+ }
+ }
+ ],
+ "outputs": [
+ {
+ "id": "system_rawResponse",
+ "key": "system_rawResponse",
+ "label": "完整响应数据",
+ "valueType": "object",
+ "type": "static"
+ },
+ {
+ "id": "error",
+ "key": "error",
+ "label": "运行错误",
+ "description": "代码运行错误信息,成功时返回空",
+ "valueType": "object",
+ "type": "static"
+ },
+ {
+ "id": "system_addOutputParam",
+ "key": "system_addOutputParam",
+ "type": "dynamic",
+ "valueType": "dynamic",
+ "label": "",
+ "customFieldConfig": {
+ "selectValueTypeList": [
+ "string",
+ "number",
+ "boolean",
+ "object",
+ "arrayString",
+ "arrayNumber",
+ "arrayBoolean",
+ "arrayObject",
+ "any",
+ "chatHistory",
+ "datasetQuote",
+ "dynamic",
+ "selectApp",
+ "selectDataset"
+ ],
+ "showDescription": false,
+ "showDefaultValue": false
+ },
+ "description": "将代码中 return 的对象作为输出,传递给后续的节点。变量名需要对应 return 的 key"
+ },
+ {
+ "id": "qLUQfhG0ILRX",
+ "type": "dynamic",
+ "key": "result",
+ "valueType": "string",
+ "label": "result"
+ },
+ {
+ "id": "gR0mkQpJ4Og8",
+ "type": "dynamic",
+ "key": "data2",
+ "valueType": "string",
+ "label": "data2"
+ }
+ ]
+ },
+ {
+ "nodeId": "qlt9KJbbS9yJ",
+ "name": "判断源语言和目标语言是否相同",
+ "intro": "根据一定的条件,执行不同的分支。",
+ "avatar": "core/workflow/template/ifelse",
+ "flowNodeType": "ifElseNode",
+ "showStatus": true,
+ "position": {
+ "x": -648.2730659546055,
+ "y": 1295.3336516652123
+ },
+ "version": "481",
+ "inputs": [
+ {
+ "key": "ifElseList",
+ "renderTypeList": [
+ "hidden"
+ ],
+ "valueType": "any",
+ "label": "",
+ "value": [
+ {
+ "condition": "AND",
+ "list": [
+ {
+ "variable": [
+ "frjbsrlnJJsR",
+ "qLUQfhG0ILRX"
+ ],
+ "condition": "equalTo",
+ "value": "false"
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "outputs": [
+ {
+ "id": "ifElseResult",
+ "key": "ifElseResult",
+ "label": "判断结果",
+ "valueType": "string",
+ "type": "static"
+ }
+ ]
+ },
+ {
+ "nodeId": "frjbsrlnJJsR",
+ "name": "判断源语言和目标语言是否相同",
+ "intro": "执行一段简单的脚本代码,通常用于进行复杂的数据处理。",
+ "avatar": "core/workflow/template/codeRun",
+ "flowNodeType": "code",
+ "showStatus": true,
+ "position": {
+ "x": -1142.9562352499165,
+ "y": 1031.4486788585432
+ },
+ "version": "482",
+ "inputs": [
+ {
+ "key": "system_addInputParam",
+ "renderTypeList": [
+ "addInputParam"
+ ],
+ "valueType": "dynamic",
+ "label": "",
+ "required": false,
+ "description": "这些变量会作为代码的运行的输入参数",
+ "customInputConfig": {
+ "selectValueTypeList": [
+ "string",
+ "number",
+ "boolean",
+ "object",
+ "arrayString",
+ "arrayNumber",
+ "arrayBoolean",
+ "arrayObject",
+ "any",
+ "chatHistory",
+ "datasetQuote",
+ "dynamic",
+ "selectApp",
+ "selectDataset"
+ ],
+ "showDescription": false,
+ "showDefaultValue": true
+ }
+ },
+ {
+ "key": "codeType",
+ "renderTypeList": [
+ "hidden"
+ ],
+ "label": "",
+ "value": "js"
+ },
+ {
+ "key": "code",
+ "renderTypeList": [
+ "custom"
+ ],
+ "label": "",
+ "value": "function main({source_lang, target_lang}){\n \n return {\n result: source_lang === target_lang\n }\n}"
+ },
+ {
+ "renderTypeList": [
+ "reference"
+ ],
+ "valueType": "string",
+ "canEdit": true,
+ "key": "source_lang",
+ "label": "source_lang",
+ "customInputConfig": {
+ "selectValueTypeList": [
+ "string",
+ "number",
+ "boolean",
+ "object",
+ "arrayString",
+ "arrayNumber",
+ "arrayBoolean",
+ "arrayObject",
+ "any",
+ "chatHistory",
+ "datasetQuote",
+ "dynamic",
+ "selectApp",
+ "selectDataset"
+ ],
+ "showDescription": false,
+ "showDefaultValue": true
+ },
+ "required": true,
+ "value": [
+ "VARIABLE_NODE_ID",
+ "source_lang"
+ ]
+ },
+ {
+ "renderTypeList": [
+ "reference"
+ ],
+ "valueType": "string",
+ "canEdit": true,
+ "key": "target_lang",
+ "label": "target_lang",
+ "customInputConfig": {
+ "selectValueTypeList": [
+ "string",
+ "number",
+ "boolean",
+ "object",
+ "arrayString",
+ "arrayNumber",
+ "arrayBoolean",
+ "arrayObject",
+ "any",
+ "chatHistory",
+ "datasetQuote",
+ "dynamic",
+ "selectApp",
+ "selectDataset"
+ ],
+ "showDescription": false,
+ "showDefaultValue": true
+ },
+ "required": true,
+ "value": [
+ "VARIABLE_NODE_ID",
+ "target_lang"
+ ]
+ }
+ ],
+ "outputs": [
+ {
+ "id": "system_rawResponse",
+ "key": "system_rawResponse",
+ "label": "完整响应数据",
+ "valueType": "object",
+ "type": "static"
+ },
+ {
+ "id": "error",
+ "key": "error",
+ "label": "运行错误",
+ "description": "代码运行错误信息,成功时返回空",
+ "valueType": "object",
+ "type": "static"
+ },
+ {
+ "id": "system_addOutputParam",
+ "key": "system_addOutputParam",
+ "type": "dynamic",
+ "valueType": "dynamic",
+ "label": "",
+ "customFieldConfig": {
+ "selectValueTypeList": [
+ "string",
+ "number",
+ "boolean",
+ "object",
+ "arrayString",
+ "arrayNumber",
+ "arrayBoolean",
+ "arrayObject",
+ "any",
+ "chatHistory",
+ "datasetQuote",
+ "dynamic",
+ "selectApp",
+ "selectDataset"
+ ],
+ "showDescription": false,
+ "showDefaultValue": false
+ },
+ "description": "将代码中 return 的对象作为输出,传递给后续的节点。变量名需要对应 return 的 key"
+ },
+ {
+ "id": "qLUQfhG0ILRX",
+ "type": "dynamic",
+ "key": "result",
+ "valueType": "boolean",
+ "label": "result"
+ }
+ ]
+ },
+ {
+ "nodeId": "dFxrGZS3Wmnz",
+ "name": "提示源语言与目标语言相同",
+ "intro": "该模块可以直接回复一段指定的内容。常用于引导、提示。非字符串内容传入时,会转成字符串进行输出。",
+ "avatar": "core/workflow/template/reply",
+ "flowNodeType": "answerNode",
+ "position": {
+ "x": -554.7555863373991,
+ "y": 1727.175384457058
+ },
+ "version": "481",
+ "inputs": [
+ {
+ "key": "text",
+ "renderTypeList": [
+ "textarea",
+ "reference"
+ ],
+ "valueType": "any",
+ "required": true,
+ "label": "core.module.input.label.Response content",
+ "description": "core.module.input.description.Response content",
+ "placeholder": "core.module.input.description.Response content",
+ "selectedTypeIndex": 0,
+ "value": "{{source_lang}} 无需再次翻译为 {{target_lang}} ~"
+ }
+ ],
+ "outputs": []
+ },
+ {
+ "nodeId": "tqzmK5oPR9BA",
+ "name": "输出翻译",
+ "intro": "该模块可以直接回复一段指定的内容。常用于引导、提示。非字符串内容传入时,会转成字符串进行输出。",
+ "avatar": "core/workflow/template/reply",
+ "flowNodeType": "answerNode",
+ "position": {
+ "x": 4378.294585712487,
+ "y": 1268.975092230105
+ },
+ "version": "481",
+ "inputs": [
+ {
+ "key": "text",
+ "renderTypeList": [
+ "textarea",
+ "reference"
+ ],
+ "valueType": "any",
+ "required": true,
+ "label": "core.module.input.label.Response content",
+ "description": "core.module.input.description.Response content",
+ "placeholder": "core.module.input.description.Response content",
+ "selectedTypeIndex": 1,
+ "value": [
+ "ppPP6o7YYSTJ",
+ "dYalXmYJ60bj"
+ ]
+ }
+ ],
+ "outputs": []
+ },
+ {
+ "nodeId": "kbr342XlxSZR",
+ "name": "提取字幕信息",
+ "intro": "执行一段简单的脚本代码,通常用于进行复杂的数据处理。",
+ "avatar": "core/workflow/template/codeRun",
+ "flowNodeType": "code",
+ "showStatus": true,
+ "position": {
+ "x": 185.35869756392378,
+ "y": 1004.6884026918935
+ },
+ "version": "482",
+ "inputs": [
+ {
+ "key": "system_addInputParam",
+ "renderTypeList": [
+ "addInputParam"
+ ],
+ "valueType": "dynamic",
+ "label": "",
+ "required": false,
+ "description": "这些变量会作为代码的运行的输入参数",
+ "customInputConfig": {
+ "selectValueTypeList": [
+ "string",
+ "number",
+ "boolean",
+ "object",
+ "arrayString",
+ "arrayNumber",
+ "arrayBoolean",
+ "arrayObject",
+ "any",
+ "chatHistory",
+ "datasetQuote",
+ "dynamic",
+ "selectApp",
+ "selectDataset"
+ ],
+ "showDescription": false,
+ "showDefaultValue": true
+ }
+ },
+ {
+ "key": "codeType",
+ "renderTypeList": [
+ "hidden"
+ ],
+ "label": "",
+ "value": "js"
+ },
+ {
+ "key": "code",
+ "renderTypeList": [
+ "custom"
+ ],
+ "label": "",
+ "value": "function main({text}){\n const lines = text.split('\\n');\n const timePattern = /\\d{2}:\\d{2}:\\d{2},\\d{3} --> \\d{2}:\\d{2}:\\d{2},\\d{3}/;\n const numberInfo = [];\n const timeInfo = [];\n const textInfo = [];\n let currentText = [];\n\n // 提取序号、时间戳和文本信息\n lines.forEach(line => {\n if (/^\\d+$/.test(line.trim())) {\n numberInfo.push(line.trim());\n } else if (timePattern.test(line)) {\n timeInfo.push(line);\n if (currentText.length > 0) {\n textInfo.push(currentText.join(' '));\n currentText = [];\n }\n } else if (line.trim() === '') {\n // Skip empty lines\n } else {\n currentText.push(line.trim());\n }\n });\n\n if (currentText.length > 0) {\n textInfo.push(currentText.join(' '));\n }\n\n return { numberInfo, timeInfo, textInfo };\n}"
+ },
+ {
+ "renderTypeList": [
+ "reference"
+ ],
+ "valueType": "string",
+ "canEdit": true,
+ "key": "text",
+ "label": "text",
+ "customInputConfig": {
+ "selectValueTypeList": [
+ "string",
+ "number",
+ "boolean",
+ "object",
+ "arrayString",
+ "arrayNumber",
+ "arrayBoolean",
+ "arrayObject",
+ "any",
+ "chatHistory",
+ "datasetQuote",
+ "dynamic",
+ "selectApp",
+ "selectDataset"
+ ],
+ "showDescription": false,
+ "showDefaultValue": true
+ },
+ "required": true,
+ "value": [
+ "448745",
+ "userChatInput"
+ ]
+ }
+ ],
+ "outputs": [
+ {
+ "id": "system_rawResponse",
+ "key": "system_rawResponse",
+ "label": "完整响应数据",
+ "valueType": "object",
+ "type": "static"
+ },
+ {
+ "id": "error",
+ "key": "error",
+ "label": "运行错误",
+ "description": "代码运行错误信息,成功时返回空",
+ "valueType": "object",
+ "type": "static"
+ },
+ {
+ "id": "system_addOutputParam",
+ "key": "system_addOutputParam",
+ "type": "dynamic",
+ "valueType": "dynamic",
+ "label": "",
+ "customFieldConfig": {
+ "selectValueTypeList": [
+ "string",
+ "number",
+ "boolean",
+ "object",
+ "arrayString",
+ "arrayNumber",
+ "arrayBoolean",
+ "arrayObject",
+ "any",
+ "chatHistory",
+ "datasetQuote",
+ "dynamic",
+ "selectApp",
+ "selectDataset"
+ ],
+ "showDescription": false,
+ "showDefaultValue": false
+ },
+ "description": "将代码中 return 的对象作为输出,传递给后续的节点。变量名需要对应 return 的 key"
+ },
+ {
+ "id": "h3qVuGhV9HNm",
+ "valueType": "arrayString",
+ "type": "dynamic",
+ "key": "timeInfo",
+ "label": "timeInfo"
+ },
+ {
+ "id": "zGYRMNA9xGuI",
+ "valueType": "arrayString",
+ "type": "dynamic",
+ "key": "textInfo",
+ "label": "textInfo"
+ },
+ {
+ "id": "dhzTt6Riz8Dp",
+ "valueType": "arrayString",
+ "type": "dynamic",
+ "key": "numberInfo",
+ "label": "numberInfo"
+ }
+ ]
+ },
+ {
+ "nodeId": "ppPP6o7YYSTJ",
+ "name": "格式化字幕文件",
+ "intro": "执行一段简单的脚本代码,通常用于进行复杂的数据处理。",
+ "avatar": "core/workflow/template/codeRun",
+ "flowNodeType": "code",
+ "showStatus": true,
+ "position": {
+ "x": 3825.553384884565,
+ "y": 956.4575651844932
+ },
+ "version": "482",
+ "inputs": [
+ {
+ "key": "system_addInputParam",
+ "renderTypeList": [
+ "addInputParam"
+ ],
+ "valueType": "dynamic",
+ "label": "",
+ "required": false,
+ "description": "这些变量会作为代码的运行的输入参数",
+ "customInputConfig": {
+ "selectValueTypeList": [
+ "string",
+ "number",
+ "boolean",
+ "object",
+ "arrayString",
+ "arrayNumber",
+ "arrayBoolean",
+ "arrayObject",
+ "any",
+ "chatHistory",
+ "datasetQuote",
+ "dynamic",
+ "selectApp",
+ "selectDataset"
+ ],
+ "showDescription": false,
+ "showDefaultValue": true
+ }
+ },
+ {
+ "key": "codeType",
+ "renderTypeList": [
+ "hidden"
+ ],
+ "label": "",
+ "value": "js"
+ },
+ {
+ "key": "code",
+ "renderTypeList": [
+ "custom"
+ ],
+ "label": "",
+ "value": "function main({combinedText, transedText, timeInfo, currentIndex=0,numberInfo}){\n const textLines = combinedText.split('<T>');\n const resultLines = transedText.split('<T>');\n const combinedLines = [];\n\n resultLines.forEach((line, index) => {\n combinedLines.push(numberInfo[currentIndex+index]);\n combinedLines.push(timeInfo[currentIndex+index]);\n combinedLines.push(line)\n combinedLines.push(textLines[index]);\n combinedLines.push('');\n });\n\n const srtContent = combinedLines.join('\\n');\n \n\n return {\n srtContent,\n currentIndex: currentIndex+textLines.length\n }\n}"
+ },
+ {
+ "renderTypeList": [
+ "reference"
+ ],
+ "valueType": "string",
+ "canEdit": true,
+ "key": "combinedText",
+ "label": "combinedText",
+ "customInputConfig": {
+ "selectValueTypeList": [
+ "string",
+ "number",
+ "boolean",
+ "object",
+ "arrayString",
+ "arrayNumber",
+ "arrayBoolean",
+ "arrayObject",
+ "any",
+ "chatHistory",
+ "datasetQuote",
+ "dynamic",
+ "selectApp",
+ "selectDataset"
+ ],
+ "showDescription": false,
+ "showDefaultValue": true
+ },
+ "required": true,
+ "value": [
+ "quYZgsW32ApA",
+ "eCp73lztAEGK"
+ ]
+ },
+ {
+ "renderTypeList": [
+ "reference"
+ ],
+ "valueType": "string",
+ "canEdit": true,
+ "key": "transedText",
+ "label": "transedText",
+ "customInputConfig": {
+ "selectValueTypeList": [
+ "string",
+ "number",
+ "boolean",
+ "object",
+ "arrayString",
+ "arrayNumber",
+ "arrayBoolean",
+ "arrayObject",
+ "any",
+ "chatHistory",
+ "datasetQuote",
+ "dynamic",
+ "selectApp",
+ "selectDataset"
+ ],
+ "showDescription": false,
+ "showDefaultValue": true
+ },
+ "required": true,
+ "value": [
+ "vlNHndpNuFXB",
+ "qLUQfhG0ILRX"
+ ]
+ },
+ {
+ "renderTypeList": [
+ "reference"
+ ],
+ "valueType": "arrayString",
+ "canEdit": true,
+ "key": "timeInfo",
+ "label": "timeInfo",
+ "customInputConfig": {
+ "selectValueTypeList": [
+ "string",
+ "number",
+ "boolean",
+ "object",
+ "arrayString",
+ "arrayNumber",
+ "arrayBoolean",
+ "arrayObject",
+ "any",
+ "chatHistory",
+ "datasetQuote",
+ "dynamic",
+ "selectApp",
+ "selectDataset"
+ ],
+ "showDescription": false,
+ "showDefaultValue": true
+ },
+ "required": true,
+ "value": [
+ "kbr342XlxSZR",
+ "h3qVuGhV9HNm"
+ ]
+ },
+ {
+ "renderTypeList": [
+ "reference"
+ ],
+ "valueType": "number",
+ "canEdit": true,
+ "key": "currentIndex",
+ "label": "currentIndex",
+ "customInputConfig": {
+ "selectValueTypeList": [
+ "string",
+ "number",
+ "boolean",
+ "object",
+ "arrayString",
+ "arrayNumber",
+ "arrayBoolean",
+ "arrayObject",
+ "any",
+ "chatHistory",
+ "datasetQuote",
+ "dynamic",
+ "selectApp",
+ "selectDataset"
+ ],
+ "showDescription": false,
+ "showDefaultValue": true
+ },
+ "required": true,
+ "value": [
+ "ppPP6o7YYSTJ",
+ "u6eqeC0pEPe0"
+ ]
+ },
+ {
+ "renderTypeList": [
+ "reference"
+ ],
+ "valueType": "arrayString",
+ "canEdit": true,
+ "key": "numberInfo",
+ "label": "numberInfo",
+ "customInputConfig": {
+ "selectValueTypeList": [
+ "string",
+ "number",
+ "boolean",
+ "object",
+ "arrayString",
+ "arrayNumber",
+ "arrayBoolean",
+ "arrayObject",
+ "any",
+ "chatHistory",
+ "datasetQuote",
+ "dynamic",
+ "selectApp",
+ "selectDataset"
+ ],
+ "showDescription": false,
+ "showDefaultValue": true
+ },
+ "required": true,
+ "value": [
+ "kbr342XlxSZR",
+ "dhzTt6Riz8Dp"
+ ]
+ }
+ ],
+ "outputs": [
+ {
+ "id": "system_rawResponse",
+ "key": "system_rawResponse",
+ "label": "完整响应数据",
+ "valueType": "object",
+ "type": "static"
+ },
+ {
+ "id": "error",
+ "key": "error",
+ "label": "运行错误",
+ "description": "代码运行错误信息,成功时返回空",
+ "valueType": "object",
+ "type": "static"
+ },
+ {
+ "id": "system_addOutputParam",
+ "key": "system_addOutputParam",
+ "type": "dynamic",
+ "valueType": "dynamic",
+ "label": "",
+ "customFieldConfig": {
+ "selectValueTypeList": [
+ "string",
+ "number",
+ "boolean",
+ "object",
+ "arrayString",
+ "arrayNumber",
+ "arrayBoolean",
+ "arrayObject",
+ "any",
+ "chatHistory",
+ "datasetQuote",
+ "dynamic",
+ "selectApp",
+ "selectDataset"
+ ],
+ "showDescription": false,
+ "showDefaultValue": false
+ },
+ "description": "将代码中 return 的对象作为输出,传递给后续的节点。变量名需要对应 return 的 key"
+ },
+ {
+ "id": "dYalXmYJ60bj",
+ "valueType": "string",
+ "type": "dynamic",
+ "key": "srtContent",
+ "label": "srtContent"
+ },
+ {
+ "id": "u6eqeC0pEPe0",
+ "valueType": "number",
+ "type": "dynamic",
+ "key": "currentIndex",
+ "label": "currentIndex"
+ }
+ ]
+ },
+ {
+ "nodeId": "y3WEYOQ09CGC",
+ "name": "切分文本",
+ "intro": "执行一段简单的脚本代码,通常用于进行复杂的数据处理。",
+ "avatar": "core/workflow/template/codeRun",
+ "flowNodeType": "code",
+ "showStatus": true,
+ "position": {
+ "x": 742.138506499589,
+ "y": 1011.2409789066801
+ },
+ "version": "482",
+ "inputs": [
+ {
+ "key": "system_addInputParam",
+ "renderTypeList": [
+ "addInputParam"
+ ],
+ "valueType": "dynamic",
+ "label": "",
+ "required": false,
+ "description": "这些变量会作为代码的运行的输入参数",
+ "customInputConfig": {
+ "selectValueTypeList": [
+ "string",
+ "number",
+ "boolean",
+ "object",
+ "arrayString",
+ "arrayNumber",
+ "arrayBoolean",
+ "arrayObject",
+ "any",
+ "chatHistory",
+ "datasetQuote",
+ "dynamic",
+ "selectApp",
+ "selectDataset"
+ ],
+ "showDescription": false,
+ "showDefaultValue": true
+ }
+ },
+ {
+ "key": "codeType",
+ "renderTypeList": [
+ "hidden"
+ ],
+ "label": "",
+ "value": "js"
+ },
+ {
+ "key": "code",
+ "renderTypeList": [
+ "custom"
+ ],
+ "label": "",
+ "value": "function main({textArray}){\n const groupSize = 20\n const delimiter = '<T>'\n\n const result = [];\n\n for (let i = 0; i < textArray.length; i += groupSize) {\n result.push(textArray.slice(i, i + groupSize).join(delimiter));\n }\n\n return {result};\n}"
+ },
+ {
+ "renderTypeList": [
+ "reference"
+ ],
+ "valueType": "arrayString",
+ "canEdit": true,
+ "key": "textArray",
+ "label": "textArray",
+ "customInputConfig": {
+ "selectValueTypeList": [
+ "string",
+ "number",
+ "boolean",
+ "object",
+ "arrayString",
+ "arrayNumber",
+ "arrayBoolean",
+ "arrayObject",
+ "any",
+ "chatHistory",
+ "datasetQuote",
+ "dynamic",
+ "selectApp",
+ "selectDataset"
+ ],
+ "showDescription": false,
+ "showDefaultValue": true
+ },
+ "required": true,
+ "value": [
+ "kbr342XlxSZR",
+ "zGYRMNA9xGuI"
+ ]
+ }
+ ],
+ "outputs": [
+ {
+ "id": "system_rawResponse",
+ "key": "system_rawResponse",
+ "label": "完整响应数据",
+ "valueType": "object",
+ "type": "static"
+ },
+ {
+ "id": "error",
+ "key": "error",
+ "label": "运行错误",
+ "description": "代码运行错误信息,成功时返回空",
+ "valueType": "object",
+ "type": "static"
+ },
+ {
+ "id": "system_addOutputParam",
+ "key": "system_addOutputParam",
+ "type": "dynamic",
+ "valueType": "dynamic",
+ "label": "",
+ "customFieldConfig": {
+ "selectValueTypeList": [
+ "string",
+ "number",
+ "boolean",
+ "object",
+ "arrayString",
+ "arrayNumber",
+ "arrayBoolean",
+ "arrayObject",
+ "any",
+ "chatHistory",
+ "datasetQuote",
+ "dynamic",
+ "selectApp",
+ "selectDataset"
+ ],
+ "showDescription": false,
+ "showDefaultValue": false
+ },
+ "description": "将代码中 return 的对象作为输出,传递给后续的节点。变量名需要对应 return 的 key"
+ },
+ {
+ "id": "qLUQfhG0ILRX",
+ "type": "dynamic",
+ "key": "result",
+ "valueType": "arrayString",
+ "label": "result"
+ }
+ ]
+ }
+ ],
+ "edges": [
+ {
+ "source": "bxz97Vg4Omux",
+ "target": "yjFO3YcM7KG2",
+ "sourceHandle": "bxz97Vg4Omux-source-right",
+ "targetHandle": "yjFO3YcM7KG2-target-left"
+ },
+ {
+ "source": "a2lqxASWi1vb",
+ "target": "w4heEpNflz59",
+ "sourceHandle": "a2lqxASWi1vb-source-right",
+ "targetHandle": "w4heEpNflz59-target-left"
+ },
+ {
+ "source": "w4heEpNflz59",
+ "target": "izsNX8FXGD1t",
+ "sourceHandle": "w4heEpNflz59-source-IF",
+ "targetHandle": "izsNX8FXGD1t-target-left"
+ },
+ {
+ "source": "448745",
+ "target": "frjbsrlnJJsR",
+ "sourceHandle": "448745-source-right",
+ "targetHandle": "frjbsrlnJJsR-target-left"
+ },
+ {
+ "source": "frjbsrlnJJsR",
+ "target": "qlt9KJbbS9yJ",
+ "sourceHandle": "frjbsrlnJJsR-source-right",
+ "targetHandle": "qlt9KJbbS9yJ-target-left"
+ },
+ {
+ "source": "tqzmK5oPR9BA",
+ "target": "a2lqxASWi1vb",
+ "sourceHandle": "tqzmK5oPR9BA-source-right",
+ "targetHandle": "a2lqxASWi1vb-target-left"
+ },
+ {
+ "source": "yjFO3YcM7KG2",
+ "target": "vlNHndpNuFXB",
+ "sourceHandle": "yjFO3YcM7KG2-source-right",
+ "targetHandle": "vlNHndpNuFXB-target-left"
+ },
+ {
+ "source": "ppPP6o7YYSTJ",
+ "target": "tqzmK5oPR9BA",
+ "sourceHandle": "ppPP6o7YYSTJ-source-right",
+ "targetHandle": "tqzmK5oPR9BA-target-left"
+ },
+ {
+ "source": "kbr342XlxSZR",
+ "target": "y3WEYOQ09CGC",
+ "sourceHandle": "kbr342XlxSZR-source-right",
+ "targetHandle": "y3WEYOQ09CGC-target-left"
+ },
+ {
+ "source": "y3WEYOQ09CGC",
+ "target": "quYZgsW32ApA",
+ "sourceHandle": "y3WEYOQ09CGC-source-right",
+ "targetHandle": "quYZgsW32ApA-target-left"
+ },
+ {
+ "source": "quYZgsW32ApA",
+ "target": "bxz97Vg4Omux",
+ "sourceHandle": "quYZgsW32ApA-source-right",
+ "targetHandle": "bxz97Vg4Omux-target-left"
+ },
+ {
+ "source": "w4heEpNflz59",
+ "target": "quYZgsW32ApA",
+ "sourceHandle": "w4heEpNflz59-source-ELSE",
+ "targetHandle": "quYZgsW32ApA-target-left"
+ },
+ {
+ "source": "qlt9KJbbS9yJ",
+ "target": "kbr342XlxSZR",
+ "sourceHandle": "qlt9KJbbS9yJ-source-IF",
+ "targetHandle": "kbr342XlxSZR-target-left"
+ },
+ {
+ "source": "qlt9KJbbS9yJ",
+ "target": "dFxrGZS3Wmnz",
+ "sourceHandle": "qlt9KJbbS9yJ-source-ELSE",
+ "targetHandle": "dFxrGZS3Wmnz-target-right"
+ },
+ {
+ "source": "vlNHndpNuFXB",
+ "target": "ppPP6o7YYSTJ",
+ "sourceHandle": "vlNHndpNuFXB-source-right",
+ "targetHandle": "ppPP6o7YYSTJ-target-left"
+ }
+ ],
+ "chatConfig": {
+ "welcomeText": "你好,欢迎使用长字幕反思翻译机器人。\n\n在完成下方设置后,可以直接输入需要翻译的文本",
+ "variables": [
+ {
+ "id": "v98n5b",
+ "key": "source_lang",
+ "label": "源语言",
+ "type": "select",
+ "required": true,
+ "maxLen": 50,
+ "enums": [
+ {
+ "value": "简体中文"
+ },
+ {
+ "value": "繁體中文"
+ },
+ {
+ "value": "English"
+ },
+ {
+ "value": "Español"
+ },
+ {
+ "value": "Français"
+ },
+ {
+ "value": "Deutsch"
+ },
+ {
+ "value": "Italiano"
+ },
+ {
+ "value": "日本語"
+ },
+ {
+ "value": "한국어"
+ },
+ {
+ "value": "Русский"
+ },
+ {
+ "value": "العربية"
+ },
+ {
+ "value": "Bahasa Indonesia"
+ },
+ {
+ "value": "Polski"
+ }
+ ],
+ "icon": "core/app/variable/select"
+ },
+ {
+ "id": "c3tvge",
+ "key": "target_lang",
+ "label": "目标语言",
+ "type": "select",
+ "required": true,
+ "maxLen": 50,
+ "enums": [
+ {
+ "value": "简体中文"
+ },
+ {
+ "value": "繁體中文"
+ },
+ {
+ "value": "English"
+ },
+ {
+ "value": "Español"
+ },
+ {
+ "value": "Français"
+ },
+ {
+ "value": "Deutsch"
+ },
+ {
+ "value": "Italiano"
+ },
+ {
+ "value": "日本語"
+ },
+ {
+ "value": "한국어"
+ },
+ {
+ "value": "Русский"
+ },
+ {
+ "value": "العربية"
+ },
+ {
+ "value": "Bahasa Indonesia"
+ },
+ {
+ "value": "Polski"
+ }
+ ],
+ "icon": "core/app/variable/select"
+ }
+ ],
+ "scheduledTriggerConfig": {
+ "cronString": "",
+ "timezone": "Asia/Shanghai",
+ "defaultPrompt": ""
+ },
+ "_id": "6688b45317c65410d61d58aa"
+ }
+}
+
FastGPT 接入钉钉机器人教程
从 4.8.16 版本起,FastGPT 商业版支持直接接入钉钉机器人,无需额外的 API。
在 FastGPT 中选择要接入的应用,在发布渠道页面,新建一个接入钉钉机器人的发布渠道。
将前面拿到的 Client ID 和 Client Secret 填入配置弹窗中。
创建完成后,点击请求地址按钮,然后复制回调地址。
在钉钉开发者后台,点击左侧添加应用能力,为刚刚创建的企业内部应用添加 机器人 应用能力。
点击左侧机器人 应用能力,然后将底部消息接受模式设置为HTTP模式,消息接收地址填入前面复制的 FastGPT 的回调地址。
调试完成后,点击发布。
机器人发布后,还需要在版本管理与发布页面发布应用版本。
点击创建新版本后,设置版本号和版本描述后点击保存发布即可。
应用发布后,即可在钉钉企业中使用机器人功能,可对机器人私聊。或者在群组添加机器人后@机器人
,触发对话。
FastGPT 接入飞书机器人教程
从 4.8.10 版本起,FastGPT 商业版支持直接接入飞书机器人,无需额外的 API。
开一个免费的测试企业更方便进行调试。
添加一个机器人应用。
在fastgpt中选择想要接入的应用,在 发布渠道 页面,新建一个接入飞书机器人的发布渠道,填写好基础信息。
在飞书开放平台开发者后台,刚刚创建的企业自建应用中,找到 App ID 和 App Secret,填入 FastGPT 新建发布渠道的对话框里面。
填入两个参数到 FastGPT 配置弹窗中。
(可选)在飞书开放平台开发者后台,点击事件与回调 -> 加密策略 获取 Encrypt Key,并填入飞书机器人接入的对话框里面
Encrypt Key 用于加密飞书服务器与 FastGPT 之间通信。 +建议如果使用 Https 协议,则不需要 Encrypt Key。如果使用 Http 协议通信,则建议使用 Encrypt Key +Verification Token 默认生成的这个 Token 用于校验来源。但我们使用飞书官方推荐的另一种更为安全的校验方式,因此可以忽略这个配置项。
新建好发布渠道后,点击请求地址,复制对应的请求地址。
在飞书控制台,点击左侧的 事件与回调
,点击配置订阅方式
旁边的编辑 icon,粘贴刚刚复制的请求地址到输入框中。
接收消息
事件在事件与回调
页面,点击添加事件
。
搜索接收消息
,或者直接搜索 im.message.receive_v1
,找到接收消息 v2.0
的时间,勾选上并点击确认添加
。
添加事件后,增加两个权限:点击对应权限,会有弹窗提示添加权限,添加上图两个权限。
不推荐启用上图中的两个“历史版本”,而是使用新版本的权限。
在飞书控制台,点击左侧的 权限管理
,搜索框中输入发消息
,找到以应用的身份发消息
的权限,点击开通权限。
点击飞书控制台左侧的版本管理与发布
,即可发布机器人。
然后就可以在工作台里找到你的机器人啦。接下来就是把机器人拉进群组,或者单独与它对话。
外部应用通过多种方式调用 FastGPT 功能的教程
FastGPT 接入微信公众号教程
从 4.8.10 版本起,FastGPT 商业版支持直接接入微信公众号,无需额外的 API。
注意⚠️: 目前只支持通过验证的公众号(服务号和订阅号都可以)
在 FastGPT 中选择想要接入的应用,在 发布渠道 页面,新建一个接入微信公众号的发布渠道,填写好基础信息。
打开微信公众号官网:https://mp.weixin.qq.com
只支持通过验证的公众号,未通过验证的公众号暂不支持。
开发者可以从这个链接申请微信公众号的测试号进行测试,测试号可以正常使用,但不能配置 AES Key
私有部署的用户可自行查阅自己的 IP 地址。
海外版用户(cloud.tryfastgpt.ai)可以填写下面的 IP 白名单:
+ 35.240.227.100
+34.124.237.188
+34.143.240.160
+34.87.51.146
+34.87.79.202
+35.247.163.68
+34.87.102.86
+35.198.192.104
+34.126.163.205
+34.124.189.116
+34.143.149.171
+34.87.173.252
+34.142.157.52
+34.87.180.104
+34.87.20.189
+34.87.110.152
+34.87.44.74
+34.87.152.33
+35.197.149.75
+35.247.161.35
+
国内版用户(fastgpt.cn)可以填写下面的 IP 白名单:
+ 47.97.1.240
+121.43.105.217
+121.41.178.7
+121.40.65.187
+47.97.59.172
+101.37.205.32
+120.55.195.90
+120.26.229.115
+120.55.193.112
+47.98.190.173
+112.124.41.79
+121.196.235.183
+121.41.75.88
+121.43.108.48
+112.124.12.6
+121.43.52.222
+121.199.162.43
+121.199.162.102
+120.55.94.163
+47.99.59.223
+112.124.46.5
+121.40.46.247
+
随机生成AESKey,填入 FastGPT 配置弹窗中。
选择加密方式为安全模式。
现在用户向公众号发消息,消息则会被转发到 FastGPT,通过公众号返回对话结果。
FastGPT 对接 chatgpt-on-wechat
由于 FastGPT 的 API 接口和 OpenAI 的规范一致,可以无需变更原来的应用即可使用 FastGPT 上编排好的应用。API 使用可参考 这篇文章。编排示例,可参考 高级编排介绍
依次选择应用 -> 「API访问」,然后点击「API 密钥」来创建密钥。
密钥需要自己保管好,一旦关闭就无法再复制密钥,只能创建新密钥再复制。
只需要修改 OPEN_AI_API_KEY
和 OPEN_AI_API_BASE
两个环境变量即可。其中 OPEN_AI_API_KEY
为第一步获取的密钥,OPEN_AI_API_BASE
为 FastGPT 的 OpenAPI 地址,例如:https://api.fastgpt.in/api/v1
。
随便找一个目录,创建一个 docker-compose.yml 文件,将下面的代码复制进去。
+ version: '2.0'
+services:
+ chatgpt-on-wechat:
+ image: zhayujie/chatgpt-on-wechat
+ container_name: chatgpt-on-wechat
+ security_opt:
+ - seccomp:unconfined
+ environment:
+ OPEN_AI_API_KEY: 'fastgpt-z51pkjqm9nrk03a1rx2funoy'
+ OPEN_AI_API_BASE: 'https://api.fastgpt.in/api/v1'
+ MODEL: 'gpt-3.5-turbo'
+ CHANNEL_TYPE: 'wx'
+ PROXY: ''
+ HOT_RELOAD: 'False'
+ SINGLE_CHAT_PREFIX: '["bot", "@bot"]'
+ SINGLE_CHAT_REPLY_PREFIX: '"[bot] "'
+ GROUP_CHAT_PREFIX: '["@bot"]'
+ GROUP_NAME_WHITE_LIST: '["ChatGPT测试群", "ChatGPT测试群2"]'
+ IMAGE_CREATE_PREFIX: '["画", "看", "找"]'
+ CONVERSATION_MAX_TOKENS: 1000
+ SPEECH_RECOGNITION: 'False'
+ CHARACTER_DESC: '你是ChatGPT, 一个由OpenAI训练的大型语言模型, 你旨在回答并解决人们的任何问题,并且可以使用多种语言与人交流。'
+ SUBSCRIBE_MSG: '感谢您的关注!\n这里是ChatGPT,可以自由对话。\n支持语音对话。\n支持图片输入。\n支持图片输出,画字开头的消息将按要求创作图片。\n支持tool、角色扮演和文字冒险等丰富的插件。\n输入{trigger_prefix}#help 查看详细指令。'
+ EXPIRES_IN_SECONDS: 3600
+ USE_GLOBAL_PLUGIN_CONFIG: 'True'
+ USE_LINKAI: 'False'
+ LINKAI_API_KEY: ''
+ LINKAI_APP_CODE: ''
+
+ docker-compose pull
+docker-compose up -d
+
通过 API 访问 FastGPT 应用
在 FastGPT 中,你可以为每一个应用创建多个 API 密钥,用于访问应用的 API 接口。每个密钥仅能访问一个应用。完整的接口可以查看应用对话接口。
依次选择应用 -> 「API访问」,然后点击「API 密钥」来创建密钥。
密钥需要自己保管好,一旦关闭就无法再复制密钥,只能创建新密钥再复制。
Tips: 安全起见,你可以设置一个额度或者过期时间,放置 key 被滥用。
+ OPENAI_API_BASE_URL: https://api.fastgpt.in/api (改成自己部署的域名)
+OPENAI_API_KEY = 上一步获取到的密钥
+
ChatGPT Next Web 示例:
ChatGPT Web 示例:
FastGPT 接入微信和企业微信
私人微信和企业微信接入的方式基本一样,不同的地方会刻意指出。
查看视频教程
首先找到我们需要接入的应用,然后点击「外部使用」->「API访问」创建一个APIKey并保存。
打开微秘书 注册登录后找到菜单栏「基础配置」->「智能配置」,按照下图配置。
继续往下看到 apikey
和服务器根地址
,这里apikey
填写我们在 FastGPT 应用外部访问中创建的 APIkey,服务器根地址填写官方地址或者私有化部署的地址,这里用官方地址示例,注意要添加/v1
后缀,填写完毕后保存。
访问sealos 登录进来之后打开「应用管理」-> 「新建应用」。
往下翻页找到「高级配置」-> 「编辑环境变量」
这里需要填写三个环境变量:
+ AIBOTK_KEY=微秘书 APIKEY
+AIBOTK_SECRET=微秘书 APISECRET
+WORK_PRO_TOKEN=你申请的企微 token (企业微信需要填写,私人微信不需要)
+
这里最后的企业微信 Token 在微秘书的->会员开通栏目中自行购买。
这里环境变量我们介绍下如何填写:
AIBOTK_KEY
和 AIBOTK_SECRET
我们需要回到微秘书找到「个人中心」,这里的 APIKEY 对应 AIBOTK_KEY ,APISECRET 对应 AIBOTK_SECRET
。
WORK_PRO_TOKEN
微秘书的会员中心中自行购买即可。
填写完毕后点右上角「部署」,等待应用状态变为运行中。
返回微秘书 找到「首页」,扫码登录需要接入的微信号。
只需要发送信息,或者拉入群聊@登录的微信就会回复信息啦。 +
有关 FastGPT 其他实践案例的更多信息
Lotus Docs is a highly configurable Hugo documentation theme. Yet, with the default configuration you can deploy and publish your documentation site in a matter of minutes. Check out some core features below.
4 x 100’s score on Google Lighthouse by default. Lotus Docs removes unused CSS, prefetches asset links, and lazy loads content images.
Data is automatically structured to be SEO friendly. Includes Meta tags, Opengraph, and Twitter cards. Choose the settings that best suit you.
Lotus Docs’ default configuration scores A+ on Mozilla Observatory. You can update the default Security Headers to suit your requirements.
Many Lotus Docs features are configurable via optional parameters. Require DocSearch for your site? Then enable it via a single setting.
Deploy to Vercel in seconds. Vercel Functions, Vercel Redirects/Rewrites, and Vercel Headers are all configurable for an enriched experience.
Prefer not to be blasted by the sun while reading? Switch to a low-light UI with the click of a button. Modify colour variables to match your branding.
Search your docs with DocSearch. A powerful, efficient and accessible search solution built on Algolia Crawler & Autocomplete. TBC.
Lotus Docs supports Hugo’s Multilingual Mode. Create documentation in multiple languages side by side with i18n support.
Built on Bootstrap 5, Lotus Docs allows for a familiar, flexible, and intuitive developer experience. Easily customise your site via SCSS variables and files.
Much of Lotus Docs’ appearance can be customised. Dark mode is optional (enabled by default) and you can choose a Google font that suites you via the config parameters.