streamlit 搭建LLM交互应用

streamlit 搭建LLM交互应用

背景

本文主要讨论使用Qwen2-7B-Instruct搭建一个可调节核心参数的LLM对话式应用。页面交互采用streamlit,模型推理部分采langchainvllm两种部署推理框架。

本文将可以学习了解一下内容:

  • streamlit的搭建流程,以及常见的组件使用
  • 使用langchain推理框架部署LLM模型
  • 使用vllm推理框部署LLM模型
  • langchainvllm的主要区别及LLM使用中的一些核心参数的含义

预备知识

1、常见模型名称的理解

LLM 中会经常看到以Instruct和chat结尾的模型名称,其含义是不同的

Qwen2-7B-Instruct侧重于理解和执行用户给出的指令或任务。
Qwen2-7B-Chat 侧重于自然流畅的对话交互。

比如编写代码或者回答具体的指令问题 那么 Qwen2-7B-Instruct 可能是更好的选择。
如果你的目标是建立一个能够进行自然对话的聊天机器人,则 Qwen2-7B-Chat 更合适。

2、模型输出随机性参数控制

temperature 参数:用于控制生成文本的随机性,影响模型在生成文本时如何选择下一个词汇的概率分布。

temperature较高时,模型会更倾向于探索低概率的词汇,这增加了生成文本的随机性和多样性。
temperature较低时,模型会更倾向于选择高概率的词汇,这使得生成的文本更加可预测和保守。

top_p 参数:用于控制核采样策略,选择累积概率达到一定阈值 top_p 的词汇子集进行采样。

top_p 设置为较小的值时,只有少数高概率的词汇会被保留下来,通常会导致生成的文本更加聚焦和连贯,可能减少多样性。反之会增加生成文本的多样性和创造性。

top_k 参数 用于控制生成多样性和文本质量的一种策略。

top_k 设置为较大的值时,更多的词汇会被考虑,可能会增加生成文本的多样性,但同时也可能导致文本质量的下降。相反,当top_k 设置为较小的值时,只有少数高概率的词汇会被考虑,通常会使生成的文本更加聚焦和连贯,但也可能减少多样性。

repetition_penalty 参数:用来控制生成文本中重复内容的数量。

repetition_penalty的默认值通常是1.0,意味着没有重复惩罚,即模型在生成下一个词汇时不会特别避免重复之前已经生成过的词汇。

repetition_penalty 的值大于1.0时,模型会在计算候选词汇的概率时对已经出现过的词汇加一定的惩罚,从而降低它们再次被选中的概率。值越大,惩罚力度越强,生成的文本中重复的内容就越少。

如果repetition_penalty 的值小于1.0,将会鼓励模型重复生成某些词汇,但这在实践中很少使用,因为通常我们希望生成的文本尽可能多样化。

小结:

top_p 更多地影响生成文本的多样性

top_k 考虑候选词汇的数量

temperature 更多地影响生成文本的随机性和连贯性

repetition_penalty 文本词汇的重复程度

环境搭建以及模型下载

本项目仓地址github

langchain推理部署

自定义Qwen2_LLM类继承LLM,重写__init___call_llm_type函数,代码如下

from langchain.llms.base import LLM
from typing import Any, List, Optional
from langchain.callbacks.manager import CallbackManagerForLLMRun
from transformers import AutoTokenizer, AutoModelForCausalLM, GenerationConfig
import torch

class Qwen2_LLM(LLM):
    # 基于本地Qwen2自定义LLM类
    tokenizer: AutoTokenizer = None
    model: AutoModelForCausalLM = None
    
    def __init__(self, model_name_or_path: str):
        super().__init__()
        print("正在从本地加载模型...")
        self.tokenizer = AutoTokenizer.from_pretrained(model_name_or_path, use_fast=False)
        self.model = AutoModelForCausalLM.from_pretrained(
            model_name_or_path, torch_dtype=torch.bfloat16, device_map="auto"
        )
        self.model.generation_config = GenerationConfig.from_pretrained(model_name_or_path)
        print("完成本地模型的加载")

    def _call(
        self,
        prompt: str,
        stop: Optional[List[str]] = None,
        run_manager: Optional[CallbackManagerForLLMRun] = None,
        **kwargs: Any
    ):

        messages = [{"role": "user", "content": prompt}]
        input_ids = self.tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
        model_inputs = self.tokenizer([input_ids], return_tensors="pt").to("cuda")

        # 使用 kwargs 中的 temperature 参数覆盖默认值
        base_generation_config = self.model.generation_config.to_dict()
        updated_generation_config = {
            **base_generation_config,
            **kwargs,
        }

        generated_ids = self.model.generate(model_inputs.input_ids, **updated_generation_config)
        generated_ids = [
            output_ids[len(input_ids) :] for input_ids, output_ids in zip(model_inputs.input_ids, generated_ids)
        ]
        response = self.tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]

        return response

    @property
    def _llm_type(self) -> str:
        return "Qwen2-7B-Instruct"

推理使用

from langchain_model import Qwen2_LLM
from langchain.callbacks.base import BaseCallbackHandler
from langchain.callbacks.manager import CallbackManager
from typing import Any
from config import base_config


# 定义一个简单的回调类,可忽视
class SimpleCallbackHandler(BaseCallbackHandler):
    def on_llm_start(self, serialized: dict, prompts: list, **kwargs: Any) -> None:
        print(f"Starting LLM run with prompts: {prompts}")

    def on_llm_end(self, response: Any, **kwargs: Any) -> None:
        print(f"LLM run completed. Response: {response}")

    def on_llm_error(self, error: Exception, **kwargs: Any) -> None:
        print(f"Error during LLM run: {error}")


callback_handler = SimpleCallbackHandler()
callback_manager = CallbackManager([callback_handler])

# 需按实际模型位置进行修改
model_name_or_path = base_config.model_name_or_path

llm = Qwen2_LLM(model_name_or_path)

# langchain会调用子类的_call函数
# response = llm("你是谁", callbacks=callback_manager)

# 携带自定义参数
param = {"temperature": 0.5, "max_new_tokens": 512}
response = llm("你是谁", **param)
print(response)

当前文件运行 streamlit run langchain_streamlit_demo.py 界面如下
在这里插入图片描述

vllm推理部署

vllm_model.py文件如下

1、加载模型对象

from vllm import LLM, SamplingParams


def get_model(model_name_or_path):
    llm = LLM(
        model=model_name_or_path,
        tokenizer=model_name_or_path,
        max_num_seqs=100,
        trust_remote_code=True,
    )
    return llm

2、重写文本生成采样率

def get_completion(tokenizer=None, repetition_penalty=1.05, top_p=0.8, top_k=20, **kwargs):
    stop_token_ids = [151329, 151336, 151338]
    # SamplingParams部分默认参数和Qwen2-7B-Instruct/generation_config.json配置的参数不一致
    # 修改SamplingParams的默认值,使repetition_penalty、top_p、top_k和原模型保持一致

    kwargs.update({"repetition_penalty": repetition_penalty, "top_p": top_p, "top_k": top_k})
    # print(f"SamplingParams param: {kwargs}")
    sampling_params = SamplingParams(**kwargs, stop_token_ids=stop_token_ids)

    return sampling_params

3、调用模型生成文本

def call(llm, prompt, sampling_params):
    outputs = llm.generate(prompt, sampling_params)
    for output in outputs:
        response = output.outputs[0].text
    return response

测试如下

from vllm_model import call, get_model, get_completion
from config import base_config


model_name_or_path = base_config.model_name_or_path
llm = get_model(model_name_or_path)

# 多样性文本参数控制
param = dict(max_tokens=512, temperature=0.7)
sampling_params = get_completion(**param)

# 用户提示词
prompt = "介绍你自己?"
response = call(
    llm,
    prompt,
    sampling_params,
)
print(response)

langchain和vllm的主要区别

LangChain 是一个用于端到端构建应用程序的框架,专注于利用大型语言模型(LLMs)来处理自然语言任务。
特点:

  • 提供了一套工具和接口来连接不同的数据源和模型。
  • 支持多种大型语言模型,如 OpenAI 的模型等。
  • 可以构建复杂的语言处理流水线,比如问答系统或文本生成应用。

VLLM 是一个针对大型语言模型进行优化推理和部署的引擎方案。
特点:

  • 主要用于部署和运行大规模预训练语言模型。
  • 提供了高效的批量处理和序列化功能,以提高推理速度。
  • 通常用于生产环境中的高性能推理服务。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值