chatgpt 怎么通过减少token 减少花费

1,205 阅读10分钟

目录

  1. 怎么利用huggingface 免费资源快速部署 AI
  2. 前面说到 减少 token的办法,怎么实现呢?

怎么利用huggingface 免费资源快速部署 AI

有了一个可以聊天的机器人,相信你已经迫不及待地想让你的朋友也能用上它了。那么我们就把它部署到 HuggingFace 上去。

首先你需要注册一个 HuggingFace 的账号,点击左上角的头像,然后点击 “+New Space”

image.png

创建一个新的项目空间。在接下来的界面里,给你的 Space 取一个名字,然后在 Select the Space SDK 里面,选择第二个 Gradio。硬件我们在这里就选择免费的,项目我们在这里选择 public,让其他人也能够看到。不过要注意,public 的 space,是连你后面上传的代码也能够看到的。

这里其实可以选私有的 比较靠谱,但是需要邮箱验证

image.png

创建成功后,会跳转到 HuggingFace 的 App 界面。里面给了你如何 Clone 当前的 space,然后提交代码部署 App 的方式。我们只需要通过 Git 把当前 space 下载下来,然后提交两个文件就可以了,分别是:app.py 包含了我们的 Gradio 应用;requirements.txt 包含了这个应用依赖的 Python 包,这里我们只依赖 OpenAI 这一个包。你可以得到这个HuggingFace space的Git地址代码提交之后,HuggingFace 的页面会自动刷新,你可以直接看到对应的日志和 Chatbot 的应用。不过这个时候,我们还差一步工作。因为我们的代码里是通过环境变量获取 OpenAI 的 API Key 的,所以我们还要在这个 HuggingFace 的 Space 里设置一下这个环境变量。你可以点击界面里面的 Settings,然后往下找到 Repository secret。

image.png

在 Name 这里输入 OPENAI_API_KEY,然后在 Secret value 里面填入你的 OpenAI 的密钥。设置完成之后,你还需要点击一下 Restart this space 确保这个应用重新加载一遍,以获取到新设置的环境变量。

image.png

好啦,这个时候,你可以重新点击 App 这个 Tab 页面,试试你的聊天机器人是否可以正常工作了。我把今天给你看到的 Chatbot 应用放到了 HuggingFace 上,你可以直接复制下来试一试。

image.png

资料

requirements.txt

openai

a


import gradio as gr

import openai
import os
openai.api_key = os.environ.get("OPENAI_API_KEY")

class Conversation:
    def __init__(self, prompt, num_of_round):
        self.prompt = prompt
        self.num_of_round = num_of_round
        self.messages = []
        self.messages.append({"role": "system", "content": self.prompt})

    def ask(self, question):
        try:
            self.messages.append({"role": "user", "content": question})
            response = openai.ChatCompletion.create(
                model="gpt-3.5-turbo",
                messages=self.messages,
                temperature=0.5,
                max_tokens=2048,
                top_p=1,
            )
        except Exception as e:
            print(e)
            return e

        message = response["choices"][0]["message"]["content"]
        self.messages.append({"role": "assistant", "content": message})

        if len(self.messages) > self.num_of_round*2 + 1:
            del self.messages[1:3]
        return message


prompt = """你是一个中国厨师,用中文回答做菜的问题。你的回答需要满足以下要求:
1. 你的回答必须是中文
2. 回答限制在100个字以内"""

conv = Conversation(prompt, 10)

def answer(question, history=[]):
    history.append(question)
    response = conv.ask(question)
    history.append(response)
    responses = [(u,b) for u,b in zip(history[::2], history[1::2])]
    return responses, history

with gr.Blocks(css="#chatbot{height:300px} .overflow-y-auto{height:500px}") as demo:
    chatbot = gr.Chatbot(elem_id="chatbot")
    state = gr.State([])

    with gr.Row():
        txt = gr.Textbox(show_label=False, placeholder="Enter text and press enter").style(container=False)

    txt.submit(answer, [txt, state], [chatbot, state])

demo.launch()

前面说到 减少 token的办法,怎么实现呢?

文本聚类

文本聚类就是把很多没有标注过的文本,根据它们之间的相似度,自动地分成几类。基于 GPT 系列的模型进行文本聚类很简单,因为我们可以通过 Embedding 把文本变成一段向量。而对于向量我们自然可以用一些简单的聚类算法,比如我们采用最简单的 K-Means 算法就可以了。

利用文本摘要支持无限轮数的聊天

如果不只是保留过去几轮对话,我们怎么在对话轮数越来越多的时候让 AI 记住尽量多的上下文?有一个办法,就是将过去几轮的上下文内容,先交给 AI 做一个 100 字的总结。然后,把这个总结也作为对话的 Prompt 信息,告诉 AI 这是聊天的背景,再重新开始新的一轮对话。

1 我们拿上一讲的一段聊天记录,让 AI 先总结一下,可以看到 AI 总结了 User 和 Assistant 之间聊了什么。

history = """User : 你是谁? Assistant : 我是一个人工智能语言模型,可以回答各种问题,包括做菜的问题。

User : 请问鱼香肉丝怎么做? Assistant : 鱼香肉丝的做法:

  1. 猪里脊肉切丝,加入盐、淀粉、料酒搅拌均匀,腌制10分钟
  2. 胡萝卜、青椒、木耳切丝备用
  3. 热锅凉油,放入蒜末、姜末煸炒出香味,加入肉丝翻炒至变色
  4. 加入胡萝卜、青椒、木耳翻炒,加入酱油、糖、醋、盐、味精、水淀粉搅拌均匀,倒入锅中翻炒均匀即可。

提示:鱼香肉丝的关键是调料的配比,酱油、糖、醋、盐、味精的比例要适合自己的口味。

User : 那蚝油牛肉呢? Assistant : 蚝油牛肉的做法:

  1. 将牛肉切成薄片,加入盐、淀粉、料酒腌制10分钟
  2. 葱姜切末,蒜切片,青红椒切丝备用
  3. 热锅凉油,放入葱姜末、蒜片煸炒出香味,加入牛肉翻炒至变色
  4. 加入蚝油、酱油、糖、水淀粉调味,加入青红椒翻炒均匀即可。

提示:蚝油牛肉的关键是牛肉要切薄,翻炒时火候要快,保证牛肉口感鲜嫩。调味时,蚝油和酱油的比例也要适合自己的口味。 """

def summarize(text, max_tokens=200): response = openai.Completion.create( model=COMPLETIONS_MODEL, prompt=text + "\n\n请总结一下上面User和Assistant聊了些什么:\n", max_tokens=max_tokens, ) return response["choices"][0]["text"]

summarized = summarize(history) print(summarized)


history = """User : 你是谁?
Assistant : 我是一个人工智能语言模型,可以回答各种问题,包括做菜的问题。

User : 请问鱼香肉丝怎么做?
Assistant : 鱼香肉丝的做法:

1. 猪里脊肉切丝,加入盐、淀粉、料酒搅拌均匀,腌制10分钟
2. 胡萝卜、青椒、木耳切丝备用
3. 热锅凉油,放入蒜末、姜末煸炒出香味,加入肉丝翻炒至变色
4. 加入胡萝卜、青椒、木耳翻炒,加入酱油、糖、醋、盐、味精、水淀粉搅拌均匀,倒入锅中翻炒均匀即可。

提示:鱼香肉丝的关键是调料的配比,酱油、糖、醋、盐、味精的比例要适合自己的口味。

User : 那蚝油牛肉呢?
Assistant : 蚝油牛肉的做法:

1. 将牛肉切成薄片,加入盐、淀粉、料酒腌制10分钟
2. 葱姜切末,蒜切片,青红椒切丝备用
3. 热锅凉油,放入葱姜末、蒜片煸炒出香味,加入牛肉翻炒至变色
4. 加入蚝油、酱油、糖、水淀粉调味,加入青红椒翻炒均匀即可。

提示:蚝油牛肉的关键是牛肉要切薄,翻炒时火候要快,保证牛肉口感鲜嫩。调味时,蚝油和酱油的比例也要适合自己的口味。
"""

def summarize(text, max_tokens=200):
    response = openai.Completion.create(
        model=COMPLETIONS_MODEL,
        prompt=text + "\n\n请总结一下上面User和Assistant聊了些什么:\n",
        max_tokens=max_tokens,
    )
    return response["choices"][0]["text"]

summarized = summarize(history)
print(summarized)

输出结果

User和Assistant聊了鱼香肉丝和蚝油牛肉的制作方法。User问了Assistant两个关于如何做鱼香肉丝和蚝油牛肉的问题,Assistant给出了回答并介绍了每道菜的具体制作方法,同时也提示了调料的配比和牛肉制作时要注意的细节。


User和Assistant聊了鱼香肉丝和蚝油牛肉的制作方法。User问了Assistant两个关于如何做鱼香肉丝和蚝油牛肉的问题,Assistant给出了回答并介绍了每道菜的具体制作方法,同时也提示了调料的配比和牛肉制作时要注意的细节。

2 然后,我们再新建一个 Conversation,这次的提示语里,我们先加上了总结的内容,然后告诉 AI 把对话继续下去。

prompt = summarized + "\n\n请你根据已经聊了的内容,继续对话:"
conversation = Conversation(prompt, 5)

question = "那宫保鸡丁呢?"
answer = conversation.ask(question)
print("User : %s" % question)
print("Assistant : %s\n" % answer)


注意,如果你是在 Notebook 里面执行的话,你需要把上一讲的 Conversation 类的代码复制过来先执行一下。这里,我们启动了一个新的对话对象,将之前的几轮对话的内容总结了一下,放在 Prompt 的最前面,然后让 AI 根据已经聊了的内容,继续往下聊。

3 当我们直接问,“那宫保鸡丁呢?”,AI 会正确回答出宫保鸡丁的做法。输出结果:


User : 那宫保鸡丁呢?
Assistant : 宫保鸡丁的制作方法也比较简单。首先,将鸡肉切成小丁状,用料酒、盐、生抽腌制一下。然后将青椒、红椒、葱姜蒜切成丁状备用。接着,将花生米炒香备用。
热锅凉油,油温七成热时放入鸡丁煸炒至变色,捞出备用。再将葱姜蒜爆香,加入青红椒丁翻炒一下,然后加入鸡丁,翻炒均匀。最后加入适量的糖、盐、醋、生抽、老抽、料酒、水淀粉炒匀,最后加入炒香的花生米即可。
需要注意的是,炒鸡丁的时候要用大火,这样鸡肉会更嫩。另外,调料的配比也很关键,需要根据个人口味适量调整。

而如果我们没有加上 AI 总结的之前的对话,只是让 AI 对话,它只能和你闲扯一些别的


conversation = Conversation("请你根据已经聊了的内容,继续对话:", 5)

question = "那宫保鸡丁呢?"
answer = conversation.ask(question)
print("User : %s" % question)
print("Assistant : %s\n" % answer)

输出结果


User : 那宫保鸡丁呢?
Assistant : 宫保鸡丁是一道非常有名的川菜,口感麻辣鲜香,非常美味。你喜欢吃辣的食物吗?

额外解决办法

有可能你再想 是不是还有别的办法 减少token,有的

使用英文来减少 Token 的使用

虽然灾害只有两个中文汉字,但是我们通过 Tiktoken 去处理的时候,我们打印了对应的 Token 的 id 是什么,实际上有 5 个 Token。这里其实和我们之前看到的英文一样,并不是一个字或者一个单词是一个 Token。事实上,同样含义的中文,目前消耗的 Token 数量是比英文多的。比如,我们把上面的一句话翻译成英文,然后数一下对应同样内容的中英文的 Token 数。


def translate(text):
    messages = []
    messages.append( {"role": "system", "content": "你是一个翻译,把用户的话翻译成英文"})
    messages.append( {"role": "user", "content": text})
    response = openai.ChatCompletion.create(
        model="gpt-3.5-turbo", messages=messages, temperature=0.5, max_tokens=2048,        n=1
    )
    return response["choices"][0]["message"]["content"]

chinese = long_text
english = translate(chinese)

num_of_tokens_in_chinese = len(encoding.encode(chinese))
num_of_tokens_in_english = len(encoding.encode(english))
print(english)
print(f"chinese: {num_of_tokens_in_chinese} tokens")
print(f"english: {num_of_tokens_in_english} tokens")

返回结果


In this fast-paced modern society, each of us faces various challenges and difficulties. Some of these challenges and difficulties are caused by external factors, such as economic recession, global warming, and natural disasters. There are also some caused by internal factors, such as emotional issues, health problems, and self-doubt. To overcome these challenges and difficulties, we need to adopt a positive attitude and take action. This means we must possess a strong will and creative thinking, as well as the ability to seek external support. Only in this way can we truly realize our potential and achieve success.
chinese: 432 tokens
english: 115 tokens

可以看到,同样的内容,中文消耗的 Token 数量超过 400,而英文的 Token 数量只有 100 出头。如果你在生产环境中使用 OpenAI 的接口,最好还是使用英文的提示语,最多在输出结果的时候,告诉它 “generate Chinese” 之类的,可以极大地节约成本。