摘要
最近想搭建一个大模型提供给校友使用,同时发现谷歌的 Gemini pro模型的强大超乎想想,leetcode 上高难度的题目一次性通过,而且 gemini 还是免费的,于是开始动手实践
搭建完成效果展示:
按照本教程搭建完成,支持:
- 域名配置+https 加密
- 支持流式输出
- 支持知识库配置
- 免科学上网访问
- 支持存储对话记录、对话隔离
- 高性能、高可用
环境准备
ubuntu TLS 22.4服务器,我这里使用的是国内服务器,需要配置代理,如果是国外服务器可以省去这一个步骤
配置要求:
- cpu:2 核+
- 内存 4g+(实测 2g 不行,安装 oneapi 时候会卡,同时再装 fastgpt 会直接爆内存卡死)
- 带宽:3m+
- 硬盘:40g+
- 网络:有公网 ip,能海外 ip(韩国、新加坡、日本) 最好
个人选择,这里选的腾讯云的云轻量服务器,2 核4g,168 块钱一年,很便宜了,系统镜像选的 ubuntu22+docker22,之所以还价格docker22是因为预装的 docker 设置好了 docker 镜像源,懒得自己配置了。。。。。。但是这个预装 docker 有个缺点,无法解析有个好用的预置地址host.docker.internal,这个地址本来是指向宿主机的 localhost 的,但是在这个腾讯预装 dock 上似乎不能识别,部署 oneapi会报错:
[FATAL] 2024/03/18 - 13:50:50 | [failed to get gpt-3.5-turbo token encoder: Get "https://openaipublic.blob.core.windows.net/encodings/cl100k_base.tiktoken": proxyconnect tcp: dial tcp: lookup host.docker.internal on 183.60.83.19:53: no such host]
之前买的阿里云服务 2
核2g,100 块钱一年,本来想退掉,一看退不了多少钱,算了那就留着跑我自己的博客和个人一些项目,以及 clash,腾讯的这个服务器专门跑大模型这些业务
三,安装宝塔面板(可选)
宝塔面板可以方便上传下载文件,所以这里安装个宝塔面板:
curl -sSO https://download.bt.cn/install/install_panel.sh && bash install_panel.sh 12f2c1d72
显示下面的信息就是安装完成:
========================面板账户登录信息==========================
外网面板地址: https://xxxxxxxx:35098/81f22375
内网面板地址: https://xxxxxxxx:35098/81f22375
username: xxx
password: xxx
=========================打开面板前请看===========================
【云服务器】请在安全组放行 35098 端口
别着急登录,先去放行端口!!!
打开外网面板地址,输入 username 和 pw,阅读协议,绑定账号,安装套件选LNMP(推荐),等待安装完成,吧该解析的域名解析一下
四,配置代理
gemini 或者 openai 的访问需要魔法环境,所以这里配置下代理
1,第一种方式:clash_docker(推荐)
使用 clash 的 docker 容器配置,特点是简单方便,建议使用这种方式
创建文件docker-compose.yml
mkdir /opt/clash_docker
cd /opt/clash_docker
vim docker-compose.yml
写入以下内容
# docker-compose版本
version: '3.7'
# 服务列表
services:
# clash后台服务
clash:
# 设置image
image: dreamacro/clash
# 停止了总是重启
restart: always
volumes:
# 将配置文件挂载到容器中
- /opt/clash_docker:/root/.config/clash
container_name: clash
ports:
# 这些端口都在配置文件中配置过,容器外地址可随心情配置
- 7890:7890
- 7895:7895
- 9090:9090
clash_web:
image: haishanh/yacd
restart: always
depends_on:
# 依赖于上面的clash服务,在clash启动后,web才启动
- clash
ports:
- 7899:80
container_name: clash_web
然后配置文件:
vim config.yaml
需要写入你的配置文件,如何拿到你的配置文件呢,在 mac 上,右键你的魔法软件图标,点击如下:
把这俩文件(根据订阅的不同文件名会有不同)上传到/opt/clash_docker 文件夹下,把 yaml 文件改名为 config.yaml。因为 gemini 禁止香港 ip 访问,所以打开 config.yaml,删除掉香港相关的所有规则和节点,保存
然后启动clash_docker:
cd /opt/clash_docker
docker-compose up -d
然后服务器控制台去开下 7899 端口(如果需要的话开下 7890 端口,这样手机等其他设备也能用了)
测试一下:
curl -x 127.0.0.1:7890 https://ipinfo.io/json
或者
proxychains curl https://ipinfo.io/json
显示国外 ip 就好了
如果没有proxychains那么安装下 proxychains(强制走代理工具):
apt-get update
apt install proxychains
# 配置一下:
mkdir ~/.proxychains
vim ~/.proxychains/proxychains.conf
写入:
strict_chain
remote_dns_subnet 224
tcp_read_time_out 15000
tcp_connect_time_out 8000
[ProxyList]
# add proxy here ...
# meanwile
# defaults set to "tor"
#填一个就行了
http 127.0.0.1 7890
保存,测试:
proxychains curl https://ipinfo.io/json
或者:
curl -x 127.0.0.1:7890 https://ipinfo.io/json
显示国外 ip 就好了
(可选)添加到环境变量实现自动按需代理的命令:
export https_proxy=127.0.0.1:7890 && export http_proxy=127.0.0.1:7890
取消:
unset https_proxy
unset http_proxy
后面说 clash 的具体配置
2,第二种方式:clash 客户端
推荐 docker 运行 clash,这只是一种备选方法,建议跳过
1,上传 clash 文件
gzip -d clash-linux-amd64-v1.18.0.gz
mv clash-linux-amd64-v1.9.0.gz clash
放入配置文件,然后前台启动(不推荐):
./clash -d .
后台启动:
vim ~/..bashrc开始准备命令并把下面的写进入
alias clash_start="screen -S clash /home/root/clash/clash -d /opt/clash/"
alias clash_stop="pkill clash"
alias proxy_on="export https_proxy=127.0.0.1:7890 && export http_proxy=127.0.0.1:7890"
alias proxy_off="unset http_proxy https_proxy"
source ~/..bashrc 重新载入
clash_start会进入screen 按 ctrl + a + d退出后台
proxy_on开启代理
curl https://www.youtube.com/会发现马上返回结果
3,clash配置说明
浏览器访问 ip:7899
API BASE URL 填你的 ip:9090
点击 add 就把clash 外部控制地址添加了,点击刚才添加的控制地址进入 clash 控制面板,打开“代理”选项卡,会发现有很多代理(根据机场的不同而不同):
- 这些都可以理为策略组,当域名被匹配到某个规则时候,由规则决定使用哪个选项组,比如api.openai.com会被匹配到使用OpenAI这个策略组,打开这个策略组,会发现下面还有好多个节点,策略组下的节点我们可以自己选择,选择哪个策略组是由配置文件决定的,在clash客户端操作不了
- 所以,即使你的配置文件里面有香港节点,那么只需要手动设置下设置每个策略组都不要使用香港节点即可
4,可选:开发代理端口配置域名,作为代理服务器
解析一个二级域名到服务器,然后添加一个 nginx 规则:
server {
#clash 代理服务
listen 80;
server_name 这里填你的域名;
location / {
proxy_pass http://localhost:7890;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
保存,接着在需要使用代理服务器的设备上设置手动代理,域名填写你的服务器域名,端口为 7890 即可(注意,暂时没设置密码,域名不要泄露)
五,部署 one-api
1,部署
cd /opt
下载 oneapi 项目:
git clone https://github.com/songquanpeng/one-api.git
配置 docker-compose.yml文件:
version: '3.4'
services:
one-api:
image: justsong/one-api:latest
container_name: one-api
restart: always
command: --log-dir /app/logs
ports:
- "3001:3000"
volumes:
- ./data/oneapi:/data
- ./logs:/app/logs
environment:
- http_proxy=http://上面你刚配置的代理域名:7890
- https_proxy=https://上面你刚配置的代理域名:7890
- SQL_DSN=oneapi:你的密码@tcp(db:3306)/one-api # 修改此行,或注释掉以使用 SQLite 作为数据库
- REDIS_CONN_STRING=redis://redis
- SESSION_SECRET="abcdefg1234567" # 修改为随机字符串
- TZ=Asia/Shanghai
# - NODE_TYPE=slave # 多机部署时从节点取消注释该行
# - SYNC_FREQUENCY=60 # 需要定期从数据库加载数据时取消注释该行
# - FRONTEND_BASE_URL=https://openai.justsong.cn # 多机部署时从节点取消注释该行
depends_on:
- redis
- db
healthcheck:
test: [ "CMD-SHELL", "wget -q -O - http://localhost:3000/api/status | grep -o '\"success\":\\s*true' | awk -F: '{print $2}'" ]
interval: 30s
timeout: 10s
retries: 3
redis:
image: redis:latest
container_name: redis
restart: always
db:
image: mysql:8.2.0
restart: always
container_name: mysql
volumes:
- ./data/mysql:/var/lib/mysql # 挂载目录,持久化存储
ports:
- '3307:3306'
environment:
TZ: Asia/Shanghai # 设置时区
MYSQL_ROOT_PASSWORD: '你的密码' # 设置 root 用户的密码
MYSQL_USER: oneapi # 创建专用用户
MYSQL_PASSWORD: '你的密码' # 设置专用用户密码
MYSQL_DATABASE: one-api # 自动创建数据库
注意:
- macos 上,{print $2}要修改为{print $$2}
- 注意黄色标出来的部分,注意不要和外部的端口冲突
docker-compose 启动:
docker-compose up -d
docker-compose ps
检查下是否正常启动,可能会有报错:
ERROR 1130 (HY000): Host ‘172.20.0.1’ is not allowed to connect to this MySQL server
可能是因为 ubuntu 这边下载的 mysql 初始 root 权限不一样,不允许非 localhost 之外的 host 连接
docker exec -it mysql bash
mysql -u root -p
输入您的root
密码。或者直接输入 mysql
SELECT host, user FROM mysql.user;
+-----------+------------------+
| host | user |
+-----------+------------------+
| localhost | mysql.infoschema |
| localhost | mysql.session |
| localhost | mysql.sys |
| localhost | root |
+-----------+------------------+
可以看到 oneapi、root 用户只有 localhost 连接权限,给予全部权限:
CREATE USER 'oneapi'@'%' IDENTIFIED BY '你的密码';
GRANT ALL PRIVILEGES ON *.* TO 'oneapi'@'%' WITH GRANT OPTION;
UPDATE mysql.user SET Host='%' WHERE User='root' AND Host='localhost';
FLUSH PRIVILEGES;
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' WITH GRANT OPTION;
FLUSH PRIVILEGES;
重新启动看看
还是不行,使用 docker 命令部署吧
这里代理地址使用公网 ip 地址(proxy.nwuserv.top),为什么呢,实测发现,我的 docker 不支持那个 docker.host.internel 地址,设置环境变了地址时候实际会先判断是否是内网地址,是的话就在内网中找,找到不到报错,因为代理程序跑在另一个 docker,暴露 7890 端口到宿主机网络中,所以这里只能填写公网 ip 地址
docker run --name one-api -d \
-e http_proxy="http://上面你刚配置的代理域名:7890" \
-e https_proxy="http://上面你刚配置的代理域名:7890" \
--restart always \
-p 3001:3000 \
-e TZ=Asia/Shanghai \
-v /home/ubuntu/data/one-api:/data justsong/one-api
一下子就好了。。。。。
2,配置二级域名和 ssl
解析一个二级域名过去,申请一个证书,写入 nginx一条配置:
server {
#oneapi服务
listen 80;
server_name 你的oneapi域名;
return 301 https://$server_name$request_uri;
}
server {
#oneapi服务
listen 443 ssl;
server_name 你的oneapi域名;
ssl_certificate /www/certs/你的oneapi域名.pem;
ssl_certificate_key /www/certs/你的oneapi域名.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers "ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384";
location / {
proxy_pass http://localhost:3001;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
3,渠道设置
打开 oneapi管理页面,点击渠道,添加你需要的渠道,填入对应的 apikey 即可
gpt:
sk-xxx
geminipro(每分钟限制 60 次调用,香港地区不支持):
xxx-xxx
六,fastgpt 部署
1,部署
curl -O https://raw.githubusercontent.com/labring/FastGPT/main/projects/app/data/config.json
或者配置自己的模型,手动创建文件config.json:
{
"systemEnv": {
"openapiPrefix": "fastgpt",
"vectorMaxProcess": 15,
"qaMaxProcess": 15,
"pgHNSWEfSearch": 100
},
"llmModels": [
{
"model": "gemini-pro",
"name": "Gemini Pro",
"maxContext": 16000,
"maxResponse": 4000,
"quoteMaxToken": 13000,
"maxTemperature": 1.2,
"charsPointsPrice": 0,
"censor": false,
"vision": true,
"datasetProcess": false,
"usedInClassify": true,
"usedInExtractFields": true,
"usedInToolCall": true,
"usedInQueryExtension": true,
"toolChoice": true,
"functionCall": false,
"customCQPrompt": "",
"customExtractPrompt": "",
"defaultSystemChatPrompt": "",
"defaultConfig": {}
},
{
"model": "chatglm_turbo",
"name": "本地CHATGLM",
"maxContext": 20000,
"maxResponse": 10000,
"quoteMaxToken": 13000,
"maxTemperature": 1.2,
"charsPointsPrice": 0,
"censor": false,
"vision": false,
"datasetProcess": false,
"usedInClassify": true,
"usedInExtractFields": true,
"usedInToolCall": true,
"usedInQueryExtension": true,
"toolChoice": true,
"functionCall": false,
"customCQPrompt": "",
"customExtractPrompt": "",
"defaultSystemChatPrompt": "",
"defaultConfig":{}
},
{
"model": "gpt-4-turbo-preview",
"name": "gpt-4-turbo-preview",
"maxContext": 16000,
"maxResponse": 4000,
"quoteMaxToken": 13000,
"maxTemperature": 1.2,
"charsPointsPrice": 0,
"censor": false,
"vision": false,
"datasetProcess": false,
"usedInClassify": true,
"usedInExtractFields": true,
"usedInToolCall": true,
"usedInQueryExtension": true,
"toolChoice": true,
"functionCall": false,
"customCQPrompt": "",
"customExtractPrompt": "",
"defaultSystemChatPrompt": "",
"defaultConfig": {}
},
{
"model": "gpt-4-vision-preview",
"name": "gpt-4-vision",
"maxContext": 128000,
"maxResponse": 4000,
"quoteMaxToken": 100000,
"maxTemperature": 1.2,
"charsPointsPrice": 0,
"censor": false,
"vision": true,
"datasetProcess": false,
"usedInClassify": false,
"usedInExtractFields": false,
"usedInToolCall": false,
"usedInQueryExtension": false,
"toolChoice": true,
"functionCall": false,
"customCQPrompt": "",
"customExtractPrompt": "",
"defaultSystemChatPrompt": "",
"defaultConfig": {}
},
{
"model": "gpt-3.5-turbo",
"name": "gpt-3.5-turbo",
"maxContext": 16000,
"maxResponse": 4000,
"quoteMaxToken": 13000,
"maxTemperature": 1.2,
"charsPointsPrice": 0,
"censor": false,
"vision": false,
"datasetProcess": false,
"usedInClassify": true,
"usedInExtractFields": true,
"usedInToolCall": true,
"usedInQueryExtension": true,
"toolChoice": true,
"functionCall": false,
"customCQPrompt": "",
"customExtractPrompt": "",
"defaultSystemChatPrompt": "",
"defaultConfig": {}
},
{
"model": "qwen-turbo",
"name": "通义千问",
"maxContext": 16000,
"maxResponse": 4000,
"quoteMaxToken": 13000,
"maxTemperature": 1.2,
"charsPointsPrice": 0,
"censor": false,
"vision": false,
"datasetProcess": false,
"usedInClassify": true,
"usedInExtractFields": true,
"usedInToolCall": true,
"usedInQueryExtension": true,
"toolChoice": true,
"functionCall": false,
"customCQPrompt": "",
"customExtractPrompt": "",
"defaultSystemChatPrompt": "",
"defaultConfig":{}
}
],
"vectorModels": [
{
"model": "text-embedding-ada-002",
"name": "Embedding-2",
"charsPointsPrice": 0,
"defaultToken": 700,
"maxToken": 3000,
"weight": 100
}
],
"reRankModels": [],
"audioSpeechModels": [
{
"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": {
"model": "whisper-1",
"name": "Whisper1",
"charsPointsPrice": 0
}
}
创建文件docker-compose.yml:
# 非 host 版本, 不使用本机代理
# (不懂 Docker 的,只需要关心 OPENAI_BASE_URL 和 CHAT_API_KEY 即可!)
version: '3.3'
services:
pg:
image: ankane/pgvector:v0.5.0 # git
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/pgvector:v0.5.0 # 阿里云
container_name: pg
restart: always
ports: # 生产环境建议不要暴露
- 5433:5432
networks:
- fastgpt
environment:
# 这里的配置只有首次运行生效。修改后,重启镜像是不会生效的。需要把持久化数据删除再重启,才有效果
- POSTGRES_USER=username
- POSTGRES_PASSWORD=password
- POSTGRES_DB=postgres
volumes:
- ./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
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
- ./mongodb.key:/data/mongodb.key
fastgpt:
container_name: fastgpt
image: ghcr.io/labring/fastgpt:latest # git
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:latest # 阿里云
ports:
- 3002:3000
networks:
- fastgpt
depends_on:
- mongo
- pg
restart: always
environment:
# root 密码,用户名为: root
- DEFAULT_ROOT_PSW=这里填你的密码
# 中转地址,如果是用官方号,不需要管。务必加 /v1
- OPENAI_BASE_URL=http://host.docker.internal:3001/v1
- CHAT_API_KEY= 这里填 oneapi 创建的令牌
- DB_MAX_LINK=5 # database max link
- TOKEN_KEY=any
- ROOT_KEY=root_key
- FILE_TOKEN_KEY=filetoken
# mongo 配置,不需要改. 用户名myname,密码mypassword。
- MONGODB_URI=mongodb://username:password@mongo:27017/fastgpt?authSource=admin
# pg配置. 不需要改
- PG_URL=postgresql://username:password@pg:5432/postgres
volumes:
- ./config.json:/app/data/config.json
networks:
fastgpt:
构建运行:
linux:
# 进入项目目录
cd 项目目录
# 创建 mongo 密钥
openssl rand -base64 756 > ./mongodb.key
chmod 600 ./mongodb.key
chown 999:root ./mongodb.key
# 启动容器
docker-compose pull
docker-compose up -d
Macos:
# 进入项目目录
cd 项目目录
# 创建 mongo 密钥
openssl rand -base64 756 > ./mongodb.key
chmod 600 ./mongodb.key
# 启动容器
docker-compose pull
docker-compose up -d
初始化 Mongo 副本集:
# 查看 mongo 容器是否正常运行
docker ps
# 进入容器
docker exec -it mongo bash
# 连接数据库
mongo -u username -p password --authenticationDatabase admin
# 初始化副本集。如果需要外网访问,mongo:27017 可以改成 ip:27017。但是需要同时修改 FastGPT 连接的参数(MONGODB_URI=mongodb://myname:mypassword@mongo:27017/fastgpt?authSource=admin => MONGODB_URI=mongodb://myname:mypassword@ip:27017/fastgpt?authSource=admin)
rs.initiate({
_id: "rs0",
members: [
{ _id: 0, host: "mongo:27017" }
]
})
# 检查状态。如果提示 rs0 状态,则代表运行成功
rs.status()
访问ip:3002即可
注意:实测发现,当使用非gpt模型时,创建知识库时候会出现报错创建失败:
但是又实测:解决方案是先用官方文config.json,docker-compose up -d 一遍后,上去创建一个知识库,然后删除镜像,使用你自己的config.json重新docker-compose up -d 上去打开刚才创建的知识库,这样就可以用了
2,nginx域名+ssl配置
server {
#fastgpt服务
listen 80;
server_name 这里填你的域名;
location / {
proxy_pass http://localhost:3002;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
server {
#fastgpt 服务
listen 443 ssl;
server_name 这里填你的域名;
ssl_certificate /www/certs/你的域名.pem;
ssl_certificate_key /www/certs/你的域名.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers "ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384";
location / {
proxy_pass http://localhost:3002;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
完成后,访问你的域名即可