[!info] 版本更新
在网友的提醒下增加了 CF OpenAI Azure Proxy

缘起

OpenAI 余额不足,去年充值的渠道已经不可用,找了一圈也没有找到靠谱的渠道,朋友说用 Azure 吧,据说比 OpenAI 还便宜点。那就用 Azure 的 OpenAI 服务吧。

现状

我现在提供的服务:

image-20240627095718175

  • 一个部署在 Vercel 的套壳站,给媳妇和两个朋友提供 OpenAI 服务,壳用的是 ChatGPT-Next-Web。我在部署的时候设定好 OpenAI API 的密钥和访问密码,他们访问的时候直接使用密码就能访问了。Vercel 可以自定义域名,域名托管在 Cloudflare,国内能直接访问。
  • 八爷的 OpenCat 服务,我建了一个团队版,给另外几个朋友提供手机上的 OpenAI 服务,在我的一台美国 VPS 上运行了 OpenCat for Team 的镜像,提供中转服务。这台 VPS 国内能直接访问。

ChatGTP-Next-Web 没有在部署的时候提供 Azure 的支持,只能在用户 Web界面里设置 Azure OpenAI 服务,包括密钥,deployment,API version,这有泄露密钥的风险,而且也不便于管理。

OpenCat for Team 用 docker 部署,部署的时候没有提供 Azure OpenAI 的选项,所以应该是直连 OpenAI.

方案

利用一个 Azure OpenAI Proxy 服务,把来自 ChatGPT-Next-Web 和 Opencat for Team 对 OpenAI 的请求转换成对 Azure OpenAI 的请求。更新后的拓扑如下:

image-20240627095739391

各个客户端都能支持自定义 OpenAI Proxy URL.

部署和配置

部署 Azure OpenAI Proxy

在 VPS 上用 Docker compose 部署 GitHub - stulzq/azure-openai-proxy GitHub 页面有比较详细的介绍,我的配置文件如下:

1
2
3
4
5
6
7
8
9
10
11
12
version: '3'

services:
azure-openai:
image: stulzq/azure-openai-proxy
ports:
- 127.0.0.1:9090:8080
environment:
AZURE_OPENAI_ENDPOINT: https://<YourID>.openai.azure.com
AZURE_OPENAI_MODEL_MAPPER: GPT-4o=my-gpt4o,gpt-4o=my-gpt4o
AZURE_OPENAI_API_VER: 2024-02-15-preview

几个点:

  • Azure Endpoint:在 Azure AI Studio 里找到资源和密钥,里边有终结点,这就是 Endpoint.
  • AZURE_OPENAI_MODEL_MAPPER: OpenAI GPT model 和你的部署名称的对应关系,示例中的 my-gpt4o 是我在 Azure 里的部署名称,注意不是模型名称。
  • API_VER: 这个去聊天操场(Playground)里看示例代码,不是最新的或者默认的(2024-02-01), 我在这里被坑的不轻

9987c9cd0dcde456d6fa6beed1106f8a_MD5

部署完后在 VPS 上的 Nginx 上分配一个子域名给这个服务:

073039f60569bbf6a31343e4cbbc2fd1_MD5

服务起来后,用 curl 做个简单的测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ curl http://xxxxx:9090/v1/chat/completions   -H "Content-Type: application/json"   -H "Authorization: Bearer <You Key>"   -d '{
"model": "GPT-4o",
"messages": [
{
"role": "system",
"content": "You are a poetic assistant, skilled in explaining complex programming concepts with creative flair."
},
{
"role": "user",
"content": "Compose a poem that explains the concept of recursion in programming."
}
]
}'

{"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"finish_reason":"stop","index":0,"logprobs":null,"message":{"content":"In code's enchanted forest, deep and vast,\nWhere logic weaves its spells both slow and fast,\nThere thrives a mystic concept, bold and terse—\nA riddle wrapped in loops, named \"Recursion's Verse.\"\n\nIn this land of algorithms bright,\nWhere problems grow and spin like stars at night,\nA function calls itself, a circling song,\nTo break down mighty tasks and make them small.\n\nOh, Recursion, with your deft embrace,\nYou split the grand into a simpler trace,\nA staircase of solutions, step by step,\nDescend the rabbit hole, and secrets kept.\n\nA base case stands, so humble, clear, and true,\nThe anchor point where journeys do construe,\nFor without it, endless loops may bind,\nEternal spirals in the coder's mind.\n\nIn Fibonacci’s dance of numbers rare,\nOr trees of nodes that branch in spectral air,\nYou wield your magic wand with subtle grace,\nAnd guide us through the labyrinthine space.\n\nLet factor's factorial find its ground,\nWithin the nested loops your light is found,\nGently leading towards the task's demise,\nA fractal beauty, mirrored in your eyes.\n\nWith every call, a mirror’s depth is shown,\nUntil at last the simplest truth is known,\nThen up the call stack, ripple in reverse,\nUntangling all complexities that curse.\n\nSo here’s to Recursion, art so pure and wise,\nA tale of self-reflection, in disguise,\nIn code’s enchanted forest, where dreams unfurl,\nYou are the heart of logic’s spiraling swirl.","role":"assistant"}}],"created":1719387673,"id":"chatcmpl-9eHZBnzdbGpgAodlr31aMAHB80LxT","model":"gpt-4o-2024-05-13","object":"chat.completion","prompt_filter_results":[{"prompt_index":0,"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}}}],"system_fingerprint":"fp_abc28019ad","usage":{"completion_tokens":317,"prompt_tokens":39,"total_tokens":356}}


能返回内容 就代表服务没问题。

部署 CF OpenAI Azure Proxy

还有另外一个部署在 Cloudflare worker 上的代理工具:GitHub - haibbo/cf-openai-azure-proxy: A Cloudflare worker script to proxy OpenAI‘s request to Azure OpenAI Service

用这个工具,能省一个 VPS。部署方式 Github 页面上介绍的很详细,这里有两点需要注意的:

  • 不支持 GPT-4o:源代码有六个月没有更新了,不支持 GPT-4o,不过没关系,我们直接在代码里加一行即可,或者直接把 gpt-4 替换成 gpt-4o:
1
2
3
4
5
6
7
8
9
10
const mapper = {
'gpt-3.5-turbo': DEPLOY_NAME_GPT35,
'gpt-3.5-turbo-0613': DEPLOY_NAME_GPT35,
'gpt-3.5-turbo-1106': DEPLOY_NAME_GPT35,
'gpt-3.5-turbo-16k': DEPLOY_NAME_GPT35,
'gpt-4o': DEPLOY_NAME_GPT4,
'gpt-4-0613': DEPLOY_NAME_GPT4,
'gpt-4-1106-preview': DEPLOY_NAME_GPT4,
'gpt-4-32k': DEPLOY_NAME_GPT4,
'dall-e-3': typeof DEPLOY_NAME_DALLE3 !== 'undefined' ? DEPLOY_NAME_DALLE3 : "dalle3",
  • 源代码里 API version 是写死的,我们要把这个改成变量,以便后续维护,部署后在 CF Worker 环境变量里记得把这个参数设上:
1
const apiVersion=API_VERSION

配置 ChatGPT-Next-Web

打开 Vercel 的项目页面,找到 ChatGTP-Next-Web 的部署,在 Setting 里找到 Environment Variables:

  • BASE_URL: 填你刚给 Azure Proxy 分配的子域名。比如: https://azure.xxxx.com
  • OPENAI_API_KEY: 填 Azure 的密钥

保存后重新 deploy 即可

配置 LobeChat

LobeChat 本身支持 Azure OpenAI,但是我用起来总有问题,索性也用这个 Azure Proxy 了。

环境变量设置如下:

  • OPENAI_PROXY_URL: 填你刚给 Azure Proxy 分配的子域名+v1,比如: https://azure.xxx.com/v1
  • OPENAI_API_KEY: Azure 的密钥

保存重新 deploy 即可

OpenCat for Team

启动 OpenCat for Team Docker 镜像的时候设置环境变量 API_DOMAIN, Docker compose 文件示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
version: "3.8"
services:
opencatd:
image: bayedev/opencatd
container_name: opencatd
restart: always
volumes:
- ~/opencat/data:/opt/db
ports:
- "127.0.0.1:8043:80"
environment:
- API_DOMAIN=https://azure.xxxxx.com


API KEY 记得使用 Azure 的密钥

总结

利用 Azure OpenAI Proxy 服务把所有向 OpenAI 的请求都重定向到 Azure OpenAI 。各个客户端把 OpenAI URL 指向 Azure OpenAI Proxy 的地址,密钥要填 Azure 的密钥。

至此,OpenAI 到 Azure OpenAI 无痛切换完成。