ChatGLM3-6B对话流式输出

ChatGLM3-6B被太多框架使用,基本的流式输出函数竟然一时找不到了。
目前看到的有两个地方有相关的:
第一个:
ChatGLM3/basic_demo/cli_demo.py at main · THUDM/ChatGLM3
https://github.com/THUDM/ChatGLM3/blob/main/basic_demo/cli_demo.py

stop_stream = False
def main():
    past_key_values, history = None, []
    global stop_stream
    print(welcome_prompt)
    while True:
        query = input("\n用户:")
        if query.strip() == "stop":
            break
        if query.strip() == "clear":
            past_key_values, history = None, []
            os.system(clear_command)
            print(welcome_prompt)
            continue
        print("\nChatGLM:", end="")
        current_length = 0
        for response, history, past_key_values in model.stream_chat(tokenizer, query, history=history, top_p=1,
                                                                    temperature=0.01,
                                                                    past_key_values=past_key_values,
                                                                    return_past_key_values=True):
            if stop_stream:
                stop_stream = False
                break
            else:
                print(response[current_length:], end="", flush=True)
                current_length = len(response)
        print("")

这是一个命令行运行大模型的例子,是流式输出的,但是用户和ai的历史输出是直接放在字符串中拼接的,我倾向于一个json结构的对话历史。

第二个:
THUDM/ChatGLM3: ChatGLM3 series: Open Bilingual Chat LLMs | 开源双语对话语言模型 https://github.com/THUDM/ChatGLM3

>> from transformers import AutoTokenizer, AutoModel
>> tokenizer = AutoTokenizer.from_pretrained("THUDM/chatglm3-6b", trust_remote_code=True)
>> model = AutoModel.from_pretrained("THUDM/chatglm3-6b", trust_remote_code=True, device='cuda')
>> model = model.eval()
>> response, history = model.chat(tokenizer, "你好", history=[])
>> print(response)

你好👋!我是人工智能助手 ChatGLM3 - 6B, 很高兴见到你, 欢迎问我任何问题。
>> response, history = model.chat(tokenizer, "晚上睡不着应该怎么办", history=history)
>> print(response)

这是官网给的例子,不是流式输出,不过输出历史都是用[{‘role’: ‘user’, ‘content’:…}]格式保存的。
这两个能结合起来吗?注意到方法model.stream_chat和model.chat形式很像,尝试拼接了一下,发现居然可行。
封装为函数时,history作为外部变量保存历史,出现了报错:UnboundLocalError: cannot access local variable ‘history’ where it is not associated with a value。
不想用global关键字,也不想把history作为参数传入函数。
把内部循环的history变量修改为inner_history解决了问题。

from transformers import AutoTokenizer, AutoModel

tokenizer = AutoTokenizer.from_pretrained("/new/workspace/models/ChatGLM3/chatglm3-6b", trust_remote_code=True)
model = AutoModel.from_pretrained("/new/workspace/models/ChatGLM3/chatglm3-6b", trust_remote_code=True, device='cuda')
model = model.eval()

def ask(query='你好',new_chat=False):
    past_key_values=None
    stop_stream = False
    current_length = 0
    for response, inner_history, past_key_values in model.stream_chat(tokenizer, query, history=history, top_p=1,
                                                                temperature=0.01,
                                                                past_key_values=past_key_values,
                                                                return_past_key_values=True):
        if stop_stream:
            stop_stream = False
            break
        else:
            print(response[current_length:], end="", flush=True)
            current_length = len(response)
    print("")
    history.clear()
    history.extend(inner_history)

history=[]
ask('一年有几个季节')
ask('第四个有什么特征')

输出效果:
一年通常分为四个季节,分别是春季、夏季、秋季和冬季。但不同地区的气候和季节变化可能会略有不同。
冬季通常出现在北半球的冬季,而在南半球则是夏季。在冬季,气温通常较低,天气也较为寒冷,天气也较为阴沉,降水也较为少。植物也会进入休眠状态,动物也会采取不同的生存策略以适应寒冷的环境。

history内容:

[{'role': 'user', 'content': '一年有几个季节'},
 {'role': 'assistant',
  'metadata': '',
  'content': '一年通常分为四个季节,分别是春季、夏季、秋季和冬季。但不同地区的气候和季节变化可能会略有不同。'},
 {'role': 'user', 'content': '第四个有什么特征'},
 {'role': 'assistant',
  'metadata': '',
  'content': '冬季通常出现在北半球的冬季,而在南半球则是夏季。在冬季,气温通常较低,天气也较为寒冷,天气也较为阴沉,降水也较为少。植物也会进入休眠状态,动物也会采取不同的生存策略以适应寒冷的环境。'}]
  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值