news 2026/2/26 19:54:29

从零构建大模型智能体:OpenAI Function Calling 实战全流程详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
从零构建大模型智能体:OpenAI Function Calling 实战全流程详解

引言

随着大模型能力的不断增强,仅依靠自然语言对话已难以满足真实业务场景的需求。模型不仅需要“会说话”,还需要能够访问外部数据、调用业务能力,并参与实际流程执行。为此,OpenAI 提供了Function Calling(工具调用)机制,使模型能够在对话过程中主动选择并调用开发者定义的函数,从而实现与外部系统的深度集成。

Function Calling 本质上为大模型打开了一扇“连接现实世界”的大门:模型可以根据用户意图,结构化地生成函数调用参数,由应用程序执行真实逻辑后再将结果反馈给模型,最终生成面向用户的自然语言回复。这种模式极大地降低了 AI 与业务系统集成的复杂度,也成为构建 AI Agent、智能助手和自动化流程的核心能力之一。

本文将基于 OpenAI 官方文档与示例,系统性地介绍 Function Calling 的基本概念、工作流程以及完整的调用链路,并通过一个天气查询的实战示例,演示从工具定义、模型触发函数调用,到函数执行结果回传并生成最终回答的完整过程。希望通过这篇文章,帮助你快速理解并在实际项目中正确、稳定地使用 Function Calling 能力。

Function calling

Function calling(tool caling)为模型提供访问新功能和数据的权限,使其能够遵循指令并响应提示。

Function calling为OpenAI模型提供了一种强大且灵活的方式,可以与外部系统对接并访问器训练数据以外的数据(调用工具)。本节来展示它的工作原理。

工具-我们赋予模型的功能

工具(Tool)就是我们告诉模型它可以访问的额外功能,当模型根据提示词生成响应时,它可能会决定需要调用工具提供的数据或功能以遵循提示的指示。

当我想模型发送带有提示的API请求时,可以包含一个工具列表,让模型在处理时考虑使用这些工具,就和上篇文章一样。我们以获取某地天气情况的工具get_weather为例,它可能会带有location参数。

工具调用-模型请求使用工具的指令

工具调用(function call)是指模型在分析提示词后,如果认为为了遵循提示中的指令,需要调研我们为其提供的某个工具,则会返回的一种特殊响应。

如果模型接收到一个类似"what is the weather in Paris?" 的API请求,它可能会使用get_weather工具进行工具调用,其中Paris作为location的参数。

工作调用输出-我们为模型生成的输出

工作调用输出指的是工具使用模型的工具调用输入生成的响应,工具调用输出可以是结构化的JSON或纯文本,并包含对特定模型工具调用的引用(call_id)。为了完成我们的天气示例:

  • 模型可以访问get_weather工具,参数为location
  • 在接收到类似"what is the weather in Paris?" 这样的提示后,模型会返回一个包含location参数且值为Paris的工具调用。
  • 工具调用的输出可能返回一个JSON对象、图像内容或文件内容。

然后我们将所有工具定义、原始提示、模型的工具调用以及工具调用输出再次发送给模型,最终获得类似:

The weather in Paris today is 25C.

函数与工具

  • 函数是一种特定类似的工具,由JSON模式(schema)定义。函数定义允许模型将数据传递给你的应用程序,你的代码可以访问模型建议的数据或采取相应的操作。
  • 除了函数工具外, 还有自定义工具,它们可以与自由文本输入和输出配合使用。
  • 此外,还有OpenAI平台内建的工具。

Function calling流程

Function calling是通过OpenAI API在应用程序和模型之间进行的多轮对话,其流程包含五个高层次步骤:

  1. 向模型发起它可调用的工具的请求
  2. 从模型接收工具调用
  3. 在应用程序端使用工具调用的输入执行代码
  4. 使用工具调用的输出向模型发起第二次请求
  5. 接收来自模型的最终响应(或更多工具调用)

(工具调用流程,图片来自于参考1)

函数工具示例

我们还是以获取天气为例,看一个工具调用流程的例子。

fromopenaiimportOpenAIimportjsonimportos os.environ["OPENAI_API_KEY"]="sk-xx"os.environ["OPENAI_BASE_URL"]="xx"model_id="gpt-4o-mini"client=OpenAI()# 定义一个辅助函数defchat_completion_request(messages,tools=None,tool_choice="auto"):try:response=client.chat.completions.create(model=model_id,messages=messages,tools=tools,tool_choice=tool_choice,)returnresponseexceptExceptionase:print(f"Exception:{e}")returne# 1. 为模型定义一个可调用工具列表# OpenAI支持的工具定义Schematools=[{"type":"function","function":{"name":"get_current_weather","description":"获取当前天气","parameters":{"type":"object","properties":{"location":{"type":"string","description":"城市,例如:深圳、北京",}},"required":["location"]},}},{"type":"function","function":{"name":"get_n_day_weather_forecast","description":"获取N天的天气预报","parameters":{"type":"object","properties":{"location":{"type":"string","description":"城市,例如:深圳、北京",},"num_days":{"type":"integer","description":"要预报的天数",}},"required":["location","num_days"]},}},]

定义两个模拟函数(也可以接入真实的查询天气API):

importrandomfromdatetimeimportdatetime,timedeltadefget_current_weather(location:str)->dict:""" 模拟获取当前天气 """# 随机生成温度temp=round(random.uniform(10,30),1)# 随机生成天气描述conditions=["晴天","多云","小雨","大雨","雷阵雨","阴天"]condition=random.choice(conditions)return{"location":location,"temperature":temp,"condition":condition,"unit":"摄氏度","time":datetime.now().strftime("%Y-%m-%d %H:%M:%S")}defget_n_day_weather_forecast(location:str,num_days:int)->dict:""" 模拟获取N天的天气预报 """forecast=[]conditions=["晴天","多云","小雨","大雨","雷阵雨","阴天"]foriinrange(num_days):temp=round(random.uniform(10,30),1)day_forecast={"date":(datetime.now()+timedelta(days=i)).strftime("%Y-%m-%d"),"temperature":temp,"unit":"摄氏度","condition":random.choice(conditions)}forecast.append(day_forecast)return{"location":location,"forecast":forecast}# 测试print(get_current_weather("北京"))print(get_n_day_weather_forecast("北京",5))
{'location': '北京', 'temperature': 11.2, 'condition': '大雨', 'unit': '摄氏度', 'time': '2025-12-13 09:50:29'} {'location': '北京', 'forecast': [{'date': '2025-12-13', 'temperature': 15.6, 'unit': '摄氏度', 'condition': '雷阵雨'}, {'date': '2025-12-14', 'temperature': 25.6, 'unit': '摄氏度', 'condition': '晴天'}, {'date': '2025-12-15', 'temperature': 28.3, 'unit': '摄氏度', 'condition': '阴天'}, {'date': '2025-12-16', 'temperature': 24.7, 'unit': '摄氏度', 'condition': '晴天'}, {'date': '2025-12-17', 'temperature': 15.5, 'unit': '摄氏度', 'condition': '雷阵雨'}]}

注册工具:

TOOLS={"get_current_weather":get_current_weather,"get_n_day_weather_forecast":get_n_day_weather_forecast}
messages=[]messages.append({"role":"system","content":"当用户的问题需要使用工具时,请调用对应的工具,而不是直接回答"})messages.append({"role":"user","content":"未来5天深圳的天气会怎么样?"})# 将定义好的工具传递给模型chat_response=chat_completion_request(messages,tools=tools)result=chat_response.choices[0].messageprint(result)
ChatCompletionMessage(content=None, refusal=None, role='assistant', annotations=[], audio=None, function_call=None, tool_calls=[ChatCompletionMessageFunctionToolCall(id='call_h68QzRexg3U1r4rSuDYRclUu', function=Function(arguments='{"location":"深圳","num_days":5}', name='get_n_day_weather_forecast'), type='function')])

这里构造一个系统消息,然后用户咨询未来五天的天气情况,把消息类别和定义好的工具传递给模型,这里tool_choice取的默认值auto,它的取值含义:

  • auto: 默认值,可以由模型自行决定调用零个、一个或多个函数。
  • none:禁止调用函数。
  • 调用指定函数:{"type": "function", "function": {"name": "my_function"}}
  • required:必须调用一个或多个函数。

接下来是很重要的一步:

# 3. 增加工具调用消息(注意格式)messages.append({"role":"assistant","content":None,"tool_calls":[{"c":call.id,"type":"function","function":{"name":call.function.name,"arguments":call.function.arguments}}forcallinresult.tool_calls]})

我们必须增加工具调用消息到列表中,这里传入的id后面工具调用结果消息会用到,必须保持一致:

foriteminresult.tool_calls:ifitem.type=="function":func=TOOLS[item.function.name]# 4. 执行函数func_result=func(**json.loads(item.function.arguments))# 5. 告诉模型函数调用结果messages.append({"role":"tool","tool_call_id":item.id,"content":str(func_result)})print(messages)
messages = [ { "role": "system", "content": "当用户的问题需要使用工具时,请调用对应的工具,而不是直接回答" }, { "role": "user", "content": "未来5天深圳的天气会怎么样?" }, { "role": "assistant", "content": None, "tool_calls": [ { "id": "call_h68QzRexg3U1r4rSuDYRclUu", "type": "function", "function": { "name": "get_n_day_weather_forecast", "arguments": "{'location':'深圳','num_days':5}" } } ] }, { "role": "tool", "tool_call_id": "call_h68QzRexg3U1r4rSuDYRclUu", "content": "{'location': '深圳', 'forecast': [{'date': '2025-12-13', 'temperature': 14.2, 'unit': '摄氏度', 'condition': '多云'}, {'date': '2025-12-14', 'temperature': 19.2, 'unit': '摄氏度', 'condition': '大雨'}, {'date': '2025-12-15', 'temperature': 19.5, 'unit': '摄氏度', 'condition': '晴天'}, {'date': '2025-12-16', 'temperature': 22.5, 'unit': '摄氏度', 'condition': '雷阵雨'}, {'date': '2025-12-17', 'temperature': 27.3, 'unit': '摄氏度', 'condition': '雷阵雨'}]}" } ]

整个消息列表如上所示,注意这里的assistant消息包含了工具调用,我们就应该把工具调用结果通过tool消息附加进去,并且tool_call_id需保持一致。

最后再次传递给大模型,让模型给出最终回答:

chat_completion_request(messages,tools)
ChatCompletion(id='chatcmpl-Cm9B8aWEcZYi5OBoXnTL7temNyD53', choices=[Choice(finish_reason='stop', index=0, logprobs=None, message=ChatCompletionMessage(content='未来5天深圳的天气预报如下:\n\n- **12月13日**:多云,温度14.2°C\n- **12月14日**:大雨,温度19.2°C\n- **12月15日**:晴天,温度19.5°C\n- **12月16日**:雷阵雨,温度22.5°C\n- **12月17日**:雷阵雨,温度27.3°C\n\n请注意天气变化,出行时合理安排!', refusal=None, role='assistant', annotations=[], audio=None, function_call=None, tool_calls=None))], created=1765591062, model='gpt-4o-mini-2024-07-18', object='chat.completion', service_tier=None, system_fingerprint='fp_efad92c60b', usage=CompletionUsage(completion_tokens=115, prompt_tokens=341, total_tokens=456, completion_tokens_details=CompletionTokensDetails(accepted_prediction_tokens=0, audio_tokens=0, reasoning_tokens=0, rejected_prediction_tokens=0), prompt_tokens_details=PromptTokensDetails(audio_tokens=0, cached_tokens=0)))

(渲染后的结果如下:)


未来5天深圳的天气预报如下:

  • 12月13日:多云,温度14.2°C
  • 12月14日:大雨,温度19.2°C
  • 12月15日:晴天,温度19.5°C
  • 12月16日:雷阵雨,温度22.5°C
  • 12月17日:雷阵雨,温度27.3°C
    请注意天气变化,出行时合理安排!

参考

  1. Function calling (内容可能会变化)
  2. How to call functions with chat models
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/2/25 19:23:45

验证码暴力破解

这里介绍两中方法第一种:1.随便输入验证码进行抓包2.发送到intruder模块4.设置payload5.分析(这里一共1000000条,内容很多,速度慢)使用第二种方法绕过直接进入第二种方法:(不一定成功&#xff0…

作者头像 李华
网站建设 2026/2/20 15:23:14

性价比高安全体验馆哪家靠谱

探寻性价比高且靠谱的安全体验馆引言在当今注重安全意识培养的时代,安全体验馆成为众多企业和机构提升人员安全素养的重要场所。然而,面对市场上琳琅满目的选择,如何挑选一家性价比高且靠谱的安全体验馆成为关键问题。黑云智能科技&#xff1…

作者头像 李华
网站建设 2026/2/26 4:04:56

8、SELinux 用户登录管理全解析

SELinux 用户登录管理全解析 1. 角色与可访问域 在 SELinux 中,角色定义了与之关联的用户可以访问的域。 seinfo 工具不仅能显示可用角色,还能借助 -x 选项列出某个角色可访问的域。示例如下: # seinfo -rdbadm_r -x dbadm_rDominated Roles:dbadm_rTypes:qmail_inj…

作者头像 李华
网站建设 2026/2/24 16:32:43

如何在5分钟内搭建ZeroTier游戏加速网络?

如何在5分钟内搭建ZeroTier游戏加速网络? 【免费下载链接】ZeroTierOne A Smart Ethernet Switch for Earth 项目地址: https://gitcode.com/GitHub_Trending/ze/ZeroTierOne 还在为游戏联机延迟高、卡顿频繁而烦恼?NAT穿透失败让玩家间的直接连接…

作者头像 李华
网站建设 2026/2/23 12:58:53

Hover Zoom+终极图片预览神器:告别繁琐点击,悬停即放大

Hover Zoom终极图片预览神器:告别繁琐点击,悬停即放大 【免费下载链接】hoverzoom Google Chrome extension for zooming images on mouse hover 项目地址: https://gitcode.com/gh_mirrors/ho/hoverzoom 在当今信息爆炸的时代,网页浏…

作者头像 李华
网站建设 2026/2/26 16:38:50

Open Interface:开启电脑全自动驾驶新时代

Open Interface:开启电脑全自动驾驶新时代 【免费下载链接】Open-Interface Control Any Computer Using LLMs 项目地址: https://gitcode.com/gh_mirrors/op/Open-Interface 在人工智能技术飞速发展的今天,你是否曾想象过你的电脑能够像自动驾驶…

作者头像 李华