马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
目前AI模子领域百家争鸣,尽管LangChain官方提供了一些接口,但是可能并不支持所有模子。假如你需要自界说模子并将其接入LangChain框架,这是一种可能的选择。刚好文心一言能力全面开放,本教程借助文心一言大模子解说在LangChain怎样自界说 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_key和ernie_secret_key,如:
- 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]
使用方法:
- 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的一些关键参数,如temperature、top_p和penalty_score,并展示了怎样根据需要调解这些参数来优化模子的回答结果。最后,文章提到了使用缓存的方法,通过启动LLM的缓存来加快模子的响应速度,并通过两次调用的结果展示了缓存的效果。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |