当启用 stream=true 的时候,以流响应,返回的数据大体如下:
data: {"id":"chatcmpl-6r3B875xFqmzK9lMm8sousVO3iBN4","object":"chat.completion.chunk","created":1678101622,"model":"gpt-3.5-turbo-0301","choices":[{"delta":{"role":"assistant"},"index":0,"finish_reason":nul
l}]}
data: {"id":"chatcmpl-6r3B875xFqmzK9lMm8sousVO3iBN4","object":"chat.completion.chunk","created":1678101622,"model":"gpt-3.5-turbo-0301","choices":[{"delta":{"content":"\n\n"},"index":0,"finish_reason":null}
]}
data: {"id":"chatcmpl-6r3B875xFqmzK9lMm8sousVO3iBN4","object":"chat.completion.chunk","created":1678101622,"model":"gpt-3.5-turbo-0301","choices":[{"delta":{"content":"作"},"index":0,"finish_reason":null}]}
data: {"id":"chatcmpl-6r3B875xFqmzK9lMm8sousVO3iBN4","object":"chat.completion.chunk","created":1678101622,"model":"gpt-3.5-turbo-0301","choices":[{"delta":{"content":"为"},"index":0,"finish_reason":null}]}
data: {"id":"chatcmpl-6r3B875xFqmzK9lMm8sousVO3iBN4","object":"chat.completion.chunk","created":1678101622,"model":"gpt-3.5-turbo-0301","choices":[{"delta":{"content":"一个"},"index":0,"finish_reason":null}}
...
data: [DONE]
每一个 event data 的 json 串,得到的 content 内容仅仅是一个字,看完真觉得浪费流量啊,是否我的调用方式不对呢?有其他的参数或调用方式来避免这种浪费吗?
1
string2020 2023-03-07 10:38:41 +08:00
流量要花钱?
|
2
brader OP @string2020 更多思考的是技术方面的东西,这样 API 的传输效率不好
|
3
orangie 2023-03-07 10:53:20 +08:00
传输效率不高,但是用户体验确实很好的,追求的是响应时间更短,而不是吞吐量更高,不过感觉其他的 id 和标记可以再简化一下,一个会话用一个简单的 id 。
|
4
string2020 2023-03-07 10:55:04 +08:00 1
api 提供商都不在乎的东西你个外人跑来在乎。有这功夫,优化下前端,帮用户省点磁盘内存
|
5
brader OP @string2020 这和我是相关的,我们并不想暴露 token 等敏感信息,不是由前端直接调用的 chatgpt ,中间有一层我们的服务端在代理,所以这情况同样会影响到我们服务端的带宽和响应时间
|
6
Kinnice 2023-03-07 11:05:46 +08:00
那关闭 stream 呗
|
7
ibegyourpardon 2023-03-07 11:06:11 +08:00 11
我认为恰恰是楼主想提供更好的方式和体验,才试图找到更好的方法来优化。
而不是像有的人说的很搞笑,花不花钱,提供商在不在乎。 |
8
ideacco 2023-03-07 11:07:00 +08:00
这可能是未来一段时间 AI 接口请求的基础“通病”了,因为之前的 ai 接口,不太依靠上下文,所以直接请求即可。而现在是非常依赖上下文的,那你怎么办?就是你想请求的问题,必须是在上线问基础上它才能回答的更好,SO ,现在有些大佬的方案是,每过一段时时间,对上面的问题进行总结(同样使用 gpt 接口)。然后删掉旧的上下文,使用总结后的上下文继续请求。
另外需要 API 接口这边做一些中间件,比如把会话内容存在数据库中,然后前端用的时候可以中间插入或修改某些回话,就像 GPT 网页端做的那样。 |
9
tool2d 2023-03-07 11:11:50 +08:00
我昨天还想发帖来着,就是很浪费流量。
关键点还不是 data:这种格式,因为这种格式不是 openai 发明的,而是 firefox 发明的。 而是 openai 服务器,无法进行任何的压缩传输!!我试了所有的压缩方法,都没有能开启文本压缩功能( content-encoding 始终不生效)。 |
10
locoz 2023-03-07 11:18:04 +08:00
当时抓包看到这返回方式的时候就感觉很蠢...明明可以分开两部分传输,却非要放在一个 json 里返回,导致流量浪费极大。只能说做术业有专攻,做 AI 的并不懂后端和网络。
|
11
brader OP @Kinnice 经测试,关闭 stream ,在提问某些问题的时候,AI 思考需要的时间太久了,响应的 20s 以上,我想用户是无法等待的
|
12
brader OP @ideacco 这里我讨论的不是上下文的问题,请求入参传递的 messages 数组上下文对话,才是你说的东西。
这里质疑的是它的响应报文,该响应报文是单次回答的,只是流式响应的时候,拆分后数据格式太臃肿 |
13
zhang77555 2023-03-07 11:38:37 +08:00 via Android
就是原 API 返回的字符串结果改成了用 stream 返回,方便实现前端单个字吐出来的效果,我做 demo 的时候也是这么干的😂
|
14
string2020 2023-03-07 12:01:37 +08:00
离谱。大兄弟,传送 10b 和传送 100b 的响应时间差别有多大 有测试过?
|
15
string2020 2023-03-07 12:03:13 +08:00
服务端的带宽,我想知道你们服务端最大带宽是多少,平常用到了 1%没有?
|
16
brader OP @string2020 作为一个 5 年以上的服务端开发人员,虽然我的大部分菱角和追求都被磨灭了,但我依然很不认可你的这个心态。
一个有一定发展历史的系统,它的 API 接口非常多,不仅仅只这一个,如果每一个接手项目的人,做东西的心态都是:这个接口 100ms 和 150ms 的响应时间有什么区别,没关系、不理他。系统多年堆积下来,整体的响应时间、并发率,是非常堪忧的 |
17
8520ccc 2023-03-07 12:10:46 +08:00 via iPhone
宽带影响不大吧,自己二次开发一下,然后减少返回的信息就行
|
19
brader OP @8520ccc 目前我也是有这方面的想法,就是服务端似乎很少有像 js 解析 Event stream format 数据的扩展包,正打算自己写一个解析工具
|
20
brader OP @lambdaq 我认可这种一字一字输出的行为的,我意思是它的 API 设计,在流传输的时候,传一个字过来,附带大量其它臃肿的信息
|
21
youthfire 2023-03-07 12:25:05 +08:00
我昨天也在看这个 stream ,发现比非流式慢很多。
以下理解不知道对不对: 按照官方说法,free-20RPM,credit card (48hrs)-60RPM,credit card (aft 48hrs)-3500RPM 我现在理解是 60RPM 相当于 1s 吐一个字呗,因为它一次请求就返回一个字的内容。非流式只有在 3500RPM 才有实用价值吧。 问 ai ,它解释非流式默认 600RPM ,那的确就是必须绑卡 48 小时后才有实用价值,否则还不如老老实实非流式了。 另外我想说,stream=True 返回的是生成器,不加应该直接可以用 response['choices'][0]['message']['content'].strip(),但是我发现设定 stream=False 返回的也是生成器,不能取值,不知道是不是我方法不对,第一次接触这类。 |
22
tool2d 2023-03-07 12:26:49 +08:00
@brader 其实不臃肿,你试一下用 gzip 流式压缩这些重复字符串,
我这里 60k 左右的文本数据回答,可以压缩到 2k 之内。 就是 openai 把这项特性关了,只打开了 chunk 传输,贼讨厌。 |
23
tool2d 2023-03-07 13:05:59 +08:00
我又想了一下。
既然 openai 在 http 协议上不支持压缩( accept-encoding: gzip, deflate, br ),那么干脆换个思路,让 openai 用 HTTPS 代理文本内容的时候,用 SSL 开启压缩功能(HANDSHAKE_SERVER_HELLO 里的 compression flag)就可以了。 这样 openai 的服务器代码,也可以不需要改动。 |
24
string2020 2023-03-07 13:06:34 +08:00
装个锤子,正常开发人员都会知道带宽根本没影响。
你自己一点测试都不做,凭空优化(不,你根本优化不了。api 的代码你都控制不了。凭空要求 openai 优化)。 最好的情况是,openai 帮你做了优化。 最后响应时间从 100ms 优化到了 100ms 。带宽从 1%占用优化到了 1%占用。 你浪费了大家时间。 |
25
otakustay 2023-03-07 13:08:43 +08:00
楼主的意思是用 stream 是好的,但没必要 stream 里每一份 data 都包一个 json ,可以每个 data 就一个内容字符串就行了
我是认同楼主的想法的,json 重复内容太多了 |
26
tool2d 2023-03-07 13:10:29 +08:00 1
|
28
string2020 2023-03-07 13:19:31 +08:00
离大谱。想到了,父母让女儿找富二代的笑话。
|
29
xingjue 2023-03-07 13:35:15 +08:00
离大谱。想到了,父母让女儿找富二代的笑话。
|
30
vishun 2023-03-07 15:05:24 +08:00
@string2020 #24 ?? 我都怀疑你是否是开发人员了?又不是只有一个用户在访问,怎么可能没有影响?
|
31
dobelee 2023-03-07 15:17:38 +08:00
可以理解为元数据。做成长连接也得有基础协议的元数据。
|
32
string2020 2023-03-07 15:21:03 +08:00
@vishun 什么东西。这里说的带宽是指什么你懂吗?
|
33
vishun 2023-03-07 16:53:37 +08:00
@string2020 #32 说下指什么?
|
34
string2020 2023-03-07 17:05:17 +08:00
@vishun 这里说的是楼主的服务器和 openai 之间的下行带宽,和用户关系在哪?
|
35
wqhui 2023-03-07 17:42:12 +08:00
像极了人,人说话也是一个字一个字的说(doge
|
36
wtfedc 2023-03-07 17:52:49 +08:00
@string2020 如果有 1000k 的用户同时用,中间做日志存储,如果再有实时分析,怎么可能 IO 没影响。带宽不是问题,你这意思是不够用就加硬件呗,反正不是自己花钱。程序员要都是你这想法,淘宝 JD 都不一定能开起来。
|
37
string2020 2023-03-07 17:57:44 +08:00
大兄弟。在这个提问中,用户就只有楼主自己,占用的带宽是服务器的下行带宽,下行带宽一般情况下免费的 1%都不会用到。你该不会是在为 openai 考虑吧?
|
38
yuezk 2023-03-07 18:01:54 +08:00
你如果抓一下 ChatGPT 的接口,你会发现每个 data 都会重复前面的内容,还不如 OpenAI 的接口省带宽。
``` event: add id: 1 data: {"message":{"id":"chatcmpl-6rOOU6qBvhphYF8aL0Rw1VMitV5U8","role":"assistant","user":null,"create_time":null,"update_time":null,"end_turn":null,"weight":0,"recipient":"all","metadata":null,"content":{"content_type":"text","parts":["I"]}},"error":null} event: add id: 2 data: {"message":{"id":"chatcmpl-6rOOU6qBvhphYF8aL0Rw1VMitV5U8","role":"assistant","user":null,"create_time":null,"update_time":null,"end_turn":null,"weight":0,"recipient":"all","metadata":null,"content":{"content_type":"text","parts":["I'm"]}},"error":null} event: add id: 3 data: {"message":{"id":"chatcmpl-6rOOU6qBvhphYF8aL0Rw1VMitV5U8","role":"assistant","user":null,"create_time":null,"update_time":null,"end_turn":null,"weight":0,"recipient":"all","metadata":null,"content":{"content_type":"text","parts":["I'm sorry"]}},"error":null} event: add id: 4 data: {"message":{"id":"chatcmpl-6rOOU6qBvhphYF8aL0Rw1VMitV5U8","role":"assistant","user":null,"create_time":null,"update_time":null,"end_turn":null,"weight":0,"recipient":"all","metadata":null,"content":{"content_type":"text","parts":["I'm sorry,"]}},"error":null} event: add id: 5 data: {"message":{"id":"chatcmpl-6rOOU6qBvhphYF8aL0Rw1VMitV5U8","role":"assistant","user":null,"create_time":null,"update_time":null,"end_turn":null,"weight":0,"recipient":"all","metadata":null,"content":{"content_type":"text","parts":["I'm sorry, I"]}},"error":null} event: add id: 6 data: {"message":{"id":"chatcmpl-6rOOU6qBvhphYF8aL0Rw1VMitV5U8","role":"assistant","user":null,"create_time":null,"update_time":null,"end_turn":null,"weight":0,"recipient":"all","metadata":null,"content":{"content_type":"text","parts":["I'm sorry, I'm"]}},"error":null} ``` |
39
string2020 2023-03-07 18:04:51 +08:00
(带宽费用)[!https://imgur.com/HT9oEzk]
|
40
string2020 2023-03-07 18:15:03 +08:00
阿里云都是免费的,不知道要省啥
|
41
UIXX 2023-03-07 18:32:54 +08:00
OP 的问题可以总结为:能否省略或者压缩流式响应中的元数据。
我的看法倾向于 8L 的观点,这个接口输出被设计成通用性更强、结构更明显的 chunk 形式,方便调用者直接使用。将其他形式的输出实现交给二次开发者。 |
42
zhwithsweet 2023-03-07 18:53:01 +08:00
支持 event source / SSE 的接口是这样的,写得时候图省事,直接把数据体写到 response 里边,出来必要的 { event, id data, retry } 别的感觉是能够压缩
|
43
neotheone2333 2023-03-07 21:57:42 +08:00
楼主想要的应该是类似 pb 的那种形式
上面有的人可能没用过除了 JSON 以外的数据交换格式 |
44
byzod 2023-03-07 23:50:32 +08:00
虽然但是,ai 答复的后端资源需求是非常高的,传输带宽只是流程上一个优先级非常低的环节,大概率不是性能热点
正经程序员也不会在业务逻辑耗时 2000ms 的时候扭头去想办法把 parser 的时间从 2.5ms 优化到 1ms 吧,虽然这是 60%的性能提升——对于这个环节来说 |
45
iseki 2023-03-08 00:07:52 +08:00 via Android
但是这样的 API 对接起来容易
|
46
iseki 2023-03-08 00:13:33 +08:00 via Android
楼主的关注点可能是每个条目都包含了重复的信息,id object 什么的…只能说优化这个挺麻烦,得在现在这种简单的模式基础上再包装一层了
|
47
superares 2023-03-08 08:22:00 +08:00 via iPhone
有没有可能一个流就是一个 token ?
|
48
vinciarts 2023-03-08 09:22:40 +08:00 via Android
弱弱的问一下,为什么要自己服务器转发,而不是直出啊?
|
49
conn4575 2023-03-08 13:34:39 +08:00 via Android
我觉得 websocket 才是解决方案
|