用通俗易懂的方式讲解大模型:使用 LangChain 封装自定义的 LLM,太棒了

Langchain 默认使用 OpenAI 的 LLM(大语言模型)来进行文本推理工作,但主要的问题就是数据的安全性,跟 OpenAI LLM 交互的数据都会上传到 OpenAI 的服务器。

企业内部如果想要使用 LangChain 来构建应用,那最好是让 LangChain 使用企业内部的 LLM,这样才能保证数据不泄露。

LangChain 提供了集成多种 LLM 的能力,包括自定义的 LLM,今天我们就来介绍一下如何使用 LangChain 来集成自定义的 LLM 以及其中的实现原理。

开源大模型

虽然现在的商业大模型(OpenAI 和 Anthropic)功能十分强大,但开源大模型愈来愈有迎头赶上的趋势,比如最近刚发布的Falcon-180B[1]大模型,具备 1800 亿参数,(号称)性能甚至直逼 GPT-4。所以对于想构建 AI 应用,又不想自身数据泄露的企业来说,开源大模型是首要选择。

开源大模型也有很多选择,要根据自身的需求来考虑。比如需要大量自然语言处理的项目,选择一个专注于文本处理的模型会比选择图像或视频的模型更合适,再比如需要提供多语言的项目,那么大模型就需要支持多语言而不仅仅是英文。另外模型的大小和复杂性也是一个考虑因素,大模型虽然能够处理更复杂的任务,但它们通常需要更多的计算资源和存储空间。对于有限资源的中小企业,可能需要选择一个更轻量级的模型。

对于一些简单的应用,我们可以选择现在国内比较流行的中文开源大模型——ChatGLM 或者 BaiChuan,它们不仅支持中英文,还开源了小参数的 LLM,比如 ChatGLM2-6B、Baichuan2-13B 等。

通俗易懂讲解大模型系列

  • 用通俗易懂的方式讲解大模型:使用 FastChat 部署 LLM 的体验太爽了
  • 用通俗易懂的方式讲解大模型:基于 Langchain 和 ChatChat 部署本地知识库问答系统
  • 用通俗易懂的方式讲解大模型:使用 Docker 部署大模型的训练环境
  • 用通俗易懂的方式讲解大模型:在 Ubuntu 22 上安装 CUDA、Nvidia 显卡驱动、PyTorch等大模型基础环境
  • 用通俗易懂的方式讲解大模型:Llama2 部署讲解及试用方式
  • 用通俗易懂的方式讲解大模型:LangChain 知识库检索常见问题及解决方案
  • 用通俗易懂的方式讲解大模型:基于 LangChain 和 ChatGLM2 打造自有知识库问答系统
  • 用通俗易懂的方式讲解大模型:代码大模型盘点及优劣分析
  • 用通俗易懂的方式讲解大模型:Prompt 提示词在开发中的使用

技术交流

建了大模型技术交流群! 想要学习、技术交流、获取如下原版资料的同学,可以直接加微信号:mlc2060。加的时候备注一下:研究方向 +学校/公司+CSDN,即可。然后就可以拉你进群了。

方式①、微信搜索公众号:机器学习社区,后台回复:加群
方式②、添加微信号:mlc2060,备注:来自CSDN + 技术交流

在这里插入图片描述

LLM 部署

后面我们会用 LangChain 来集成 ChatGLM2 进行介绍,所以我们需要先部署 ChatGLM2-6B 这个 LLM。ChatGLM2-6B 部署有多种方式,可以使用它自身的代码仓库进行部署,也可以使用其他框架来进行部署。我们主要部署 ChatGLM2-6B 的 API 服务,具体步骤可以参考我之前的文章:使用 FastChat 部署 LLM,这里就不再赘述。

部署后的 API 服务地址我们假设是http://localhost:5000,调用/chat/completions接口会返回类似 OpenAI 接口的信息:

$ curl -X 'POST' \
  'http://localhost:5000/v1/chat/completions' \
  -H 'accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
  "model": "chatglm2-6b",
  "messages": [{"role": "user", "content": "你好"}]
}'

# 输出结果
{
  "id": "chatcmpl-TPvsyLsybHEJ2nd953q7E2",
  "object": "chat.completion",
  "created": 1694497436,
  "model": "chatglm2-6b",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "你好!我是人工智能助手 ChatGLM2-6B,很高兴见到你,欢迎问我任何问题。"
      },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 4,
    "total_tokens": 145,
    "completion_tokens": 141
  }
}

这个接口是兼容 OpenAI 接口的,其中 model 和 messages 参数是必须的,messages 中 role 的值有userassistant, system这几项,content 是对应角色的内容,更多参数信息可以参考OpenAI 的 API 官方文档[3]。下面我们主要使用这个 API 来封装我们的自定义 LLM。

封装自定义 LLM

使用 LangChain 封装自定义的 LLM 并不复杂,可以看下面的代码示例:

import requests
from typing import Any, List, Mapping, Optional

from langchain.callbacks.manager import CallbackManagerForLLMRun
from langchain.llms.base import LLM

class CustomLLM(LLM):
    endpoint: str = "http://localhost:5000"
    model: str = "chatglm2-6b"

    def _call(
        self,
        prompt: str,
        stop: Optional[List[str]] = None,
        callbacks: Optional[CallbackManagerForLLMRun] = None,
        **kwargs: Any,
    ) -> str:
        headers = {"Content-Type": "application/json"}
        data = {"model": self.model, "messages": [{"role": "user", "content": prompt}]}
        response = requests.post(f"{self.endpoint}/chat/completions", headers=headers, json=data)
        response.raise_for_status()

        result = response.json()
        text = result["choices"][0]["message"]["content"]
        return text

  • 首先我们需要创建一个类继承自LLM,然后实现_call方法

  • 方法的最主要的参数是提示词prompt,这个参数就是上面接口中的messages参数中的用户内容

  • _call方法中,我们构造 API 接口所需参数,包括 headers 和 data

  • 调用 API 接口,获取到返回结果,最后返回choicesmessage的内容

_call方法的实现逻辑就是接收用户的输入,然后将其传递给 LLM,然后获取到 LLM 的输出,最后再返回结果给用户。在方法中可以调用 API 服务,也可以用 transformer 来初始化模型然后直接调用模型进行推理,总之可以用各种方法来调用 LLM,只要能得到LLM返回的结果即可。

自定义 LLM 的其他方法

除了_call方法外,我们还需要实现其他方法,比如_llm_type方法,这个方法是用来定义 LLM 的名称,因为我们用的是 ChatGLM2-6B 模型,所以我们可以这样实现:

    @property
    def _llm_type(self) -> str:
        return "chatglm2-6b"

还有_identifying_params方法,这个方法是用来打印自定义 LLM 类的参数信息,方便我们做调试,它返回的是一个字典,代码示例如下:

    @property
    def _identifying_params(self) -> Mapping[str, Any]:
        """Get the identifying parameters."""
        return {"endpoint": self.endpoint, "model": self.model}

自定义 LLM 的使用

自定义 LLM 的使用跟使用其他 LLM 一样,我们可以直接调用自定义 LLM 的实例,代码示例如下:

llm = CustomLLM()
print(llm("你好"))

# 输出结果
"""
你好!我是人工智能助手 ChatGLM2-6B,很高兴见到你,欢迎问我任何问题。
"""

_call 方法的其他参数

_call方法中除了 prompt 参数外,我们还看到了其他参数,这些参数都是可选的,我们来看一下这些参数的作用:

stop

这个参数是传入一个字符串集合,当检测到 LLM 的输出内容中包含了这些字符串时,输出内容会立即截断,只保留前面的内容。比如我们得到的 LLM 结果如下:

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

当我们将stop参数设置为["欢迎"]时,输出结果就会变成:

你好!我是人工智能助手 ChatGLM2-6B,很高兴见到你,

如果是自定义 LLM,stop参数的逻辑也需要我们自己来实现,LangChain 其实提供了对应的工具方法,我们直接使用就可以了,代码示例如下:

from langchain.llms.utils import enforce_stop_tokens

def _call(
        self,
        prompt: str,
        stop: Optional[List[str]] = None,
        callbacks: Optional[CallbackManagerForLLMRun] = None,
        **kwargs: Any,
    ) -> str:
        .....
        if stop is not None:
            text = enforce_stop_tokens(text, stop)

callbacks

这个参数是一个CallbackManagerForLLMRun对象,用于在 LLM 运行过程中执行回调函数,比如在 LLM 运行前后执行一些操作,比如记录日志、保存模型等。这个参数是可选的,我们使用 LangChain 提供的日志记录回调函数来演示下功能:

from loguru import logger
from langchain.callbacks import FileCallbackHandler

if __name__ == "__main__":
    llm = CustomLLM()
    logfile = "output.log"
    logger.add(logfile, colorize=True, enqueue=True)
    handler = FileCallbackHandler(logfile)
    result = llm("你好", stop=["欢迎"], callbacks=[handler])
    logger.info(result)

执行完程序后,会在当前目录下生成一个output.log文件,文件内容如下:

2023-09-12 11:28:19.029 | INFO     | __main__:<module>:110 - 你好!我是人工智能助手 ChatGLM2-6B,很高兴见到你,

注意: 在 LangChain 官方文档的示例代码中将callbacks参数写成了run_manager,其实最新代码中这个参数名已经改成了callbacks了,可能官方文档还没有及时更新。

LangChain 还提供了更多的回调方法,想了解更多信息的可以参考这个文档[4]。

LangChain 官方文档上也给出了自定义 LLM 的简单代码示例,可以参考:Custom LLM[5]。

其他自定义的 LLM

除了参考以上示例来编写自定义的 LLM 外,还可以参考 LangChain 中已经集成的其他 LLM。

ChatGLM

这个是封装比较早的 ChatGLM LLM,用的还是一代的 ChatGLM,除非部署方式一致,否则不建议直接使用该 LLM,建议参照其中的代码来实现自己的 LLM。

  • 相关文档:ChatGLM LLM[6]

  • 相关代码:chatglm.py[7]

Fake LLM

这是一个假的 LLM,用于测试,自定义内容来模拟 LLM 的输出,可以参考其中的代码来实现自己的 LLM,其中包含了流式输出,异步调用等功能的实现逻辑。

  • 相关文档:Fake LLM[8]

  • 相关代码:fake.py[9]

还有很多其他的 LLM,包括 OpenAI 的 LLM,如果感兴趣的也可以去看看它们的源码,相对会比较复杂,更多信息可以参考这里[10]。

总结

今天我们主要介绍了如何使用 LangChain 来集成自定义的 LLM,以及其中的实现原理,实现自己的 LangChain LLM 并不复杂,但如果要实现一个功能强大,性能高效的 LLM,就需要花费更多的时间和精力了,好在 LangChain 提供了一系列的工具和组件,可以帮助我们快速实现自己的功能。希望今天的文章能够帮助到大家,也希望使用过 LangChain 的同学一起来交流学习,欢迎在评论区留言。

关注我,一起学习各种人工智能和 AIGC 新技术,欢迎交流,如果你有什么想问想说的,欢迎在评论区留言。

参考:

[1]Falcon-180B: https://huggingface.co/spaces/tiiuae/falcon-180b-demo

[3] OpenAI 的 API 官方文档: https://platform.openai.com/docs/api-reference/chat/create

[4]这个文档: https://python.langchain.com/docs/modules/callbacks/

[5]Custom LLM: https://python.langchain.com/docs/modules/model_io/models/llms/custom_llm

[6]ChatGLM LLM: https://python.langchain.com/docs/integrations/llms/chatglm

[7] chatglm.py: https://github.com/langchain-ai/langchain/blob/master/libs/langchain/langchain/llms/chatglm.py

[8]Fake LLM: https://python.langchain.com/docs/modules/model_io/models/llms/fake_llm

[9]fake.py: https://github.com/langchain-ai/langchain/blob/master/libs/langchain/langchain/llms/fake.py

[10]这里: https://python.langchain.com/docs/integrations/llms/

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

2024年【裂解(裂化)工艺】考试题库及裂解(裂化)工艺考试总结

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 裂解&#xff08;裂化&#xff09;工艺考试题库考前必练&#xff01;安全生产模拟考试一点通每个月更新裂解&#xff08;裂化&#xff09;工艺考试总结题目及答案&#xff01;多做几遍&#xff0c;其实通过裂解&#…

第3课 使用FFmpeg获取并播放音频流

本课对应源文件下载链接&#xff1a; https://download.csdn.net/download/XiBuQiuChong/88680079 FFmpeg作为一套庞大的音视频处理开源工具&#xff0c;其源码有太多值得研究的地方。但对于大多数初学者而言&#xff0c;如何快速利用相关的API写出自己想要的东西才是迫切需要…

关于“Python”Django 管理网站的核心知识点整理大全52

目录 注意 18.2.2 激活模型 settings.py 18.2.3 Django 管理网站 1. 创建超级用户 注意 2. 向管理网站注册模型 admin.py 注意 3. 添加主题 Climbing。 18.2.4 定义模型 Entry models.py 18.2.5 迁移模型 Entry 18.2.6 向管理网站注册 Entry admin.py 往期快速…

C++:stack、queue、priority_queue增删查改模拟实现、deque底层原理

C:stack、queue、priority_queue增删查改模拟实现 前言一、Cstack的介绍和使用1.1 引言1.2 satck模拟实现 二、Cqueue的介绍和使用2.1 引言2.2 queue增删查改模拟实现 三、STL标准库中stack和queue的底层结构:deque3.1 deque的简单介绍(了解)3.2 deque的缺陷3.3 为什么选择dequ…

c++哈希表——超实用的数据结构

文章目录 1. 概念引入1.1 整数哈希1.1.1 直接取余法。1.1.2 哈希冲突1.1.2.1 开放寻址法1.1.2.2 拉链法 1.2 字符串哈希 3.结语 1. 概念引入 哈希表是一种高效的数据结构 。 H a s h Hash Hash表又称为散列表&#xff0c;一般由 H a s h Hash Hash函数(散列函数)与链表结构共同…

【代码随想录】刷题笔记Day42

前言 这两天机器狗终于搞定了&#xff0c;一个控制ROS大佬&#xff0c;一个计院编程大佬&#xff0c;竟然真把创新点这个弄出来了&#xff0c;牛牛牛牛&#xff08;菜鸡我只能负责在旁边喊加油&#xff09;。下午翘了自辩课来刷题&#xff0c;这次应该是元旦前最后一刷了&…

车载电子电器架构 —— 电子电气系统开发角色定义

车载电子电器架构 —— 电子电气系统开发角色定义 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 注:本文12000字,深度思考者进!!! 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的…

鸿蒙应用开发 新闻数据加载

1 HTTP 数据请求概述 日常生活中我们使用应用程序看新闻、发送消息等&#xff0c;都需要连接到互联网&#xff0c;从服务端获取数据。例如&#xff0c;新闻应用可以从新闻服务器中获取最新的热点新闻&#xff0c;从而给用户打造更加丰富、更加实用的体验。 那么要实现这样一种…

技术阅读周刊第十二期

年前最后一篇推送&#xff0c;提前祝大家新年快乐。 技术阅读周刊&#xff0c;每周更新。 历史更新 20231201&#xff1a;第八期20231215&#xff1a;第十期20231122&#xff1a;第十一期 Deno vs Go: Native hello world performance | Tech Tonic URL: https://medium.com/de…

R306指纹识别模块的硬件接口

1.外部接口尺寸图 采集芯片外形尺寸&#xff1a;33.4*20.4*3.79 mm 2.串行通讯 R306 指纹模块通讯接口定义&#xff1a; 3.USB 通讯 4.接口说明 4.1 UART a) UART 缺省波特率为 57.6kbps&#xff0c;数据格式&#xff1a;8 位数据位&#xff08;低位在前&#xff09;&#…

【leetcode100-020】【矩阵】旋转图像

【题干】 给定一个 n n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。 你必须在 原地 旋转图像&#xff0c;这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。 【思路】 怎么还整上小学奥数题了&#xff08;不是对角翻转水平/垂…

什么是SEO?

什么是SEO&#xff1f; SEO代表“搜索引擎优化”。这是通过非付费&#xff08;也称为“自然”&#xff09;搜索引擎结果来提高网站流量的质量和数量以及品牌曝光率的做法。 尽管有首字母缩略词&#xff0c;但 SEO 既关乎搜索引擎本身&#xff0c;也关乎人。这是关于了解人们在…

设计模式(4)--类行为(10)--模板方法

1. 意图 定义一个操作中的算法的骨架&#xff0c;而将一些步骤延迟到子类中。 模板方法使子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。 2. 两种角色 抽象类(Abstract Class)、具体类(Concrete Class) 3. 优点 3.1 一种代码复用的基本技术。提取公共行为&am…

现代建筑 Modern Design 展示前端界面html推荐

前言 一款展示现代建筑的网页 一、需求分析 一个现代建筑展示网站是指利用现代技术和设计风格&#xff0c;以展示和推广各种建筑项目和设计作品为主要目的的网站。 作为一个现代建筑展示网站&#xff0c;以下是一些需要的要素&#xff1a; 响应式设计&#xff1a;现代建筑展…

mixins混淆请求字典封装库

摘要&#xff1a; 页面请求要使用到很多重点的查询&#xff0c;写在本页面的逻辑代码太混乱&#xff0c;所以可以抽离封装成功一个js库混淆进来&#xff01; commonMixins.js: import {Toast} from "vant"; export const oplistMix {mounted() {this.GETSTORE_LOCA…

基于电商场景的高并发RocketMQ实战-Consumer端队列负载均衡分配机制、并发消费以及消费进度提交

&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308; 【11来了】文章导读地址&#xff1a;点击查看文章导读&#xff01; &#x1f341;&#x1f341;&#x1f341;&#x1f341;&#x1f341;&#x1f341;&#x1f3…

迅软科技助力高科技防泄密:从华为事件中汲取经验教训

近期&#xff0c;涉及华为芯片技术被窃一事引起广泛关注。据报道&#xff0c;华为海思的两个高管张某、刘某离职后成立尊湃通讯&#xff0c;然后以支付高薪、股权支付等方式&#xff0c;诱导多名海思研发人员跳槽其公司&#xff0c;并指使这些人员在离职前通过摘抄、截屏等方式…

MFC - 给系统菜单(About Dialog)发消息

文章目录 MFC - 给系统菜单(About Dialog)发消息概述笔记resource.h菜单的建立菜单项的处理MSDN上关于系统菜单项值的说法END MFC - 给系统菜单(About Dialog)发消息 概述 做了一个对话框程序, 在系统菜单(在程序上面的标题栏右击)中有"关于"的菜单. 这个是程序框架…

4.24 构建onnx结构模型-Slice

前言 构建onnx方式通常有两种&#xff1a; 1、通过代码转换成onnx结构&#xff0c;比如pytorch —> onnx 2、通过onnx 自定义结点&#xff0c;图&#xff0c;生成onnx结构 本文主要是简单学习和使用两种不同onnx结构&#xff0c; 下面以 Slice 结点进行分析 方式 方法一…

Grafana增加仪表盘

1.Grafana介绍 grafana 是一款采用Go语言编写的开源应用&#xff0c;主要用于大规模指标数据的可视化展现&#xff0c;是网络架构和应用分析中最流行的时序数据展示工具&#xff0c;目前已经支持绝大部分常用的时序数据库。 Grafana下载地址&#xff1a;https://grafana.com/g…