当前位置:AIGC资讯 > AIGC > 正文

自定义 LLM:LangChain与文心一言擦出火花

自定义 LLM

自定义 LLM 需要实现以下必要的函数:

_call :它需要接受一个字符串、可选的停用词,并返回一个字符串。

它还可以实现第二个可选的函数:

_identifying_params :用于帮助打印 LLM 信息。该函数应该返回一个字典。

使用LLM模块来封装我们的模型接口,可以带来许多好处,其中之一就是有利于与LangChain的其他模块进行协同工作。

下面我们通过 LangChain自定义LLM 实现文心一言 ERNIE-Bot-turbo 大模型接入:

import json
import time
from typing import Any, List, Mapping, Optional, Dict, Union, Tuple
​
import logging
import requests
from langchain.callbacks.manager import CallbackManagerForLLMRun
from langchain.llms.base import LLM
from langchain.utils import get_from_dict_or_env
from pydantic import Field, root_validator
​
logger = logging.getLogger(__name__)
​
​
def get_access_token(api_key: str, secret_key: str):
    """
    使用 API Key,Secret Key 获取access_token
    """
    url = f"https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id={api_key}&client_secret={secret_key}"
​
    payload = json.dumps("")
    headers = {
        'Content-Type': 'application/json',
        'Accept': 'application/json'
    }
​
    resp = requests.request("POST", url, headers=headers, data=payload)
    return resp.json().get("access_token")
​
​
class ErnieLLm(LLM):
    url = "https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/eb-instant"
    model_name: str = Field(default="ERNIE-Bot-turbo", alias="model")
    request_timeout: Optional[Union[float, Tuple[float, float]]] = None
    temperature: float = 0.95
    """temperature 说明:
    (1)较高的数值会使输出更加随机,而较低的数值会使其更加集中和确定
    (2)默认0.95,范围 (0, 1.0],不能为0
    (3)建议该参数和top_p只设置1个
    (4)建议top_p和temperature不要同时更改
    """
    top_p: float = 0.8
    """top_p 说明:
    (1)影响输出文本的多样性,取值越大,生成文本的多样性越强
    (2)默认0.8,取值范围 [0, 1.0]
    (3)建议该参数和temperature只设置1个
    (4)建议top_p和temperature不要同时更改
    """
    penalty_score: float = 1.0
    """通过对已生成的token增加惩罚,减少重复生成的现象。说明:
    (1)值越大表示惩罚越大
    (2)默认1.0,取值范围:[1.0, 2.0]
    """
    ernie_api_key: Optional[str] = None
    """文心一言大模型 apiKey"""
    ernie_secret_key: Optional[str] = None
    """文心一言大模型 secretKey"""
    user_id: Optional[str] = None
    """表示最终用户的唯一标识符,可以监视和检测滥用行为,防止接口恶意调用"""
    streaming: bool = False
    """是否以流式接口的形式返回数据,默认false"""
    cache: bool = False
    """是否开启缓存,默认为false"""
    model_kwargs: Dict[str, Any] = Field(default_factory=dict)
    """Holds any model parameters valid for `create` call not explicitly specified."""
​
    @root_validator()
    def validate_environment(cls, values: Dict) -> Dict:
        """Validate that api key and python package exists in environment."""
        values["ernie_api_key"] = get_from_dict_or_env(
            values, "ernie_api_key", "ERNIE_API_KEY"
        )
        values["ernie_secret_key"] = get_from_dict_or_env(
            values,
            "ernie_secret_key",
            "ERNIE_SECRET_KEY"
        )
        return values
​
    @property
    def _default_params(self) -> Dict[str, Any]:
        """获取调用Ennie API的默认参数。"""
        normal_params = {
            "temperature": self.temperature,
            "top_p": self.top_p,
            "penalty_score": self.penalty_score,
            "request_timeout": self.request_timeout,
        }
        return {**normal_params, **self.model_kwargs}
​
    def _construct_query(self, prompt: str) -> Dict:
        """构造请求体"""
        query = {
            "messages": [
                {
                    "role": "user",
                    "content": prompt
                }
            ],
            "stream": self.streaming,
            "temperature": self.temperature,
            "top_p": self.top_p,
            "penalty_score": self.penalty_score,
            "user_id": self.user_id,
        }
        return query
​
    @property
    def _identifying_params(self) -> Mapping[str, Any]:
        """Get the identifying parameters."""
        return {**{"model_name": self.model_name}, **self._default_params}
​
    @property
    def _llm_type(self) -> str:
        return "ernie"
​
    def _call(
            self,
            prompt: str,
            stop: Optional[List[str]] = None,
            run_manager: Optional[CallbackManagerForLLMRun] = None,
            **kwargs: Any,
    ) -> str:
        """_call 实现对模型的调用"""
        # construct query
        query = self._construct_query(prompt=prompt)
        # post
        _headers = {"Content-Type": "application/json"}
        with requests.session() as session:
            resp = session.post(
                self.url + "?access_token=" + get_access_token(self.ernie_api_key, self.ernie_secret_key),
                json=query,
                headers=_headers,
                timeout=60)
            if resp.status_code == 200:
                resp_json = resp.json()
                predictions = resp_json["result"]
                return predictions
        return "请求失败"

使用自定义 LLM

配置及加载环境变量

在 .env 文件中配置变量:

ERNIE_API_KEY=******
ERNIE_SECRET_KEY=******

加载配置文件:

import dotenv
​
dotenv.load_dotenv('.env')

调用 LLM

最简单的调用:

from ErnieModel import ErnieLLm
​
llm = ErnieLLm()
​
print(llm("你是文心一言吗?"))

运行结果:

是的,我是文心一言。我能够与人对话互动,回答问题,协助创作,高效便捷地帮助人们获取信息、知识和灵感。

也可以通过构造直接传入 ernie_api_keyernie_secret_key,如:

llm = ErnieLLm(ernie_api_key="******",ernie_secret_key="******")

LLM 关键参数

我们可以通过调整 temperaturetop_ppenalty_score等参数来优化模型回答的结果。

temperature

说明: (1)较高的数值会使输出更加随机,而较低的数值会使其更加集中和确定 (2)默认0.95,范围 (0, 1.0],不能为0 (3)建议该参数和top_p只设置1个 (4)建议top_p和temperature不要同时更改

top_p

说明: (1)影响输出文本的多样性,取值越大,生成文本的多样性越强 (2)默认0.8,取值范围 [0, 1.0] (3)建议该参数和temperature只设置1个 (4)建议top_p和temperature不要同时更改

penalty_score

通过对已生成的token增加惩罚,减少重复生成的现象。说明: (1)值越大表示惩罚越大 (2)默认1.0,取值范围:[1.0, 2.0]

使用方法:

llm = ErnieLLm(temperature=0.99)
print(llm("给我讲一个笑话"))
​
llm = ErnieLLm(temperature=0.95, top_p=1.0)
print(llm("给我讲一个笑话"))

运行结果:

当然可以,这是一个关于两只熊的笑话:
​
有一天,一只熊从动物园里跑了出来,吓坏了的人们纷纷逃窜。但是,动物园的管理员很镇定,他决定去和熊谈判。他对熊说:“熊啊,我知道你是饿了,但是你也不能吃人啊。我们去动物园里吃竹子好不好?”熊想了想,觉得有道理,于是就答应了。
​
管理员带熊去了动物园的竹林,让熊吃了一顿丰盛的竹子大餐。熊很开心,于是问管理员:“你为什么知道我那么喜欢吃竹子呢?”管理员回答:“因为我是管理员啊。”
​
熊一脸懵逼地看着管理员,然后突然明白了什么,说:“原来你是个‘装熊’的家伙啊!”
​
​
好的,这里有一个笑话:
​
有天捡到一个神灯,灯神宣布可以许一个愿望。
我当即许愿:请赐予我一个美女相伴。
只见灯神拿出一个通关文牒,哗啦啦地翻了很多页,然后递给我说:抱歉,您的愿望尚未出现。

添加缓存

从之前的文章中我们讲过如何使用缓存以及多种缓存方式,在这里我们使用本地内存缓存,配置缓存后,如果同一个问题被第二次提问,模型可以快速给出答案。

from langchain.cache import InMemoryCache

# 启动llm的缓存
langchain.llm_cache = InMemoryCache()


由于在自定义LLM时,缓存参数 cache默认为 False,这里我们需要设置为 True。同时我们通过两次执行来看看效果:

llm = ErnieLLm(temperature=0.95, top_p=1.0, cache=True)

s = time.perf_counter()
# 第一次调用
print(llm("给我讲一个笑话"))
elapsed = time.perf_counter() - s
print("\033[1m" + f"第一次调用耗时 {elapsed:0.2f} 秒." + "\033[0m")

s = time.perf_counter()
# 第一次调用
print(llm("给我讲一个笑话"))
elapsed = time.perf_counter() - s
print("\033[1m" + f"第二次调用耗时 {elapsed:0.2f} 秒." + "\033[0m")


运行结果:

当然可以,这是一个关于两只鸟的笑话:

有两只小鸟,一只小鸟问:“哥哥,人们都说你长得好帅,你觉得自己帅吗?”哥哥小鸟羞涩地回答:“不,我不觉得自己帅,我只是很可爱。”而第二只小鸟打断了他:“哥呀,人家说的是你旁边的蝴蝶卷毛哈。”
第一次调用耗时 2.37 秒.
当然可以,这是一个关于两只鸟的笑话:

有两只小鸟,一只小鸟问:“哥哥,人们都说你长得好帅,你觉得自己帅吗?”哥哥小鸟羞涩地回答:“不,我不觉得自己帅,我只是很可爱。”而第二只小鸟打断了他:“哥呀,人家说的是你旁边的蝴蝶卷毛哈。”
第二次调用耗时 0.00 秒.


可以看到第二次请求所用时间近乎为0(可能是纳秒级别)。

小结

本文主要介绍了在LangChain平台上自定义LLM的步骤和参数,并以文心一言的ERNIE-Bot-turbo模型为例进行了详细说明。文章首先介绍了自定义LLM需要实现的必要函数,包括_call函数和_identifying_params函数。然后,通过导入dotenv模块和配置环境变量,示例代码演示了如何加载配置文件并调用自定义LLM。接下来,文章介绍了LLM的一些关键参数,如temperaturetop_ppenalty_score,并展示了如何根据需要调整这些参数来优化模型的回答结果。最后,文章提到了使用缓存的方法,通过启动LLM的缓存来加速模型的响应速度,并通过两次调用的结果展示了缓存的效果。

如何学习AI大模型?

我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。

我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在人工智能学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。但苦于知识传播途径有限,很多互联网行业朋友无法获得正确的资料得到学习提升,故此将并将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。

第一阶段: 从大模型系统设计入手,讲解大模型的主要方法;

第二阶段: 在通过大模型提示词工程从Prompts角度入手更好发挥模型的作用;

第三阶段: 大模型平台应用开发借助阿里云PAI平台构建电商领域虚拟试衣系统;

第四阶段: 大模型知识库应用开发以LangChain框架为例,构建物流行业咨询智能问答系统;

第五阶段: 大模型微调开发借助以大健康、新零售、新媒体领域构建适合当前领域大模型;

第六阶段: 以SD多模态大模型为主,搭建了文生图小程序案例;

第七阶段: 以大模型平台应用与开发为主,通过星火大模型,文心大模型等成熟大模型构建大模型行业应用。

?学会后的收获:?
• 基于大模型全栈工程实现(前端、后端、产品经理、设计、数据分析等),通过这门课可获得不同能力;

• 能够利用大模型解决相关实际项目需求: 大数据时代,越来越多的企业和机构需要处理海量数据,利用大模型技术可以更好地处理这些数据,提高数据分析和决策的准确性。因此,掌握大模型应用开发技能,可以让程序员更好地应对实际项目需求;

• 基于大模型和企业数据AI应用开发,实现大模型理论、掌握GPU算力、硬件、LangChain开发框架和项目实战技能, 学会Fine-tuning垂直训练大模型(数据准备、数据蒸馏、大模型部署)一站式掌握;

• 能够完成时下热门大模型垂直领域模型训练能力,提高程序员的编码能力: 大模型应用开发需要掌握机器学习算法、深度学习框架等技术,这些技术的掌握可以提高程序员的编码能力和分析能力,让程序员更加熟练地编写高质量的代码。

1.AI大模型学习路线图
2.100套AI大模型商业化落地方案
3.100集大模型视频教程
4.200本大模型PDF书籍
5.LLM面试题合集
6.AI产品经理资源合集

?获取方式:
?有需要的小伙伴,可以保存图片到wx扫描二v码免费领取【保证100%免费】?

总结

**文章总结**
本文介绍了自定义Large Language Models(LLM)的步骤,特别是与LangChain平台结合使用的文心一言ERNIE-Bot-turbo模型。文章从创建自定义LLM的必要性开始,解释了所需的关键函数如`_call`和`_identifying_params`,并详细演示了如何利用`ErnieLLm`类实现文心一言模型的接口封装。文中提到的重要点包括:
1. **自定义LLM的关键函数**:封装LLM接口需实现`_call`函数以及其他可选函数如`_identifying_params`,以便与其他LangChain模块协同工作。
2. **文心一言ERNIE-Bot-turbo的接入**:通过编写自定义的`ErnieLLm`类,实现对文心一言模型API的调用,同时可以设置和调整模型参数(如`temperature`、`top_p`等)以优化输出。
3. **环境配置与LLM调用**:文章通过.env文件配置API密钥,并展示了如何加载配置文件和调用LLM的方法,以及如何通过修改LLM参数来改变模型输出。
4. **添加缓存功能**:通过引入`InMemoryCache`实现缓存机制,以减少对相同问题的处理时间,从而提高应答速度。
5. **学习AI大模型**:文章最后介绍了学习AI大模型的建议路线图,包括资料分享、技能提升和职业应用场景,旨在帮助读者系统学习AI大模型相关的知识和技能。
此外,文章末尾提供了AI大模型的学习资料获取方式,涵盖了从学习路线图、落地方案到实际开发所需的视频教程、书籍等资源,旨在帮助读者深入掌握AI大模型的应用开发。

更新时间 2024-07-15