自界说 LLM:LangChain与文心一言擦出火花

打印 上一主题 下一主题

主题 528|帖子 528|积分 1584

目前AI模子领域百家争鸣,尽管LangChain官方提供了一些接口,但是可能并不支持所有模子。假如你需要自界说模子并将其接入LangChain框架,这是一种可能的选择。刚好文心一言能力全面开放,本教程借助文心一言大模子解说在LangChain怎样自界说 LLM,点击查看[《文心一言注册及调用教程》] [《LangChain 入门到实战教程》更多内容]
  自界说 LLM

自界说 LLM 需要实现以下必要的函数:


  • _call :它需要担当一个字符串、可选的停用词,并返回一个字符串。
它还可以实现第二个可选的函数:


  • _identifying_params :用于帮助打印 LLM 信息。该函数应该返回一个字典。
使用LLM模块来封装我们的模子接口,可以带来很多利益,其中之一就是有利于与LangChain的其他模块进行协同工作。
下面我们通过 LangChain自界说LLM 实现文心一言 ERNIE-Bot-turbo 大模子接入:
  1. import json
  2. import time
  3. from typing import Any, List, Mapping, Optional, Dict, Union, Tuple
  4. import logging
  5. import requests
  6. from langchain.callbacks.manager import CallbackManagerForLLMRun
  7. from langchain.llms.base import LLM
  8. from langchain.utils import get_from_dict_or_env
  9. from pydantic import Field, root_validator
  10. logger = logging.getLogger(__name__)
  11. def get_access_token(api_key: str, secret_key: str):
  12.     """
  13.     使用 API Key,Secret Key 获取access_token
  14.     """
  15.     url = f"https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id={api_key}&client_secret={secret_key}"
  16.     payload = json.dumps("")
  17.     headers = {
  18.         'Content-Type': 'application/json',
  19.         'Accept': 'application/json'
  20.     }
  21.     resp = requests.request("POST", url, headers=headers, data=payload)
  22.     return resp.json().get("access_token")
  23. class ErnieLLm(LLM):
  24.     url = "https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/eb-instant"
  25.     model_name: str = Field(default="ERNIE-Bot-turbo", alias="model")
  26.     request_timeout: Optional[Union[float, Tuple[float, float]]] = None
  27.     temperature: float = 0.95
  28.     """temperature 说明:
  29.     (1)较高的数值会使输出更加随机,而较低的数值会使其更加集中和确定
  30.     (2)默认0.95,范围 (0, 1.0],不能为0
  31.     (3)建议该参数和top_p只设置1个
  32.     (4)建议top_p和temperature不要同时更改
  33.     """
  34.     top_p: float = 0.8
  35.     """top_p 说明:
  36.     (1)影响输出文本的多样性,取值越大,生成文本的多样性越强
  37.     (2)默认0.8,取值范围 [0, 1.0]
  38.     (3)建议该参数和temperature只设置1个
  39.     (4)建议top_p和temperature不要同时更改
  40.     """
  41.     penalty_score: float = 1.0
  42.     """通过对已生成的token增加惩罚,减少重复生成的现象。说明:
  43.     (1)值越大表示惩罚越大
  44.     (2)默认1.0,取值范围:[1.0, 2.0]
  45.     """
  46.     ernie_api_key: Optional[str] = None
  47.     """文心一言大模型 apiKey"""
  48.     ernie_secret_key: Optional[str] = None
  49.     """文心一言大模型 secretKey"""
  50.     user_id: Optional[str] = None
  51.     """表示最终用户的唯一标识符,可以监视和检测滥用行为,防止接口恶意调用"""
  52.     streaming: bool = False
  53.     """是否以流式接口的形式返回数据,默认false"""
  54.     cache: bool = False
  55.     """是否开启缓存,默认为false"""
  56.     model_kwargs: Dict[str, Any] = Field(default_factory=dict)
  57.     """Holds any model parameters valid for `create` call not explicitly specified."""
  58.     @root_validator()
  59.     def validate_environment(cls, values: Dict) -> Dict:
  60.         """Validate that api key and python package exists in environment."""
  61.         values["ernie_api_key"] = get_from_dict_or_env(
  62.             values, "ernie_api_key", "ERNIE_API_KEY"
  63.         )
  64.         values["ernie_secret_key"] = get_from_dict_or_env(
  65.             values,
  66.             "ernie_secret_key",
  67.             "ERNIE_SECRET_KEY"
  68.         )
  69.         return values
  70.     @property
  71.     def _default_params(self) -> Dict[str, Any]:
  72.         """获取调用Ennie API的默认参数。"""
  73.         normal_params = {
  74.             "temperature": self.temperature,
  75.             "top_p": self.top_p,
  76.             "penalty_score": self.penalty_score,
  77.             "request_timeout": self.request_timeout,
  78.         }
  79.         return {**normal_params, **self.model_kwargs}
  80.     def _construct_query(self, prompt: str) -> Dict:
  81.         """构造请求体"""
  82.         query = {
  83.             "messages": [
  84.                 {
  85.                     "role": "user",
  86.                     "content": prompt
  87.                 }
  88.             ],
  89.             "stream": self.streaming,
  90.             "temperature": self.temperature,
  91.             "top_p": self.top_p,
  92.             "penalty_score": self.penalty_score,
  93.             "user_id": self.user_id,
  94.         }
  95.         return query
  96.     @property
  97.     def _identifying_params(self) -> Mapping[str, Any]:
  98.         """Get the identifying parameters."""
  99.         return {**{"model_name": self.model_name}, **self._default_params}
  100.     @property
  101.     def _llm_type(self) -> str:
  102.         return "ernie"
  103.     def _call(
  104.             self,
  105.             prompt: str,
  106.             stop: Optional[List[str]] = None,
  107.             run_manager: Optional[CallbackManagerForLLMRun] = None,
  108.             **kwargs: Any,
  109.     ) -> str:
  110.         """_call 实现对模型的调用"""
  111.         # construct query
  112.         query = self._construct_query(prompt=prompt)
  113.         # post
  114.         _headers = {"Content-Type": "application/json"}
  115.         with requests.session() as session:
  116.             resp = session.post(
  117.                 self.url + "?access_token=" + get_access_token(self.ernie_api_key, self.ernie_secret_key),
  118.                 json=query,
  119.                 headers=_headers,
  120.                 timeout=60)
  121.             if resp.status_code == 200:
  122.                 resp_json = resp.json()
  123.                 predictions = resp_json["result"]
  124.                 return predictions
  125.         return "请求失败"
复制代码
使用自界说 LLM

设置及加载环境变量

在 .env 文件中设置变量:
  1. ERNIE_API_KEY=******
  2. ERNIE_SECRET_KEY=******
复制代码
加载设置文件:
  1. import dotenv
  2. dotenv.load_dotenv('.env')
复制代码
调用 LLM

最简单的调用:
  1. from ErnieModel import ErnieLLm
  2. llm = ErnieLLm()
  3. print(llm("你是文心一言吗?"))
复制代码
运行结果:
  1. 是的,我是文心一言。我能够与人对话互动,回答问题,协助创作,高效便捷地帮助人们获取信息、知识和灵感。
复制代码
也可以通过构造直接传入 ernie_api_key和ernie_secret_key,如:
  1. llm = ErnieLLm(ernie_api_key="******",ernie_secret_key="******")
复制代码
LLM 关键参数

我们可以通过调解 temperature、top_p、penalty_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]
使用方法:
  1. llm = ErnieLLm(temperature=0.99)
  2. print(llm("给我讲一个笑话"))
  3. llm = ErnieLLm(temperature=0.95, top_p=1.0)
  4. print(llm("给我讲一个笑话"))
复制代码
运行结果:
  1. 当然可以,这是一个关于两只熊的笑话:
  2. 有一天,一只熊从动物园里跑了出来,吓坏了的人们纷纷逃窜。但是,动物园的管理员很镇定,他决定去和熊谈判。他对熊说:“熊啊,我知道你是饿了,但是你也不能吃人啊。我们去动物园里吃竹子好不好?”熊想了想,觉得有道理,于是就答应了。
  3. 管理员带熊去了动物园的竹林,让熊吃了一顿丰盛的竹子大餐。熊很开心,于是问管理员:“你为什么知道我那么喜欢吃竹子呢?”管理员回答:“因为我是管理员啊。”
  4. 熊一脸懵逼地看着管理员,然后突然明白了什么,说:“原来你是个‘装熊’的家伙啊!”
  5. 好的,这里有一个笑话:
  6. 有天捡到一个神灯,灯神宣布可以许一个愿望。
  7. 我当即许愿:请赐予我一个美女相伴。
  8. 只见灯神拿出一个通关文牒,哗啦啦地翻了很多页,然后递给我说:抱歉,您的愿望尚未出现。
复制代码
添加缓存

从之前的文章中我们讲过怎样使用缓存以及多种缓存方式,在这里我们使用当地内存缓存,设置缓存后,假犹如一个问题被第二次提问,模子可以快速给出答案。
  1. from langchain.cache import InMemoryCache
  2. # 启动llm的缓存
  3. langchain.llm_cache = InMemoryCache()
复制代码
由于在自界说LLM时,缓存参数 cache默认为 False,这里我们需要设置为 True。同时我们通过两次执行来看看效果:
  1. llm = ErnieLLm(temperature=0.95, top_p=1.0, cache=True)
  2. s = time.perf_counter()
  3. # 第一次调用
  4. print(llm("给我讲一个笑话"))
  5. elapsed = time.perf_counter() - s
  6. print("\033[1m" + f"第一次调用耗时 {elapsed:0.2f} 秒." + "\033[0m")
  7. s = time.perf_counter()
  8. # 第一次调用
  9. print(llm("给我讲一个笑话"))
  10. elapsed = time.perf_counter() - s
  11. print("\033[1m" + f"第二次调用耗时 {elapsed:0.2f} 秒." + "\033[0m")
复制代码
运行结果:
  1. 当然可以,这是一个关于两只鸟的笑话:
  2. 有两只小鸟,一只小鸟问:“哥哥,人们都说你长得好帅,你觉得自己帅吗?”哥哥小鸟羞涩地回答:“不,我不觉得自己帅,我只是很可爱。”而第二只小鸟打断了他:“哥呀,人家说的是你旁边的蝴蝶卷毛哈。”
  3. 第一次调用耗时 2.37 秒.
  4. 当然可以,这是一个关于两只鸟的笑话:
  5. 有两只小鸟,一只小鸟问:“哥哥,人们都说你长得好帅,你觉得自己帅吗?”哥哥小鸟羞涩地回答:“不,我不觉得自己帅,我只是很可爱。”而第二只小鸟打断了他:“哥呀,人家说的是你旁边的蝴蝶卷毛哈。”
  6. 第二次调用耗时 0.00 秒.
复制代码
可以看到第二次请求所用时间近乎为0(可能是纳秒级别)。
小结

本文紧张介绍了在LangChain平台上自界说LLM的步骤和参数,并以文心一言的ERNIE-Bot-turbo模子为例进行了具体阐明。文章起首介绍了自界说LLM需要实现的必要函数,包罗_call函数和_identifying_params函数。然后,通过导入dotenv模块和设置环境变量,示例代码演示了怎样加载设置文件并调用自界说LLM。接下来,文章介绍了LLM的一些关键参数,如temperature、top_p和penalty_score,并展示了怎样根据需要调解这些参数来优化模子的回答结果。最后,文章提到了使用缓存的方法,通过启动LLM的缓存来加快模子的响应速度,并通过两次调用的结果展示了缓存的效果。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

用户国营

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表