(19-1)操作国产大模型:LangChain与ChatGLM实践

LangChain是一个强大的工具,用于构建由语言模型(LLM)驱动的应用程序,它提供了与多种不同语言模型交互的标准接口。在本书前面的内容中,绝大多数LangChain例子都是基于OpenAI的ChatGPT模型实现的,其实LangChain可以适配并使用我们的国产模型。在本章的内容中,将详细讲解使用LangChain操作国产模型的知识。

7.2.1  LangChain与ChatGLM实践

ChatGLM 是由智谱AI推出的一系列大模型,这些模型基于大规模预训练技术,具备强大的自然语言处理能力。因为ChatGLM已经开源了包括 ChatGLM-6B在内的多个模型版本,为了降低大家的学习成本,本书将以ChatGLM-6B为例介绍LangChain操作ChatGLM的知识。

1. ChatGLM介绍

ChatGLM-6B是ChatGLM大模型系列中的一个开源模型(开源地址https://github.com/THUDM/ChatGLM-6B),这个模型基于General Language Model (GLM)架构,拥有62亿参数,并且特别针对中文进行了优化。ChatGLM-6B在1:1比例的中英语料上训练了1T的token量,兼具双语能力,并且通过模型量化技术,可以在消费级的显卡上进行本地部署,INT4量化级别下最低只需6GB显存。

ChatGLM系列大模型包括但不限于对话生成、智能问答等任务,而LangChain可以适配并使用这些模型。ChatGLM的基本信息如下所示:

  1. 模型支持:LangChain支持ChatGLM模型,并且有专门的第三方实现集中在LangChain-Community库中。
  2. 集成ChatGLM:开发者可以通过继承LangChain提供的基类并实现相关方法来创建自定义的ChatModel,从而集成ChatGLM模型。
  3. API适配:为了适配ChatGLM的API,开发者可能需要自定义适配器,并确保与LangChain的接口兼容。
  4. 使用示例:有教程和代码示例说明了如何在本地环境中部署ChatGLM模型,并与LangChain结合使用,以创建知识库和执行问答任务。
  5. 微调和应用:LangChain不仅可以加载和运行ChatGLM模型,还可以用于模型的微调和在特定领域的应用。
  6. 开源社区:LangChain的开源社区提供了多种集成和应用示例,包括与ChatGLM模型的集成。
  7. 模型升级:LangChain能够支持ChatGLM模型的更新,并实现接口的兼容性,这表明LangChain能够适应模型的升级和变化,保持应用的连续性。
  8. 文档和教程:存在详细的文档和教程,帮助用户理解如何将ChatGLM与LangChain结合使用,包括如何加载模型、处理文件、向量化文本、以及如何使用LangChain进行问答。

2. 准备开发环境

建议直接参考ChatGLM-6B开源地址中的配置文件https://github.com/THUDM/ChatGLM-6B/blob/main/requirements.txt:

protobuf
transformers==4.27.1
cpm_kernels
torch>=1.10
gradio
mdtex2html
sentencepiece
accelerate

通过如下命令安装所需要的库:

pip install -r requirements.txt

3. 准备模型文件

在目前的就似乎条件下,可以通过如下三种方法准备文件:

(1)直接从huggingface模型仓库拉取模型文件,这种方法的缺点是需要先安装Git LFS,拉取速度很慢。

git clone https://huggingface.co/THUDM/chatglm-6b

(2)从huggingface模型残酷拉取模型实现,然后从清华仓库下载模型参数文件,然后替换到chatglm-6b文件夹中。

GIT_LFS_SKIP_SMUDGE=1 git clone https://huggingface.co/THUDM/chatglm-6b
# 下载模型参数文件...
mv chatglm-6b/* THUDM/chatglm-6b/

(3)通过使用transformers库中的类AutoTokenizer和类AutoModel,自动实现ChatGLM-6B模型和分词器的下载及加载工作。

import os
from transformers import AutoTokenizer, AutoModel
tokenizer = AutoTokenizer.from_pretrained("THUDM/chatglm-6b", trust_remote_code=True)
model = AutoModel.from_pretrained("THUDM/chatglm-6b", trust_remote_code=True)

请看下面的实例,演示了实用第三种方法调用ChatGLM-6B模型进行对话的过程。

实例7-1:使用自定义的LLM返回输入信息中的前n个字符(源码路径:codes\7\qing.py

实例文件qing.py的具体实现代码如下所示。

import os
from transformers import AutoTokenizer, AutoModel

# 指定使用编号为0的GPU
os.environ["CUDA_VISIBLE_DEVICES"] = "0"

# 加载分词器和模型
tokenizer = AutoTokenizer.from_pretrained("THUDM/chatglm-6b", trust_remote_code=True)
model = AutoModel.from_pretrained("THUDM/chatglm-6b", trust_remote_code=True)

# 将模型发送到GPU,并设置为评估模式
model = model.to('cuda')  # 这将模型移动到默认的GPU上
model = model.eval()

# 将模型转换为半精度
model.half()
human_input = "你好"
response, history = model.chat(tokenizer, human_input, history=[])

print(f"Human: {human_input}")
print(f"AI: {response}")

上述代码的目的是使用库transformers从Hugging Face模型库中加载并运行一个名为"THUDM/chatglm-6b"的预训练对话模型,以下是代码的详细步骤和功能:

(1)环境设置:os.environ["CUDA_VISIBLE_DEVICES"] = "0":这行代码设置了环境变量,指定程序只能看到编号为0的GPU。如果你的系统中有多个GPU,这可以用来决定哪个GPU用于模型的推理或训练。

(2)加载分词器和模型

  1. tokenizer = AutoTokenizer.from_pretrained("THUDM/chatglm-6b", trust_remote_code=True):加载与"THUDM/chatglm-6b"模型配套的分词器。分词器用于将文本转换为模型可以理解的格式。
  2. model = AutoModel.from_pretrained("THUDM/chatglm-6b", trust_remote_code=True):加载预训练的"THUDM/chatglm-6b"模型。trust_remote_code=True参数允许加载远程代码,这在加载自定义或第三方模型时是必需的。

(3)准备模型进行推理

  1. model = model.to('cuda'):将模型的权重移动到GPU上,以利用GPU加速模型的推理过程。这一步假定你的机器上安装了NVIDIA的GPU和CUDA。
  2. model = model.eval():将模型设置为评估模式,这通常关闭了模型训练时使用的特定功能,如dropout。

(4)model.half():将模型转换为半精度(float16),这可以减少模型在GPU上的内存占用,允许更大的模型或批量大小,但也需要硬件和深度学习框架支持半精度运算。

(5)生成对话响应

  1. human_input = "你好":定义人类的输入文本。
  2. response, history = model.chat(tokenizer, human_input, history=[]):调用模型的chat方法来生成响应。这个方法需要分词器、用户的输入,以及对话历史。

(6)打印结果:最后,代码打印输出了用户的输入和AI生成的回答响应。执行后会输出:

Loading checkpoint shards: 100%|██████████| 8/8 [00:38<00:00,  4.87s/it]
Human: 你好

AI: 你好��!我是人工智能助手 ChatGLM-6B,很高兴见到你,欢迎问我任何问题。

4. 模型服务调用接口

在大模型开发应用中,模型服务调用接口(API)扮演着至关重要的角色,主要体现在以下几个方面:

  1. 封装复杂性:API为终端用户或下游应用提供了一个简单、标准化的接口来与模型交互,隐藏了背后的复杂实现细节。
  2. 可访问性:通过API,用户可以远程访问模型的推理能力,而无需了解模型的内部工作原理或直接与模型文件交互。
  3. 扩展性:API允许模型服务水平扩展,以支持大量并发请求,满足不同规模用户的需求。
  4. 灵活性:API可以轻松地集成到不同的应用程序中,包括Web应用、移动应用、聊天机器人、以及其他第三方服务。
  5. 安全性:API服务器可以实现认证和授权机制,确保只有合法用户可以调用模型服务。
  6. 监控和管理:API服务器可以集成监控和日志记录工具,以跟踪模型的使用情况,及时发现并解决潜在问题。
  7. 版本控制:通过API,可以更容易地对模型进行版本控制和更新,而不会影响现有用户。
  8. 负载均衡:API服务器可以分配请求到多个模型实例,实现负载均衡,提高服务的可用性和响应速度。
  9. 计费和配额管理:API可以用于实现计费系统,对使用模型的频率和次数进行限制和跟踪。
  10. 跨平台兼容性:API使得模型服务可以跨越不同的操作系统和编程语言,提供广泛的兼容性。
  11. 简化部署:API允许开发者将模型作为服务(Model as a Service, MaaS)部署,简化了部署和运维流程。
  12. 促进协作:API可以作为团队或组织之间协作的基础,允许不同团队独立地开发、部署和使用模型。

在实际应用中,模型服务调用接口通常是通过HTTP协议实现的,使用RESTful或GraphQL等风格。这些接口可以返回JSON、XML或其他格式的数据,以便于客户端处理。通过精心设计API,可以提高大模型的可用性、灵活性和整体的用户体验。

请看下面的例子,使用Flask技术实现了一个简单的模型服务调用接口。在这个Web应用中,使用库transformers加载了一个预训练的对话模型ChatGLM-6B,并提供了一个HTTP端点来接收用户的输入并返回模型的响应。

实例7-2使用Flask实现一个简单的模型服务调用接口(源码路径:codes\7\diao.py

实例文件diao.py的具体实现代码如下所示。

import os
import json
from flask import Flask, request, jsonify
from transformers import AutoTokenizer, AutoModel

# 系统参数
os.environ["CUDA_VISIBLE_DEVICES"] = "0"

# 加载分词器和模型
tokenizer = AutoTokenizer.from_pretrained("THUDM/chatglm-6b", trust_remote_code=True)
model = AutoModel.from_pretrained("THUDM/chatglm-6b", trust_remote_code=True)
model = model.to('cuda')  # 将模型发送到GPU
model = model.eval()  # 将模型设置为评估模式
model.half()  # 将模型转换为半精度

app = Flask(__name__)

@app.route("/", methods=["GET"])
def root():
    ""“根路由响应。”""
    return "这是主页."

@app.route("/chat", methods=["POST"])
def chat():
    """处理聊天请求."""
    # 从POST请求中获取JSON数据
    data = request.json
    human_input = data.get("human_input", "")

    # 从模型生成响应
    response, _ = model.chat(tokenizer, human_input, history=[])

    # 创建一个结果字典
    result = {
        "human_input": human_input,
        "ai_response": response
    }

    # 将响应作为JSON返回
    return jsonify(result)

if __name__ == "__main__":
    app.run(host="127.0.0.1", port=8595, debug=False)

上述代码的实现流程如下所示:

(1)设置环境变量:使用os.environ指定程序只能看到编号为0的GPU,这样模型训练或推理时只会使用这个GPU。

  1. 加载模型和分词器
  1. 使用AutoTokenizer.from_pretrained和AutoModel.from_pretrained方法加载预训练的分词器和模型,将模型发送到GPU(如果可用)。
  2. 将模型设置为评估模式,关闭某些训练时使用的特性,如dropout。
  3. 将模型转换为半精度,以节省GPU内存。

(3)初始化Flask应用:创建一个Flask应用实例。

(4)定义路由和视图函数,使用@app.route装饰器定义两个路由:

  1. /:根路由,返回欢迎信息。
  2. /chat:聊天路由,处理POST请求,生成并返回聊天响应。

(5)聊天视图函数 (chat())

  1. 从POST请求的JSON数据中获取用户输入,使用模型和分词器生成AI的响应创建一个包含用户输入和AI响应的字典。
  2. 使用jsonify将结果字典转换为JSON格式的响应,并返回。

(6)运行Flask应用:使用app.run()启动Flask应用,监听127.0.0.1的8595端口,不开启调试模式。

(8)客户端请求处理:当客户端(如Web浏览器、API测试工具或自定义脚本)发送POST请求到/chat端点时,Flask应用将处理这个请求,并返回AI的响应。

执行实例文件diao.py后会输出:

Loading checkpoint shards: 100%|██████████| 8/8 [00:48<00:00,  6.12s/it]
 * Serving Flask app 'diao'
 * Debug mode: off
* Running on http://127.0.0.1:8595

打开一个新的命令行窗口(例如CMD或curl),然后运行以下命令:

curl -X POST -H "Content-Type: application/json" -d "{\"human_input\": \"你好\"}" http://127.0.0.1:8595/chat

上述命令会向Flask应用发送一个JSON格式的POST请求,请求体包含一个键为human_input,值为“你好”的字符串。按下回车键后会获得ChatGLM-6B的回复信息,完整的执行过程如下:

C:\Users\37197>curl -X POST -H "Content-Type: application/json" -d "{\"human_input\": \"你好\"}" http://127.0.0.1:8595/chat
{"response": "你好👋!我是人工智能助手 ChatGLM-6B,很高兴见到你,欢迎问我任何问题。"}

5. LangChain调用ChatGLM

在前面的内容中,已经使用Flask实现了一个ChatGLM-6B模型服务的调用接口,请看下面的例子,使用LangChain构建了一个聊天语言模型(LLM)的接口,并与运行在本地服务器上的模型进行交互。在本实例中,使用LLMs模块封装了ChatGLM模型。

实例7-3使用LangChain构建一个聊天语言模型的接口(源码路径:codes\7\lang.py

实例文件lang.py的具体实现代码如下所示。

import time
import logging
import requests
from typing import Optional, List, Dict, Mapping, Any

import langchain
from langchain.llms.base import LLM
from langchain.cache import InMemoryCache

logging.basicConfig(level=logging.INFO)
# 启动llm的缓存
langchain.llm_cache = InMemoryCache()

class ChatGLM(LLM):
    
    # 模型服务url
    url = "http://127.0.0.1:8595/chat"

    @property
    def _llm_type(self) -> str:
        return "chatglm"

    def _construct_query(self, prompt: str) -> Dict:
        """构造请求体
        """
        query = {
            "human_input": prompt
        }
        return query

    @classmethod
    def _post(cls, url: str,
        query: Dict) -> Any:
        """POST请求
        """
        _headers = {"Content_Type": "application/json"}
        with requests.session() as sess:
            resp = sess.post(url, 
                json=query, 
                headers=_headers, 
                timeout=60)
        return resp

    
    def _call(self, prompt: str, 
        stop: Optional[List[str]] = None) -> str:
        """_call
        """
        # construct query
        query = self._construct_query(prompt=prompt)

        # post
        resp = self._post(url=self.url,
            query=query)
        
        if resp.status_code == 200:
            resp_json = resp.json()
            predictions = resp_json["response"]
            return predictions
        else:
            return "请求模型" 
    
    @property
    def _identifying_params(self) -> Mapping[str, Any]:
        """Get the identifying parameters.
        """
        _param_dict = {
            "url": self.url
        }
        return _param_dict

if __name__ == "__main__":
    llm = ChatGLM()
    while True:
        human_input = input("Human: ")

        begin_time = time.time() * 1000
        # 请求模型
        response = llm(human_input, stop=["you"])
        end_time = time.time() * 1000
        used_time = round(end_time - begin_time, 3)
        logging.info(f"chatGLM process time: {used_time}ms")

        print(f"ChatGLM: {response}")

上述代码的实现流程如下所示:

(1)配置日志记录:使用 logging.basicConfig 设置日志记录的基本配置,日志级别为 INFO。

(2)初始化LLM缓存:langchain.llm_cache 被设置为 InMemoryCache,这意味着LLM的响应可能会被缓存在内存中,以加快后续请求的处理速度。

(3)定义类ChatGLM:该类继承自 langchain.llms.base.LLM,实现了一个与远程模型服务交互的聊天模型接口。

  1. 类变量url:包含了模型服务的 URL。
  2. 属性_llm_type:返回字符串 "chatglm",标识模型类型。
  3. 方法_construct_query:用于构造请求体,将提示(prompt)封装为一个字典。
  4. 方法_post,用于发送 POST 请求到模型服务,传递 JSON 数据。
  5. 方法_call:实现了基类 LLM 的抽象方法,用于构造查询,发送 POST 请求,并处理响应。如果响应状态码为200,它将解析 JSON 响应并返回预测结果;否则,它将返回字符串 "请求模型"。
  6. 属性_identifying_params:返回一个包含 URL 的字典,这些参数用于标识模型。

(4)主程序:在 if __name__ == "__main__": 块中,代码创建了一个 ChatGLM 实例,并进入一个无限循环,不断从用户那里接收输入,然后调用 llm 实例和用户的输入来获取响应。

(5)性能监控:使用函数time.time()来测量处理每个请求所需的时间,并以毫秒为单位打印出来。

(6)处理请求和响应:用户输入被传递给 ChatGLM 实例的调用,接收的响应被打印到控制台上。

首先运行前面的Flask程序文件diao.py,然后执行本实例程序文件,执行后会输出:

Human: 你好
INFO:root:chatGLM process time: 993.685ms
ChatGLM: 你好 !我是人工智能助手 ChatGLM-6B,很高兴见到你,欢迎问我任何问题。
Human: 你好
INFO:root:chatGLM process time: 0.116ms
ChatGLM: 你好 !我是人工智能助手 ChatGLM-6B,很高兴见到你,欢迎问我任何问题。

  • 21
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码农三叔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值