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

1.4 面试:Function Calling(函数调用)

Function Calling(函数调用),在最新技术语境下,特指大语言模型(LLM)与外部世界交互的一种标准化机制。通俗地说,它让AI从“只会聊天的话痨”变成了“能动手办事的助理”。

为了让你彻底搞懂,我从三个维度拆解:

1. 核心逻辑(它到底在干什么?)
传统的AI收到提问,只能根据训练数据“猜”答案。而Function Calling的流程是:

  • 第一步(定义):你提前把外部工具(如查天气API、发邮件接口、数据库查询)的“使用说明书”告诉AI。
  • 第二步(识别):用户提问时,AI不是直接回答,而是先“思考”——判断是否需要调用工具。如果需要,它不直接执行操作,而是输出一个结构化的JSON数据(包含应该调用哪个函数、参数是什么)。
  • 第三步(执行):你(开发者)拿到这个JSON,在自己的服务器上真正去执行函数(比如真的调天气接口),拿到结果。
  • 第四步(回复):你把执行结果再喂给AI,AI结合真实数据,生成最终自然语言回复给用户。

2. 通俗类比(帮你秒懂)
想象你是一位大老板(用户),AI是您的高级助理,外面有财务(查账)、司机(导航)、秘书(发邮件)等专员(外部函数)。

  • 没有函数调用:你问“我银行卡还剩多少钱?”助理只能瞎编一个数,因为他不负责管账。
  • 有函数调用:助理听完后,写了一张标准工单(结构化JSON)递给财务部:“请查账户X余额”。财务部查完把数字(执行结果)拿回来,助理再把数字念给你听。助理本身不查账,但他知道“何时”以及“如何”指挥别人。

3. 核心价值(为什么它是AI应用爆发的基石)

  • 突破数据时效:模型训练数据截止于过去,但它可以通过调用实时API获取今天的天气、股价或新闻。
  • 获得“行动”能力:AI不再只输出文字,它可以帮你订机票、创建日程、发送消息,真正实现自动化执行任务。
  • 保证输出格式:它强制AI输出固定的JSON格式,这对程序员非常友好,可以直接映射为前端页面的数据,避免AI“胡说八道”的格式错乱。

4. 实际应用场景

  • 智能客服:用户问“我的订单到哪了?” -> AI调用订单查询函数 -> 返回物流信息。
  • 数据分析:用户说“帮我拉一下上个月销售额报表” -> AI调用SQL生成函数 -> 自动查库并生成图表。
  • 物联网:用户说“太冷了” -> AI调用“设定温度”函数 -> 智能家居温度上调。

特别提醒(避坑指南)
AI本身并不执行代码,它只负责“推荐”该调用哪个函数。真正的代码执行必须发生在你受控的后端服务器上。如果不做这一步,直接把AI生成的函数调用拿去执行,会有巨大的安全风险(比如AI被诱导调用“删除数据库”函数)。


如果你正在考虑接入某个大模型的Function Calling,我可以给你看看具体的代码示例(比如OpenAI或DeepSeek的调用格式),需要我展开讲讲吗? 😊
好的,既然你想“展开说一下”,那我们就不再停留在概念层面,直接钻进代码底层,把Function Calling的完整数据流转高级玩法以及最容易翻车的坑全部摊开来讲。

为了让你看得更过瘾,我把技术细节拆解为四个深度维度:

1. 底层数据流转(AI到底在“看”什么?)

很多人误以为AI能“直接调用”代码,其实完全不是。本质上,这是两次独立的HTTP请求

  • 第一次请求(带“说明书”):你在调用API时,在tools参数里传入一堆JSON格式的函数定义(包括函数名、参数类型、必填项)。AI收到后,并不执行,而是根据用户问题做逻辑推理。
  • AI的“特殊回复”:AI返回的choices[0].message里,content通常是空的,但会多出一个tool_calls数组。里面包含:
    • id(本次调用的唯一追踪ID)
    • function.name(它选中的函数名)
    • function.arguments(它是一个字符串,里面是AI填好的参数JSON,比如{"city": "西安"}

关键认知:直到这一步,AI的工作就结束了。真正查天气、调数据库的动作,必须由你(开发者)在后端用代码去解析这个JSON并执行。

2. 硬核代码实战(Python伪代码全流程)

如果不用任何第三方框架(如LangChain),裸调OpenAI/DeepSeek的代码逻辑是这样的:

# 第一步:定义工具(说明书)tools=[{"type":"function","function":{"name":"get_weather","description":"查询指定城市的实时天气","parameters":{"type":"object","properties":{"city":{"type":"string","description":"城市名称,如北京"},"unit":{"type":"string","enum":["celsius","fahrenheit"]}},"required":["city"]}}}]# 第二步:发起第一次请求response=client.chat.completions.create(model="gpt-4",messages=[{"role":"user","content":"西安今天热吗?"}],tools=tools,tool_choice="auto"# 让AI自己决定是否调用)# 第三步:解析AI返回的调用指令tool_call=response.choices[0].message.tool_calls[0]function_name=tool_call.function.name# 结果是 "get_weather"arguments=json.loads(tool_call.function.arguments)# 结果是 {"city": "西安"}# 第四步:【关键】你在本地真正执行函数iffunction_name=="get_weather":result=requests.get(f"https://api.weather.com?city={arguments['city']}").json()# 第五步:第二次请求,把结果喂给AImessages.append(response.choices[0].message)# 保存AI的调用指令messages.append({"role":"tool",# 注意:这里是 tool 角色"tool_call_id":tool_call.id,# 必须绑定ID"content":json.dumps(result)# 把查到的28℃传回去})final_response=client.chat.completions.create(model="gpt-4",messages=messages)# 最终AI输出:"西安今天28℃,比较热,建议穿短袖。"

3. 进阶高级玩法(不止是“一问一答”)

  • 并行函数调用(Parallel Function Calling):用户问“北京和上海明天哪个会下雨?”,AI会一次性返回两个tool_calls(分别查北京和上海)。你可以并发请求两个天气API,大幅降低响应延迟。
  • 强制调用(tool_choice):将tool_choice设为{"type": "function", "function": {"name": "get_weather"}}。这时AI不会回答任何文字,只会乖乖返回函数参数。这种模式常用于结构化数据提取(比如把用户的闲聊强制转成JSON表单)。
  • 链式反应(ReAct模式):第一次调用的结果返回后,AI根据结果决定再次调用下一个函数。比如:查天气发现下雨 -> 自动调用“查询附近室内场馆”函数 -> 最后推荐咖啡馆。这需要你在代码里写while循环处理多次请求。

4. 程序员最常踩的三大“深坑”(务必注意)

  • 陷阱一:参数类型幻觉:AI给日期参数填成"明天",但你的API只认YYYY-MM-DD解决方案:在parametersdescription里必须写死格式,比如"格式必须为2026-06-23"
  • 陷阱二:Token计费暴涨:每次函数调用的tools定义都很长(动辄几百个Token)。如果每次对话都传完整的函数列表,成本会很高。优化方案:使用/v1/assistants(助手API)预存工具,或者只给本轮对话可能用到的Top-3函数。
  • 陷阱三:安全越权(最致命):AI可能被提示词注入攻击,诱导调用delete_user函数。铁律永远不要在Function里直接放执行SQL或删除文件的代码。必须在你的后端加一层鉴权中间件,校验当前用户的身份是否有权操作AI请求过来的参数。

5. 各家大模型的“方言”差异

虽然逻辑相同,但字段名略有不同,接入时要注意:

  • OpenAI / DeepSeek:使用tools字段,消息角色用tool
  • Anthropic Claude:使用tools字段,但函数定义放在input_schema里,返回结果放在contenttool_use块中。
  • Google Gemini:使用functionDeclarations,返回的是functionCall对象,回复结果要用functionResponse

讲到这里,基本上已经把Function Calling的“骨架”和“血肉”都拆干净了。如果你正准备上手写代码,你是想看看某个特定语言(比如Java或Node.js)的完整接入Demo,还是想知道如何在流式输出(Streaming)中处理函数调用?可以告诉我,我继续给你精准拆解。😊

http://www.gsyq.cn/news/1581941.html

相关文章:

  • ATA5279天线驱动芯片Boost转换器与电流调节环路设计实战指南
  • LLaMA-Factory 原生支持 ROCm 是真的香,配合 HIPify 几分钟完成环境验证
  • Origin 2025 下载Origin2025安装教程——科学绘图与数据分析入门
  • Microchip嵌入式开发资源全攻略:从数据手册到社区支持的高效导航
  • Meilisearch:一个为搜索速度而生的开源引擎
  • 【2026】FreeOK官网入口,一键直达在线观看
  • 2026年GEO信源媒体发稿平台全盘点:三种模式、代表玩家与适用场景
  • 主表 + 扩展表设计模式
  • 从稳压到基准:CD47温度补偿齐纳基准源原理、选型与实战指南
  • ClockStudio图表进阶:双Y轴与高级工具实战指南
  • RTK:给 AI 编程助手装个 Token 压缩器
  • Atmel SMD封装PCB热设计:从热阻参数到焊接工艺的嵌入式系统散热实战
  • DMA技术解析:ADC与USART数据传输中的CPU利用率优化实践
  • XMEGA A3BU嵌入式开发实战:低功耗、高精度ADC与时钟系统深度优化
  • 从互联网产品经理到AI产品经理:8大行业方向深度解析,避开“坑”一步到位!
  • 用 Typeoff 口述代码思路:从原始想法到结构化 Markdown
  • Langchain学习三:使用记忆模块(已废弃)
  • SAMA5D3 Xplained开发板嵌入式Linux系统启动与开发环境搭建指南
  • 数据说话:洞见人和多模态模型为何在综合对比中居首
  • 基于ATA6870与ATmega32HVB的12串BMS评估板设计与实战解析
  • AVR微控制器端口复用详解:从原理到实战配置指南
  • 芯片级原子钟SA.45s:原理、低功耗设计与嵌入式应用指南
  • ATmega328P定时器与SPI实战:从寄存器配置到多任务调度
  • 嵌入式物联网开发:BitCloud框架下事件管理与内存优化的核心实践
  • ARM7TDMI编程模型与Thumb指令集:嵌入式开发的底层基石
  • 基于Microchip BM71 BLE模块的智能传感器开发实战指南
  • Windows COM端口注册表清理与重置终极指南
  • 服务网格运维
  • ATmega328P USART寄存器配置与中断编程实战指南
  • 佛山代加工贴牌推荐榜单