docs
@@ -1,92 +0,0 @@
|
||||
# Docker 部署 FastGpt
|
||||
|
||||
## 代理环境(国外服务器可忽略)
|
||||
|
||||
选择一个即可。这只是代理!!!不是项目。
|
||||
|
||||
1. [sealos nginx 方案](./proxy/sealos.md) - 推荐。约等于不用钱,不需要额外准备任何东西。
|
||||
2. [clash 方案](./proxy/clash.md) - 仅需一台服务器(需要有 clash)
|
||||
3. [nginx 方案](./proxy/nginx.md) - 需要一台国外服务器
|
||||
4. [cloudflare 方案](./proxy/cloudflare.md) - 需要有域名(每日免费 10w 次代理请求)
|
||||
5. [腾讯云函数代理方案](https://github.com/easychen/openai-api-proxy/blob/master/FUNC.md) - 仅需一台服务器
|
||||
|
||||
## openai key 池管理方案
|
||||
|
||||
推荐使用 [one-api](https://github.com/songquanpeng/one-api) 项目来管理 key 池,兼容 openai 和微软等多渠道。部署可以看该项目的 README.md,也可以看 [在 Sealos 1 分钟部署 one-api](./one-api/sealos.md)
|
||||
|
||||
### 1. 准备一些内容
|
||||
|
||||
> 1. 服务器开通 80 端口。用代理的话,对应的代理端口也需要打开。
|
||||
> 2. QQ 邮箱 Code:进入 QQ 邮箱 -> 账号 -> 申请 SMTP 账号
|
||||
> 3. 有域名的准备好 SSL 证书
|
||||
|
||||
### 2. 安装 docker 和 docker-compose
|
||||
|
||||
这个不同系统略有区别,百度安装下。验证安装成功后进行下一步。下面给出一个例子:
|
||||
|
||||
```bash
|
||||
# 安装docker
|
||||
curl -L https://get.daocloud.io/docker | sh
|
||||
sudo systemctl start docker
|
||||
# 安装 docker-compose
|
||||
curl -L https://github.com/docker/compose/releases/download/1.23.2/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
|
||||
sudo chmod +x /usr/local/bin/docker-compose
|
||||
# 验证安装
|
||||
docker -v
|
||||
docker-compose -v
|
||||
# 如果docker-compose运行不了,可以把 deploy/fastgpt/docker-compose 文件复制到服务器,然后在 docker-compose 文件夹里执行 sh init.sh。会把docker-compose文件复制到对应目录。
|
||||
```
|
||||
|
||||
### 2. 创建 3 个初始化文件
|
||||
|
||||
fastgpt 文件夹。分别为:fastgpt/docker-compose.yaml, fastgpt/pg/init.sql, fastgpt/nginx/nginx.conf
|
||||
|
||||
手动创建或者直接把 fastgpt 文件夹复制过去。
|
||||
|
||||
### 3. 运行 docker-compose
|
||||
|
||||
下面是一个辅助脚本,也可以直接 docker-compose up -d
|
||||
|
||||
**run.sh 运行文件**
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
docker-compose pull
|
||||
docker-compose up -d
|
||||
|
||||
echo "Docker Compose 重新拉取镜像完成!"
|
||||
|
||||
# 删除本地旧镜像
|
||||
images=$(docker images --format "{{.ID}} {{.Repository}}" | grep fastgpt)
|
||||
|
||||
# 将镜像 ID 和名称放入数组中
|
||||
IFS=$'\n' read -rd '' -a image_array <<<"$images"
|
||||
|
||||
# 遍历数组并删除所有旧的镜像
|
||||
for ((i=1; i<${#image_array[@]}; i++))
|
||||
do
|
||||
image=${image_array[$i]}
|
||||
image_id=${image%% *}
|
||||
docker rmi $image_id
|
||||
done
|
||||
```
|
||||
|
||||
## FastGpt Admin
|
||||
|
||||
参考 admin 里的 README.md
|
||||
|
||||
## 其他优化点
|
||||
|
||||
# Git Action 自动打包镜像
|
||||
|
||||
.github 里拥有一个 git 提交到 main 分支时自动打包 amd64 和 arm64 镜像的 actions。你仅需要提前在 git 配置好 session。
|
||||
|
||||
1. 创建账号 session: 头像 -> settings -> 最底部 Developer settings -> Personal access tokens -> tokens(classic) -> 创建新 session,把一些看起来需要的权限勾上。
|
||||
2. 添加 session 到仓库: 仓库 -> settings -> Secrets and variables -> Actions -> 创建 secret
|
||||
3. 填写 secret: Name-GH_PAT, Secret-第一步的 tokens
|
||||
|
||||
## 其他问题
|
||||
|
||||
### Mac 可能的问题
|
||||
|
||||
> 因为教程有部分镜像不兼容 arm64,所以写个文档指导新手如何快速在 mac 上面搭建 fast-gpt[在 mac 上面部署 fastgpt 可能存在的问题](./mac.md)
|
@@ -1,22 +0,0 @@
|
||||
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: [香港V02×1.5,ABC, 印度01, 台湾03, 新加坡02, 新加坡03, 日本01, 日本02, 新加坡01, 美国01, 美国02, 台湾01, 台湾02], url: 'https://api.openai.com', interval: 3600}
|
||||
rules:
|
||||
- 'DOMAIN-SUFFIX,google.com,♻️ 自动选择'
|
||||
- 'DOMAIN-SUFFIX,ai.fastgpt.run,♻️ 自动选择'
|
||||
- 'DOMAIN-SUFFIX,openai.com,♻️ 自动选择'
|
||||
- 'DOMAIN-SUFFIX,api.openai.com,♻️ 自动选择'
|
||||
- 'MATCH,DIRECT'
|
@@ -1,18 +0,0 @@
|
||||
export ALL_PROXY=socks5://127.0.0.1:7891
|
||||
export http_proxy=http://127.0.0.1:7890
|
||||
export https_proxy=http://127.0.0.1:7890
|
||||
export HTTP_PROXY=http://127.0.0.1:7890
|
||||
export HTTPS_PROXY=http://127.0.0.1:7890
|
||||
|
||||
OLD_PROCESS=$(pgrep clash)
|
||||
if [ ! -z "$OLD_PROCESS" ]; then
|
||||
echo "Killing old process: $OLD_PROCESS"
|
||||
kill $OLD_PROCESS
|
||||
fi
|
||||
sleep 2
|
||||
|
||||
cd /root/fastgpt/clash/fast
|
||||
rm -f ./nohup.out || true
|
||||
rm -f ./cache.db || true
|
||||
nohup ./clash-linux-amd64-v3 -d ./ &
|
||||
echo "Restart clash fast"
|
@@ -1,10 +0,0 @@
|
||||
export ALL_PROXY=''
|
||||
export http_proxy=''
|
||||
export https_proxy=''
|
||||
export HTTP_PROXY=''
|
||||
export HTTPS_PROXY=''
|
||||
OLD_PROCESS=$(pgrep clash)
|
||||
if [ ! -z "$OLD_PROCESS" ]; then
|
||||
echo "Killing old process: $OLD_PROCESS"
|
||||
kill $OLD_PROCESS
|
||||
fi
|
@@ -1,256 +0,0 @@
|
||||
# 非 host 版本, 不使用本机代理
|
||||
version: '3.3'
|
||||
services:
|
||||
pg:
|
||||
# image: ankane/pgvector:v0.4.2 # dockerhub
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/pgvector:v0.4.2 # 阿里云
|
||||
container_name: pg
|
||||
restart: always
|
||||
ports: # 生产环境建议不要暴露
|
||||
- 8100:5432
|
||||
networks:
|
||||
- fastgpt
|
||||
environment:
|
||||
# 这里的配置只有首次运行生效。修改后,重启镜像是不会生效的。需要把持久化数据删除再重启,才有效果
|
||||
- POSTGRES_USER=fastgpt
|
||||
- POSTGRES_PASSWORD=1234
|
||||
- POSTGRES_DB=fastgpt
|
||||
volumes:
|
||||
# 刚创建的文件
|
||||
- ./pg/init.sql:/docker-entrypoint-initdb.d/init.sh
|
||||
- ./pg/data:/var/lib/postgresql/data
|
||||
mongo:
|
||||
# image: mongo:5.0.18
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/mongo:5.0.18 # 阿里云
|
||||
container_name: mongo
|
||||
restart: always
|
||||
ports: # 生产环境建议不要暴露
|
||||
- 27017:27017
|
||||
networks:
|
||||
- fastgpt
|
||||
environment:
|
||||
# 这里的配置只有首次运行生效。修改后,重启镜像是不会生效的。需要把持久化数据删除再重启,才有效果
|
||||
- MONGO_INITDB_ROOT_USERNAME=username
|
||||
- MONGO_INITDB_ROOT_PASSWORD=password
|
||||
volumes:
|
||||
- ./mongo/data:/data/db
|
||||
- ./mongo/logs:/var/log/mongodb
|
||||
fastgpt:
|
||||
container_name: fastgpt
|
||||
# image: c121914yu/fast-gpt:latest # docker hub
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:latest # 阿里云
|
||||
# network_mode: host #
|
||||
ports:
|
||||
- 3000:3000
|
||||
networks:
|
||||
- fastgpt
|
||||
depends_on:
|
||||
- mongo
|
||||
- pg
|
||||
restart: always
|
||||
environment: # 可选的变量,不需要的话需要去掉
|
||||
- PORT=3000 # 运行的端口地址,如果不是 3000,需要修改成实际地址。
|
||||
- DB_MAX_LINK=5 # database max link
|
||||
# proxy(可选)
|
||||
- AXIOS_PROXY_HOST=127.0.0.1
|
||||
- AXIOS_PROXY_PORT=7890
|
||||
# 发送邮箱验证码配置。用的是QQ邮箱。参考 nodeMail 获取MAILE_CODE,自行百度。
|
||||
- MY_MAIL=54545@qq.com
|
||||
- MAILE_CODE=1234
|
||||
# 阿里短信服务(邮箱和短信至少二选一)
|
||||
- aliAccessKeyId=xxxx
|
||||
- aliAccessKeySecret=xxxx
|
||||
- aliSignName=xxxxx
|
||||
- aliTemplateCode=SMS_xxxx
|
||||
# google V3 安全校验(可选)
|
||||
- CLIENT_GOOGLE_VER_TOKEN=xxx
|
||||
- SERVICE_GOOGLE_VER_TOKEN=xx
|
||||
# token加密凭证(随便填,作为登录凭证)
|
||||
- TOKEN_KEY=any
|
||||
# root key, 最高权限,可以内部接口互相调用
|
||||
- ROOT_KEY=root_key
|
||||
# 和上方mongo镜像的username,password对应
|
||||
- MONGODB_URI=mongodb://username:password@mongo:27017/?authSource=admin
|
||||
- MONGODB_NAME=fastgpt
|
||||
- PG_HOST=pg
|
||||
- PG_PORT=5432
|
||||
# 和上方PG镜像对应.
|
||||
- PG_USER=fastgpt
|
||||
- PG_PASSWORD=1234
|
||||
- PG_DB_NAME=fastgpt
|
||||
# oneapi 配置 推荐使用 one-api 管理key
|
||||
- ONEAPI_URL=https://xxxxx.cloud.sealos.io/v1
|
||||
- ONEAPI_KEY=sk-xxxxxx
|
||||
# openai 相关配置:使用了 oneapi 后,下面只需要填下 OPENAI_BASE_URL (国外可全忽略)
|
||||
- OPENAIKEY=sk-xxxxx
|
||||
- OPENAI_BASE_URL=https://api.openai.com/v1
|
||||
- OPENAI_BASE_URL_AUTH=可选的安全凭证,会放到 header.auth 里
|
||||
fastgpt-admin:
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-admin:latest
|
||||
container_name: fastgpt-admin
|
||||
restart: always
|
||||
ports:
|
||||
- 3001:3001
|
||||
networks:
|
||||
- fastgpt
|
||||
depends_on:
|
||||
- mongo
|
||||
- fastgpt
|
||||
environment:
|
||||
- MONGODB_URI=mongodb://username:password@mongo:27017/?authSource=admin
|
||||
- MONGODB_NAME=fastgpt
|
||||
- ADMIN_USER=username
|
||||
- ADMIN_PASS=password
|
||||
- ADMIN_SECRET=any
|
||||
- PARENT_URL=http://fastgpt:3000
|
||||
- PARENT_ROOT_KEY=root_key
|
||||
keyadmin:
|
||||
container_name: keyadmin
|
||||
image: justsong/one-api
|
||||
restart: always
|
||||
ports:
|
||||
- 3002:3000
|
||||
environment:
|
||||
- TZ=Asia/Shanghai
|
||||
volumes:
|
||||
- /keyadmin:/data
|
||||
nginx: # 宝塔不需要额外装 nginx
|
||||
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/nginx:alpine3.17
|
||||
# image: nginx:alpine3.17
|
||||
container_name: nginx
|
||||
restart: always
|
||||
network_mode: host
|
||||
volumes:
|
||||
# 刚创建的文件
|
||||
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
|
||||
- ./nginx/logs:/var/log/nginx
|
||||
# https证书,没有的话不填,对应的nginx.conf也要修改
|
||||
- ./nginx/ssl/docgpt.key:/ssl/docgpt.key
|
||||
- ./nginx/ssl/docgpt.pem:/ssl/docgpt.pem
|
||||
networks:
|
||||
fastgpt:
|
||||
# host 版本, 不推荐,推荐直接用上面的,用个 BASE_URL 中转
|
||||
# version: '3.3'
|
||||
# services:
|
||||
# pg:
|
||||
# # image: ankane/pgvector:v0.4.2 # dockerhub
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/pgvector:v0.4.2 # 阿里云
|
||||
# container_name: pg
|
||||
# restart: always
|
||||
# ports: # 生产环境建议不要暴露
|
||||
# - 8100:5432
|
||||
# networks:
|
||||
# - fastgpt
|
||||
# environment:
|
||||
# # 这里的配置只有首次运行生效。修改后,重启镜像是不会生效的。需要把持久化数据删除再重启,才有效果
|
||||
# - POSTGRES_USER=fastgpt
|
||||
# - POSTGRES_PASSWORD=1234
|
||||
# - POSTGRES_DB=fastgpt
|
||||
# volumes:
|
||||
# # 刚创建的文件
|
||||
# - ./pg/init.sql:/docker-entrypoint-initdb.d/init.sh
|
||||
# - ./pg/data:/var/lib/postgresql/data
|
||||
# mongo:
|
||||
# # image: mongo:5.0.18
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/mongo:5.0.18 # 阿里云
|
||||
# container_name: mongo
|
||||
# restart: always
|
||||
# ports: # 生产环境建议不要暴露
|
||||
# - 27017:27017
|
||||
# networks:
|
||||
# - fastgpt
|
||||
# environment:
|
||||
# # 这里的配置只有首次运行生效。修改后,重启镜像是不会生效的。需要把持久化数据删除再重启,才有效果
|
||||
# - MONGO_INITDB_ROOT_USERNAME=username
|
||||
# - MONGO_INITDB_ROOT_PASSWORD=password
|
||||
# volumes:
|
||||
# - ./mongo/data:/data/db
|
||||
# - ./mongo/logs:/var/log/mongodb
|
||||
# fastgpt:
|
||||
# # image: ghcr.io/c121914yu/fastgpt:latest # github
|
||||
# # image: c121914yu/fast-gpt:latest # docker hub
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:latest # 阿里云
|
||||
# network_mode: host
|
||||
# restart: always
|
||||
# container_name: fastgpt
|
||||
# environment: # 可选的变量,不需要的话需要去掉
|
||||
# - PORT=3000 # 运行的端口地址,如果不是 3000,需要修改成实际地址。
|
||||
# - DB_MAX_LINK=15 # database max link
|
||||
# # proxy(可选)
|
||||
# - AXIOS_PROXY_HOST=127.0.0.1
|
||||
# - AXIOS_PROXY_PORT=7890
|
||||
# # 发送邮箱验证码配置。用的是QQ邮箱。参考 nodeMail 获取MAILE_CODE,自行百度。
|
||||
# - MY_MAIL=54545@qq.com
|
||||
# - MAILE_CODE=1234
|
||||
# # 阿里短信服务(邮箱和短信至少二选一)
|
||||
# - aliAccessKeyId=xxxx
|
||||
# - aliAccessKeySecret=xxxx
|
||||
# - aliSignName=xxxxx
|
||||
# - aliTemplateCode=SMS_xxxx
|
||||
# # google V3 安全校验(可选)
|
||||
# - CLIENT_GOOGLE_VER_TOKEN=xxx
|
||||
# - SERVICE_GOOGLE_VER_TOKEN=xx
|
||||
# # token加密凭证(随便填,作为登录凭证)
|
||||
# - TOKEN_KEY=xxxx
|
||||
# # root key, 最高权限,可以内部接口互相调用
|
||||
# - ROOT_KEY=xxx
|
||||
# # 和上方mongo镜像的username,password对应
|
||||
# - MONGODB_URI=mongodb://username:password@0.0.0.0:27017/?authSource=admin
|
||||
# - MONGODB_NAME=fastgpt
|
||||
# - PG_HOST=0.0.0.0
|
||||
# - PG_PORT=8100
|
||||
# # 和上方PG镜像对应.
|
||||
# - PG_USER=fastgpt
|
||||
# - PG_PASSWORD=1234
|
||||
# - PG_DB_NAME=fastgpt
|
||||
# # oneapi 配置 推荐使用 one-api 管理key
|
||||
# - ONEAPI_URL=https://xxxxx.cloud.sealos.io/v1
|
||||
# - ONEAPI_KEY=sk-xxxxx
|
||||
# # openai 相关配置:使用了 oneapi 后,下面只需要填下 OPENAI_BASE_URL (国外可全忽略)
|
||||
# - OPENAIKEY=sk-xxxxx
|
||||
# - OPENAI_BASE_URL=https://api.openai.com/v1
|
||||
# - OPENAI_BASE_URL_AUTH=可选的安全凭证,会放到 header.auth 里
|
||||
# fastgpt-admin:
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-admin:latest
|
||||
# container_name: fastgpt-admin
|
||||
# restart: always
|
||||
# ports:
|
||||
# - 3001:3001
|
||||
# networks:
|
||||
# - fastgpt
|
||||
# depends_on:
|
||||
# - mongo
|
||||
# - fastgpt
|
||||
# environment:
|
||||
# - MONGODB_URI=mongodb://username:password@mongo:27017/?authSource=admin
|
||||
# - MONGODB_NAME=fastgpt
|
||||
# - ADMIN_USER=username
|
||||
# - ADMIN_PASS=password
|
||||
# - ADMIN_SECRET=any
|
||||
# - PARENT_URL=http://fastgpt:3000
|
||||
# - PARENT_ROOT_KEY=root_key
|
||||
# key-admin:
|
||||
# container_name: key-admin
|
||||
# image: justsong/one-api
|
||||
# restart: always
|
||||
# ports:
|
||||
# - 3002:3000
|
||||
# environment:
|
||||
# - TZ=Asia/Shanghai
|
||||
# volumes:
|
||||
# - /home/ubuntu/data/one-api:/data
|
||||
# nginx: # 宝塔不需要额外装 nginx
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/nginx:alpine3.17
|
||||
# # image: nginx:alpine3.17
|
||||
# container_name: nginx
|
||||
# restart: always
|
||||
# network_mode: host
|
||||
# volumes:
|
||||
# # 刚创建的文件
|
||||
# - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
|
||||
# - ./nginx/logs:/var/log/nginx
|
||||
# # https证书,没有的话不填,对应的nginx.conf也要修改
|
||||
# - ./nginx/ssl/docgpt.key:/ssl/docgpt.key
|
||||
# - ./nginx/ssl/docgpt.pem:/ssl/docgpt.pem
|
||||
# networks:
|
||||
# fastgpt:
|
@@ -1,2 +0,0 @@
|
||||
cp ./docker-compose /usr/local/bin/docker-compose
|
||||
sudo chmod +x /usr/local/bin/docker-compose
|
@@ -1,69 +0,0 @@
|
||||
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;
|
||||
|
||||
gzip on;
|
||||
gzip_min_length 1k;
|
||||
gzip_buffers 4 8k;
|
||||
gzip_http_version 1.1;
|
||||
gzip_comp_level 6;
|
||||
gzip_vary on;
|
||||
gzip_types text/plain application/x-javascript text/css application/javascript application/json application/xml;
|
||||
gzip_disable "MSIE [1-6]\.";
|
||||
|
||||
open_file_cache max=1000 inactive=1d;
|
||||
open_file_cache_valid 30s;
|
||||
open_file_cache_min_uses 8;
|
||||
open_file_cache_errors off;
|
||||
|
||||
server {
|
||||
listen 443 ssl;
|
||||
server_name docgpt.ahapocket.cn;
|
||||
ssl_certificate /ssl/docgpt.pem;
|
||||
ssl_certificate_key /ssl/docgpt.key;
|
||||
ssl_session_timeout 5m;
|
||||
|
||||
location / {
|
||||
proxy_pass http://localhost:3000;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
}
|
||||
}
|
||||
server {
|
||||
listen 80;
|
||||
server_name docgpt.ahapocket.cn;
|
||||
rewrite ^(.*) https://$server_name$1 permanent;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 3000;
|
||||
server_name 120.0.0.0;
|
||||
|
||||
location / {
|
||||
proxy_pass http://localhost:3000;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,21 +0,0 @@
|
||||
set -e
|
||||
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL
|
||||
|
||||
CREATE EXTENSION IF NOT EXISTS vector;
|
||||
-- init table
|
||||
CREATE TABLE IF NOT EXISTS modeldata (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
vector VECTOR(1536) NOT NULL,
|
||||
user_id VARCHAR(50) NOT NULL,
|
||||
kb_id VARCHAR(50) NOT NULL,
|
||||
source VARCHAR(100),
|
||||
q TEXT NOT NULL,
|
||||
a TEXT NOT NULL
|
||||
);
|
||||
-- 索引设置,按需取
|
||||
-- CREATE INDEX IF NOT EXISTS modeldata_userId_index ON modeldata USING HASH (user_id);
|
||||
-- CREATE INDEX IF NOT EXISTS modeldata_kbId_index ON modeldata USING HASH (kb_id);
|
||||
-- CREATE INDEX IF NOT EXISTS idx_model_data_md5_q_a_user_id_kb_id ON modeldata (md5(q), md5(a), user_id, kb_id);
|
||||
-- CREATE INDEX modeldata_id_desc_idx ON modeldata (id DESC);
|
||||
-- vector 索引,可以参考 [pg vector](https://github.com/pgvector/pgvector) 去配置,根据数据量去配置
|
||||
EOSQL
|
@@ -1,19 +0,0 @@
|
||||
#!/bin/bash
|
||||
docker-compose pull
|
||||
docker-compose up -d
|
||||
|
||||
echo "Docker Compose 重新拉取镜像完成!"
|
||||
|
||||
# 删除本地旧镜像
|
||||
images=$(docker images --format "{{.ID}} {{.Repository}}" | grep fastgpt)
|
||||
|
||||
# 将镜像 ID 和名称放入数组中
|
||||
IFS=$'\n' read -rd '' -a image_array <<<"$images"
|
||||
|
||||
# 遍历数组并删除所有旧的镜像
|
||||
for ((i=1; i<${#image_array[@]}; i++))
|
||||
do
|
||||
image=${image_array[$i]}
|
||||
image_id=${image%% *}
|
||||
docker rmi $image_id
|
||||
done
|
@@ -1,101 +0,0 @@
|
||||
## Mac 上部署可能遇到的问题
|
||||
|
||||
### 前置条件
|
||||
|
||||
1、可以 curl api.openai.com
|
||||
|
||||
2、有 openai key
|
||||
|
||||
3、有邮箱 MAILE_CODE
|
||||
|
||||
4、有 docker
|
||||
|
||||
```
|
||||
docker -v
|
||||
```
|
||||
|
||||
5、有 pnpm ,可以使用`brew install pnpm`安装
|
||||
|
||||
6、需要创建一个放置 pg 和 mongo 数据的文件夹,这里创建在`~/fastgpt`目录中,里面有`pg` 和`mongo `两个文件夹
|
||||
|
||||
```
|
||||
➜ fastgpt pwd
|
||||
/Users/jie/fastgpt
|
||||
➜ fastgpt ls
|
||||
mongo pg
|
||||
```
|
||||
|
||||
### docker 部署方式
|
||||
|
||||
这种方式主要是为了方便调试,可以使用`pnpm dev ` 运行 fastgpt 项目
|
||||
|
||||
**1、.env.local 文件**
|
||||
|
||||
```
|
||||
# proxy
|
||||
AXIOS_PROXY_HOST=127.0.0.1
|
||||
AXIOS_PROXY_PORT_FAST=7890
|
||||
AXIOS_PROXY_PORT_NORMAL=7890
|
||||
# email
|
||||
MY_MAIL= {Your Mail}
|
||||
MAILE_CODE={Yoir Mail code}
|
||||
# ali ems
|
||||
aliAccessKeyId=xxx
|
||||
aliAccessKeySecret=xxx
|
||||
aliSignName=xxx
|
||||
aliTemplateCode=SMS_xxx
|
||||
# token
|
||||
TOKEN_KEY=sswada
|
||||
# 使用 oneapi
|
||||
ONEAPI_URL=[https://api.xyz.com/v1](https://xxxxx.cloud.sealos.io/v1)
|
||||
ONEAPI_KEY=sk-xxxxxx
|
||||
# openai
|
||||
OPENAIKEY=sk-xxx # 对话用的key
|
||||
OPENAI_TRAINING_KEY=sk-xxx # 训练用的key
|
||||
# db
|
||||
MONGODB_URI=mongodb://username:password@0.0.0.0:27017/test?authSource=admin
|
||||
PG_HOST=0.0.0.0
|
||||
PG_PORT=8100
|
||||
PG_USER=xxx
|
||||
PG_PASSWORD=xxx
|
||||
PG_DB_NAME=fastgpt
|
||||
```
|
||||
|
||||
**2、部署 mongo**
|
||||
|
||||
```
|
||||
docker run --name mongo -p 27017:27017 -e MONGO_INITDB_ROOT_USERNAME=username -e MONGO_INITDB_ROOT_PASSWORD=password -v ~/fastgpt/mongo/data:/data/db -d mongo:4.0.1
|
||||
```
|
||||
|
||||
**3、部署 pgsql**
|
||||
|
||||
```
|
||||
docker run -it --name pg -e "POSTGRES_DB=fastgpt" -e "POSTGRES_PASSWORD=xxx" -e POSTGRES_USER=xxx -p 8100:5432 -v ~/fastgpt/pg/data:/var/lib/postgresql/data -d octoberlan/pgvector:v0.4.1
|
||||
```
|
||||
|
||||
进 pgsql 容器运行
|
||||
|
||||
```
|
||||
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL
|
||||
|
||||
CREATE EXTENSION IF NOT EXISTS vector;
|
||||
-- init table
|
||||
CREATE TABLE IF NOT EXISTS modeldata (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
vector VECTOR(1536) NOT NULL,
|
||||
user_id VARCHAR(50) NOT NULL,
|
||||
kb_id VARCHAR(50) NOT NULL,
|
||||
source VARCHAR(100),
|
||||
q TEXT NOT NULL,
|
||||
a TEXT NOT NULL
|
||||
);
|
||||
-- 索引设置,按需取
|
||||
-- CREATE INDEX IF NOT EXISTS modeldata_userId_index ON modeldata USING HASH (user_id);
|
||||
-- CREATE INDEX IF NOT EXISTS modeldata_kbId_index ON modeldata USING HASH (kb_id);
|
||||
-- CREATE INDEX IF NOT EXISTS idx_model_data_md5_q_a_user_id_kb_id ON modeldata (md5(q), md5(a), user_id, kb_id);
|
||||
-- CREATE INDEX modeldata_id_desc_idx ON modeldata (id DESC);
|
||||
-- vector 索引,可以参考 [pg vector](https://github.com/pgvector/pgvector) 去配置,根据数据量去配置
|
||||
EOSQL
|
||||
```
|
||||
|
||||
4、**最后在 FASTGPT 项目里面运行 pnpm dev 运行项目,然后进入 localhost:3000 看项目是否跑起来了**
|
@@ -1,36 +0,0 @@
|
||||
# 在 Sealos 1 分钟部署 one-api
|
||||
|
||||
## 1. 进入 Sealos 公有云
|
||||
|
||||
https://cloud.sealos.io/
|
||||
|
||||
## 2. 打开 AppLaunchpad(应用管理) 工具
|
||||
|
||||

|
||||
|
||||
## 3. 点击创建新应用
|
||||
|
||||
## 4. 填写对应参数
|
||||
|
||||
镜像:ghcr.io/songquanpeng/one-api:latest
|
||||
|
||||

|
||||
打开外网访问开关后,Sealos 会自动分配一个可访问的地址,不需要自己配置。
|
||||
|
||||

|
||||
填写完参数后,点击右上角部署即可。
|
||||
|
||||
## 5. 访问
|
||||
|
||||
点击 Sealos 提供的外网访问地址,即可访问 one-api 项目。
|
||||

|
||||

|
||||
|
||||
## 6. 替换 FastGpt 的环境变量
|
||||
|
||||
```
|
||||
# 下面的地址是 Sealos 提供的,务必写上 v1
|
||||
ONEAPI_URL=https://xxxx.cloud.sealos.io/v1
|
||||
# 下面的 key 由 one-api 提供
|
||||
ONEAPI_KEY=sk-xxxxxx
|
||||
```
|
Before Width: | Height: | Size: 6.0 MiB |
Before Width: | Height: | Size: 208 KiB |
Before Width: | Height: | Size: 215 KiB |
Before Width: | Height: | Size: 247 KiB |
Before Width: | Height: | Size: 128 KiB |
@@ -1,68 +0,0 @@
|
||||
# 安装 clash
|
||||
|
||||
clash 会在本机启动代理。对应的,你需要配置项目的两个环境变量:
|
||||
|
||||
```
|
||||
AXIOS_PROXY_HOST=127.0.0.1
|
||||
AXIOS_PROXY_PORT=7890
|
||||
```
|
||||
|
||||
需要注的是,在你的 config.yaml 文件中,最好仅指定 api.openai.com 走代理,其他请求都直连。
|
||||
|
||||
**安装clash**
|
||||
```bash
|
||||
# 下载包
|
||||
curl https://glados.rocks/tools/clash-linux.zip -o clash.zip
|
||||
# 解压
|
||||
unzip clash.zip
|
||||
# 下载终端配置⽂件(改成自己配置文件路径)
|
||||
curl https://update.glados-config.com/clash/98980/8f30944/70870/glados-terminal.yaml > config.yaml
|
||||
# 赋予运行权限
|
||||
chmod +x ./clash-linux-amd64-v1.10.0
|
||||
```
|
||||
|
||||
**runClash.sh**
|
||||
```sh
|
||||
# 记得配置端口变量:
|
||||
export ALL_PROXY=socks5://127.0.0.1:7891
|
||||
export http_proxy=http://127.0.0.1:7890
|
||||
export https_proxy=http://127.0.0.1:7890
|
||||
export HTTP_PROXY=http://127.0.0.1:7890
|
||||
export HTTPS_PROXY=http://127.0.0.1:7890
|
||||
|
||||
# 运行脚本: 删除clash - 到 clash 目录 - 删除缓存 - 执行运行. 会生成一个 nohup.out 文件,可以看到 clash 的 logs
|
||||
OLD_PROCESS=$(pgrep clash)
|
||||
if [ ! -z "$OLD_PROCESS" ]; then
|
||||
echo "Killing old process: $OLD_PROCESS"
|
||||
kill $OLD_PROCESS
|
||||
fi
|
||||
sleep 2
|
||||
cd **/clash
|
||||
rm -f ./nohup.out || true
|
||||
rm -f ./cache.db || true
|
||||
nohup ./clash-linux-amd64-v1.10.0 -d ./ &
|
||||
echo "Restart clash"
|
||||
```
|
||||
|
||||
**config.yaml配置例子**
|
||||
```yaml
|
||||
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'
|
||||
```
|
@@ -1,46 +0,0 @@
|
||||
# cloudflare 代理配置
|
||||
|
||||
[来自 "不做了睡觉" 教程](https://gravel-twister-d32.notion.site/FastGPT-API-ba7bb261d5fd4fd9bbb2f0607dacdc9e)
|
||||
|
||||
**workers 配置文件**
|
||||
|
||||
```js
|
||||
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;
|
||||
}
|
||||
```
|
||||
|
||||
**对应的环境变量**
|
||||
务必别忘了填 v1
|
||||
|
||||
```
|
||||
OPENAI_BASE_URL=https://xxxxxx/v1
|
||||
OPENAI_BASE_URL_AUTH=auth_code
|
||||
```
|
Before Width: | Height: | Size: 2.9 MiB |
Before Width: | Height: | Size: 205 KiB |
Before Width: | Height: | Size: 152 KiB |
Before Width: | Height: | Size: 88 KiB |
Before Width: | Height: | Size: 224 KiB |
@@ -1,73 +0,0 @@
|
||||
# nginx 反向代理 openai 接口
|
||||
|
||||
如果你有国外的服务器,可以通过配置 nginx 反向代理,转发 openai 相关的请求,从而让国内的服务器可以通过访问该 nginx 去访问 openai 接口。
|
||||
|
||||
```conf
|
||||
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 32k;
|
||||
large_client_header_buffers 4 32k;
|
||||
client_max_body_size 50M;
|
||||
|
||||
gzip on;
|
||||
gzip_min_length 1k;
|
||||
gzip_buffers 4 8k;
|
||||
gzip_http_version 1.1;
|
||||
gzip_comp_level 6;
|
||||
gzip_vary on;
|
||||
gzip_types text/plain application/x-javascript text/css application/javascript application/json application/xml;
|
||||
gzip_disable "MSIE [1-6]\.";
|
||||
|
||||
open_file_cache max=1000 inactive=1d;
|
||||
open_file_cache_valid 30s;
|
||||
open_file_cache_min_uses 8;
|
||||
open_file_cache_errors off;
|
||||
|
||||
server {
|
||||
listen 443 ssl;
|
||||
server_name your_host;
|
||||
ssl_certificate /ssl/your_host.pem;
|
||||
ssl_certificate_key /ssl/your_host.key;
|
||||
ssl_session_timeout 5m;
|
||||
|
||||
location ~ /openai/(.*) {
|
||||
# auth check
|
||||
if ($auth != "xxxxxx") {
|
||||
return 403;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
server {
|
||||
listen 80;
|
||||
server_name ai.fastgpt.run;
|
||||
rewrite ^(.*) https://$server_name$1 permanent;
|
||||
}
|
||||
}
|
||||
```
|
@@ -1,100 +0,0 @@
|
||||
# sealos 部署 openai 中转
|
||||
|
||||
## 登录 sealos cloud
|
||||
|
||||
[sealos cloud](https://cloud.sealos.io/)
|
||||
|
||||
## 创建应用
|
||||
|
||||
打开 App Launchpad -> 新建应用
|
||||
|
||||

|
||||

|
||||
|
||||
### 开启外网访问
|
||||
|
||||

|
||||
|
||||
### 添加 configmap 文件
|
||||
|
||||
1. 复制下面这段代码,注意 `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/(.*) {
|
||||
# auth check
|
||||
if ($http_auth != "auth") { # 安全凭证
|
||||
return 403;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
2. 点开高级配置
|
||||
3. 点击新增 configmap
|
||||
4. 文件名写: `/etc/nginx/nginx.conf`
|
||||
5. 文件值为刚刚复制的那段代码
|
||||
6. 点击确认
|
||||
|
||||

|
||||
|
||||
### 部署应用
|
||||
|
||||
填写完毕后,点击右上角的 `部署应用`,即可完成。
|
||||
|
||||
## 修改 FastGpt 环境变量
|
||||
|
||||
1. 进入刚刚部署应用的详情,复制外网地址
|
||||

|
||||
|
||||
2. 修改环境变量(是 FastGpt 的环境变量,不是 sealos 的):
|
||||
|
||||
```
|
||||
OPENAI_BASE_URL=https://tgohwtdlrmer.cloud.sealos.io/openai/v1
|
||||
OPENAI_BASE_URL_AUTH=auth
|
||||
```
|
||||
|
||||
**Done!**
|
@@ -1,23 +0,0 @@
|
||||
# FastGpt 本地开发
|
||||
|
||||
第一次开发,请先[部署教程](../deploy/docker.md),需要部署数据库.
|
||||
|
||||
client: FastGpt 网页项目
|
||||
admin: 管理端
|
||||
|
||||
## 环境变量配置 (可能更新不及时,以 docker-compose 里的变量为准)
|
||||
|
||||
复制.env.template 文件,生成一个.env.local 环境变量文件夹,修改.env.local 里内容。
|
||||
|
||||
## 运行
|
||||
|
||||
```
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
## 镜像打包
|
||||
|
||||
```bash
|
||||
# 代理可选,不需要的去掉
|
||||
docker build -t registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:latest . --network host --build-arg HTTP_PROXY=http://127.0.0.1:7890 --build-arg HTTPS_PROXY=http://127.0.0.1:7890
|
||||
```
|
Before Width: | Height: | Size: 240 KiB |
Before Width: | Height: | Size: 328 KiB |
Before Width: | Height: | Size: 294 KiB |
Before Width: | Height: | Size: 302 KiB |
Before Width: | Height: | Size: 150 KiB |
Before Width: | Height: | Size: 86 KiB |
Before Width: | Height: | Size: 101 KiB |
Before Width: | Height: | Size: 40 KiB |
Before Width: | Height: | Size: 77 KiB |
Before Width: | Height: | Size: 80 KiB |
Before Width: | Height: | Size: 101 KiB |
Before Width: | Height: | Size: 165 KiB |
Before Width: | Height: | Size: 335 KiB |
Before Width: | Height: | Size: 137 KiB |
Before Width: | Height: | Size: 115 KiB |
Before Width: | Height: | Size: 193 KiB |
Before Width: | Height: | Size: 307 KiB |
@@ -1,123 +0,0 @@
|
||||
# 利用 FastGpt 打造高质量 AI 知识库
|
||||
|
||||
## 前言
|
||||
|
||||
自从去年 12 月 chatgpt 发布后,带动了新的一轮应用交互革命。尤其是 gpt35 接口全面放开后,LLM 应用雨后春笋般快速涌现,但因为 gpt 的可控性、随机性和合规性等问题,很多应用场景都没法落地。
|
||||
3 月时候,在 twitter 上刷到一个老哥使用 gpt 训练自己的博客记录,并且成本非常低(比起 FT)。他给出了一个完整的流程图:
|
||||
|
||||

|
||||
|
||||
看到这个推文后,我灵机一动,应用场景就十分清晰了。直接上手开干,在经过不到 1 个月时间,FastGpt 在原来多助手管理基础上,加入了向量搜索。于是便有了最早的一期视频:https://www.bilibili.com/video/BV1Wo4y1p7i1/?vd_source=92041a1a395f852f9d89158eaa3f61b4
|
||||
|
||||
3 个月过去了,FastGpt 延续着早期的思路去完善和扩展,目前在向量搜索 + LLM 线性问答方面的功能基本上完成了。不过我们始终没有出一期关于如何构建知识库的教程,趁着 V4 在开发中,我们计划介绍一期《如何在 FastGpt 上构建高质量知识库》,以便大家更好的使用。
|
||||
|
||||
## FastGpt 知识库完整逻辑
|
||||
|
||||
在正式构建知识库前,我们先来了解下 FastGpt 是如何进行知识库检索的。首先了解几个基本概念:
|
||||
|
||||
1. 向量:将人类直观的语言(文字、图片、视频等)转成计算机可识别的语言(数组)。
|
||||
2. 向量相似度:两个向量之间可以进行计算,得到一个相似度,即代表:两个语言相似的程度。
|
||||
3. 语言大模型的一些特点:上下文理解、总结和推理。
|
||||
|
||||
结合上述 3 个概念,便有了 “向量搜索 + 大模型 = 知识库问答” 的公式。下图是 FastGpt V3 中知识库问答功能的完整逻辑:
|
||||
|
||||

|
||||
|
||||
与大部分其他知识库问答产品不一样的是, FastGpt 采用了 QA 问答对进行存储,而不是仅进行 chunk(文本分块)处理。目的是为了减少向量化内容的长度,让向量能更好的表达文本的含义,从而提高搜索精准度。
|
||||
此外 FastGpt 还提供了搜索测试和对话测试两种途径对数据进行调整,从而方便用户调整自己的数据。根据上述流程和方式,我们以构建一个 FastGpt 常见问题机器人为例,展示如何构建一个高质量的 AI 知识库。
|
||||
|
||||
## 构建知识库应用
|
||||
|
||||
首先,先创建一个 FastGpt 常见问题知识库
|
||||
|
||||

|
||||
|
||||
### 通过 QA 拆分,获取基础知识
|
||||
|
||||
我们先直接把 FastGpt Git 上一些已有文档,进行 QA 拆分,从而获取一些 FastGpt 基础的知识。下面是 README 例子。
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
### 修正 QA
|
||||
|
||||
通过 README 我们一共得到了 11 组数据,整体的质量还是不错的,图片和链接都提取出来了。不过最后一个知识点出现了一些截断,我们需要手动的修正一下。
|
||||
|
||||
此外,我们观察到第一列第三个知识点。这个知识点是介绍了 FastGpt 一些资源链接,但是 QA 拆分将答案放置在了 A 中,但通常来说用户的提问并不会直接问“有哪些链接”,通常会问:“部署教程”,“问题文档”之类的。因此,我们需要将这个知识点进行简单的一个处理,如下图:
|
||||
|
||||

|
||||
|
||||
我们先来创建一个应用,看看效果如何。 首先需要去创建一个应用,并且在知识库中关联相关的知识库。另外还需要在配置页的提示词中,告诉 GPT:“知识库的范围”。
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
整体的效果还是不错的,链接和对应的图片都可以顺利的展示。
|
||||
|
||||
### 录入社区常见问题
|
||||
|
||||
接着,我们再把 FastGPT 常见问题的文档导入,由于平时整理不当,我们只能手动的录入对应的问答。
|
||||
|
||||

|
||||
|
||||
导入结果如上图。可以看到,我们均采用的是问答对的格式,而不是粗略的直接导入。目的就是为了模拟用户问题,进一步的提高向量搜索的匹配效果。可以为同一个问题设置多种问法,效果更佳。
|
||||
FastGpt 还提供了 openapi 功能,你可以在本地对特殊格式的文件进行处理后,再上传到 FastGpt,具体可以参考:[FastGpt Api Docs](https://kjqvjse66l.feishu.cn/docx/DmLedTWtUoNGX8xui9ocdUEjnNh)
|
||||
|
||||
## 知识库微调和参数调整
|
||||
|
||||
FastGpt 提供了搜索测试和对话测试两种途径对知识库进行微调,我们先来使用搜索测试对知识库进行调整。我们建议你提前收集一些用户问题进行测试,根据预期效果进行跳转。可以先进行搜索测试调整,判断知识点是否合理。
|
||||
|
||||
### 搜索测试
|
||||
|
||||

|
||||
|
||||
你可能会遇到下面这种情况,由于“知识库”这个关键词导致一些无关内容的相似度也被搜索进去,此时就需要给第四条记录也增加一个“知识库”关键词,从而去提高它的相似度。
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
### 提示词设置
|
||||
|
||||
提示词的作用是引导模型对话的方向。在设置提示词时,遵守 2 个原则:
|
||||
|
||||
1. 告诉 Gpt 回答什么方面内容。
|
||||
2. 给知识库一个基本描述,从而让 Gpt 更好的判断用户的问题是否属于知识库范围。
|
||||
|
||||

|
||||
|
||||
### 更好的限定模型聊天范围
|
||||
|
||||
首先,你可以通过调整知识库搜索时的相似度和最大搜索数量,实现从知识库层面限制聊天范围。通常我们可以设置相似度为 0.82,并设置空搜索回复内容。这意味着,如果用户的问题无法在知识库中匹配时,会直接回复预设的内容。
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
由于 openai 向量模型并不是针对中文,所以当问题中有一些知识库内容的关键词时,相似度
|
||||
会较高,此时无法从知识库层面进行限定。需要通过限定词进行调整,例如:
|
||||
|
||||
> 我的问题如果不是关于 FastGpt 的,请直接回复:“我不确定”。你仅需要回答知识库中的内容,不在其中的内容,不需要回答。
|
||||
|
||||
效果如下:
|
||||
|
||||

|
||||
|
||||
当然,gpt35 在一定情况下依然是不可控的。
|
||||
|
||||
### 通过对话调整知识库
|
||||
|
||||
与搜索测试类似,你可以直接在对话页里,点击“引用”,来随时修改知识库内容。
|
||||
|
||||

|
||||
|
||||
## 总结
|
||||
|
||||
1. 向量搜索是一种可以比较文本相似度的技术。
|
||||
2. 大模型具有总结和推理能力,可以从给定的文本中回答问题。
|
||||
3. 最有效的知识库构建方式是 QA 和手动构建。
|
||||
4. Q 的长度不宜过长。
|
||||
5. 需要调整提示词,来引导模型回答知识库内容。
|
||||
6. 可以通过调整搜索相似度、最大搜索数量和限定词来控制模型回复的范围。
|
@@ -1,36 +0,0 @@
|
||||
# 3分钟在Fastgpt上用上GLM
|
||||
## 前言
|
||||
Fast GPT 允许你使用自己的 openai API KEY 来快速的调用 openai 接口,目前集成了 Gpt35, Gpt4 和 embedding. 可构建自己的知识库。但考虑到数据安全的问题,我们并不能将所有的数据都交付给云端大模型。那如何在fastgpt上接入私有化模型呢,本文就以清华的ChatGLM2为例,为各位讲解如何在fastgpt中接入私有化模型。
|
||||
## ChatGLM2简介
|
||||
ChatGLM2-6B 是开源中英双语对话模型 ChatGLM-6B 的第二代版本,具体介绍请看项目:https://github.com/THUDM/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
|
||||
## 环境配置
|
||||
Python 3.8.10
|
||||
CUDA 11.8
|
||||
科学上网环境
|
||||
## 简单的步骤
|
||||
1. 根据上面的环境配置配置好环境,具体教程自行GPT;
|
||||
1. 在命令行输入pip install -r requirments.txt
|
||||
2. 打开你需要启动的py文件,在代码的第76行配置token,这里的token只是加一层验证,防止接口被人盗用
|
||||
2. python openai_api.py 16//这里的数字根据上面的配置进行选择
|
||||
|
||||
然后等待模型下载,直到模型加载完毕,出现报错先问GPT
|
||||
上面两个文件在本文档的同目录
|
||||
|
||||
启动成功后应该会显示如下地址:
|
||||

|
||||
这里的http://0.0.0.0:6006就是连接地址
|
||||
|
||||
然后现在回到.env.local文件,依照以下方式配置地址:
|
||||
|
||||
OPENAI_BASE_URL=http://127.0.0.1:6006/v1
|
||||
OPENAIKEY=sk-aaabbbcccdddeeefffggghhhiiijjjkkk //这里是你在代码中配置的token
|
||||
这里的OPENAIKEY可以任意填写
|
||||
|
||||
这样就成功接入ChatGLM2了
|
Before Width: | Height: | Size: 100 KiB |
@@ -1,243 +0,0 @@
|
||||
# coding=utf-8
|
||||
import time
|
||||
import torch
|
||||
import uvicorn
|
||||
from pydantic import BaseModel, Field
|
||||
from fastapi import FastAPI, HTTPException
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from contextlib import asynccontextmanager
|
||||
from typing import List, Literal, Optional, Union
|
||||
from transformers import AutoTokenizer, AutoModel
|
||||
from sse_starlette.sse import EventSourceResponse
|
||||
from fastapi import Depends, HTTPException, Request
|
||||
from starlette.status import HTTP_401_UNAUTHORIZED
|
||||
import argparse
|
||||
import tiktoken
|
||||
import numpy as np
|
||||
from sentence_transformers import SentenceTransformer
|
||||
from sklearn.preprocessing import PolynomialFeatures
|
||||
|
||||
|
||||
@asynccontextmanager
|
||||
async def lifespan(app: FastAPI): # collects GPU memory
|
||||
yield
|
||||
if torch.cuda.is_available():
|
||||
torch.cuda.empty_cache()
|
||||
torch.cuda.ipc_collect()
|
||||
|
||||
|
||||
app = FastAPI(lifespan=lifespan)
|
||||
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=["*"],
|
||||
allow_credentials=True,
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
)
|
||||
|
||||
|
||||
class ChatMessage(BaseModel):
|
||||
role: Literal["user", "assistant", "system"]
|
||||
content: str
|
||||
|
||||
|
||||
class DeltaMessage(BaseModel):
|
||||
role: Optional[Literal["user", "assistant", "system"]] = None
|
||||
content: Optional[str] = None
|
||||
|
||||
|
||||
class ChatCompletionRequest(BaseModel):
|
||||
model: str
|
||||
messages: List[ChatMessage]
|
||||
temperature: Optional[float] = None
|
||||
top_p: Optional[float] = None
|
||||
max_length: Optional[int] = None
|
||||
stream: Optional[bool] = False
|
||||
|
||||
|
||||
class ChatCompletionResponseChoice(BaseModel):
|
||||
index: int
|
||||
message: ChatMessage
|
||||
finish_reason: Literal["stop", "length"]
|
||||
|
||||
|
||||
class ChatCompletionResponseStreamChoice(BaseModel):
|
||||
index: int
|
||||
delta: DeltaMessage
|
||||
finish_reason: Optional[Literal["stop", "length"]]
|
||||
|
||||
|
||||
class ChatCompletionResponse(BaseModel):
|
||||
model: str
|
||||
object: Literal["chat.completion", "chat.completion.chunk"]
|
||||
choices: List[Union[ChatCompletionResponseChoice, ChatCompletionResponseStreamChoice]]
|
||||
created: Optional[int] = Field(default_factory=lambda: int(time.time()))
|
||||
|
||||
async def verify_token(request: Request):
|
||||
auth_header = request.headers.get('Authorization')
|
||||
if auth_header:
|
||||
token_type, _, token = auth_header.partition(' ')
|
||||
if token_type.lower() == "bearer" and token == "sk-aaabbbcccdddeeefffggghhhiiijjjkkk": # 这里配置你的token
|
||||
return True
|
||||
raise HTTPException(
|
||||
status_code=HTTP_401_UNAUTHORIZED,
|
||||
detail="Invalid authorization credentials",
|
||||
)
|
||||
|
||||
class EmbeddingRequest(BaseModel):
|
||||
input: List[str]
|
||||
model: str
|
||||
|
||||
class EmbeddingResponse(BaseModel):
|
||||
data: list
|
||||
model: str
|
||||
object: str
|
||||
usage: dict
|
||||
|
||||
def num_tokens_from_string(string: str) -> int:
|
||||
"""Returns the number of tokens in a text string."""
|
||||
encoding = tiktoken.get_encoding('cl100k_base')
|
||||
num_tokens = len(encoding.encode(string))
|
||||
return num_tokens
|
||||
|
||||
def expand_features(embedding, target_length):
|
||||
poly = PolynomialFeatures(degree=2)
|
||||
expanded_embedding = poly.fit_transform(embedding.reshape(1, -1))
|
||||
expanded_embedding = expanded_embedding.flatten()
|
||||
if len(expanded_embedding) > target_length:
|
||||
# 如果扩展后的特征超过目标长度,可以通过截断或其他方法来减少维度
|
||||
expanded_embedding = expanded_embedding[:target_length]
|
||||
elif len(expanded_embedding) < target_length:
|
||||
# 如果扩展后的特征少于目标长度,可以通过填充或其他方法来增加维度
|
||||
expanded_embedding = np.pad(expanded_embedding, (0, target_length - len(expanded_embedding)))
|
||||
return expanded_embedding
|
||||
|
||||
|
||||
@app.post("/v1/chat/completions", response_model=ChatCompletionResponse)
|
||||
async def create_chat_completion(request: ChatCompletionRequest, token: bool = Depends(verify_token)):
|
||||
global model, tokenizer
|
||||
|
||||
if request.messages[-1].role != "user":
|
||||
raise HTTPException(status_code=400, detail="Invalid request")
|
||||
query = request.messages[-1].content
|
||||
|
||||
prev_messages = request.messages[:-1]
|
||||
if len(prev_messages) > 0 and prev_messages[0].role == "system":
|
||||
query = prev_messages.pop(0).content + query
|
||||
|
||||
history = []
|
||||
if len(prev_messages) % 2 == 0:
|
||||
for i in range(0, len(prev_messages), 2):
|
||||
if prev_messages[i].role == "user" and prev_messages[i+1].role == "assistant":
|
||||
history.append([prev_messages[i].content, prev_messages[i+1].content])
|
||||
|
||||
if request.stream:
|
||||
generate = predict(query, history, request.model)
|
||||
return EventSourceResponse(generate, media_type="text/event-stream")
|
||||
|
||||
response, _ = model.chat(tokenizer, query, history=history)
|
||||
choice_data = ChatCompletionResponseChoice(
|
||||
index=0,
|
||||
message=ChatMessage(role="assistant", content=response),
|
||||
finish_reason="stop"
|
||||
)
|
||||
|
||||
return ChatCompletionResponse(model=request.model, choices=[choice_data], object="chat.completion")
|
||||
|
||||
|
||||
async def predict(query: str, history: List[List[str]], model_id: str):
|
||||
global model, tokenizer
|
||||
|
||||
choice_data = ChatCompletionResponseStreamChoice(
|
||||
index=0,
|
||||
delta=DeltaMessage(role="assistant"),
|
||||
finish_reason=None
|
||||
)
|
||||
chunk = ChatCompletionResponse(model=model_id, choices=[choice_data], object="chat.completion.chunk")
|
||||
yield "{}".format(chunk.json(exclude_unset=True, ensure_ascii=False))
|
||||
|
||||
current_length = 0
|
||||
|
||||
for new_response, _ in model.stream_chat(tokenizer, query, history):
|
||||
if len(new_response) == current_length:
|
||||
continue
|
||||
|
||||
new_text = new_response[current_length:]
|
||||
current_length = len(new_response)
|
||||
|
||||
choice_data = ChatCompletionResponseStreamChoice(
|
||||
index=0,
|
||||
delta=DeltaMessage(content=new_text),
|
||||
finish_reason=None
|
||||
)
|
||||
chunk = ChatCompletionResponse(model=model_id, choices=[choice_data], object="chat.completion.chunk")
|
||||
yield "{}".format(chunk.json(exclude_unset=True, ensure_ascii=False))
|
||||
|
||||
|
||||
choice_data = ChatCompletionResponseStreamChoice(
|
||||
index=0,
|
||||
delta=DeltaMessage(),
|
||||
finish_reason="stop"
|
||||
)
|
||||
chunk = ChatCompletionResponse(model=model_id, choices=[choice_data], object="chat.completion.chunk")
|
||||
yield "{}".format(chunk.json(exclude_unset=True, ensure_ascii=False))
|
||||
yield '[DONE]'
|
||||
|
||||
@app.post("/v1/embeddings", response_model=EmbeddingResponse)
|
||||
async def get_embeddings(request: EmbeddingRequest, token: bool = Depends(verify_token)):
|
||||
|
||||
|
||||
# 计算嵌入向量和tokens数量
|
||||
embeddings = [embeddings_model.encode(text) for text in request.input]
|
||||
|
||||
# 如果嵌入向量的维度不为1536,则使用插值法扩展至1536维度
|
||||
embeddings = [expand_features(embedding, 1536) if len(embedding) < 1536 else embedding for embedding in embeddings]
|
||||
|
||||
# Min-Max normalization
|
||||
embeddings = [(embedding - np.min(embedding)) / (np.max(embedding) - np.min(embedding)) if np.max(embedding) != np.min(embedding) else embedding for embedding in embeddings]
|
||||
|
||||
# 将numpy数组转换为列表
|
||||
embeddings = [embedding.tolist() for embedding in embeddings]
|
||||
prompt_tokens = sum(len(text.split()) for text in request.input)
|
||||
total_tokens = sum(num_tokens_from_string(text) for text in request.input)
|
||||
|
||||
|
||||
response = {
|
||||
"data": [
|
||||
{
|
||||
"embedding": embedding,
|
||||
"index": index,
|
||||
"object": "embedding"
|
||||
} for index, embedding in enumerate(embeddings)
|
||||
],
|
||||
"model": request.model,
|
||||
"object": "list",
|
||||
"usage": {
|
||||
"prompt_tokens": prompt_tokens,
|
||||
"total_tokens": total_tokens,
|
||||
}
|
||||
}
|
||||
|
||||
return response
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--model_name", default="16", type=str, help="Model name")
|
||||
args = parser.parse_args()
|
||||
|
||||
model_dict = {
|
||||
"4": "THUDM/chatglm2-6b-int4",
|
||||
"8": "THUDM/chatglm2-6b-int8",
|
||||
"16": "THUDM/chatglm2-6b"
|
||||
}
|
||||
|
||||
model_name = model_dict.get(args.model_name, "THUDM/chatglm2-6b")
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True)
|
||||
model = AutoModel.from_pretrained(model_name, trust_remote_code=True).cuda()
|
||||
embeddings_model = SentenceTransformer('moka-ai/m3e-large',device='cpu')
|
||||
|
||||
uvicorn.run(app, host='0.0.0.0', port=6006, workers=1)
|
Before Width: | Height: | Size: 247 KiB |
Before Width: | Height: | Size: 355 KiB |
Before Width: | Height: | Size: 411 KiB |
@@ -1,22 +0,0 @@
|
||||
# 通过 OpenAPI 接入第三方应用
|
||||
|
||||
## 1. 获取 API 秘钥
|
||||
|
||||
注意复制,关掉了需要新建~
|
||||
|
||||

|
||||
|
||||
## 2. 组合秘钥
|
||||
|
||||
利用刚复制的 API 秘钥加上 AppId 组合成一个新的秘钥,格式为: API 秘钥-AppId,例如:`fastgpt-z51pkjqm9nrk03a1rx2funoy-642adec15f04d67d4613efdb`
|
||||
|
||||
## 3. 替换三方应用的变量
|
||||
|
||||
OPENAI_API_BASE_URL: https://fastgpt.run/api/openapi (改成自己部署的域名)
|
||||
OPENAI_API_KEY = 组合秘钥
|
||||
|
||||
**[chatgpt next](https://github.com/Yidadaa/ChatGPT-Next-Web) 示例**
|
||||

|
||||
|
||||
**[chatgpt web](https://github.com/Chanzhaoyu/chatgpt-web) 示例**
|
||||

|
Before Width: | Height: | Size: 413 KiB |
@@ -1,19 +0,0 @@
|
||||
# 模块编排介绍
|
||||
|
||||
FastGpt V4 后将采用新的交互方式来构建 AI 应用。使用了“节点”编排的方式去掉原先的表单方式。提高可玩性和扩展性的同时也提高了上手的门槛,这篇文章就来简单介绍一下 “预览版” 的模块编排基本使用方法。
|
||||
|
||||

|
||||
|
||||
预览版仅包含了 8 个模块,你可以利用它们来完全实现 V3 的知识库功能。此外,预览版还加入了问题分类模块,可以实现多路线任务。
|
||||
|
||||
## 基础知识
|
||||
|
||||
### 什么是模块
|
||||
|
||||
在程序中,模块可以理解为一个个 function 或者接口。对于非技术背景同学,可以理解为它就是一个**步骤**。将多个模块一个个拼接起来,即可一步步的去实现最终的 AI 输出。
|
||||
|
||||
### 如何阅读和理解
|
||||
|
||||
1. 建议从左往右阅读。
|
||||
2. 从 **用户问题** 模块开始。用户问题模块,代表的是用户发送了一段文本,触发任务开始。
|
||||
3.
|