赞
踩
ChatGLM3训练数据更多样、训练步数更充分、训练策略更合理,在语义、数学、推理、代码、知识等不同角度的数据集上表现出色,目前在44个中英文公开数据集测试国内第一。
从一问一答的对话模式转为多角色问答模型,如下图
2023年6月Function Calling功能首次由OpenAI宣布在Chat Completion模型中进行使用,代表着Chat模型不再需要LangChain框架就可以直接在模型内部调用外部工具API,从而更便捷的使用LLM,进行AI Agent的开发。
LangChain框架
LangChain是一个用于开发由语言模型驱动的应用程序的框架。
主要功能:
- 调用语言模型
- 将不同的数据源接到语言模型的交互中
- 允许语言模型与运行环境交互
提供的模块:
- Modules:支持的模型类型和集成
- Prompt:提示词管理、优化和序列
- Memory:在链/代理调用之间持续存在的状态
- Indexes:加载、查询和更新外部数据的接口和集成
- Chain:结构化的调用序列
- Agents:链,其中LLM在给定高级指令和一组工具的情况下,反复决定操作,执行操作并观察结果,直到高级指令完成
- Callbacks:回调允许记录和流式传输任何链的中间步骤,从而轻松观察、调试和评估应用程序内部
基于LangChain+ChatGLM的本地知识库问答实现原理流程图
Function Calling功能可以弥补LLM的一些缺点,比如实时信息的缺乏、特定领域能力,使得能够进一步利用LLM的逻辑推理能力,可以将问题进行分解处理,解决问题能力更加强大。
简单类AI Agent项目:
进阶类AI Agent项目:
ChatGLM3模型提供了基于openai框架的调用使用方法,对于使用OpenAI API创建的应用而言,想要将基础模型更改为ChatGLM3,只需要将model参数修改为‘chatglm3-6b’即可。一个统一的调用方式对开发者来说是重大利好的。
import openai
if __name__ == "__main__":
openai.api_base = "http://localhost:8000/v1"
openai.api_key = "none"
for chunk in openai.ChatCompletion.create(
model = "chatglm3-6b",
messages = [
{"role": "user", "content": "你好"}
],
stream = True
):
if hasatter(chunk.choices[0].delta, "content"):
print(chunk.choices[0].delta.content, end="", flush=True)
response_glm3 = openai.ChatCompletion.create(
model = "chatglm3-6b",
messages = [
{"role": "user", "content": "你好"}
]
)
print(response_glm3['choices'][0]['message']['content'])
# 输出为:你好!我是人工智能助手ChatGLM3-6B,很高兴见到你,欢迎问我任何问题。
- messages
:基本构成元素为字典的列表,每一个字典都代表一条独立的消息。role表示某条消息的作者,content表示消息的具体内容。
- choices
:返回答案是一个列表,通过参数的设置,可以返回不止一条答案。
返回结果response_glm3是高度结构化的json对象,其结构如下图所示
- metadata
:为调用的工具名。(Code Interpreter固定为interpreter。)
messages是一种用于描述ChatCompletion模型与用户之间通信信息的高级抽象,从表示形式上来看,一个messages是一个列表,包含多个字典,每一个字典都代表一条独立的消息。role表示某条消息的作者,content表示消息的具体内容。
- role
:某条消息的作者。角色身份:system(系统提示词,指明模型扮演的角色信息),user(用户输入),assistant(模型回复),observation(工具调用、代码执行结果)。
- content
:消息的具体内容。
为LLM模型指定某种虚拟身份,更便于激活模型能力。设置身份的方法主要有两种:
一是在content
中直接假设
response_glm3 = openai.ChatCompletion.create(
model = "chatglm3-6b",
messages = [
{"role": "user", "content": "假设你是一名资深的大学教授,请问机器学习是什么?"}
]
)
二是使用system role
response_glm3 = openai.ChatCompletion.create(
model = "chatglm3-6b",
messages = [
{"role": "system", "content": "假设你是一名资深的大学教授。"},
{"role": "user", "content": "请问机器学习是什么?"}
]
)
Function Calling功能的本质是让LLM调用外部函数,即Chat模型不再仅仅根据自身的数据库知识进行回答,而是可以额外挂载一个函数库,根据用户提问进行函数库检索,根据实际需求调用外部函数并获取函数运行结果,再基于函数运行结果进行回答。基本过程如下图所示:
import requests def get_weather(loc): """ 查询即时天气预报 param loc:当前需要查询城市的名称,中国城市要用对应城市的英文名称。 :return:OpenWeather API查询即时天气的结果,返回结果对象类型为解析之后的JSON格式对象。 """ # step1 构建请求 URL = "https://api.openweathermaporg/data/2.5/weather" # step2 设置查询参数 params = { "q": loc, "appid": open_weather_key, # 获取的API key "units": "metric", # 使用摄氏度而不是华氏度 "lang": "zh_cn" # 输出语言为简体中文 } # step3 发送get请求 response = requests.get(URL, params=params) # step4 解析响应 data = response.json() return json.dumps(data) # 测试函数是否能使用 weather = get_weather("Hangzhou") print(weather)
正常运行时,上述输出如下图所示
最后需要创建get_weather函数的functions参数
weather_api_spec = [ { 'name': 'get_weather', 'description': '输入城市名称,查询即时天气函数。', 'parameters': { 'type': 'object', 'properties': { 'loc': { 'description': '城市名称,中国城市要用对应城市的英文名称。', 'type': 'string', 'required': True } } } } ]
将get_weather函数放入函数库(写入functions_list函数列表),然后启用外链函数库之后的多伦对话机器人chat_with_model,查看对话效果。下面对整个对话流程进行简要的说明。
第一步:构建消息内容
# 设定LLM身份
system_info = {
"role": "system",
"content": "Answer the following questions a best as you can. You have access to the following tools:",
"tools": weather_api_spec
}
# 用户提问消息内容
messages = [
system_info,
{
"role": "user",
"content": "请问今天北京天气如何?"
}
]
第二步:首次调用LLM
# 第一次调用LLM
first_response = openai.ChatCompletion.create(
model = "chatglm3-6b",
messages = messages,
return_function_call = True
)
first_response_message = first_response['choices'][0]['message']
print(first_response_message)
输出结果如下图所示
这表明想要获得问题的答案需要调用外部函数。
对first_response_message内容进行解析
function_call = json.loads(first_response_message.content)
print(function_call)
输出结果如下图所示
该解析结果中包含了需要调用的外部函数的名称以及所需参数。
第三步:外部函数调用
# 获取函数名及参数
function_name = function_call["name"]
function_args = function_call["parameters"]
# 获取外部函数
functions_list = [get_weather]
available_functions = {func.__name__: func for func in functions_list}
function_to_call = available_functions[function_name]
# 运行外部函数
function_response = function_to_call(**function_args)
print(function_response)
输出结果如下图所示
得到的是外部函数运行的结果,接下来需要再一次使用LLM对上述结果进行解析并输出最初问题的答案。
第四步:第二次调用LLM
# messages中拼接first_response_message消息 messages.append(first_response_message) # messages中拼接外部函数输出结果 messages.append( { "role": "observation", # 角色为observation,表示为外部函数发的消息 "name": function_name, "content": function_response } ) # 第二次调用LLM second_response = openai.ChatCompletion.create( model = "chatglm3-6b", messages = messages ) final_response = second_response['choices'][0]['message']['content'] print(final_response)
输出结果如下图所示
对上述过程进行函数封装,实现自动执行外部函数的LLM对话功能。
def run_conv_glm(messages, functions_list=None, functions=None, model="chatglm3-6b", return_function_call = True): """ 能够自动执行外部函数调用的Chat对话模型 :param messages:必要参数,输入到对话模型的messages参数对象 :param functions_list:可选参数,默认为None,可以设置为包含全部外部函数的函数列表 :param functions:外部函数的说明 :param model:可选参数,LLM模型,默认为chatglm3-6b :return: """ def is_json_string(s): try: json_object = json.loads(s) except ValueError as e: retrun False return True user_messages = messages # 如果没有外部函数库,则执行普通的对话任务 if functions_list == None: response = openai.ChatCompletion.create( model = model, messages = user_messages ) response_message = response['choices'][0]['message'] final_response = response_message['content'] # 有外部函数库 else: # 创建外部函数的system_message system_info = { "role": "system", "content": "Answer the following questions a best as you can. You have access to the following tools:", "tools": functions } # 创建外部函数库字典 available_functions = {func.__name__: func for func in functions_list} # 创建包含用户问题的messages messages = system_info + user_messages # first response first_response = openai.ChatCompletion.create( model = "chatglm3-6b", messages = messages, return_function_call = return_function_call ) first_response_message = first_response['choices'][0]['message'] # 判断返回结果是否为json格式对象,即是否需要调用外部函数 if is_json_string(first_response_message['content']): # 需要调用 function_call = json.loads(first_response_message.content) # 获取函数名及参数 function_name = function_call["name"] function_args = function_call["parameters"] # 获取外部函数 function_to_call = available_functions[function_name] # 运行外部函数 function_response = function_to_call(**function_args) # messages中拼接first_response_message消息 messages.append(first_response_message) # messages中拼接外部函数输出结果 messages.append( { "role": "observation", # 角色为observation,表示为外部函数发的消息 "name": function_name, "content": function_response } ) # 第二次调用LLM second_response = openai.ChatCompletion.create( model = "chatglm3-6b", messages = messages ) final_response = second_response['choices'][0]['message']['content'] else: final_response = first_response_message['content'] return final_response
上述实现为单轮对话,下面基于上述函数实现多轮对话函数。
def chat_with_glm(messages, functions_list=None, functions=None, model="chatglm3-6b", return_function_call = True): messages = [{"role": "system", "content": question}] while True: answer = run_conv_glm(messages, functions_list=None, functions=None, model="chatglm3-6b", return_function_call = True ) print(f"模型回答:{answer}") question = input("您还有其他问题吗?(输入退出以结束对话)") if question == "退出": break message.append({"role": "assistant", "content": answer}) message.append({"role": "user", "content": question}) del messages
多轮对话功能测试如下图所示
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。