动手学大模型应用开发,第2天:调用大模型(下)
五、调用智谱 AI
1. ChatGLM 大模型
智谱 AI 是由清华大学计算机系技术成果转化而来的公司,致力于打造新一代认知智能通用模型。公司合作研发了双语千亿级超大规模预训练模型 GLM-130B,并构建了高精度通用知识图谱,形成数据与知识双轮驱动的认知引擎,基于此模型打造了 ChatGLM(chatglm.cn)。
ChatGLM 系列模型,包括 ChatGLM-130B 和 ChatGLM-6B 模型,支持相对复杂的自然语言指令,并且能够解决困难的推理类问题。其中,ChatGLM-6B 模型吸引了全球超过 160 万人下载安装,该模型在 Hugging Face (HF) 全球大模型下载榜中连续 12 天位居第一名,在国内外的开源社区中产生了较大的影响。
本章节将指导开发者如何将智谱 AI API 的使用方式,也将介绍如何将其封装成个性化 LLM 嵌入 LangChain 使用。
2. 申请调用权限
首先进入到智谱AI开放平台,点击“开始使用”或者“开发者工具台”进行注册:
如果是没有领取过免费试用包的用户,可以领取到 18 元的 token 的试用量;如下图右边绿色框所示。智谱 AI 提供了三种不同的模型 API,ChatGLM-Pro, ChatGLM-Std, ChatGLM-Lite 三种不同的模型分别适用于不同的场景,可以点击蓝色框中的立即体验直接体验。对于需要使用 API key 来搭建应用的话,需要点击右边红框中的查看 API key,就会进入到我们个人的 API 管理列表中。
在该界面,我们就可以看到我们获取到的 API 所对应的应用名字和 API key
了。
我们可以点击 添加新的 API key
并输入对应的名字即可生成新的 API key。
3. 调用智谱 AI API
智谱 AI 提供了 SDK 和原生 HTTP 来实现模型 API 的调用,建议使用 SDK 进行调用以获得更好的编程体验。
注意,需要在环境中安装配置示例中的所需第三方库。
首先我们需要配置秘钥信息:
!pip install zhipuai
import zhipuai
zhipuai.api_key = "your api key" #填写控制台中获取的 APIKey 信息
model = "chatglm_std" #用于配置大模型版本
智谱的调用传参和其他类似,也需要传入一个列表,列表中包括 role 和 prompt,我们首先定义一个从用户输入 prompt 生成传入参数的函数:
def getText(role, content, text = []):
# role 是指定角色,content 是 prompt 内容
jsoncon = {}
jsoncon["role"] = role
jsoncon["content"] = content
text.append(jsoncon)
return text
接着,我们将一个用户输入 prompt 封装为这样一个传入参数列表:
question = getText("user", "你好")
question
[{'role': 'user', 'content': '你好'}]
然后再调用 zhipuai SDK 中封装的 invoke 函数即可:
# 请求模型
response = zhipuai.model_api.invoke(
model=model,
prompt=question
)
print(response)
{'code': 200, 'msg': '操作成功', 'data': {'request_id': '8023318729410566227', 'task_id': '8023318729410566227', 'task_status': 'SUCCESS', 'choices': [{'role': 'assistant', 'content': '" 你好👋!我是人工智能助手 智谱清言,可以叫我小智🤖,很高兴见到你,欢迎问我任何问题。"'}], 'usage': {'prompt_tokens': 2, 'completion_tokens': 28, 'total_tokens': 30}}, 'success': True}
这里对传入 zhipuai 的参数进行简单介绍:
prompt (list)
: 调用对话模型时,将当前对话信息列表作为提示输入给模型; 按照 {"role": "user", "content": "你好"} 的键值对形式进行传参; 总长度超过模型最长输入限制后会自动截断,需按时间由旧到新排序。temperature (float)
: 采样温度,控制输出的随机性,必须为正数。取值范围是:(0.0,1.0],不能等于 0,默认值为 0.95。值越大,会使输出更随机,更具创造性;值越小,输出会更加稳定或确定。top_p (float)
: 用温度取样的另一种方法,称为核取样。取值范围是:(0.0, 1.0) ,开区间,不能等于 0 或 1,默认值为 0.7。模型考虑具有 top_p 概率质量 tokens 的结果。例如:0.1 意味着模型解码器只考虑从前 10% 的概率的候选集中取 tokens。request_id (string)
: 由用户端传参,需保证唯一性;用于区分每次请求的唯一标识,用户端不传时平台会默认生成return_type (string)
: 用于控制每次返回内容的类型,空或者没有此字段时默认按照 json_string 返回。json_string
返回标准的 JSON 字符串。text
返回原始的文本内容- 建议您根据应用场景调整 top_p 或 temperature 参数,但不要同时调整两个参数
4. 使用 LangChain 调用智谱 AI
我们同样可以通过 LangChain 框架来调用智谱 AI 大模型,以将其接入到我们的应用框架中。
同文心大模型类似,原生的 LangChain 是不支持智谱 AI 调用的,我们需要自定义一个 LLM。
此处,我们可以直接调用已自定义好的 ZhipuAILLM
from zhipuai_llm import ZhipuAILLM
zhipuai_model = ZhipuAILLM(model="chatglm_std", temperature=0, zhipuai_api_key=zhipuai.api_key)
zhipuai_model.generate(['你好'])
LLMResult(generations=[[Generation(text='" 你好👋!我是人工智能助手 智谱清言,可以叫我小智🤖,很高兴见到你,欢迎问我任何问题。"', generation_info=None)]], llm_output=None, run=[RunInfo(run_id=UUID('36840571-ce83-4bcb-8095-a222d59f32a4'))])
六、调用智谱 AI 生成 embedding
1. 调用智谱 AI Embedding API
智谱 AI 及ChatGLM 在上一章已经进行了简单介绍,本章将介绍如何通过其获得文本的 embedding 的,以及将其封装成个性化 embedding 嵌入 LangChain 使用。关于什么是 embedding,具体作用为何,请参见第四部分《数据库搭建》。
import zhipuai
zhipuai.api_key = "your api key" #填写控制台中获取的 APIKey 信息
model = "text_embedding" #选择调用生成 embedding 的模型
自定义要生产 embedding 的文本
text = "要生成 embedding 的输入文本,字符串形式。每个输入不得超过模型的最大输入tokens数量512"
调用远程 API
response = zhipuai.model_api.invoke( model=model, prompt=text )
官方的 SDK 返回的结果是字典的格式,这里我们可以直接传入键获得值。
我们通过查看 code
是否 == 200 来判断请求是否成功
print(response['code'])
200
返回的 embedding, token 等内容被存放在 data
中。我们可以查看生产 embedding 的长度
print(f"生成的 embedding 长度为: {len(response['data']['embedding'])}")
生成的 embedding 长度为: 1024
对于每次模型的调用来说,都是要消耗 token 的(花钱),token 的消耗都存放在 data
的 usage
中。
一般情况下 ChatGLM 模型中 token 和字数的换算比例约为 1:1.8,但因为不同模型的分词不同,所以换算比例也存在差异,每一次实际处理 token 数量以模型返回为准。
我们可以查看输入的 tokens
print(f"用户输入的 tokens 数量为: {response['data']['usage']['prompt_tokens']}")
用户输入的 tokens 数量为: 28
print(f"用户输入的文本长度为: {len(text)}")
用户输入的文本长度为: 52
print(f"本次 token 和字数的换算比例为: {response['data']['usage']['prompt_tokens']/len(text)}, 和理论值 1:1.8 = {1/1.8} 接近")
本次 token 和字数的换算比例为: 0.5384615384615384, 和理论值 1:1.8 = 0.5555555555555556 接近
因为模型其实没有生成新的文本,只是获取到输入的 embedding,所以 token 数为0
print(f"模型输出的 tokens 数量为: {response['data']['usage']['completion_tokens']}")
模型输出的 tokens 数量为: 0
print(f"总 tokens 数量为: {response['data']['usage']['total_tokens']}")
总 tokens 数量为: 28
2. 使用 LangChain 调用智谱 AI Embedding
我们同样可以通过 LangChain 框架来调用智谱 AI 大模型,以将其接入到我们的应用框架中。
原生的 LangChain 是不支持智谱 AI Embedding 调用的,我们需要自定义一个 Embedding。
此处,我们可以直接调用已自定义好的 ZhipuAILLM
import zhipuai
from zhipuai_embedding import ZhipuAIEmbeddings
zhipuai.api_key = "xxx" #输入你的 api_key
zhipuai_embeddings = ZhipuAIEmbeddings(zhipuai_api_key=zhipuai.api_key)
我们可以生成 query 的 embedding。
query_embedding = zhipuai_embeddings.embed_query('你好')
print(query_embedding[:10])
[-0.13970163464546204, 0.04416792839765549, 0.020967043936252594, -0.19684536755084991, 0.08451296389102936, -0.0685092955827713, -0.05186789482831955, 0.11296232044696808, 0.12375720590353012, 0.1507660448551178]
我们也可以生成 doc_list 的 embedding。
doc_list = [
'你好',
'什么是机器学习',
'什么是深度学习',
'什么是大模型'
]
doc_embeddings = zhipuai_embeddings.embed_documents(doc_list)
print('\n'.join([f'{doc} 的 embedding 为 {doc_embedding[:10]}...\n' for doc, doc_embedding in zip(doc_list, doc_embeddings)]))
你好 的 embedding 为 [-0.13970163464546204, 0.04416792839765549, 0.020967043936252594, -0.19684536755084991, 0.08451296389102936, -0.0685092955827713, -0.05186789482831955, 0.11296232044696808, 0.12375720590353012, 0.1507660448551178]...
什么是机器学习 的 embedding 为 [-0.04628180339932442, -0.09553179144859314, 0.010844158940017223, -0.1201983317732811, 0.16935010254383087, -0.15349552035331726, 0.17940732836723328, 0.1256963312625885, 0.09910263121128082, 0.1022590845823288]...
什么是深度学习 的 embedding 为 [-0.09552870690822601, -0.03116282820701599, 0.11060678958892822, 0.08925414085388184, 0.06898286193609238, -0.07559530436992645, 0.2021033763885498, -0.04418506473302841, 0.10697835683822632, -0.0666293203830719]...
什么是大模型 的 embedding 为 [0.10551410913467407, 0.1735556423664093, -0.24402201175689697, 0.02649446204304695, 0.09757085889577866, 0.030247822403907776, 0.4318920969963074, 0.06334380805492401, -0.02869655191898346, -0.1011139303445816]...
七、langchain 核心组件详解
1. 模型输入/输出
LangChain 中模型输入/输出模块是与各种大语言模型进行交互的基本组件,是大语言模型应用的核心元素。模型 I/O 允许您管理 prompt(提示),通过通用接口调用语言模型以及从模型输出中提取信息。该模块的基本流程如下图所示。
主要包含以下部分:Prompts
、Language Models
以及 Output Parsers
。用户原始输入与模型和示例进行组合,然后输入给大语言模型,再根据大语言模型的返回结果进行输出或者结构化处理。
2. 数据连接
大语言模型(Large Language Model, LLM), 比如 ChatGPT , 可以回答许多不同的问题。但是大语言模型的知识来源于其训练数据集,并没有用户的信息(比如用户的个人数据,公司的自有数据),也没有最新发生时事的信息(在大模型数据训练后发表的文章或者新闻) 。因此大模型能给出的答案比较受限。如果能够让大模型在训练数据集的基础上,利用我们自有数据中的信息来回答我们的问题,那便能够得到更有用的答案。
为了支持上述应用的构建,LangChain 数据连接(Data connection)模块通过以下方式提供组件来加载、转换、存储和查询数据:Document loaders
、Document transformers
、Text embedding models
、Vector stores
以及 Retrievers
。数据连接模块部分的基本框架如下图所示。
3. 链(Chain)
虽然独立使用大型语言模型能够应对一些简单任务,但对于更加复杂的需求,可能需要将多个大型语言模型进行链式组合,或与其他组件进行链式调用。链允许将多个组件组合在一起,创建一个单一的、连贯的应用程序。例如,可以创建一个链,接受用户输入,使用 PromptTemplate 对其进行格式化,然后将格式化后的提示词传递给大语言模型。也可以通过将多个链组合在一起或将链与其他组件组合来构建更复杂的链。
大语言模型链(LLMChain)是一个简单但非常强大的链,也是后面我们将要介绍的许多链的基础。我们以它为例,进行介绍:
import warnings
warnings.filterwarnings('ignore')
from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain.chains import LLMChain
# 这里我们将参数temperature设置为0.0,从而减少生成答案的随机性。
# 如果你想要每次得到不一样的有新意的答案,可以尝试调整该参数。
llm = ChatOpenAI(temperature=0.0)
#初始化提示模版
prompt = ChatPromptTemplate.from_template("描述制造{product}的一个公司的最佳名称是什么?")
#将大语言模型(LLM)和提示(Prompt)组合成链
chain = LLMChain(llm=llm, prompt=prompt)
#运行大语言模型链
product = "大号床单套装"
chain.run(product)
运行输出:
'"豪华床纺"'
除了上例中给出的 LLMChain,LangChain 中链还包含 RouterChain、SimpleSequentialChain、SequentialChain、TransformChain 等。
RouterChain
可以根据输入数据的某些属性/特征值,选择调用不同的子链(Subchain)。SimpleSequentialChain
是最简单的序列链形式,其中每个步骤具有单一的输入/输出,上一个步骤的输出是下一个步骤的输入。SequentialChain
是简单顺序链的更复杂形式,允许多个输入/输出。TransformChain
可以引入自定义转换函数,对输入进行处理后进行输出。
以下是使用 SimpleSequentialChain 的代码示例:
from langchain.chains import SimpleSequentialChain
llm = ChatOpenAI(temperature=0.9)
#创建两个子链
# 提示模板 1 :这个提示将接受产品并返回最佳名称来描述该公司
first_prompt = ChatPromptTemplate.from_template(
"描述制造{product}的一个公司的最好的名称是什么"
)
chain_one = LLMChain(llm=llm, prompt=first_prompt)
# 提示模板 2 :接受公司名称,然后输出该公司的长为20个单词的描述
second_prompt = ChatPromptTemplate.from_template(
"写一个20字的描述对于下面这个\
公司:{company_name}的"
)
chain_two = LLMChain(llm=llm, prompt=second_prompt)
#构建简单顺序链
#现在我们可以组合两个LLMChain,以便我们可以在一个步骤中创建公司名称和描述
overall_simple_chain = SimpleSequentialChain(chains=[chain_one, chain_two], verbose=True)
#运行简单顺序链
product = "大号床单套装"
overall_simple_chain.run(product)
运行输出:
> Entering new SimpleSequentialChain chain...
优床制造公司
优床制造公司是一家专注于生产高品质床具的公司。
> Finished chain.
'优床制造公司是一家专注于生产高品质床具的公司。'
4. 记忆(Memory)
在 LangChain 中,记忆(Memory)指的是大语言模型(LLM)的短期记忆。为什么是短期记忆?那是因为LLM训练好之后 (获得了一些长期记忆),它的参数便不会因为用户的输入而发生改变。当用户与训练好的LLM进行对话时,LLM 会暂时记住用户的输入和它已经生成的输出,以便预测之后的输出,而模型输出完毕后,它便会“遗忘”之前用户的输入和它的输出。因此,之前的这些信息只能称作为 LLM 的短期记忆。
正如上面所说,在与语言模型交互时,你可能已经注意到一个关键问题:它们并不记忆你之前的交流内容,这在我们构建一些应用程序(如聊天机器人)的时候,带来了很大的挑战,使得对话似乎缺乏真正的连续性。因此,在本节中我们将介绍 LangChain 中的记忆模块,即如何将先前的对话嵌入到语言模型中的,使其具有连续对话的能力。
5. 代理(Agents)
大型语言模型(LLMs)非常强大,但它们缺乏“最笨”的计算机程序可以轻松处理的特定能力。LLM 对逻辑推理、计算和检索外部信息的能力较弱,这与最简单的计算机程序形成对比。例如,语言模型无法准确回答简单的计算问题,还有当询问最近发生的事件时,其回答也可能过时或错误,因为无法主动获取最新信息。这是由于当前语言模型仅依赖预训练数据,与外界“断开”。要克服这一缺陷, LangChain 框架提出了 “代理”( Agent ) 的解决方案。代理作为语言模型的外部模块,可提供计算、逻辑、检索等功能的支持,使语言模型获得异常强大的推理和获取信息的超能力。
6.回调(Callback)
LangChain提供了一个回调系统,允许您连接到LLM应用程序的各个阶段。这对于日志记录、监视、流式处理和其他任务非常有用。
Callback 模块扮演着记录整个流程运行情况的角色,充当类似于日志的功能。在每个关键节点,它记录了相应的信息,以便跟踪整个应用的运行情况。例如,在 Agent 模块中,它记录了调用 Tool 的次数以及每次调用的返回参数值。Callback 模块可以将收集到的信息直接输出到控制台,也可以输出到文件,甚至可以传输到第三方应用程序,就像一个独立的日志管理系统一样。通过这些日志,可以分析应用的运行情况,统计异常率,并识别运行中的瓶颈模块以进行优化。
Callback 模块的具体实现包括两个主要功能,对应CallbackHandler
和 CallbackManager
的基类功能:
- CallbackHandler 用于记录每个应用场景(如 Agent、LLchain 或 Tool )的日志,它是单个日志处理器,主要记录单个场景的完整日志信息。
- 而CallbackManager则封装和管理所有的 CallbackHandler ,包括单个场景的处理器,也包括整个运行时链路的处理器。"
在哪里传入回调 ?
该参数可用于整个 API 中的大多数对象(链、模型、工具、代理等),位于两个不同位置::
构造函数回调
:在构造函数中定义,例如 LLMChain(callbacks=[handler], tags=['a-tag']) ,它将被用于对该对象的所有调用,并且将只针对该对象,例如,如果你向 LLMChain 构造函数传递一个 handler ,它将不会被附属于该链的 Model 使用。
请求回调
:定义在用于发出请求的 call() / run() / apply() 方法中,例如 chain.call(inputs, callbacks=[handler]) ,它将仅用于该特定请求,以及它包含的所有子请求(例如,对 LLMChain 的调用会触发对 Model 的调用,该 Model 使用 call() 方法中传递的相同 handler)。
verbose 参数在整个 API 的大多数对象(链、模型、工具、代理等)上都可以作为构造参数使用,例如 LLMChain(verbose=True),它相当于将 ConsoleCallbackHandler 传递给该对象和所有子对象的 callbacks 参数。这对调试很有用,因为它将把所有事件记录到控制台。
你想在什么时候使用这些东西呢?
构造函数回调对诸如日志、监控等用例最有用,这些用例不是针对单个请求,而是针对整个链。例如,如果你想记录所有向 LLMChain 发出的请求,你可以向构造函数传递一个处理程序。
请求回调对流媒体等用例最有用,你想把单个请求的输出流向特定的 websocket 连接,或其他类似用例。例如,如果你想把单个请求的输出流到一个 websocket ,你会把一个处理程序传递给 call() 方法.
关于langchain组件的更多使用方法和示例,可以参考以下材料:
八、总结
在本章中,我们简要介绍了四种常用大模型 API 的调用方式:ChatGPT、百度文心、讯飞星火、智谱 AI。四种模型 API 都具有不同的调用要求,我们分别进行了介绍并对其原生接口进行了封装,方便用户直接调用使用;同时,我们也简要介绍了如何将大模型 API 封装到 LangChain 的自定义 LLM 中,如何将大模型 API 封装成统一方式调用的本地 API,以及如何将大模型 Embedding API 封装到 LangChain 的自定义 LLM 中。我们分别以百度文心、讯飞星火、智谱 AI作为示例介绍了调用方式,欢迎读者们自行实践尝试将更多的模型进行统一封装。
学习完本章,你应该掌握了常用大模型的基本调用方式,那么接下来,你就可以开始着手基于大模型打造自己的应用啦!
以上所有代码仅为思路,因API更新太快,请以官方文档为准!
__EOF__
优秀不够,你是否无可替代
软件测试交流QQ群:721256703,期待你的加入!!
欢迎关注我的微信公众号:软件测试君
![](https://www.cnblogs.com/images/cnblogs_com/longronglang/1061549/o_QQ%E6%88%AA%E5%9B%BE20190728134401.jpg)
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 本地部署 DeepSeek:小白也能轻松搞定!
· 如何给本地部署的DeepSeek投喂数据,让他更懂你
· 在缓慢中沉淀,在挑战中重生!2024个人总结!
· 大人,时代变了! 赶快把自有业务的本地AI“模型”训练起来!
· 从 Windows Forms 到微服务的经验教训
2017-02-01 MonkeyRunner之MonkeyRecorder录制回放脚本(亲测可正常运行)
2017-02-01 selenium python2.7安装配置