关于chatGPT的上下文以及消耗

chatGPT 的表现出乎人的意料,很多人想把它用在日常工作中,因此我自己做了一层对接,可以让大家在没有特殊网络的情况下也可以使用:
https://chat.vacuity.me

本文主要是想记录一下对接过程中几个意外的点,方便大家了解。

上下文

大家都知道目前与 chatGPT 对话是有上下文的,比如:

你:中国的首都是哪里
chatGPT:中国的首都是北京。
你:日本的呢
chatGPT:日本的首都是东京。

第二句你只问了“日本的呢”,他通过上下文意识到你要问的是“日本的首都”。用过目前的智能语音助手的人就知道这个上下文有多么重要:他保证了对话的连续性。
那在和 gpt 对接中这个是怎么实现的呢,答案其实有点奇怪:把历史对话上传。
比如 A 代表你,B 代表 gpt ,发生了如下一段对话:
A:A1
B:B1
A:A2
B:B2
A:A3
B:B3
在每一次和 gpt 交互时,发送的数据都是一个列表,列表的每一项包含对话的内容和角色,比如
在A1时,发送过去的是:

[
  {"user": A1}
]

在A2时,发送过去的是:

[
  {"user": A1},
  {"assistant": B1},
  {"user": A2}
]

也就是说每次对话其实都重复发送了前面所有的对话历史

消耗

chatGPT 和其他的生成式 ai(比如 Google 的 Gemini )计算消耗用的都是 token 。token 可以理解为AI世界中的字数,关于token的计算有很多开源库可以实现,我目前用的java的一个库:
knuddelsgmbh/jtokkit: JTokkit is a Java tokenizer library designed for use with OpenAI models.

而且还有一点要注意的是gpt不仅对你发送的数据需要计费,对他回答的同样是需要计费的,比如上面的对话,
第一轮对话消耗:A1+B1
第二轮对话消耗:A1+B1+A2+B2,前两轮总消耗:(A1+B1)+ (A1+B1+A2+B2)
同理可算出这段对话的总消耗:
(A1+B1)+(A1+B1+A2+B2)+(A1+B1+A2+B2+A3+B3)

因此问和前面对话无关的新的问题时,最好新开一个对话,这样可以减少消耗,以及最大化的利用token限制。

模型对比

日常使用的时候,简单的问题其实 gpt3.5 和 gpt4 没有太大差别,但是遇到一些比较专业的问题或者逻辑性比较强的时候,gpt4 会比 gpt3.5 强很多。我也对接了一下 Google 的新模型 gemini-pro,目前来看和 gpt3.5 差不多,在一月份他们会发布 gemini-ultra,据说会对标 gpt4,可能会带来更好的效果。
还有一些国内的模型,我查看了一下他们的计费,发现普遍比 gpt 和 gemini 的高很多,同时效果又不会更好,因此就暂时没有进行对接了。

Assistant

我同时也对接了 openai 的 assistant,基本上就是gpts,可以在对话中传输文件,同时他会自己写函数以及调用函数,可以进行对话、读文档、生成文档等,功能还是比较强大的。但是由于目前 openai 还不支持 assistant 的流式传输,所以每次要等他生成完一个回答才能获取到回复内容,因此响应感觉起来会比较慢。