oynix

于无声处听惊雷,于无色处见繁花

微信公众号接入ChatGPT

前段时间把ChatGPT接到了公众号的后台,最终效果大致就是给公众号发消息,等同于在GPT的网页上发消息,可以正常回复消息,且可以识别上下文。趁着端午节有时间,记录一下过程。

在微信公众号后台接入点东西,是一件麻烦且不稳定的事情,其实不单单是微信,整个腾讯系都如此,毕竟无风不起浪,腾讯四处招骂都是凭本事做到的。

之前我看过不少接入ChatGPT的公众号、小程序,但基本都没挺过头七,然后就搜不到了。网上见到有网友在问,说自己的号被封了,微信只给了一个条款链接,也不说到底违反了哪一条哪一款,客服也联系不上,提问公众号到底允不允许接入ChatGPT。

没有人可以说得清,微信的政策是一个已经上升到玄学高度的问题,所以我一直没有试一试的想法,上一秒还正常,下一秒可能号就没了。

直到我关注的一个ChatGPT问答的小程序,活生生坚挺了一个多月竟然还健在,仔细看了看,发现原来他还接入了腾讯审核,真相大白,真是机灵。所以我猜测,微信封的不是ChatGPT,而是里面的文字内容,原因在于国内互联网有些内容是不能提的。

1. 公众号的消息机制

微信开发者文档关于消息机制的介绍

公众号后台把消息分为2种,一种是主动消息,一种是被动消息。

首先一个前提是,在公众号后台配置一个URL后,这个URL就会收到用户发送的所有消息,以及相关事件,比如关注、菜单栏点击,等。

当用户给公众号发一条消息后,后台收到这条消息,并回复一条消息,这种消息叫做被动消息。即非主动发送,是对用户发过来的消息的被动回复,这种消息要求实时性。

如果回复完之后,还想给用户发消息怎么办?这个时候就需要发送主动消息,公众号后台管这种叫做客服消息。一般使用场景是,用户咨询了一个问题,对于这个问题无法立即给出回答,需要经过一段时间处理后,才可以给用户回复他提问的答案,这种消息不要求实时性。

被动消息

URL在收到微信服务器发来的带着用户消息的请求后,需要在5秒以内给出response,如果超时,微信的服务器会发起重试,最多重试3次。换句话说,用户发送一条消息,开发者最多有15秒的处理时间,如果超过15秒还没有给出response,那么用户那边就会看到一个提示:

该公众号暂时无法提供服务,请稍后再试

主动消息(客服消息)

这个类型的消息有限制,48小时内只允许发5次,看这个频率就知道,不适合这种问答场景。同时,它的设计是按照客服体系结构的,需要提前创建客服,URL收到消息后需要将这个消息分配给某个客服,然后这个客服需要在48小时内给出回复。

2. 消息交互方式选择

问ChatGPT一个问题,它回复需要的时间是不稳定的,具体影响因素有网络、问题本身、上下文长度、回答的长度等,快的时候一两秒就能回来,慢的时候需要十几秒,甚至几十秒。按理说,这种时间跨度,使用不限时的客服消息是比较好的选择,但是无奈于它的条数限制,所以只能选择被动消息的方式。

对于15秒仍无法给出答案的问题,这种情况的一般处理方式是,给用户回复一个提示,引导他再发一条消息,这样一来又有了15秒的时间。虽然体验上差了一点,但是起码保证了基本的可用性。故终决定使用此方式。

3. 服务选择

关于服务器,当下有2种选择,一种是长期跑着一台机器来提供服务,即EC2,另一种是按需使用,即FaaS。量小的话就选FaaS,省钱,量大的话就选EC2,也是为了省钱。

我用的是阿里云,新用户送了一些计算资源、带宽资源和存储资源,有效期3个月,前期就不用花钱了。

服务器URL直接用Function服务的调用URL,也没走API Gateway,因为阿里云没送,存储没用RDS,用的是OSS,也是因为阿里云送了免费的资源,那就先用着。

内容审核肯定是要接腾讯的了,文本审核按条收费,一万条收费22块钱,这大概是唯一的必要花费了。

对于ChatGPT,早年间我注册过一个账号,那个时候还不像现在这么艰难,注册很容易。里面送了18块钱的额度,6月1号过期,一直在用,按理说可以用到过期。但五月份的时候用着用着账号就被封了,突然就没得用了,于是就赶紧从众多的二道贩子中选了一个用户稍微多点的,价格比官方贵了20%左右,当然贵也很正常,很好理解,人家就是赚差价的。虽然没了账号的困扰,但是随之而来的是安全性,自己的所有数据都会经过他们的手,即便他们嘴上说着不会存储,但心里也不踏实,所以有办法的话还是要自己搞个官方账号。

所以,所有需要接入的服务如下:

  • 阿里云的Function服务
  • 阿里云的Log日志服务
  • 阿里云的OSS对象存储服务
  • 腾讯云的内容审核服务
  • 第三方的ChatGPT服务

4. 阿里云Function服务使用

首先需要的就是接通阿里云的函数服务,可以做到向函数URL发送一个request,代码中可以正确接收、处理,并返回response。

语言和框架

函数服务可以选择不同语言的不同版本,鉴于ChatGPT用的Python,所以我选了Python,3.9版本。服务框架有2种选择,一个是普通的事件模式,http请求的所有参数,包括请求参数、请求头、请求体等,会被包装成一个event,我们在代码里要做的就是要处理一个一个不同类型的事件;另一个则是Flask框架,这个本就是一个轻型的http服务框架,可以处理http请求。我选的是后者。

部署

关于部署,最直接的方式是把本地代码打包,然后从管理后台上传,再部署。但最简单快速的便是一键部署,我试了常用serverless框架来部署,但是失败了,原因就是反复从文档中查找失败原因时,发现有一行字写着serverless只支持Amazon,不支持阿里云。

最终选择了通过GitHub的方式,将部署和仓库的分支绑定,向分支上提交内容则会触发自动部署操作,代码是交出去了,用几分安全性换取了几分便捷性。

在管理后台上创建函数服务时,它会自动生成一套模版代码,等它部署完之后,访问函数服务的URL就可以看到示例页面。把仓库clone到本地,在此基础上稍微修改一下部署配置就可以用了。

关于配置项不知道写什么值,这个可以逆向操作一下,在后台可视化的网页上修改配置,增加服务或者修改服务,比如给函数增加一个Log服务,完成之后右上角有一个导出配置文件,再将导出的配置整合到代码里的配置文件即可。

这里就不举例了,内容太多,文末会附一个脱敏的代码仓库,需要的话可以参考一下。

5. 阿里云的OSS对象存储服务

对象存储,就可以把它当作文件存储服务使用,这个服务最近在搞推广,可能是新产品,或者新升级的产品。需要先创建一个存储桶,用来存放文件,里面的文件可以按目录文集存储,比如创建个文件夹,按类别存储文件。其实实际上OSS没有文件的存在的,所有的文件都是直接存储在存储桶里,只不过是给文件增加了路径的属性,这是关于OSS的内部实现,我们不需要关心,它能用就行。

1
2
3
4
5
6
7
ossMountConfig:  
mountPoints:
- bucketName: wechat-bucket
endpoint: http://oss-us-east-1-internal.aliyuncs.com
bucketPath: /
mountDir: /home/app
readOnly: false

如上这个配置,则是创建了一个名字是wechat-bucket的存储桶,把桶的/目录挂载到了服务器的/home/app下。这个其实就是一个路径映射,比如桶里有2个文件,一个是名字的文本文件,一个在users目录下有个头像图片,

1
2
wechat-bucket/name.txt
wechat-bucket/users/avatar.png

当在代码里读取这两个文件时,对应的路径就是:

1
2
/home/app/name.txt
/home/app/users/avatar.png

6. 腾讯云的内容审核服务

接入文本审核,我就打心底里有种感觉,照着腾讯的文档接腾讯的服务,这是一件折磨人的事。原因在于版本多,且不统一。

比如请求的Authorization的值的计算,因为每个接口都要用,所以它在通用文档里写了一份;因为文本审核、图片审核、视频审核等所有的审核服务都要用到,所以它又在审核部分的通用部分写了一份;因为文本审核自己用到了,然后它又在文本审核里单独写了一份;每个地方的版本都有差别,而且每个地方都在互相引用,这个中间值让参考这个链接里的方式,这个中间值又要参考那个链接;甚至它还说,请求可以有这个签名的值,也可以不带这个值;还有在线计算工具,还有示例代码,每个地方都是不一样的版本。它甚至还给了python版本的SDK,照着文档去调用SDK时,SDK报错,说不支持这种审核方式。

想说的太多太多了。最终的结果就是,但是接入这个文本审核的时间,远远超出了做其他事加在一起的总时间。调试阿里云的函数服务配置时,我还觉得阿里云的文档写的不好,等到接这个腾讯云的时候,我又觉得有点错怪阿里云了,起码它没让我反复反复试错文档的错误、排除文档中的不可行性。

其实要做的事再简单不过了,发起一个request,请求体就是需要审核的文本,接收一个response,获取审核的结果,通过或者不通过,仅此而已。

7. ChatGPT

相比其他,这算是最好接入的了,有SDK,有文档,照着文档操作,可以一步到位,没有过多可说的。

官方文档地址

它有2种常用的模式,一个叫做Completions,还有一个叫做Chat。Completions适应的场景就是一问一答,然后结束,没有上下文。而Chat则可以连续对话,上下文内容会影响它的回答。

因为需要满足理解上下文的需求,我这里使用的是Chat。

其实相比于Completions,Chat也没有多神奇,它不过是每次请求时,都带着所有的聊天记录,包括你问过的问题,以及它给出的答案。这就意味着,对话的回合数越多,请求体就会越大,而ChatGPT是按照字数收费的,这个字数包括问题的字数和回答的字数。

所以为了避免问完一个问题房子就没了的困境,我限制里每个提问里携带的历史记录,只带3组历史问答。而实际上,也没有必要带上所有的历史记录,一般只有最近的几个回答有实际的参考价值。

附录

微信测试号

微信公众号有不同类别,不同种类的号有不同的限制,有些接口只有认证过的号才能调用,认证一次要好几百,而且不同认证之间不通用,也就是说这个服务需要这个认证,那个服务需要那个认证,这个时候,微信就贴心的提供了测试号,这个账号可调用所有API,可使用所有服务,且没有限制,每个微信号可注册一个。
点击进入微信测试号

ChatGPT账号

ChatGPT的网页版和API接口虽然使用的是同一个账号,但其实这是两个独立的东西,所以这两个的Plus也是相互独立不通用的,充值网页版的plus则只能使用网页版的GPT4,要想API也用GPT4,就要想办法给账号绑定个信用卡,或者GooglePay之类的支付方式,这种方式叫做Pay As You Go,OpenAI的风控系统一直在不断调整,所以支付方式也需要随机应变。

还有一点,充值过的账号比没充值的更容易被封号,就像我的账号一直用了快半年了都相安无事,结果自打在淘宝上买了个网页版的plus之后,用了一个礼拜号就没了。

参考代码

https://github.com/oynix/wechat_gpt

------------- (完) -------------
  • 本文作者: oynix
  • 本文链接: https://oynix.com/2023/06/1e82fb7532f5/
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

欢迎关注我的其它发布渠道