GPT3.5 改用 GPT4 价格翻了30倍 如何破局? GPT 对话成本推演

场景介绍

假设你搭建了一个平台,提供 ChatGPT 3.5 的聊天服务。目前已经有一批用户的使用数据,想要测算一下如果更换 GPT 4.0 服务需要多少成本?

方案阐述

如果是全切,最简单粗暴的方案就是根据提供 ChatGPT 3.5 消费的金额乘以一个倍数,这个倍数是 GPT 4 的单格/ChatGPT 3.5 的单价,不过由于输入价和输出价有差异,所以会有一定误差,但不影响全量切换的大致判断。

如果要求更精确一些,就需要根据每一次问答的输入 Token 数和输出 Token 数,分别求和,计算有多少 k Tokens,然后算一个占比,看看各自的消费占比,分别乘以输入和输出的价格倍数。
image.png
以上是直接接官方的情况,但是更多时候,可能是通过第三方服务,第三方的价格不是根据官方定价,会有出入,需要结合第三方价格具体分析。

由于 GPT 4.0 相对高昂的价格,一般需要做限制,比如:限制访问频率、限制整体用量等。
举个例子,限制每分钟不超过 3 次,每 3 小时不超过 50 次;每天 10 次,每月 100次、200 次等。
这时候就需要精确一些的计算,通过指定的算法,测算切换 GPT 4.0 的成本是多少。

本次用于示例计算的单价为:

ModelInputOutput
gpt-4$0.03 / 1K tokens$0.06 / 1K tokens
gpt-3.5-turbo-1106$0.0010 / 1K tokens$0.0020 / 1K tokens

本次拿两个限制做案例开展:

  • 案例1:限制每天 10 次
  • 案例2:限制每分钟不超过 3 次,每 3 小时不超过 50 次

创建测试数据

本次测试借助数据库 MySQL 来实现这些复杂的算法。
首先在本地创建数据库testdb

create database if not exists testdb;

创建表chat_logs,并给四个字段都加上索引,提高查询效率:

create table if not exists testdb.chat_logs(
	user_id					bigint	comment '用户ID'
  ,request_time		bigint	comment '请求时间'
  ,prompt_tokens	bigint	comment '提示词的 Tokens,input Tokens'
  ,output_tokens	bigint	comment '回答的 Tokens,output Tokens'
  ,index userid_idx(user_id)
  ,index reqtime_idx(request_time)
  ,index prompt_idx(prompt_tokens)
  ,index output_idx(output_tokens)
) comment 'GPT对话记录';

插入数据,本次demo 数据量 100 条。

由于数据较长,不便展示,另外上传到资源,可前往免费下载:GPT 对话成本推演-数据demo

插入数据方法

  • 方法1:复制代码,接着上面步骤粘贴代码,回车即可执行
  • 方法2:直接执行文件,假设文件路径为:D:\insert_into_table.sql,则执行命令如下:
SOURCE D:\insert_into_table.sql;

案例1:限制每天 10 次(总量限制)

该逻辑实现比较简单,按天聚合,然后排序计算不超过 10 有多少 Tokens,大于 10 次又有多少 Tokens,然后再分别乘以单价,计算得出限制后的成本。

使用 SQL 实现

查看每天限制 10 次 GPT 4.0,超过部分按 GPT 3.5 计算,需要先将请求的数据按天进行排序,然后计算不超过 10 的部分和大于 10 的分别的 Tokens 分别是多少。

格式化时间,将request_time转为request_date

-- 格式化时间
select user_id,from_unixtime(request_time,'%Y-%m-%d') request_date,request_time,prompt_tokens,output_tokens
from testdb.chat_logs

按天编号

with chat_logs_format as(
  -- 格式化时间
  select user_id,from_unixtime(request_time,'%Y-%m-%d') request_date,request_time,prompt_tokens,output_tokens
  from testdb.chat_logs
)
-- 对话排序
select *,row_number()over(partition by user_id,request_date order by request_time) req_sort
from chat_logs_format

分类求 Tokens 数,编号req_sort不超过 10 次的分为GPT4,其他分为GPT3.5

with chat_logs_format as(
  -- 格式化时间
  select user_id,from_unixtime(request_time,'%Y-%m-%d') request_date,request_time,prompt_tokens,output_tokens
  from testdb.chat_logs
)
,chat_sort as(
  -- 对话排序
  select user_id,request_date,prompt_tokens,output_tokens
  		,row_number()over(partition by user_id,request_date order by request_time) req_sort
  from chat_logs_format
)
-- 分类求 Tokens 数
select if(req_sort<=10,'GPT4','GPT3.5') mark_model
  ,sum(prompt_tokens)/1000 k_prompt_tokens
  ,sum(output_tokens)/1000 k_output_tokens
from chat_sort
group by mark_model

image.png

根据 Tokens 计算成本。

with chat_logs_format as(
  -- 格式化时间
  select user_id,from_unixtime(request_time,'%Y-%m-%d') request_date,request_time,prompt_tokens,output_tokens
  from testdb.chat_logs
)
,chat_sort as(
  -- 对话排序
  select user_id,request_date,prompt_tokens,output_tokens
  		,row_number()over(partition by user_id,request_date order by request_time) req_sort
  from chat_logs_format
)
,k_tokens as(
  -- 分类求 Tokens 数
  select if(req_sort<=10,'GPT4','GPT3.5') mark_model
  	,sum(prompt_tokens)/1000 k_input_tokens
    ,sum(output_tokens)/1000 k_output_tokens
  from chat_sort
  group by mark_model
)
-- gpt-4:input 0.03,output 0.06
-- gpt-3:input 0.0010,output 0.0020
select sum(0.0010*k_input_tokens+0.0020*k_output_tokens) "调整前成本"
	,sum(if(mark_model='GPT4',0.03,0.0010)*k_input_tokens+if(mark_model='GPT4',0.06,0.0020)*k_output_tokens) "调整后成本"
from k_tokens

image.png
调整前后成本相差还是挺大的,调整后成本是调整前的 12.5 倍。实际情况可以拿更多的数据,比如说一周、一个月,进行测算。

使用 Python 实现

使用 Python 实现比 SQL 实现多加了一步:读取数据,并转化为数组。之后的逻辑也是大同小异:时间格式化->记录排序、编号->分类求 Token->计算成本。

读取数据表,使用sql读取数据库数据,并使用 Pandas 转为 DataFrame。

import pandas as pd
from sqlalchemy import create_engine
def get_datas(sql):
    # 连接数据库
    # engine = create_engine("mysql+pymysql://用户名:密码@主机地址:端口号/数据库名")
    connect_info = 'mysql+pymysql://{}:{}@{}:{}/{}?charset=utf8'\
    .format("root", "123123", "127.1.1.0", "3306","testdb")
    engine = create_engine(connect_info)
    # 执行SQL语句
    prox = engine.execute(sql)
    df = pd.DataFrame(list(prox),columns=prox.keys())
    return df
sql = 'select * from testdb.chat_logs'
df = get_datas(sql)

image.png

将时间戳格式化

#将 request_time 转为日期格式
df['request_date'] = pd.to_datetime(df.request_time,unit='s').dt.date

排序编号

df['req_sort'] = df.groupby(['user_id','request_date'])['request_time'].rank(ascending=True,method='first')

分类,编号req_sort不超过 10 次的分为GPT4,其他分为GPT3.5

df['mark_model'] = df.req_sort.apply(lambda x:'GPT4' if x<=10 else 'GPT3.5')

求和,并转化为 k Token 单位

df_1 = df.groupby(['mark_model'])['prompt_tokens','output_tokens'].sum().reset_index()
df_1['k_input_tokens'] = df_1.prompt_tokens/1000
df_1['k_output_tokens'] = df_1.output_tokens/1000
df_1[['mark_model','k_input_tokens','k_output_tokens']]

image.png
计算成本

-- gpt-4input 0.03,output 0.06
-- gpt-3input 0.0010,output 0.0020
input_price_4 = 0.03
input_price_3 = 0.0010
output_price_4 = 0.06
output_price_3 = 0.0020
df_1['调整前成本'] = df_1[['mark_model','k_input_tokens','k_output_tokens']].apply(lambda x:x[1]*input_price_3+x[2]*output_price_3,axis=1)
df_1['调整后成本'] = df_1[['mark_model','k_input_tokens','k_output_tokens']].apply(lambda x:x[1]*input_price_4+x[2]*output_price_4 if x[0]=='GPT4' else x[1]*input_price_3+x[2]*output_price_3,axis=1)
df_1[['调整前成本','调整后成本']].sum()

image.png

案例2:限制每分钟不超过 3 次,每 3 小时不超过 50 次(频率限制)

该逻辑实现比较复杂一些,本质上还是先切分,然后排序再进行统计 Tokens,再计算成本。
不同点在于,前面是按天切分,有天然的便捷方式,直接格式化即可,每天看做一个桶,分桶计算,而 1 分钟和 3 小时需要自行构建相关的计算桶,不能一步到位。

过程算法其实也有多种:
比如说按自然分钟计算,每分钟为一个单位;按自然小时计算,02、35、68、911、1214、1517、1820、2123。
比如说拿一个初始的值做差值计算,然后在这个基础上分割,这个会受到初始值的影响,不过如果把初始值设置为某一天的零时零点零分,可以兼容上面一个算法,本次拿第二种来展开。

PS:实现第一种的方法:1分钟分桶:from_unixtime(request_time,’%Y-%m-%d %H:%i’);3小时分桶(日期+小时):from_unixtime(request_time,’%Y-%m-%d’)、floor(hour(from_unixtime(request_time)/3)

使用 SQL 实现

取最小时间,使用窗口函数来取值。如果是想设置固定的某个值,可以直接新增一个列。

-- 取最小的请求时间,
select user_id,request_time,prompt_tokens,output_tokens
	,min(request_time)over(partition by user_id) min_time
from chat_logs

求时间差值,使用request_time减去最小值。

-- 取时间差值
select user_id,request_time,prompt_tokens,output_tokens
  ,request_time-min(request_time)over(partition by user_id) minute_diff
from chat_logs

分桶,1 分钟则除以 60 秒,3 小时则除以 60603 秒,然后使用ceil()函数向上取值。

-- 分桶
select user_id,request_time,prompt_tokens,output_tokens
	,ceil((request_time-min(request_time)over(partition by user_id))/60) minute_bucket
  ,ceil((request_time-min(request_time)over(partition by user_id))/60/60/3) hour_bucket
from chat_logs

排序,根据用户和分桶字段进行分组,然后对request_time升序排序

with 
-- 分桶
cut_bucket as(
  select user_id,request_time,prompt_tokens,output_tokens
    ,ceil((request_time-min(request_time)over(partition by user_id))/60) minute_bucket
    ,ceil((request_time-min(request_time)over(partition by user_id))/60/60/3) hour_bucket
  from chat_logs
)
-- 排序
select user_id,request_time,prompt_tokens,output_tokens,minute_bucket,hour_bucket
    ,row_number()over(partition by user_id,minute_bucket order by request_time) minute_bucket_sort
    ,row_number()over(partition by user_id,hour_bucket order by request_time) hour_bucket_sort
from cut_bucket

分类求和,将minute_bucket_sort<=3 and hour_bucket_sort<=50分为GPT4,其他的分为GPT3.5,然后聚合求 Tokens。

with
-- 分桶
cut_bucket as(
  select user_id,request_time,prompt_tokens,output_tokens,ceil((request_time-min(request_time)over(partition by user_id))/60) minute_bucket
    ,ceil((request_time-min(request_time)over(partition by user_id))/60/60/3) hour_bucket
  from chat_logs
)
-- 排序
,bucket_sort as(
  select user_id,request_time,prompt_tokens,output_tokens,minute_bucket,hour_bucket
      ,row_number()over(partition by user_id,minute_bucket order by request_time) minute_bucket_sort
      ,row_number()over(partition by user_id,hour_bucket order by request_time) hour_bucket_sort
  from cut_bucket
)
-- 分类
,mark_models as(
  select user_id,request_time,prompt_tokens,output_tokens,minute_bucket,hour_bucket,minute_bucket_sort,hour_bucket_sort
  	,(case when minute_bucket_sort<=3 and hour_bucket_sort<=50 then 'GPT4' else 'GPT3.5' end) mark_model
  from bucket_sort
)
-- 计算分钟<=3且3小时<=50
select mark_model
	,sum(prompt_tokens)/1000 k_input_tokens
  ,sum(output_tokens)/1000 k_output_tokens
from mark_models
group by mark_model

image.png
然后再计算成本,完事!
直接计算minute_bucket_sort<=3hour_bucket_sort<=50就可以了?
不不不!这里有坑,先不聚合,查看明细数据看看,如下图第一个红框,它不符合 1 分钟 3 次上限的逻辑,所以被剔除了,标记为 GPT3.5。而第二个框,它不符合 3 小时 50 次上限的逻辑,所以也被剔除了。
不知道你是否意识到了问题,通过肉眼看,第二个框的 3 条记录应该是要被统计到 3 小时 50 次上限的逻辑的,因为前面因为 1 分钟的限制多剔除了 3 条记录。
所以在 3 小时的桶里面排序的时候,需要建立 1 分钟的桶的基础之上,先保证每一条记录都符合 1 分钟的逻辑,再针对这些记录拿 3 小时的逻辑加以限制。
image.png
修改 3 小时的分桶排序逻辑,要建立在 1 分钟的基础上才开始排序。
新增一个步骤,对 1 分钟的桶不超过 3 次的部分和大于 3 次的部分进行分类。然后对 3 小时的分桶排序则建在 1 分钟不超过 3 次的类别上。
代码实现上,将 1 分钟不超过 3 次和大于 3 次的分类(mark_target_record)加入 3 小时的分桶排序的分组(partition by)中,然后限制只取mark_target_record=1部分作为GPT4,参考修改逻辑如下:

with 
-- 分桶
cut_bucket as(
  select user_id,request_time,prompt_tokens,output_tokens,ceil((request_time-min(request_time)over(partition by user_id))/60) minute_bucket
    ,ceil((request_time-min(request_time)over(partition by user_id))/60/60/3) hour_bucket
  from chat_logs
)
-- 排序
,bucket_sort as(
  select user_id,request_time,prompt_tokens,output_tokens,minute_bucket,hour_bucket
      ,row_number()over(partition by user_id,minute_bucket order by request_time) minute_bucket_sort
      ,row_number()over(partition by user_id,hour_bucket order by request_time) hour_bucket_sort
  from cut_bucket
)
-- 对分钟的排序数据进行分类
,mark_chatlog as(
  select user_id,request_time,prompt_tokens,output_tokens,minute_bucket,hour_bucket,minute_bucket_sort,hour_bucket_sort
    ,(case when minute_bucket_sort<=3 then 1 else 0 end) mark_target_record
  from bucket_sort
)
-- 分钟 <= 3 且 3小时 <= 50 标记为 GPT4
,mark_models as(
  select user_id,request_time,prompt_tokens,output_tokens,minute_bucket,hour_bucket,minute_bucket_sort,hour_bucket_sort,mark_target_record
    ,(case when mark_target_record=1 and row_number() over(partition by user_id,hour_bucket,mark_target_record order by request_time)<=50 then 'GPT4' else 'GPT3.5' end) mark_model
  from mark_chatlog
)
select *
from mark_models
order by user_id,request_time

修改为叠加的逻辑之后,效果如下:
image.png

计算 Token 数,根据分好的模型聚合求和即可。

with 
-- 分桶
cut_bucket as(
  select user_id,request_time,prompt_tokens,output_tokens,ceil((request_time-min(request_time)over(partition by user_id))/60) minute_bucket
    ,ceil((request_time-min(request_time)over(partition by user_id))/60/60/3) hour_bucket
  from chat_logs
)
-- 排序
,bucket_sort as(
  select user_id,request_time,prompt_tokens,output_tokens,minute_bucket,hour_bucket
      ,row_number()over(partition by user_id,minute_bucket order by request_time) minute_bucket_sort
      ,row_number()over(partition by user_id,hour_bucket order by request_time) hour_bucket_sort
  from cut_bucket
)
-- 对分钟的排序数据进行分类
,mark_chatlog as(
  select user_id,request_time,prompt_tokens,output_tokens,minute_bucket,hour_bucket,minute_bucket_sort,hour_bucket_sort
    ,(case when minute_bucket_sort<=3 then 1 else 0 end) mark_target_record
  from bucket_sort
)
-- 分钟 <= 3 且 3小时 <= 50 标记为 GPT4
,mark_models as(
  select user_id,request_time,prompt_tokens,output_tokens,minute_bucket,hour_bucket,minute_bucket_sort,hour_bucket_sort,mark_target_record
    ,(case when mark_target_record=1 and row_number() over(partition by user_id,hour_bucket,mark_target_record order by request_time)<=50 then 'GPT4' else 'GPT3.5' end) mark_model
  from mark_chatlog
)
-- 聚合求 Tokens
select mark_model
	,sum(prompt_tokens)/1000 k_input_tokens
  ,sum(output_tokens)/1000 k_output_tokens
from mark_models
group by mark_model

统计结果如下:
image.png
计算调整前后成本:

with 
-- 分桶
cut_bucket as(
  select user_id,request_time,prompt_tokens,output_tokens,ceil((request_time-min(request_time)over(partition by user_id))/60) minute_bucket
    ,ceil((request_time-min(request_time)over(partition by user_id))/60/60/3) hour_bucket
  from chat_logs
)
-- 排序
,bucket_sort as(
  select user_id,request_time,prompt_tokens,output_tokens,minute_bucket,hour_bucket
      ,row_number()over(partition by user_id,minute_bucket order by request_time) minute_bucket_sort
      ,row_number()over(partition by user_id,hour_bucket order by request_time) hour_bucket_sort
  from cut_bucket
)
-- 对分钟的排序数据进行分类
,mark_chatlog as(
  select user_id,request_time,prompt_tokens,output_tokens,minute_bucket,hour_bucket,minute_bucket_sort,hour_bucket_sort
    ,(case when minute_bucket_sort<=3 then 1 else 0 end) mark_target_record
  from bucket_sort
)
-- 分钟 <= 3 且 3小时 <= 50 标记为 GPT4
,mark_models as(
  select user_id,request_time,prompt_tokens,output_tokens,minute_bucket,hour_bucket,minute_bucket_sort,hour_bucket_sort,mark_target_record
    ,(case when mark_target_record=1 and row_number() over(partition by user_id,hour_bucket,mark_target_record order by request_time)<=50 then 'GPT4' else 'GPT3.5' end) mark_model
  from mark_chatlog
)
-- 聚合求 Tokens
,k_tokens as(
  select mark_model,sum(prompt_tokens)/1000 k_input_tokens,sum(output_tokens)/1000 k_output_tokens
  from mark_models
  group by mark_model
)
-- gpt-4:input 0.03,output 0.06
-- gpt-3:input 0.0010,output 0.0020
select sum(0.0010*k_input_tokens+0.0020*k_output_tokens) "调整前成本"
	,sum(if(mark_model='GPT4',0.03,0.0010)*k_input_tokens+if(mark_model='GPT4',0.06,0.0020)*k_output_tokens) "调整后成本"
from k_tokens

统计结果如下:
image.png
调整前后成本相差 27 倍。

使用 Python 实现

同样,使用 Python 实现比 SQL 实现多加了一步:读取数据,并转化为数组。之后的逻辑也是大同小异:求最小时间->求时间差值->分桶->1分钟排序和分类->3 小时排序和最终分类->分类求 Token->计算成本。

读取数据表,使用sql读取数据库数据,并使用 Pandas 转为 DataFrame。

import pandas as pd
from sqlalchemy import create_engine
def get_datas(sql):
    # 连接数据库
    # engine = create_engine("mysql+pymysql://用户名:密码@主机地址:端口号/数据库名")
    connect_info = 'mysql+pymysql://{}:{}@{}:{}/{}?charset=utf8'\
    .format("root", "123123", "127.1.1.0", "3306","testdb")
    engine = create_engine(connect_info)
    # 执行SQL语句
    prox = engine.execute(sql)
    df = pd.DataFrame(list(prox),columns=prox.keys())
    return df
sql = 'select * from testdb.chat_logs'
df = get_datas(sql)

取最小请求时间,并合并到原来的数据框。

#取每个key的最小请求时间
df_mintime = df.groupby(['user_id'])['request_time'].min().reset_index()
#合并到原DataFrame
df = df.merge(df_mintime,on='user_id',how='left',suffixes=['','_min'])

将请求时间和最小请求时间求差值。

#将请求时间和最小请求时间求差值;  
df['diff_time'] = df.request_time-df.request_time_min

分桶,保持单位一致,即 1 分钟转为 60 秒,3 小时转为 60603 秒。
使用math.ceil()向上取整。

#根据差值进行分桶,两层:1 分钟 和 3 小时,都向上取整数; 
import math
df['minute_bucket'] = df.diff_time.apply(lambda x:math.ceil(x/60))
df['hour_bucket'] = df.diff_time.apply(lambda x:math.ceil(x/60/60/3))

对 1 分钟的桶排序和分类:不超过 3 次的为一类用 1 标识,其他的为另外一类,用 0 表示。

#对 1 分钟的桶和 user_id 分组,按请求时间排序; 
df['minute_bucket_sort'] = df.groupby(['user_id','minute_bucket'])['request_time'].rank(ascending=True,method='first')
#对 1 分钟不超过 3 次和大于 3 次的部分进行分组
df['mark_target_record'] = df.minute_bucket_sort.apply(lambda x:1 if x<=3 else 0)

3 小时的桶排序,根据用户、分桶和 1 分钟的分类进行分组,按请求时间排序。

#3小时的桶排序
df['hour_bucket_sort'] = df.groupby(['user_id','hour_bucket','mark_target_record'])['request_time'].rank(ascending=True,method='first')

最终分类:minute_bucket_sort<=3,且hour_bucket_sort<=50为 GPT4,其他为 GPT3.5。

#最终分类
df['mark_model']  = df[['minute_bucket_sort','hour_bucket_sort']].apply(lambda x:'GPT4' if x[0]<=3 and x[1]<=50 else 'GPT3.5',axis=1)

分类聚合求 Tokens

#按请求日期和模型聚合,统计Tokens 和价格
df_1 = df.groupby(['mark_model'])['prompt_tokens','output_tokens'].sum().reset_index()
df_1['k_input_tokens'] = df_1.prompt_tokens/1000
df_1['k_output_tokens'] = df_1.output_tokens/1000
df_1[['mark_model','k_input_tokens','k_output_tokens']]

结果如下,再除以 1000 就是上面 SQL 的结果。
image.png

求最终调整前后成本

#求调整前后成本
#gpt-4:input 0.03,output 0.06
#gpt-3:input 0.0010,output 0.0020
input_price_4 = 0.03
input_price_3 = 0.0010
output_price_4 = 0.06
output_price_3 = 0.0020
df_1['调整前成本'] = df_1[['mark_model','k_input_tokens','k_output_tokens']].apply(lambda x:x[1]*input_price_3+x[2]*output_price_3,axis=1)
df_1['调整后成本'] = df_1[['mark_model','k_input_tokens','k_output_tokens']].apply(lambda x:x[1]*input_price_4+x[2]*output_price_4 if x[0]=='GPT4' else x[1]*input_price_3+x[2]*output_price_3,axis=1)
df_1[['调整前成本','调整后成本']].sum()

image.png

Python 完整代码:

import pandas as pd
from sqlalchemy import create_engine

#连接数据库读取数据,并转为 DataFrame
def get_datas(sql):
    # 连接数据库
    # engine = create_engine("mysql+pymysql://用户名:密码@主机地址:端口号/数据库名")
    connect_info = 'mysql+pymysql://{}:{}@{}:{}/{}?charset=utf8'\
    .format("root", "123123", "127.1.1.0", "3306","testdb")
    engine = create_engine(connect_info)
    # 执行SQL语句
    prox = engine.execute(sql)

    data = list()
    for result in prox:
        cur = dict()
        #     print(result)
        for k, v in result._mapping.items(): # 不用 _mapping 也可以,后续会被弃用而已
            cur[k] = v
        data.append(cur)
    df = pd.DataFrame(data)
    return df
sql = 'select * from testdb.chat_logs'
df = get_datas(sql)

#取每个key的最小请求时间
df_mintime = df.groupby(['user_id'])['request_time'].min().reset_index()
#合并到原DataFrame
df = df.merge(df_mintime,on='user_id',how='left',suffixes=['','_min'])

#将请求时间和最小请求时间求差值;  
df['diff_time'] = df.request_time-df.request_time_min

#根据差值进行分桶,两层:1 分钟 和 3 小时,都向上取整数; 
import math
df['minute_bucket'] = df.diff_time.apply(lambda x:math.ceil(x/60))
df['hour_bucket'] = df.diff_time.apply(lambda x:math.ceil(x/60/60/3))

#对 1 分钟的桶和 user_id 分组,按请求时间排序; 
df['minute_bucket_sort'] = df.groupby(['user_id','minute_bucket'])['request_time'].rank(ascending=True,method='first')
#对 1 分钟不超过 3 次和大于 3 次的部分进行分组
df['mark_target_record'] = df.minute_bucket_sort.apply(lambda x:1 if x<=3 else 0)
#3小时的桶排序
df['hour_bucket_sort'] = df.groupby(['user_id','hour_bucket','mark_target_record'])['request_time'].rank(ascending=True,method='first')
#最终分类
df['mark_model']  = df[['minute_bucket_sort','hour_bucket_sort']].apply(lambda x:'GPT4' if x[0]<=3 and x[1]<=50 else 'GPT3.5',axis=1)


#按请求日期和模型聚合,统计Tokens 和价格
df_1 = df.groupby(['mark_model'])['prompt_tokens','output_tokens'].sum().reset_index()
df_1['k_input_tokens'] = df_1.prompt_tokens/1000
df_1['k_output_tokens'] = df_1.output_tokens/1000
df_1[['mark_model','k_input_tokens','k_output_tokens']]

#求调整前后成本
#gpt-4:input 0.03,output 0.06
#gpt-3:input 0.0010,output 0.0020
input_price_4 = 0.03
input_price_3 = 0.0010
output_price_4 = 0.06
output_price_3 = 0.0020
df_1['调整前成本'] = df_1[['mark_model','k_input_tokens','k_output_tokens']].apply(lambda x:x[1]*input_price_3+x[2]*output_price_3,axis=1)
df_1['调整后成本'] = df_1[['mark_model','k_input_tokens','k_output_tokens']].apply(lambda x:x[1]*input_price_4+x[2]*output_price_4 if x[0]=='GPT4' else x[1]*input_price_3+x[2]*output_price_3,axis=1)
df_1[['调整前成本','调整后成本']].sum()

小结

从上面的两个案例来看,成本都是以十倍上涨,不过加了限制,最高也不会超过官方标价的倍数(30 倍)。
但无论如何,成本较之前都是很高的。
如果想要保证用户体验好、可以多用GPT4、成本又不高,那是很难的。
当然,解决办法还是有的:

  • 用户层面:可以搞会员制,要求不高的,用用GPT3.5,要求高的多掏钱买个会员。
  • 供应商层面:降低成本,这个要拼渠道了。

没有完美的,只有合适的,看需求搞事情~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/282108.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【FileZilla】FileZilla的使用及主动模式与被动模式----图文并茂详细讲解

目录 一 FileZilla的简介 1.1 是什么 1.2 应用场景 二 FileZilla的安装及准备工作 2.1 下载安装 2.2 主机连接VMware 三 FileZilla使用 3.1 内部连接文件管理 3.1.1 添加组 3.1.2 添加用户 3.1.3 添加用户密码 3.1.4 添加用户权限 3.1.5 连接测试 3.2 外部连接文…

Solidworks学习笔记

本内容为solidworks的学习笔记&#xff0c;根据自己的理解进行记录&#xff0c;部分可能不正确&#xff0c;请自行判断。 学习视频参考&#xff1a;【SolidWorks2018视频教程 SW2018中文版软件基础教学知识 SolidWorks自学教程软件操作教程 sw视频教程 零基础教程 视频教程】 h…

游戏软件缺少d3dcompiler.dll文件的多种修复方法分享

在操作系统中&#xff0c;d3dcompiler.dll是一个非常重要的组件&#xff0c;主要负责DirectX图形技术的编译和解析。许多用户在安装或使用某些软件时&#xff0c;提示“缺少d3dcompiler.dll”。这个错误通常出现在游戏或应用程序运行时&#xff0c;它会导致程序无法正常启动或运…

【linux】tail的基本使用

在linux可以用find查找一个文件&#xff0c;可以用grep查找符合要求的文件内容&#xff0c;但是有的时候希望查看文件的前几行或者后几行&#xff08;其实这种场景经常可以遇到&#xff0c;比如接触到日志分析的时候&#xff09;&#xff0c;那就应该使用head和tail这两个工具了…

CentOS 7 实战指南:目录操作命令详解

写在前面 想要在 CentOS 7 系统下更高效地进行目录操作吗&#xff1f;不要犹豫&#xff0c;在这里我为你准备了一篇精彩的技术文章&#xff01;这篇文章将带您深入了解 CentOS 7 下目录操作相关命令的使用方法。无论您是新手还是有一定经验的用户&#xff0c;这篇文章都将为您…

认识计算机网络——计算机网络的组成

计算机网络是由多个计算机和网络设备组成的系统&#xff0c;通过通信协议实现数据传输和信息交换。它是现代社会信息技术的重要支撑&#xff0c;广泛应用于各个领域。本文将介绍计算机网络的主要组成部分&#xff0c;包括硬件设备、软件协议和网络服务。 一、硬件设备 计算机网…

emacs:Searching for program: No such file or directory,sml;

首先&#xff0c;编辑一个现有的或新的 SML 文件&#xff08;如果没有其他方便的方法&#xff0c;可尝试C-x C-f test.smlC-x C-f test.sml 创建一个新文件&#xff09;。你会看到 Emacs 窗口底部的模式显示从 "基本"&#xff08;或其他任何模式&#xff09;变成了 S…

【Redis-10】Redis集群的实现原理和实践

Redis集群是Redis提供的分布式数据库方案&#xff0c;通过分片来进行数据共享&#xff0c;实现复制和故障转移的功能。 1. Redis集群节点 一个Redis集群由多个节点组成&#xff0c;多个节点可以通过命令实现连接&#xff0c;由独立状态转为集群状态&#xff0c;命令是cluster …

Python开源项目月排行 2023年12月

Python 趋势月报&#xff0c;按月浏览往期 GitHub,Gitee 等最热门的Python开源项目&#xff0c;入选的项目主要参考GitHub Trending,部分参考了Gitee和其他。排名不分先后&#xff0c;都是当前月份内相对热门的项目。 入选公式&#xff1d;70%GitHub Trending20%Gitee10%其他 …

回顾2023,我的编程学习之旅

文章目录 前言我与C语言初识C语言简易扫雷游戏二进制的美妙神奇的指针强大的结构体灵活的动态内存管理总结 我与竞赛我与CSDN结语 前言 6月8号高考结束了&#xff0c;虽然还没有出分&#xff0c;但是也大致规划好自己想学什么专业了&#xff0c;没错就是计算机&#xff0c;出分…

数据库系统概论SQL编程题合集(包含期末题、考研初试题以及复试题)

二、现有数据库casemanage中表结构如下图 1&#xff09;请编写sql语句对年龄进行升序排列 select * from afinfo order by birth;2&#xff09;请编写sql语句查询对“徐”姓开头的人员名单 select * from afinfo where name like 徐%;3&#xff09;请编写sql语句修改“陈晓”…

四种常见智能指针的介绍

一、介绍 当类中有指针成员时&#xff0c;一般有两种方式来管理指针成员&#xff1a;一是采用值型的方式管理&#xff0c;每个类对象都保留一份指针指向的对象的拷贝&#xff1b;另一种更优雅的方式是使用智能指针(smart pointer)&#xff0c;从而实现指针指向的对象的共享。 …

【LeetCode】每日一题 2023_12_31 一年中的第几天(日期)

文章目录 随便聊聊时间题目&#xff1a;一年中的第几天题目描述代码与解题思路 随便聊聊时间 LeetCode&#xff1f;启动&#xff01;&#xff01;&#xff01; 12 月的打卡勋章&#xff0c;get&#xff01; 题目&#xff1a;一年中的第几天 题目链接&#xff1a;1154. 一年中…

2023 年四川省职业院校技能大赛“信息安全管理与评估”样题

2023 年四川省职业院校技能大赛&#xff08;高等职业教育&#xff09; “信息安全管理与评估”样题 竞赛需要完成三个阶段的任务&#xff0c;分别完成三个模块&#xff0c;总分共计 1000分。三个模块内容和分值分别是&#xff1a; 第一阶段&#xff1a;模块一 网络平台搭建与设…

【Proteus仿真】【STM32单片机】自动除湿器系统

文章目录 一、功能简介二、软件设计三、实验现象联系作者 一、功能简介 本项目使用Proteus8仿真STM32单片机控制器&#xff0c;使用按键、LCD1602液晶、DHT11温湿度、继电器除湿模块等。 主要功能&#xff1a; 系统运行后&#xff0c;LCD1602显示DHT11传感器检测的湿度值阈值…

【实用工具】Tmux使用指南

Tmux 三个重要概念 session&#xff08;会话&#xff09;、window&#xff08;窗口&#xff09;、pane&#xff08;面板&#xff09; 一个会话可以有多个窗口&#xff0c;一个窗口可以划分为多个面板 注意在tmux中使用快捷命令的话&#xff0c;需要加上前缀ctrlb 关于session的…

不擅长设计也能做好邮件营销:实用技巧与指南分享

电子邮件营销是跨境电商中非常常见的品牌推广方式之一。但对于那些不擅长设计的人来讲&#xff0c;设计一封引人注目的电子邮件可能是一个磨练。本文将分享一些提议&#xff0c;协助跨境电商顾客处理不擅长设计问题。 不擅长设计的情况下怎么进行邮件营销&#xff1f;首先我们…

C语言——扫雷

扫雷是一款经典的小游戏&#xff0c;那如何使用C语言实现一个扫雷游戏呢&#xff1f; 一、全部源码 直接把全部源码放在开头&#xff0c;如有需要&#xff0c;直接拿走。 源码分为三个文件&#xff1a; test.cpp/c 主函数的位置 #include "game.h"int main() {…

NGUI基础-三大基础组件之Panel组件

目录 Panel组件 Panel的作用&#xff1a; 注意&#xff1a; 相关关键参数讲解&#xff1a; Alpha&#xff08;透明度值&#xff09;&#xff1a; Depth&#xff08;深度&#xff09;&#xff1a; Clippinng&#xff08;裁剪&#xff09;&#xff1a; ​编辑 None Tex…

Qt sender()函数

sender函数原型&#xff1a; QObject *sender() const; 如果在由信号激活的插槽中调用该函数&#xff0c;返回指向发送信号的对象的指针&#xff0c;否则返回0&#xff0c;该指针仅在从该对象的线程上下文调用此函数的槽执行期间有效。 主要代码如下&#xff1a; 其中运用了Q…