当前位置: 首页 > news >正文

Function Calling:让大语言模型从“问答”到“执行”的核心机制详解

1. 从“一问一答”到“自主行动”:Function Calling 的本质是什么?

如果你用过早期的聊天机器人,或者一些基础的AI助手,大概会有一个印象:你问,它答。答案可能是一段文本,也可能是一段代码,但它始终停留在“说”的层面。它告诉你“如何写一个排序算法”,但不会帮你直接运行;它告诉你“今天天气如何”,但不会帮你打开天气应用。这中间隔着一道无形的墙——模型知道“是什么”,但无法直接操作“做什么”。

Function Calling 机制,就是打破这堵墙的钥匙。它不是一个具体的函数,而是一套标准化的“协议”或“机制”,让大语言模型(LLM)能够理解并“调用”外部工具、API或函数。简单来说,它让AI从“知识库”和“文本生成器”,进化成了可以“动手做事”的智能体。

想象一下,你有一个无所不知但手脚被绑住的助手。Function Calling 就是解开了他手上的绳子,并给了他一本《标准操作手册》。现在,你可以对他说:“查一下我明天上午十点的会议安排,如果和产品评审会冲突就帮我重新预约。” 助手会先理解你的意图,然后按照手册(即定义好的函数规范)去调用“查询日历”和“修改日程”这两个外部工具,最后把操作结果整合成自然语言回复给你。整个过程,模型负责的是“理解意图”和“规划行动”,而具体的“执行动作”则由外部系统可靠地完成。

这背后的核心逻辑是分工与协同。大模型擅长语义理解、逻辑推理和内容生成,但在精确计算、实时数据获取、执行确定性操作(如数据库读写、发送邮件、控制硬件)等方面存在局限,甚至可能“胡编乱造”(幻觉)。Function Calling 机制将模型的“思考”与外部工具的“执行”解耦,让两者各司其职,从而构建出更强大、更可靠的应用。

所以,当我们谈论 Function Calling 时,我们讨论的是一种让AI具备“可操作性”的基础设施。它不仅是技术热点,更是当前构建AI应用,特别是智能体(Agent)和AI工作流的核心基石。理解了它,你就拿到了打开下一代AI应用大门的钥匙。

2. 协议与流程拆解:一次完整的 Function Calling 是如何发生的?

要理解Function Calling,不能只看概念,必须深入到一次调用的完整生命周期中。这个过程通常不是模型“主动”发起的,而是由开发者设计、系统协同完成的。我们可以将其拆解为三个核心阶段:定义、决策与执行、返回。

2.1 阶段一:函数定义与声明

这是开发者的准备工作。在向大模型发起对话之前,我们必须先告诉模型:“嘿,你现在可以指挥这些工具了,这是它们的使用说明书。”

这个“说明书”就是一个结构化列表,里面定义了每个函数(或工具)的三大要素:

  1. 名称(name):函数的唯一标识符,如get_current_weather
  2. 描述(description):用自然语言清晰说明这个函数是干什么的。这是最关键的部分,模型完全依赖这段描述来判断是否以及何时调用该函数。例如:“获取指定城市的当前天气情况。”
  3. 参数(parameters):一个遵循JSON Schema格式的详细定义,描述了函数需要的输入。例如,对于天气函数,参数可能包括location(城市名)和unit(温度单位)。你需要定义每个参数的类型(string, number等)、描述、以及是否必需。

一个典型的函数定义在代码中看起来是这样的(以OpenAI API格式为例):

{ "type": "function", "function": { "name": "get_current_weather", "description": "获取指定城市的当前天气", "parameters": { "type": "object", "properties": { "location": { "type": "string", "description": "城市名称,例如:北京,上海" }, "unit": { "type": "string", "enum": ["celsius", "fahrenheit"], "description": "温度单位" } }, "required": ["location"] } } }

在对话开始时,我们将这个函数列表作为系统提示(system message)的一部分,或者通过API的特定参数(如OpenAI的tools参数)传递给模型。从此,模型就知道了它的“武器库”里有哪些“武器”,以及每种武器的用途和用法。

2.2 阶段二:模型决策与结构化输出

当用户输入一条消息后,真正的魔法开始了。模型会结合对话历史、当前用户问题以及已知的函数列表进行推理。

  1. 意图识别:模型首先判断用户的请求是否需要调用外部函数。比如用户说“北京今天热吗?”,模型会理解其核心意图是查询天气。
  2. 函数选择:模型在所有已定义的函数中,寻找最匹配当前意图的那个。它会仔细比对函数描述和用户问题。在我们的例子中,get_current_weather的描述“获取指定城市的当前天气”与用户意图高度吻合。
  3. 参数提取:模型从用户的自然语言中,提取出调用所选函数所需的参数值。它会将“北京”映射到location参数。对于未明确提及的参数(如unit),模型可能会使用默认值或留空(如果非必需)。
  4. 结构化响应:模型不会直接执行函数,也不会在回复中说出“我要调用get_current_weather函数”。相反,它会输出一个严格遵循预定格式的JSON对象。这个JSON对象对于用户是不可见的,它是系统内部的一个指令。

这个结构化响应通常包含:

  • function_name: 选中的函数名。
  • arguments: 一个包含所有提取出的参数的JSON对象。

例如,对于“北京今天热吗?”,模型的响应可能看起来还是普通的聊天消息,但在后台,它会附加上这样一个结构:

{ "role": "assistant", "content": null, "function_call": { "name": "get_current_weather", "arguments": "{\"location\": \"北京\", \"unit\": \"celsius\"}" } }

注意,content字段为null,这明确表示“我决定不生成文本回复,而是要求调用一个函数”。这是Function Calling机制与普通聊天的根本区别。

2.3 阶段三:外部执行与结果整合

收到模型的“指令”后,控制权回到了你的应用程序(服务端)手中。

  1. 本地函数调用:你的代码会解析这个JSON,找到本地实现的、与get_current_weather同名的函数,并将arguments传递给它。这个本地函数可能去调用一个天气API(如和风天气、OpenWeatherMap),也可能查询本地数据库。
  2. 获取执行结果:外部工具执行完毕后,会返回一个结果。这个结果也是一个JSON可序列化的数据。例如:{"temperature": 22, "condition": "晴朗", "humidity": "65%"}
  3. 结果回传与最终回复:你的应用程序需要将这个执行结果,以特定格式再次传回给大模型。这通常是通过在对话历史中添加一条具有role: function的消息来完成的。
{ "role": "function", "name": "get_current_weather", "content": "{\"temperature\": 22, \"condition\": \"晴朗\", \"humidity\": \"65%\"}" }

模型收到这个函数执行结果后,会结合最初的用户问题、自己之前提出调用的决策以及这个具体结果,生成一段面向用户的、自然流畅的最终回复:“北京今天天气晴朗,气温22摄氏度,比较舒适。”

至此,一个完整的Function Calling闭环完成。用户得到了一个由AI理解、外部工具执行、AI再整合后的精准答案,整个过程浑然天成。

关键心得:很多初学者会混淆“模型调用函数”和“你的代码调用函数”。必须牢记,模型只负责输出一个结构化的调用请求,实际的函数执行永远发生在你的代码、你的服务器、你控制的环境中。这是保证安全、可控和成本效益的关键设计。

3. 超越天气查询:Function Calling 的典型应用场景与设计模式

理解了基础流程,我们来看看Function Calling能做什么。它的应用远不止查天气,几乎可以覆盖所有需要连接现实世界数据和操作的场景。下面通过几个典型模式来展开。

3.1 模式一:数据检索与增强

这是最直接的应用。当用户的问题涉及实时、私有或海量数据时,让模型去“记忆”或“生成”这些数据是不可靠的。

  • 企业知识库问答:定义search_company_docs函数,连接你的内部Confluence、Notion或向量数据库。当员工问“我们今年的销售目标是多少?”,模型自动调用搜索函数,获取最新文档片段,再组织成答案。这比让模型背诵所有公司数据要现实和准确得多。
  • 个人数据助理:定义get_my_calendarget_my_emails函数,连接Google Calendar或Outlook。用户可以说“我下午三点以后有空吗?”,AI通过调用日历接口来回答,确保了信息的私密性和实时性。
  • 实时信息查询:股票价格(get_stock_price)、航班状态(check_flight_status)、新闻头条(get_latest_news)。模型本身的知识可能过时,但通过Function Calling,它能始终提供最新信息。

设计要点:这类函数的参数设计要灵活。搜索函数通常需要query(查询词)和可选的filters(如时间范围、部门)。返回的content应尽量是结构化的摘要或关键片段,而不是整篇文档,以减少模型的令牌消耗和干扰。

3.2 模式二:事务执行与操作

让AI从“顾问”变成“执行者”。这是构建智能体(Agent)的核心。

  • 自动化工作流:定义send_emailcreate_jira_ticketsend_slack_message函数。你可以对AI说:“把刚才讨论的这个需求总结一下,发邮件给产品团队,并创建一个高优先级的Jira任务指派给张三。” AI可以规划并依次调用多个函数完成这个工作流。
  • 智能家居控制:定义turn_on_lightset_thermostatplay_music函数。通过语音或文字指令控制智能设备,模型理解“把客厅的灯调暗一点”并调用对应函数。
  • 电子商务操作:定义add_item_to_cartplace_ordertrack_package函数。用户可以通过自然语言完成购物流程。

设计要点:事务执行涉及状态改变,安全性和验证至关重要。必须在本地函数中实现严格的权限检查、二次确认(例如,“你确定要发送这封邮件吗?”)和操作日志。模型只负责生成意图和参数,是否执行、如何执行的最终决定权必须牢牢掌握在应用逻辑中。

3.3 模式三:复杂计算与专业工具调用

大模型不擅长精确计算和复杂逻辑,但可以指挥专业工具来完成。

  • 代码解释与执行:定义execute_python_code函数(在安全的沙箱环境中)。用户问“计算一下从1加到1000000的和”,模型可以生成一段Python代码并调用执行函数,返回准确结果,避免了模型自己可能出错的计算。
  • 数据分析与可视化:定义run_sql_querygenerate_chart函数。用户问“上个月销售额最高的三个产品是什么?”,模型生成SQL查询,调用函数获取数据,再组织语言回答,甚至可以进一步调用图表生成函数。
  • 格式转换与处理:定义convert_pdf_to_textresize_imagetranslate_text函数。处理模型本身无法直接处理的二进制文件或需要特定库的任务。

设计要点:确保工具接口的稳定性和错误处理。计算类函数要明确输入输出格式。对于代码执行,必须使用资源受限的沙箱环境,防止无限循环或恶意代码。

3.4 模式四:多函数协作与规划(智能体雏形)

单个Function Calling是基础,真正的威力在于让模型学会在单轮对话中顺序或并行调用多个函数,以完成复杂目标。这已经进入了智能体(Agent)的领域。

例如,用户请求:“帮我规划一个下周末从北京去上海的两日游预算,包括机票、酒店和主要景点门票。” 一个具备规划能力的AI可能会:

  1. 调用search_flights(出发地:北京,目的地:上海,时间:下周末)。
  2. 调用search_hotels(目的地:上海,时间:下周末,价格范围:中等)。
  3. 调用search_attractions(城市:上海)。
  4. 最后调用calculate_budget函数,将前三步的结果汇总,生成一份预算报告。

在这个过程中,模型需要维护上下文,理解子任务之间的依赖关系(先查机票酒店,再算预算),并处理可能出现的中间结果(如航班时间影响酒店入住日期)。

实战经验:实现多函数调用时,一个常见的挑战是模型的“思维链”可能不稳定。有时它会试图在一个回复里塞进多个函数调用,有时又会忘记之前的结果。成熟的框架(如LangChain、LlamaIndex的Agent模块)提供了更好的状态管理和工具调用循环处理。在自行实现时,一个简单的策略是:在每次函数执行结果返回后,将完整的“用户问题-模型函数调用-函数结果”历史再次喂给模型,让它基于最新状态决定下一步行动,直到它输出一个纯文本的最终答案为止。

4. 主流平台实现对比与核心代码剖析

虽然概念相通,但各大模型平台对Function Calling的实现细节和API设计各有不同。理解这些差异对于技术选型和开发至关重要。我们主要对比OpenAI、Anthropic(Claude)和开源代表(以Llama 3.1为例通过ollama)的实现方式。

4.1 OpenAI:定义标准与广泛采用

OpenAI在2023年6月随GPT-3.5-turbo-0613和GPT-4-0613模型更新正式推出了Function Calling功能(后续在Chat Completions API中更名为tools,但本质相同)。它可以说是业界的定义者和事实标准。

核心API调用流程:

  1. 定义工具:在请求的tools参数中传入函数定义列表。
  2. 模型响应:如果模型决定调用工具,响应消息中会包含tool_calls数组(早期为function_call)。
  3. 执行与回传:你执行对应函数后,将结果以tool类型的消息追加到对话历史 (messages) 中,再次请求模型生成最终回复。

示例代码片段(使用最新tools接口):

import openai from openai import OpenAI client = OpenAI(api_key="your-api-key") # 1. 定义工具(函数) tools = [ { "type": "function", "function": { "name": "get_current_weather", "description": "获取当前天气", "parameters": { "type": "object", "properties": { "location": {"type": "string", "description": "城市名"}, "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]} }, "required": ["location"] } } } ] # 2. 首次请求,模型可能决定调用工具 response = client.chat.completions.create( model="gpt-3.5-turbo", messages=[{"role": "user", "content": "北京天气怎么样?"}], tools=tools, tool_choice="auto", # “auto”让模型决定,“none”不调用,或指定某个函数 ) message = response.choices[0].message # 3. 检查是否有工具调用 if message.tool_calls: tool_call = message.tool_calls[0] function_name = tool_call.function.name function_args = json.loads(tool_call.function.arguments) # 4. 执行本地函数 if function_name == "get_current_weather": weather_result = get_current_weather(**function_args) # 你的本地函数 # 5. 将工具执行结果追加到消息历史 messages.append(message) # 先追加助理的工具调用消息 messages.append({ "role": "tool", "tool_call_id": tool_call.id, # 关键:通过id关联 "content": json.dumps(weather_result), }) # 6. 第二次请求,让模型基于结果生成最终回复 second_response = client.chat.completions.create( model="gpt-3.5-turbo", messages=messages, ) final_answer = second_response.choices[0].message.content print(final_answer)

OpenAI方案特点

  • 成熟稳定:文档丰富,社区支持最好,是大多数教程和项目的参考基准。
  • tool_call_id:引入了调用ID来精确匹配多个并行工具调用及其结果,支持更复杂的代理场景。
  • tool_choice参数:提供精细控制,可强制调用、禁止调用或由模型自动选择。

4.2 Anthropic Claude:结构化输出的原生支持

Anthropic的Claude系列模型从一开始就通过“结构化输出”来支持类似功能,其理念是让模型直接输出符合预定格式的JSON,然后由开发者解析并执行。

核心流程:

  1. 系统提示中定义:在系统提示(System Prompt)里,以文字形式详细描述你期望模型输出的JSON格式和函数用途。
  2. 模型输出JSON:模型直接在回复中输出一个合法的JSON字符串。
  3. 开发者解析执行:你解析这个JSON,获取函数名和参数,然后执行本地函数。

示例(概念性说明):在给Claude的System Prompt中,你可能会这样写:

你是一个助手,可以调用工具。当用户请求需要工具时,请输出一个严格的JSON对象,格式如下: { "function": "function_name", "arguments": { "arg1": "value1", ... } } 可用的工具有: - get_current_weather: 获取天气。参数: location (string), unit (optional, “celsius” or “fahrenheit”) ... 如果不需要工具,请正常对话。

当用户提问后,Claude可能直接回复:

{"function": "get_current_weather", "arguments": {"location": "北京", "unit": "celsius"}}

Claude方案特点

  • 灵活性高:不依赖特定的API字段,理论上任何能输出JSON的模型都可以通过系统提示来引导。
  • 依赖提示工程:效果严重依赖于系统提示词的质量和模型的遵循指令能力。
  • 更接近“思维链”:这种方式更像是让模型“思考”后输出一个行动计划,而不是API层面的硬性约束。

4.3 开源模型与ollama:本地部署的灵活实践

以Meta的Llama 3.1系列模型为例,通过ollama本地部署时,实现Function Calling通常有两种主流方式:

方式A:模仿OpenAI API格式许多本地部署框架(如FastChat、LocalAI)提供了与OpenAI API兼容的接口。这意味着你可以使用几乎相同的tools参数和调用流程,只是将 endpoint 指向你的本地服务。这是最便捷的方式。

方式B:利用模型的原生能力与提示工程对于没有封装成OpenAI格式的纯模型,可以借鉴Claude的思路,通过精心设计的系统提示词和上下文学习(In-Context Learning)来引导模型输出结构化内容。例如,在对话历史中提供几个“用户请求-模型输出JSON”的例子(少样本学习),然后让模型在回复新请求时模仿这种格式。

一个简单的ollama + Llama 3.1提示词示例:

import requests import json def query_llama_with_function(prompt): system_msg = """你是一个能调用工具的助手。当需要调用工具时,你必须严格按以下JSON格式回复,且只回复这个JSON,不要有其他文字: {"action": "call_function", "function_name": "xxx", "parameters": {...}} 可用工具: 1. 搜索网络:function_name: “web_search”, parameters: {“query”: “搜索关键词”} 2. 计算器:function_name: “calculator”, parameters: {“expression”: “数学表达式”} 如果不需要工具,请直接回答。 """ full_prompt = f"{system_msg}\n\n用户:{prompt}\n助手:" response = requests.post('http://localhost:11434/api/generate', json={ "model": "llama3.1", "prompt": full_prompt, "stream": False }) raw_output = response.json()['response'].strip() # 尝试解析JSON try: action_data = json.loads(raw_output) if action_data.get('action') == 'call_function': return action_data # 返回结构化调用请求 else: return {"action": "reply", "content": raw_output} except json.JSONDecodeError: # 如果输出不是JSON,则视为直接回复 return {"action": "reply", "content": raw_output}

开源方案特点

  • 成本与隐私可控:数据不出本地,适合处理敏感信息。
  • 定制性强:可以完全控制模型、提示词和交互流程。
  • 实现复杂度较高:需要更多底层工作来处理格式解析、错误恢复和状态管理,稳定性可能不如商业API。

选型建议:对于快速原型开发和生产级应用,OpenAI的toolsAPI是目前最省心、生态最完善的选择。如果对数据隐私和成本有极高要求,且团队有较强的工程能力,基于开源模型自建是可行之路。Claude的方式则介于两者之间,提供了很大的灵活性,但需要投入精力优化提示词。

5. 实战避坑指南:从开发到上线的关键挑战

纸上得来终觉浅,绝知此事要躬行。在实际开发中,你会遇到一系列预料之外的问题。下面是我从多个项目中总结出的核心挑战和应对策略。

5.1 函数描述的艺术:清晰、具体与边界

函数描述(description)是模型决定是否调用的唯一依据。一个模糊的描述会导致模型误调用或漏调用。

  • 反面教材“一个有用的工具”“处理数据”。这种描述等于没说。
  • 最佳实践
    1. 用动词开头,明确动作“查询用户在系统内的订单记录”“根据关键词搜索内部知识库文档”
    2. 说明触发条件“当用户需要查找文件或信息时使用此功能”
    3. 界定输入输出:在描述中简要提及关键参数。例如:“计算两个地点之间的驾驶距离与时间。需要提供起点和终点的完整地址。”
    4. 进行对比区分:如果你有多个相似函数,描述要突出差异。例如search_products_by_namesearch_products_by_category,描述中就要强调“按名称关键词”和“按产品分类”的区别。

一个常见的坑是“过度调用”。比如,用户说“我喜欢北京的秋天”,模型可能错误地调用了get_current_weather。这是因为描述可能过于宽泛,或者模型对“喜欢”和“查询”的边界判断不准。解决方法是在描述中加入限制条件,例如:“仅在用户明确询问当前或未来天气状况时调用此函数。”

5.2 参数设计的陷阱:类型、枚举与必填

参数定义的JSON Schema是模型提取信息的蓝图。设计不当会导致提取失败或提取到错误信息。

  • 类型要精确:能用enum(枚举)就不要用string。比如unit: [“celsius”, “fahrenheit”]unit: string好得多,模型不会生成“摄氏度”这样的中文,而是会从枚举值里选。
  • 描述要引导提取:参数的description字段至关重要。对于location,描述写成“城市或地区名称,例如:北京市,上海市”“地点”更能引导模型提取出标准名称。
  • 谨慎使用required:只将核心的、用户问题中大概率会出现的参数设为必填。对于可选参数,确保你的本地函数能处理默认值或空值。如果模型无法提取必填参数,它可能会放弃调用该函数,即使其他条件都符合。
  • 处理复杂嵌套:对于复杂对象,定义清晰的嵌套结构。例如,一个创建会议的函数,参数可能包含attendees(数组)、start_time(对象,包含datetimetimezone)。清晰的嵌套定义能帮助模型更好地理解结构。

5.3 错误处理与韧性:当模型“不按套路出牌”

模型是概率性的,它可能输出不符合预期的内容。你的代码必须足够健壮。

  • 解析失败:模型返回的argumentsJSON 可能格式错误或无法解析。一定要用try...except包裹json.loads(),并准备好降级方案,比如回复用户“抱歉,我理解错了,能再描述一下吗?”
  • 调用错误:本地函数执行可能失败(如API超时、参数无效)。捕获这些异常,并将清晰的错误信息作为function角色的content返回给模型。模型通常能根据错误信息生成友好的用户提示,例如“天气服务暂时不可用,请稍后再试”。
  • 模型“幻觉”调用:模型可能调用一个不存在的函数,或者参数值完全离谱(如location: “火星”)。需要在调用分发层做校验,如果函数不存在或参数明显无效,直接返回错误,而不是尝试调用。
  • 多轮对话中的状态管理:在复杂对话中,模型可能引用之前调用过的函数结果。确保你的应用能维护完整的对话历史(包括所有user,assistant,tool消息),并在每次请求时完整地发送给模型,这是保证上下文连贯性的基础。

5.4 安全与权限:致命的“越权操作”

这是Function Calling从演示走向生产必须跨越的鸿沟。模型建议的操作,必须经过业务逻辑的严格审查。

  • 永远不要相信模型的输出:模型输出的function_call只是一个“建议”。你的代码必须在执行前进行业务逻辑校验。
  • 实施权限检查:在本地函数内部,在执行任何操作前,验证当前用户是否有权执行此操作。例如,send_email函数必须检查发件人邮箱是否属于当前登录用户,delete_file函数必须检查用户对该文件是否有删除权限。
  • 关键操作需二次确认:对于删除、支付、发送重要通知等高风险操作,即使模型生成了调用请求,也应该先暂停,通过应用界面(如弹窗)向用户发起二次确认,待用户明确同意后再执行。
  • 输入验证与清理:对模型提取的所有参数进行严格的验证和清理,防止注入攻击。例如,如果参数用于拼接SQL或系统命令,必须进行转义或使用参数化查询。

血泪教训:在一个内部测试中,我们曾定义了一个execute_shell_command函数用于服务器管理。由于缺乏权限校验,测试人员开玩笑地问“能删掉日志目录吗?”,模型果然调用了rm -rf。幸好是在隔离的测试容器中,否则后果不堪设想。从此我们定下铁律:任何具有破坏性的函数,必须在描述中明确警告,并在代码中实现多层人工或自动确认机制。

6. 进阶模式:从单次调用到智能体工作流

当单个Function Calling玩转后,很自然地会想:能否让模型自主规划,连续调用多个函数来完成一个复杂目标?这就是智能体(Agent)的起点。这里介绍两种基础但强大的进阶模式。

6.1 ReAct模式:推理与行动的循环

ReAct(Reasoning + Acting)是一个经典的智能体框架。其核心思想是让模型进行“思考(Thought)”,然后决定“行动(Action)”,根据“观察(Observation)”结果再进入下一轮思考,如此循环。

在Function Calling语境下,可以这样实现一个简化版ReAct循环:

  1. 初始化:给模型提供工具列表和任务目标。
  2. 循环开始: a.推理(Thought):模型分析当前情况(任务、已有信息、可用工具),思考下一步该做什么。在实现上,我们通过系统提示要求模型在输出行动前,先输出一段“思考:...”的文字。 b.行动(Action):模型输出一个具体的函数调用请求(即标准的Function Calling JSON)。 c.执行与观察:系统执行该函数,并将结果作为“观察”反馈给模型。 d.更新状态:将“思考”、“行动”、“观察”全部追加到对话历史中。
  3. 循环判断:模型根据最新观察,判断任务是否完成。如果完成,则输出最终答案;如果未完成,回到步骤2a继续循环。

示例提示词片段:

系统指令:你是一个能使用工具的助手。请用以下格式回应: 思考:[你对当前情况和下一步的分析] 行动: ```json {"function": "function_name", "arguments": {...}}

或 最终答案:[你的回答]

可用工具:[工具列表] 当前任务:用户的目标是...

这种模式让模型的决策过程变得可解释(通过“思考”),也更稳健,能处理需要多步骤探索的任务,比如“找出公司官网上的招聘邮箱地址”。 ### 6.2 并行与串行调用规划 有些任务需要多个函数,它们之间可能存在依赖关系(串行),也可能彼此独立(并行)。高级的模型(如GPT-4)已经能在单次回复中规划多个调用。 - **串行调用**:后一个函数的输入依赖于前一个函数的输出。例如,“先查天气,如果下雨就推荐室内活动”。这需要模型在第一次函数调用结果返回后,基于新上下文决定第二次调用。这通过标准的“调用-返回-再调用”循环即可实现。 - **并行调用**:多个函数可以同时执行,互不依赖。例如,“同时查询北京和上海的天气”。OpenAI的API支持在单次响应中返回多个 `tool_calls`。你需要并行执行这些调用,然后将所有结果收集起来,一次性作为多条 `tool` 消息返回给模型,让它进行综合总结。 **处理并行调用的关键**是正确关联 `tool_call_id`。每个工具调用都有一个唯一ID,当返回结果时,必须使用对应的ID,这样模型才能知道哪个结果对应哪个调用请求。 ### 6.3 工具检索与动态扩展 在工具很多的情况下,一股脑把所有函数定义都塞给模型会消耗大量上下文窗口,且可能干扰模型判断。更优雅的方式是“工具检索”。 1. **建立工具索引**:为每个工具的名称和描述创建向量嵌入(embedding)。 2. **动态选择**:当用户提问时,先用一个轻量级模型或检索器,根据用户问题与工具描述的相似度,从工具库中检索出最相关的几个(比如Top 3)工具。 3. **仅提供相关工具**:只把这几个相关工具的定义发送给大模型进行Function Calling决策。 这种方式大大提升了效率,也使得构建拥有数百个工具的庞大智能体系统成为可能。LangChain等框架已经内置了这种“工具检索”的能力。 从单次的Function Calling,到循环的ReAct,再到并行的规划与动态的工具检索,我们一步步构建起AI智能体的核心能力。这不再是简单的问答,而是让AI具备了在复杂环境中,通过使用工具来达成目标的能力。这,正是当前AI应用开发最激动人心的前沿。
http://www.jsqmd.com/news/1409666/

相关文章:

  • Android应用多语言切换:从基础实现到架构优化的完整解决方案
  • 从“卡片归位”赛题拆解工程化思维:构建可靠可调试的自动化系统
  • 时序图实战指南:从软件交互到硬件通信的可视化建模
  • 蒙特卡罗方法:从估算圆周率到数学建模竞赛的万能钥匙
  • 模拟量指令全解析:从信号原理到工业控制实战应用
  • 解决netca_crypto.dll缺失:Oracle加密库依赖问题全攻略
  • 基于TrustBench构建AI智能体实时信任验证系统:原理、实践与避坑指南
  • 工业自动化三层控制架构:从电机控制到过程控制的系统级解析
  • HiMCM数学建模竞赛:Python编程与学术写作实战指南
  • 秩和比法:多指标评价与排序的Python建模实战
  • CSP-J初赛错题复盘:从运算符优先级到二分查找的避坑指南
  • 蛙嗨炭烧牛蛙烧烤店口碑推荐出炉,避坑指南与实力测评全解析 - 工业推荐榜
  • 网络实验报告撰写指南与核心结构解析
  • 寄大件怎么寄更划算?2026年过来人血泪总结的省钱攻略 - 快递物流资讯
  • 金融风控平台中TinyMCE5粘贴Excel内容异常解决方案
  • 2026不锈钢水箱定制避坑攻略,口碑推荐价格透明实力之选 - 工业推荐榜
  • 三相异步电动机两地控制星三角降压启动电路设计与调试全解析
  • C/C++箭头操作符->详解:从指针原理到实战应用
  • AI自动化视频生成:从文本到视频的零剪辑技术实现
  • Node.js环境变量配置全解析:从原理到实战解决undefined错误
  • Git多用户提交切换全攻略:从原理到实践
  • Windows BitLocker加密锁定:恢复密钥查找与解锁全攻略
  • RedHat Linux文件系统管理与优化实战指南
  • Windows系统通过VMware虚拟机安装macOS并运行Xcode完整指南
  • Oracle条件逻辑全解析:IF语句、CASE表达式与DECODE函数实战指南
  • 统信UOS下使用xrandr添加自定义显示器分辨率完整指南
  • 灰色预测GM(1,1)模型:小样本预测原理、Python实现与建模避坑指南
  • 数学建模竞赛全流程实战:从Python代码到论文写作的系统方法
  • Python开发环境搭建指南:Anaconda与PyCharm高效配置实践
  • Windows 11系统安全:彻底隐藏Administrator账户的三种方法与深度配置指南