赞
踩
大语言模型(LLM)可以使用自然语言与人类对话。但在使用它完成某项复杂工作时,很多时候必须依赖其他外部工具,这包括但不限于:
能识别需要使用的外部工具,能根据其结果数据完成对话的功能叫做function calling。
OpenAI的GPT作为LLM的代表作,我们将给它提出如下问题:
问题:一共有3个人,每个人有15个苹果,10个鸭梨,一共有多少苹果?
注: 这个简单的逻辑和算数题只作为实验用途;实际应用中可以扩展到复杂的计算。
我们将给GPT提供两个function/tool。一个是乘法,一个是加法。
注: 其中加法用来迷惑GPT。
我们期待的结果:GPT能判断使用乘法及其参数,并使用乘法function calling给出的结果数据,最终返回正确答案:
三个人一共有45个苹果。
我们的代码和GPT将怎样完成这个过程呢?这里将整个过程描绘在下面的时序图中:
以下内容是真实的对话历史,程序和GPT配合按照我们的预想完成了整个过程,并最终给出了正确答案。
注:以下用到的UserMessage, AIMessage, FunctionMessage都是LangChain中的概念;它比较贴切的抽象了不同role的对话项。
步骤1中的对话项:HumanMessage | 向GPT输入对话提示词。
#提示词
{
"role": "user",
"content": "一共有3个人,每个人有15个苹果,10个鸭梨,一共有多少苹果?"
}
另外,在调用GPT接口时,定义了2个function type tools:乘法multiply和加法add。内容参见下一部分的代码部分。
步骤2中的对话项:AIMessage | GPT返回需要调用的functions/tools及其调用参数。
#这里GPT没有给出最终答案,它识别出了需要调用乘法multiply,参数一first_int为3个人,参数二second_int为15个苹果/每人。 { "content": null, "role": "assistant", "function_call": null, "tool_calls": [ { "id": "call_ZMbo4SiA2iaZUSLJMyX8ZzkP", "function": { "arguments": "{\"first_int\":3,\"second_int\":15}", "name": "multiply" }, "type": "function" } ] }
步骤4中的对话项:FunctionMessage |function calling的调用结果数据。
tool_call_id对应步骤2中的tool_calls元素中的id。content为程序调用function/tool后的结果数据。
#将function calling的结果为3*15=45,设定role为tool,将其加入对话中。
{
"tool_call_id": "call_ZMbo4SiA2iaZUSLJMyX8ZzkP",
"role": "tool",
"name": "multiply",
"content": "45"
}
步骤6中的对话项:AIMessage | 程序将以上所有对话项发送给GPT,GPT用自然语言返回最终结论。
#最终结果为:三个人一共有45个苹果。
{
"content": "三个人一共有45个苹果。",
"role": "assistant",
"function_call": null,
"tool_calls": null
}
function calling的实现代码如下:
__author__ = 'liyane' import json # 初始化环境和OpenAI from openai import OpenAI from dotenv import load_dotenv, find_dotenv _ = load_dotenv(find_dotenv()) client = OpenAI() #调用GPT大模型 def get_completion(messages, tools, model="gpt-3.5-turbo"): response = client.chat.completions.create( model=model, messages=messages, # tool_choice支持设置 "auto"(由模型决定是否调用tool) 或者 "none" (不调用tool)作为value。 有tools定义时默认由模型决定。 # 也可以强制要求必须调用指定的函数,如下所示 # tool_choice= {"type": "function", "function": {"name": "multiply"}} , tools=tools ) return response.choices[0].message #定义function/tool 1: multiply def multiply(first_int: int, second_int: int) -> int: """两个整数相乘""" return first_int * second_int #定义function/tool 2: add def add(first_add: int, second_add: int) -> int: """两个整数相加""" return first_add + second_add #将function calling的schema格式告诉大模型 tools=[{ "type": "function", "function": { "name": "multiply", "description": "两个整数相乘", "parameters": { "type": "object", "properties": { "first_int": { "type": "integer", "description": "第一个乘数", }, "second_int": { "type": "integer", "description": "第二个乘数", } }, "required": ["first_int", "second_int"], } } }, { "type": "function", "function": { "name": "add", "description": "两个整数相加", "parameters": { "type": "object", "properties": { "first_add": { "type": "integer", "description": "第一个加数", }, "second_add": { "type": "integer", "description": "第二个加数", } }, "required": ["first_add", "second_add"], } } }] # 调用LLM接口,将LLM回复加入对话上下文 prompt = "一共有3个人,每个人有15个苹果,10个鸭梨,一共有多少苹果?" messages = [ {"role": "user", "content": prompt} ] response = get_completion(messages, tools) messages.append(response) # 如果LLM需要function calling,调用相应的函数,并将函数结果数据加入对话上下文,继续调用LLM。 while (response.tool_calls is not None): for tool_call in response.tool_calls: selected_tool = {"add": add, "multiply": multiply}[tool_call.function.name] args = json.loads(tool_call.function.arguments) tool_output = selected_tool(**args) messages.append({ "tool_call_id": tool_call.id, # 用于标识函数调用的 ID "role": "tool", "name": tool_call.function.name, "content": str(tool_output) # 数值result 必须转成字符串 }) response = get_completion(messages, tools) messages.append(response) print("=====最终回复=====") print(response.content)
后续更新AI系列:大语言模型的function calling(下)- 使用LangChain:如何使用LangChain实现function calling,LangChain对比原生调用能提供哪些便利。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。