大语言模型RAG-将本地大模型封装为langchain的chat model(三)

news2024/11/16 6:05:38

大语言模型RAG-将本地大模型封装为langchain的chat model(三)

往期文章:
大语言模型RAG-技术概览 (一)
大语言模型RAG-langchain models (二)

上一期langchain还在0.1时代,这期使用的langchain v0.2已经与之前不兼容了。
本期介绍如何将开源模型封装为langchainchat模型 这是后面构建RAG应用的基础。

基于langchain_core.language_models.BaseChatModel创建类。这个类就是本地llm的langchain封装,需要定义以下方法或属性。

方法/属性作用是否必要
_generate根据prompt生成聊天结果必要
_llm_type (属性)模型的唯一标识,用于生成日志必要
_identifying_params(属性)用于返回模型的一些参数,用于日志和调试可选
_stream用于流式输出可选
_agenerate本机异步的_generate可选
_astream异步的_stream可选

示例如下,只实现比较常用的功能:

from typing import Any, AsyncIterator, Dict, Iterator, List, Optional
from threading import Thread
from langchain_core.callbacks import (
    AsyncCallbackManagerForLLMRun,
    CallbackManagerForLLMRun,
)
from langchain_core.language_models import BaseChatModel, SimpleChatModel
from langchain_core.messages import AIMessageChunk, BaseMessage, HumanMessage
from langchain_core.outputs import (
ChatGeneration, 
ChatGenerationChunk, 
ChatResult
)
from langchain_core.messages import (
    AIMessage,
    BaseMessage,
    HumanMessage,
)
from typing import AsyncIterator, Literal, Iterator, Optional, List, Dict, Any
from transformers import AutoTokenizer, AutoModelForCausalLM
from pydantic import BaseModel, Field, validator
import torch

class CustomChatModel(BaseChatModel):
    """将本地模型封装为langchain的chat模型"""
    
    model_name: str  # 模型的本地地址
    device: str = "cpu"  # 计算设备
    n: int = 512  # 最大生成长度
    temperature: float = 1.0  # 温度
    
    model: Optional[AutoModelForCausalLM] = None
    tokenizer: Optional[AutoTokenizer] = None
    
    def __init__(self, model_name: str, device: str, temperature: float = 1.0, **kwargs):
    """
    我把模型加载放在初始化里面了。当然有更灵活的处理方式,这部分你可以随心所欲,只要在
    模型获得输入前加载好模型就OK。
    
    Params:
	    model_name (str): 本地模型的路径
	    device (str): 计算设备
	    temperature (float): 模型温度
	"""
        super().__init__(model_name=model_name, device=device, **kwargs)
        self.model_name = model_name
        self.device = device
        self.temperature = temperature
        
		# 加载本地模型。
        try:
            self.tokenizer = AutoTokenizer.from_pretrained(self.model_name, trust_remote_code=True, use_fast=False)
            self.model = AutoModelForCausalLM.from_pretrained(self.model_name, trust_remote_code=True).half().to(self.device)
        except Exception as e:
            raise RuntimeError(f"模型或分词器加载失败: {e}")
            
	def _generate(self, messages: List[BaseMessage], stop: Optional[List[str]] = ['.', '。', '?', '?', '!', '!'], 
                  run_manager: Optional[CallbackManagerForLLMRun] = None, **kwargs: Any) -> ChatResult:
        """
        实现模型的文本生成逻辑
		这是langchain必须的类方法。

		Params:
			messages (BaseMessage): 输入模型的消息列表
			stop (List[str]): 
				这是一个字符列表,langchain会根据这个列表中的字符找到
				完整句子的结束位置。
			run_manager (CallbackManagerForLLMRun): 
				用于管理和追踪执行的过程,通常用于实现回调和异步处理。
				虽然这个功能很重要,但本文暂时不做示例(我没玩明白)
		
		Return:ChatResult类的输出,完全符合langchain风格。
		"""
        
        last_message = messages[-1].content  # 获取最后一条消息
        inputs = self.tokenizer.encode(last_message, return_tensors="pt").to(self.device)  # 将消息内容编码为张量
        outputs = self.model.generate(inputs, max_length=self.n + len(inputs[0]), temperature=self.temperature)  # 调用模型生成文本张量
        tokens = self.tokenizer.decode(outputs[0], skip_special_tokens=True)  # 将张量解码为文本

        # 截取合适的长度(找到完整句子的结束位置)
        end_positions = [tokens.find(c) for c in stop if tokens.find(c) != -1]
        if end_positions:
            end_pos = max(end_positions) + 1  # 包括结束符
            if end_pos < self.n:
                tokens = tokens[:end_pos]
            else:
                tokens = tokens[:self.n]
        else:
            tokens = tokens[:self.n]

        message = AIMessage(content=tokens)  # 将生成的文本封装为消息
        generation = ChatGeneration(message=message)  # 封装为ChatGeneration
        

        return ChatResult(generations=[generation])

	def _stream(self, messages: List[BaseMessage], stop: Optional[List[str]] = None, 
            run_manager: Optional[CallbackManagerForLLMRun] = None, **kwargs: Any) -> Iterator[ChatGenerationChunk]:
        """
        流式生成文本。这个方法不是必须的,但实际应用中流式输出能提高用户
        体验,从这个角度来说它是必须的。下面仅给出了最基本的流式输出的逻
        辑,实际工程中你可以自行添加你需要的逻辑。
        
		Params:
			messages (BaseMessage): 输入模型的消息列表
			stop (List[str]): 
				这是一个字符列表,langchain会根据这个列表中的字符找到
				完整句子的结束位置。
			run_manager (CallbackManagerForLLMRun): 
				用于管理和追踪执行的过程,通常用于实现回调和异步处理。

		Return:ChatGenerationChunk类的输出,完全符合langchain风格。
			
        """

        last_message = messages[-1].content
        inputs = self.tokenizer(last_message, return_tensors="pt").to(self.device)
        streamer = TextIteratorStreamer(tokenizer=self.tokenizer)  # transformers提供的标准接口,专为流式输出而生
        inputs.update({"streamer": streamer, "max_new_tokens": 512})  # 这是model.generate的参数,可以自由发挥
        thread = Thread(target=self.model.generate, kwargs=inputs)  # TextIteratorStreamer需要配合线程使用
        thread.start()
        for new_token in streamer:
        # 用迭代器的返回形式 。
            yield ChatGenerationChunk(message=AIMessage(content=new_token))

	@property
    def _llm_type(self) -> str:
        """返回自定义模型的标记"""
        return "Custom"
    
    @property
    def _identifying_params(self) -> Dict[str, Any]:
        """返回自定义的debug信息"""
        return {"model_path": self.model_name, "device": self.device}

本文使用chatglm3-6b模型为例,演示最基础使用方法。

import CustomChatModel
import os
from langchain_core.messages import HumanMessage

# 模型实例化
model = LoadChatLLM(model_name="THUDM/chatglm-6b", 
                    device=“cuda”, 
                    temperature=float(1.0))

def stream_generate_text(text):
        """
        流式输出的方式打印到终端。
        原理就是每生成一个新token,就清空屏幕,然后把原先生成过的所有tokens
        都打印一次。
        """
        generated_text = ''
        count = 0
        message = [HumanMessage(content=text)]
        for new_text in model._stream(message):
            generated_text += new_text.text
            count += 1
            if count % 8 == 0:  # 避免刷新太频繁,每8个tokens刷新一次
                os.system("clear")
                print(generated_text)
            os.system("clear")
            print(generated_text)

    while True:
        ipt = input("请输入:")
        stream_generate_text(ipt)

实际效果:
我问它:如何安装Python?
在这里插入图片描述

它的输出:
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

废品回收小程序怎么做?有哪些核心功能?

废品回收行业正逐步走向高质量发展的道路。在国家政策的推动下&#xff0c;再生资源市场需求旺盛&#xff0c;行业内部竞争格局逐渐明朗。 随着互联网技术的发展&#xff0c;"互联网回收"成为废品回收行业的一个新趋势。通过微信小程序这种线上平台&#xff0c;用户…

Next-Level Agents:释放动态上下文(Dynamic Context)的巨大潜力

编者按&#xff1a; 本文深入探讨了如何通过优化动态上下文信息&#xff08;Dynamic Context&#xff09;来提升 AI Agents 的工作效率和准确性。文章首先概述了五种常见的技术策略&#xff0c;包括信息标识(Message Labeling)、针对不同需求设定不同上下文、优化系统提示词(Sy…

用python写一个基于PyQt5和OpenAI的智能问答项目

摘要&#xff1a; 使用python写一个可以对话的智能问答机器人&#xff0c;界面是使用PyQt5写的&#xff0c;通过调用OpenAl的免费接口&#xff0c;实现实时聊天功能。 1.申请免费的API key 前往页面https://github.com/chatanywhere/GPT_API_free 点击下面链接&#xff1a; …

如何判断ubuntu是桌面版(destop版)还是服务版(server版)?(systemctl status display-manager)

文章目录 用命令systemctl status display-manager 用命令systemctl status display-manager systemctl status display-manager如果是ubuntu desktop&#xff0c;将显示服务正在运行&#xff0c;如&#xff1a; 如果是ubuntu server&#xff0c;将不会显示服务&#xff0c;提…

计网ppt标黄知识点整理第(1)章节——谢希仁版本、期末复习自用

大众熟知的三大网络&#xff1a;电信网络、有线电视网络、计算机网络。发展最快起到核心的是计算机网络。Internet是全球最大、最重要的计算机网络。互联网&#xff1a;流行最广、事实上的标准译名。互连网&#xff1a;把许多网络通过一些路由器连接在一起。与网络相连的计算机…

宏集Panorama SCADA:个性化定制,满足多元角色需求

前言 在考虑不同人员在企业中的职能和职责时&#xff0c;他们对于SCADA系统的需求可能因其角色和工作职责的不同而有所差异。在SCADA系统的设计和实施过程中&#xff0c;必须充分考虑和解决这种差异性。 为了满足不同人员的需求, 宏集Panorama SCADA平台具备灵活的功能和定制…

如何通过PHP语言实现远程控制多路照明

如何通过PHP语言实现远程控制多路照明呢&#xff1f; 本文描述了使用PHP语言调用HTTP接口&#xff0c;实现控制多路照明&#xff0c;通过多路控制器&#xff0c;可独立远程控制多路照明。 可选用产品&#xff1a;可根据实际场景需求&#xff0c;选择对应的规格 序号设备名称厂…

Android Dialog使用汇总

Dialog分类 AlertDialog Dialog 类是对话框的基类&#xff0c;官方建议我们不要直接实例化它&#xff0c;而是使用其子类来获取实例。AlertDialog是系统提供的一个直接子类&#xff0c;它能帮助我们快速构建出不同类型的弹窗。接下来就看下各种类型弹窗的使用。 1、普通对话框…

【教学类-13-05】20240604《数字色块图-5*7*8-A4横板-横切》中4班

背景需求&#xff1a; 【教学类-13-04】20230404《数字色块图判断密码是否正确-5*7*8-A4横板-横切》&#xff08;中班主题《我爱我家》)_图案密码色块-CSDN博客文章浏览阅读530次。【教学类-13-04】20230404《数字色块图判断密码是否正确-5*7*8-A4横板-横切》&#xff08;中班主…

2024高质量建成新型电力系统加速发展低零碳灵活性资源研究报告

来源&#xff1a;RMI&清华大学 近期历史回顾&#xff1a;2024年中国新能源汽车出海洞察.pdf 2024可信赖的企业级生成式 AI 白皮书.pdf 2023亚洲家族办公室 2024年移动性别鸿沟报告.pdf 2024年社交媒体顶级美容品牌.pdf 2024高质量建成新型电力系统加速发展低零碳灵活性资源…

Linux 搭建 ZeroTier 的 Moon 服务器

系统&#xff1a;centos 7.6 轻量云服务器&#xff1a;腾讯云 Moon是什么&#xff0c;为什么需要Moon&#xff1f; ZeroTier通过自己的多个根服务器帮助我们建立虚拟的局域网&#xff0c;让虚拟局域网内的各台设备可以打洞直连。这些根服务器的功能有些类似于通过域名查询找到…

2024年数字化经济与金融创新国际学术会议(ICDEFI 2024)

2024年数字化经济与金融创新国际学术会议&#xff08;ICDEFI 2024&#xff09; 会议简介 2024年数字经济与金融创新国际学术会议即将召开。此次会议旨在汇集全球数字经济与金融创新领域的专家学者&#xff0c;共同探讨数字经济的发展趋势以及金融创新的路径。与会者将分享前沿…

Linux下查看进程和端口信息

1, 根据进程名(这里是模糊查询)查看进程信息&#xff0c;以查看nginx进程名为例&#xff0c;查看所对应的进程id为19013(或者使用&#xff1a; ps -aux | grep nginx查看占用内存等信息) ps -ef | grep nginx 2, 根据进程id查看进程占用端口&#xff0c;查看对应端口为8080&…

springboot+mqtt使用总结

1.软件的选型 1.1.使用免费版EMQX 1.1.1.下载 百度搜索的目前是会打开官网&#xff0c;这里提供下免费版的使用链接EMQX使用手册 文档很详细&#xff0c;这里不再记录了。 1.2.使用rabbitmq rabbitmq一般做消息队列用&#xff0c;作为mqtt用我没有找到详细资料&#xff0c…

VB.net实战(VSTO):Excel插件的安装与卸载

1. 安装 1.1编程环境&#xff1a;Visual Studio 2022 1.2创建新项目&#xff1a; 1.3 加入一行测试程序&#xff1a;MsgBox&#xff08;“hello”&#xff09;&#xff0c;点击启动&#xff0c;确认可以弹窗 1.4 点击发布 1.5 找到安装程序&#xff0c;点击安装。打开Excel程…

win10环境下nodejs安装过程

打开 https://nodejs.org/en/官网下载node.js 2.下载完成后的安装文件为node-v16.16.0-x64.msi&#xff0c;双击进行安装即可。 3.一直默认安装&#xff0c;记得可以更改安装路径 4.其他不用打勾&#xff0c;一直next&#xff0c;安装完成即可。 5.安装完成后&#xff0c;wi…

软件测试需求管理指南规范(Word原件,项目管理全资料)

3 测试需求 3.1 测试范围 3.2 测试目标 4 测试需求的现状 5 测试需求的内容 5.1 主体内容 5.2 管理内容 6 测试需求的制定 6.1 需求信息来源 6.2 需求分析 6.2.1 功能性需求 6.2.2 系统功能需求 6.2.3 界面需求 6.2.4 安装需求 6.2.5 业务需求 6.2.6 非功能性需求 6.2.7 性能需…

告别复制粘贴:AI论文写作工具的高效应用

写作这件事一直让我们从小学时期就开始头痛&#xff0c;初高中时期800字的作文让我们焦头烂额&#xff0c;一篇作文里用尽了口水话&#xff0c;拼拼凑凑才勉强完成。 大学时期以为可以轻松顺利毕业&#xff0c;结果毕业前的最后一道坎拦住我们的是毕业论文&#xff0c;这玩意不…

企业应用架构模式--详解51种企业应用架构模式

导读&#xff1a;企业应用包括哪些&#xff1f;它们又分别有哪些架构模式&#xff1f; 世界著名软件开发大师Martin Fowler给你答案 目录 01什么是企业应用02 企业应用的种类03企业架构模式 01什么是企业应用 我的职业生涯专注于企业应用&#xff0c;因此&#xff0c;这里所谈…

【Python系列】Python装饰器

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…