大家好,Stack Overflow社区,
我一直在尝试将ChatGPT的API集成到我的项目中,但在计算API请求的总令牌数时遇到了问题。特别是我在API调用中同时传递了消息和函数。
我已经找到了计算消息令牌数的方法,但对于如何计算函数使用的令牌数还不确定。
请问有人能指导我如何正确计算包括消息和函数在内的ChatGPT API请求的总令牌数吗?
任何帮助或见解都将不胜感激!
提前感谢你们。
我一直在尝试通过以不同方式格式化调用中的数据来强行解决这个问题。我使用了tokenizer和Tiktokenizer来测试我的格式。
回答:
我将向你展示如何计算gpt-3.5和gpt-4的令牌。你可以将类似的方法应用于其他模型,只需找到正确的设置即可。
我们将分别计算消息和函数使用的令牌,然后将它们加在一起以获得总数。
消息
首先,使用tiktoken获取令牌化器。我们将使用它来对消息和函数中的所有自定义文本进行令牌化。同时,为API请求中添加的额外令牌添加常量。
enc = tiktoken.encoding_for_model(model)
创建一个变量来保存消息的总令牌数,并将其设置为0。
msg_token_count = 0
遍历消息,对于每条消息,将3个令牌添加到msg_token_count
。然后遍历消息中的每个元素,编码其值,并将编码对象的长度添加到msg_token_count
。如果字典中有“name”键,则向msg_token_count
添加一个额外的令牌。
for message in messages: msg_token_count += 3 # 为每条消息添加令牌 for key, value in message.items(): msg_token_count += len(enc.encode(value)) # 添加设置消息中的令牌 if key == "name": msgTokenCount += 1 # 如果设置了名称,则添加令牌
最后,我们需要向msg_token_count
添加3个令牌,以说明结束令牌。
msgTokenCount += 3 # 添加令牌以说明结束
函数
现在我们将计算函数所需的令牌数。
首先,创建一个变量来保存函数使用的总令牌数,并将其设置为0。
func_token_count = 0
接下来,我们将遍历函数并向func_token_count
添加令牌。遍历函数,为每个函数向func_token_count
添加7个令牌。然后添加编码的名称和描述的长度。
对于每个函数,如果它有属性,则向func_token_count
添加3个令牌。然后对于属性中的每个键,再添加3个令牌和编码属性的长度,确保如果它有“enum”键,则减去3个令牌,并为enum部分的每个项目添加3个令牌。
最后,向func_token_count
添加12个令牌,以说明所有函数结束时的令牌。
for function in functions: func_token_count += 7 # 为每个函数的开始添加令牌 f_name = function["name"] f_desc = function["description"] if f_desc.endswith("."): f_desc = f_desc[:-1] line = f_name + ":" + f_desc func_token_count += len(enc.encode(line)) # 为设置的名称和描述添加令牌 if len(function["parameters"]["properties"]) > 0: func_token_count += 3 # 为每个属性的开始添加令牌 for key in list(function["parameters"]["properties"].keys()): func_token_count += 3 # 为每个设置的属性添加令牌 p_name = key p_type = function["parameters"]["properties"][key]["type"] p_desc = function["parameters"]["properties"][key]["description"] if "enum" in function["parameters"]["properties"][key].keys(): func_token_count += 3 # 如果属性有枚举列表,则添加令牌 for item in function["parameters"]["properties"][key]["enum"]: func_token_count += 3 func_token_count += len(enc.encode(item)) if p_desc.endswith("."): p_desc = p_desc[:-1] line = f"{p_name}:{p_type}:{p_desc}" func_token_count += len(enc.encode(line))func_token_count += 12
这是完整的代码。请注意,我没有硬编码额外的令牌计数,而是使用常量来保存值。
def get_token_count(model, messages, functions): # 初始化消息设置为0 msg_init = 0 msg_name = 0 msg_end = 0 # 初始化函数设置为0 func_init = 0 prop_init = 0 prop_key = 0 enum_init = 0 enum_item = 0 func_end = 0 if model in [ "gpt-3.5-turbo-0613", "gpt-4-0613" ]: # 为上述模型设置消息设置 msg_init = 3 msg_name = 1 msg_end = 3 # 为上述模型设置函数设置 func_init = 7 prop_init = 3 prop_key = 3 enum_init = -3 enum_item = 3 func_end = 12 enc = tiktoken.encoding_for_model(model) msg_token_count = 0 for message in messages: msg_token_count += msg_init # 为每条消息添加令牌 for key, value in message.items(): msg_token_count += len(enc.encode(value)) # 添加设置消息中的令牌 if key == "name": msg_token_count += msg_name # 如果设置了名称,则添加令牌 msg_token_count += msg_end # 添加令牌以说明结束 func_token_count = 0 if len(functions) > 0: for function in functions: func_token_count += func_init # 为每个函数的开始添加令牌 f_name = function["name"] f_desc = function["description"] if f_desc.endswith("."): f_desc = f_desc[:-1] line = f_name + ":" + f_desc func_token_count += len(enc.encode(line)) # 为设置的名称和描述添加令牌 if len(function["parameters"]["properties"]) > 0: func_token_count += prop_init # 为每个属性的开始添加令牌 for key in list(function["parameters"]["properties"].keys()): func_token_count += prop_key # 为每个设置的属性添加令牌 p_name = key p_type = function["parameters"]["properties"][key]["type"] p_desc = function["parameters"]["properties"][key]["description"] if "enum" in function["parameters"]["properties"][key].keys(): func_token_count += enum_init # 如果属性有枚举列表,则添加令牌 for item in function["parameters"]["properties"][key]["enum"]: func_token_count += enum_item func_token_count += len(enc.encode(item)) if p_desc.endswith("."): p_desc = p_desc[:-1] line = f"{p_name}:{p_type}:{p_desc}" func_token_count += len(enc.encode(line)) func_token_count += func_end return msg_token_count + func_token_count
如果有任何不清楚的地方,或者你有建议可以改进我的帖子,请告诉我。