摘要:大家都知道chatGpt、Deepseek、Claude等大语言模型(LLM)很厉害,但他们是基于某个时间点以前的数据训练的,意思就是他们本质是离线的。那天然导致有很大的局限性,如你问实时广州的天气是怎样时,你问下现在广州南站的人流大不大等,这种要联网的数据他
大家都知道chatGpt、Deepseek、Claude等大语言模型(LLM)很厉害,但他们是基于某个时间点以前的数据训练的,意思就是他们本质是离线的。那天然导致有很大的局限性,如你问实时广州的天气是怎样时,你问下现在广州南站的人流大不大等,这种要联网的数据他们就一脸懵逼了。
更何况我还要进一步的与外部系统互动呢?比如要跟我们自己的业务系统互动,可以做到对内部系统数据的查询,修改,直接插入数据,甚至是执行代码呢?这就引出了我们今天要讲的函数调用了。
大语言模型的函数调用是指:大语言模型可以直接调用我们自己定义的函数,从而实现大语言模型与我们代码的互动实现拓展的能力;
背景我这里的背景就以获取某个城市的实时天气为例,比如获取广州市当天的天气。本文以openai为例。
实现流程
发送function call请求:开发者先给openai(服务器)发送一个function_call定义请求;
openai返回function的参数并调用本地函数:openai返回function_call请求的function所需要用到的参数,并调用本地函数;
openai返回最终的响应:也就是结合本地函数返回值和最初的提示词发送的二次请求,openai给出最终对于初始提示词的答复。
我们接下来按流程图步骤逐步实现。
环境准备先安装OpenAI包
pip install OpenAI设置环境变量
#windowssetx OPENAI_API_KEY
1、发送function call请求fromopenaiimportOpenAI
importos
client = OpenAI
tools = [{
"type": "function",
"name": "get_weather", #函数名
"description": "Get current temperature for provided coordinates in celsius.", #函数描述要写好
"parameters": {
"type": "object",
"properties": {
"latitude": {"type": "number"}, #纬度
"longitude": {"type": "number"} #经度
},
"required": ["latitude", "longitude"], #必填参数
"additionalProperties":False
},
"strict":True#严格模式
}]
#提示词这里:问广州今天的天气怎样
input_messages = [{"role": "user", "content": "What's the weather like in Guangzhou today?"}]
response = client.responses.create(
model="gpt-4o",
input=input_messages,
tools=tools,
)
print(response.output)
输出:
[ResponseFunctionToolCall(arguments='{"latitude":23.1291,"longitude":113.2644}', call_id='call_P6ZbwrZNWaooKkdKy1QYrpdX', name='get_weather', type='function_call', id='fc_67f7b805b2c48191a2996e870cbf55650e0e19e40e69d7e3', status='completed')]看到这里打出了调用函数需要用到的参数,实参。注意这里还返回了一个call_id,后面要用到。
当然,你本地也要有这个函数:
defget_weather(latitude, longitude):print("get_weather called
response = requests.get(f"https://api.open-meteo.com/v1/forecast?latitude={latitude}&longitude={longitude}¤t=temperature_2m,wind_speed_10m&hourly=temperature_2m,relative_humidity_2m,wind_speed_10m")
data = response.Json
returndata['current']['temperature_2m']
这里我也发一个非function call的响应对比
client = OpenAIresponse = client.responses.create(
model="gpt-4o",
input=[{"role": "user", "content": "Write a one-sentence bedtime story about a unicorn."}],
)
print(response.output[0])
输出:
ResponseOutputMessage(id='msg_67f7c096a794819197a9ac7e49b3db53060290b7f1639d43', content=[ResponseOutputText(annotations=, text='Under the silver glow of the moon, the gentle unicorn danced through the whispering meadows, leaving a trail of stardust dreams for all the sleeping children.', type='output_text')], role='assistant', status='completed',type='message')2、openai返回function的参数并调用本地函数
解析参数调用本地函数
tool_call = response.output[0]args = json.loads(tool_call.arguments)
result = get_weather(args["latitude"], args["longitude"])
print(result)
输出:
get_weather called26.4
3、openai返回最终响应# 把整个function_call的响应添加到第二次的请求体里
input_messages.append(tool_call)
# input_messages 还要再加一个function_call_output类型的参数,注意tool_call.call_id
input_messages.append({
"type": "function_call_output",
"call_id": tool_call.call_id,
"output": str(result)
})
response= client.responses.create(
model="gpt-4o",
input=input_messages,
tools=tools,
)
#现在回顾下提示词:What's the weather like in Guangzhou today?
print(response.output_text)
输出:
The current temperature inGuangzhouis26.4°C.先安装包:
//这个是做http请求用的
//准备function_call tool:
privatestaticreadonlyChatTool getWeatherTool = ChatTool.CreateFunctionTool(
functionName:nameof(GetWeather),
functionDescription: "Get current temperature for provided coordinates in celsius.",
functionParameters: BinaryData.FromBytes("""
{
"type": "object",
"properties": {
"latitude": {"type": "number"},
"longitude": {"type": "number"}
},
"required": ["latitude", "longitude"],
"additionalProperties": false
}
"""u8.ToArray)
);
//1、注意这里设置好环境变量
ChatClient client =new(model: "gpt-4o", apiKey: Environment.GetEnvironmentVariable("OPENAI_API_KEY"));
ChatCompletionOptions options =new
{
//这里支持多个函数的
Tools = { getWeatherTool },
};
List messages =
[
new UserChatMessage("What's the weather like in Guangzhou today?"),
];
//发送functioncall请求
ChatCompletion completion = client.CompleteChat(messages, options);
vartoolCall = completion.ToolCalls.FirstOrDefault;
usingjsonDocument argumentsJson = JsonDocument.Parse(toolCall?.FunctionArguments);
Console.WriteLine(JsonSerializer.Serialize(argumentsJson.RootElement));
注意看tools的json,就是函数定义
当然,你本地也要有这个函数:
private static asyncTask GetWeather(decimal latitude, decimal longitude){
Console.WriteLine("get_weather called
var url = $"https://api.open-meteo.com/v1/forecast?latitude={latitude}&longitude={longitude}¤t=temperature_2m,wind_speed_10m&hourly=temperature_2m,relative_humidity_2m,wind_speed_10m";
var result =awaiturl.GetAsync.ReceiveJson;
var temperature = result.GetProperty("current").GetProperty("temperature_2m").GetDecimal;
returntemperature.ToString;
}
messages.Add(new AssistantChatMessage(completion));
//解析参数
bool hasLatitude = argumentsJson.RootElement.TryGetProperty("latitude", out JsonElement latitude);
bool hasLongitude = argumentsJson.RootElement.TryGetProperty("longitude", out JsonElement longitude);
if(!hasLatitude || !hasLongitude)
{
throw new ArgumentException(nameof(latitude), "The hasLatitude or hasLongitude argument is required.");
}
//用解析的参数调用本地函数
string toolResult =awaitGetWeather(decimal.Parse(latitude.ToString), decimal.Parse(longitude.ToString));
Console.WriteLine(toolResult);
输出:
get_weather called26.4
3、openai返回最终响应//结合本地函数返回值二次调用
messages.Add(new ToolChatMessage(toolCall.Id, toolResult));
completion = client.CompleteChat(messages, options);
Console.WriteLine($"[ASSISTANT]: {completion.Content[0].Text}");
//如果还要继续聊的要把以上记录追加到history
messages.Add(new AssistantChatMessage(completion));
输出:
整理了下以前的笔记水一篇,大家将就看看能不能查漏补缺[拜托]
源码
来源:opendotnet