写个小程序版ChatGPT
通过OpenAI接口写一个小程序版ChatGPT
使用OpenAI接口通过微信小程序写一个小程序版本的ChatGPT,效果如下。
Linus说:Talk is cheap. Show me the code。下面简要说明开发的关键步骤以及需要注意的问题。
1.技术方案
针对开发类似Chat功能的微信小程序,选择合适的技术方案至关重要。其中,Web Socket 是一个良好的选择。当然,除了它,OpenAI接口也提供了通过HTTP实时传输数据到客户端的方式(Server-Sent Events 单向通信)。如果不使用微信小程序,而是打算开发原生手机应用,采用消息协议则更为稳妥。
2.服务设计
如上图所示,在OpenAI与小程序之间设计两个服务,一个是GPT服务,负责与OpenAI通信(务必确保服务器放置在能连接到OpenAI的地区),接受Prompt并返回模型输出;另一个是Socket服务,负责接收来自GPT服务的输出结果,并通过Websocket方式传输给小程序客户端。
将这两个服务分开的原因有两方面考虑:一方面是为了解耦,能够独立部署;另一方面,GPT服务未来可能会支持更多的下游服务请求。此外,微信小程序使用Socket服务需要域名备案,这类应用服务会涉及其他基础配置,与GPT服务分离能够避免混在一起。若两个服务写在一起,一旦其中一个遇到问题(例如备案),整个服务都将无法使用。
3.关键代码
对于GPT服务,OpenAI提供了NodeJS和Python的SDK,用这两种语言建立HTTP服务都相对简单。下面是NodeJS的示例

对话类的请求使用chat.completions接口,有两点需要注意。首先,建立stream方式时需要设置为true,这种流式输出对用户体验有很大帮助,特别是对于长文本输出,能避免用户长时间等待;其次,配合前面的设置,需要采用chunk方式循环输送。关于chunk,它是一个对象,包含了GPT输出的每个字(或几个字)及其附带的信息,如下图所示

GPT给出一段完整的输出是由这些对象组成的数组,首字和尾字的delta都是空,尾字的finish_reason值是stop,这些输出对于后续的客户端对接是有价值的。然而,在实际测试中,发现不使用这些附加信息同样能达到效果。比如,判断输出是否结束,可以通过请求是否完成来判断。因此,只需向Socket服务纯粹发送这些文字即可。Socket服务则更为简单,接收来自GPT服务的请求结果,并通过socket方式同步数据给客户端。如下图所示

这里构建了一些客户端需要的格式,同一组回复中的文字都带有相同的id,而最后一个字打上end=stop的标签。对于客户端,将每次接收到的socket服务同步的文字合并在一起。为了实现逐字显示的效果,将要显示的文字记录在state中进行累加。当输出结束时,调整页面滚动位置,如下图所示

4.问题注意
一般情况下,GPT服务和Socket服务会使用不同的域名,需要通过Nginx做代理转发。这里需要特别注意,GPT服务的Nginx代理一定要禁用缓存,否则由于服务器缓存,Socket服务可能无法接收到流式输出,仅能进行一次性输出。
虽然这些开发在技术上相对较简单,但更多的精力可能会放在产品用户体验上,调试过程大约耗费了2美分。

最近,OpenAI提供了Assistant API接口能力,这相当于Agent的能力,能够快速接入本地相关服务,比如本地知识库,下一篇文章将介绍这个新功能。