群里有人反映自己部署的某ChatGPT Web UI后,Key被盗用导致额度大大超出预期。我查了下https://github.com/mckaywrigley/chatbot-ui/issues,发现确实有不少人反应这个问题。
虽然我也部署了多个ChatGPT Web UI和兼容OpenAI API的兼容URL接口。但我的系统是自研的,利用docker实现了三层架构。下图就是基本架构,下面介绍下这个系统。
UI层
这一层就是安装的各种Web UI。这种UI在GitHub里有很多,当初我还准备自己用solid.js开发一个,后来发现我缺乏艺术气息,设计出来的UI太糟糕了,在figma搜了下,也没找到满意的。只能在GitHub里找一个直接安装。不过GitHub里的Web UI分为两类。
(1)带后端的Web UI。这类的UI会自带一个node后端,UI请求的这个node后端,由后端去调取OpenAI API。这种是泄露Key的重灾区。
(2)没有后端的Web UI。这种就是直接在页面填写KEY,然后请求OpenAI API。当然,因为众所周知的原因,正常情况下是无法访问OpenAI,所以你还需要额外提供一套代理。
上面的这两种我都有安装,但都无法直连OpenAI,也无法获取我的key,而是从API中间层获取数据。
API 层
这一层包含了两块: (1)OpenAI API兼容接口。其实就是OpenAI的一个代理,除了域名不同,其他的与OpenAI的URL完全一致,可以直接使用OpenAI的SDK调用这个兼容URL。同时,可以屏蔽OpenAI的Key,避免泄露。
(2)鉴权、审核、改写。
鉴权:作为平台,肯定不能直接将OpenAI的Key交给用户,给的是一个虚拟的key,不同的用户或不同的来源,有不同的虚拟Key。鉴权模块需要对这些虚拟Key进行权限判断,并将虚拟Key改写成OpenAI的真实的Key。
审核:这一块不是必须的,主要是针对恶意提问,或一些无意义的单字提问进行过滤。同时对返回的内容进行内容审核。
改写:这一块也不是必须的,主要是针对行业的一些默认设置。而且以前ChatGPT没有Function功能,只能通过改写模块实现Function功能。
Proxy层
因为众所周知的原因,国内的服务器无法访问OpenAI的URL。为此要么购买海外服务器,要么用科学方式。
海外的服务器虽然可以直连OpenAI,但是如果提供给用户端访问,则不理想。而且海外服务器价钱也不便宜,仅仅把它当做代理有些奢侈。
科学方式就容易多了,我们只要在proxy层支持trojan,vmess,shadowsocks,socks5等协议,即可接入任何科学方式。也可以随时更换。
部署方式
整个系统是用Docker部署,docker compose管理。docker-compose.yml如下:
version: '3'
services:
api:
build:
context: .
dockerfile: Dockerfile.app
container_name: chatbot-api
entrypoint: /app/api
restart: on-failure
depends_on:
- proxy
ports:
- "127.0.0.1:7718:7718"
expose:
- "7718"
volumes:
- /data/logs/chatBot/:/app/logs/
chatgpt-ui:
image: ghcr.io/mckaywrigley/chatbot-ui:main
container_name: chatgpt-ui
restart: on-failure
depends_on:
- api
ports:
- "127.0.0.1:6718:3000"
expose:
- "3000"
environment:
OPENAI_API_KEY: test111111111111111111
OPENAI_API_HOST: "http://api:7718"
volumes:
- /data/logs/chatBot/:/app/logs/
proxy:
image: 私有docker仓库地址/tiyee/proxy:latest
container_name: proxy
entrypoint: /app/proxy run -c /etc/proxy/config.json
restart: on-failure
expose:
- "1080"
- "1087"
volumes:
- /data/logs/chatBot/:/app/logs/
- /root/chatBot/config.json:/etc/proxy/config.json
next-ui:
image: yidadaa/chatgpt-next-web:latest
container_name: next-ui
restart: on-failure
depends_on:
- api
ports:
- "127.0.0.1:8718:3000"
environment:
OPENAI_API_KEY: sk-111111111111111111
BASE_URL: "http://api:7718"
CODE: maooo,jiangt
HIDE_USER_API_KEY: 1
volumes:
- /data/logs/chatBot/:/app/logs/