《从 “喊一声就动” 到 “智能派单”:FunctionCall 的奇妙工作法则》

175 阅读9分钟

一、前言

在 AI 快速发展的当下,大语言模型(LLM)已广泛应用于智能客服、代码辅助等领域,但 “幻觉” 问题严重制约其价值发挥。当用户询问技术细节或数据分析需求时,LLM 常输出模糊、错误的回答。究其原因,基于 Transformer 架构的 LLM 本质是概率生成模型,擅长语言模式模仿,却缺乏真实问题解决能力。

而 FunctionCall 机制的出现带来转机。它就像给 LLM 的 “外挂工具箱”,让模型能根据需求调用数学计算、API 获取等工具函数,实现 “指令 - 调用 - 输出” 闭环,助力 LLM 从 “空谈” 走向 “实干”。后续我们将探究其技术逻辑与应用,一同见证这场 AI 理性革命。

二、AI对话设计(无 FunctionCall)

使用 OpenAI 客户端库调用 DeepSeek 模型回答足球相关问题的 AI 对话设计。主要内容包括:通过环境变量配置 DeepSeek API 密钥,设置基础 URL;创建客户端实例并调用deepseek-reasoner模型;设置系统提示指定 AI 为足球专家角色,用户询问 C 罗国籍,AI 回答其为葡萄牙运动员;最后打印模型的思考过程和最终答案,展示了完整的调用流程和输出结构。

from openai import OpenAI
import os
from dotenv import load_dotenv
load_dotenv('.env.local')


client = OpenAI(
  api_key=os.getenv('DEEPSEEK_API_KEY'),
  base_url="https://api.deepseek.com/v1"
)

completion = client.chat.completions.create(
  model='deepseek-reasoner',
  messages=[
    {'role': 'system', 'content': '你是一个足球领域的专家,请尽量帮我回答与足球相关的问题。'},
    {'role': 'user', 'content': 'c罗是哪个国家的足球运动员?'},
    {'role': 'assistant', 'content': 'c罗是葡萄牙足球运动员。'}
  ]
)

print('思考过程:')
print(completion.choices[0].message.reasoning_content)

print('最终答案:')
print(completion.choices[0].message.content)

2.1 密钥的安全性

相关代码解释

  • import os 提供访问和操作环境变量的基础功能,可以让文件读取到其它文件的内容
  • from dotenv import load_dotenv 将 .env 文件中的变量注入到环境变量中,增强安全性和开发便利性。

将密钥存储在.env.local文件中,不直接暴露在代码里,可避免因代码上传至公开仓库(如 GitHub)而导致密钥泄露。在涉及 FunctionCall 调用外部 API 的 AI 项目中,若密钥不慎公开,可能导致 API 滥用或数据泄露,而.env.local可有效规避这类风险。

2.2 AI对话的建立

completion = client.chat.completions.create(
  model='deepseek-reasoner',
  messages=[
    {'role': 'system', 'content': '你是一个足球领域的专家,请尽量帮我回答与足球相关的问题。'},
    {'role': 'user', 'content': 'c罗是哪个国家的足球运动员?'},
    {'role': 'assistant', 'content': 'c罗是葡萄牙足球运动员。'}
  ]
)
核心功能:创建 AI 对话

代码使用 OpenAI Python 库的client.chat.completions.create()方法向 DeepSeek 模型发送对话请求,并获取回复。这是实现聊天机器人、智能助手等功能的基础。

参数详解
(1)model='deepseek-reasoner'
  • 指定使用的 AI 模型为deepseek-reasoner
(2)messages参数
  • 对话由多个消息组成,每个消息是一个字典,包含role(角色)和content(内容):

    1. {'role': 'system', 'content': ...}

      • 人为添加,给AI一个足球领域的专家的身份,让它就足球专家的角度去思考
    2. {'role': 'user', 'content': ...}

      • 用户消息,即用户提出的问题。示例中用户询问 “C 罗是哪个国家的足球运动员?”
    3. {'role': 'assistant', 'content': ...}

      • 助手(AI)的回复。实际使用时,这部分内容由模型生成,示例中是预先写好的正确答案(实际代码运行时会被 API 返回的内容覆盖)。

注意: 如果需要多轮对话,可以通过在messages列表中添加更多消息,比如:

messages=[ 
{'role': 'system', 'content': '你是足球专家'},
{'role': 'user', 'content': 'C罗效力过哪些俱乐部?'}, 
{'role': 'assistant', 'content': '他效力过曼联、皇家马德里等俱乐部。'}, 
{'role': 'user', 'content': '他在皇马进了多少球?'} 
# 追加新问题,形成对话 ]

三、 AI对话设计(有 ·FunctionCall)

from email import message
from openai import OpenAI
import os
from dotenv import load_dotenv
load_dotenv('.env.local')

client = OpenAI(
  api_key=os.getenv('DEEPSEEK_API_KEY'),
  base_url="https://api.deepseek.com/v1",
)

def send_message(messages):
  response = client.chat.completions.create(
    model='deepseek-reasoner',
    messages=messages,
    tools=tools,
    tool_choice='auto'
  )
  return response

# 打造一个函数调用的工具
tools = [
  {
    "type": "function",
    "function": {
      "name": "get_closing_price",
      "description": "获取指定股票的收盘价",
      "parameters": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "股票名称",
          },
        },
        "required": ["name"],
      }
    }
  }
]

# 定义函数
def get_closing_price(name):
  if name == '青岛啤酒':
    return '67.92'
  elif name == '贵州茅台':
    return '1488.21'
  else:
    return '未找到该股票'


if __name__ == '__main__': 
  messages = [{"role": "user", "content": "青岛啤酒的收盘价是多少?"}]
  response = send_message(messages)

  message = response.choices[0].message
  messages.append({
    "role": message.role,
    "content": message.content,
    "tool_calls": message.tool_calls
  })


  print("回复:")
  print(response.choices[0].message.content)

3.1 AI对话的建立

给 AI 装上 “超能力外挂”!手把手教你打造 send_message 神方法
  • client.chat.completions.create() 是调用 DeepSeek 模型 API 的核心方法,用于创建一个对话完成请求。
  • model='deepseek-reasoner' 指定了使用的模型为 deepseek-reasoner,这是一个支持推理和工具调用的模型。
  • messages=messages 将函数传入的对话消息列表传递给模型,模型会基于这些消息进行回复。
  • tools=tools 引入了 FunctionCall 机制,tools 是一个预定义的列表,其中包含了可供模型调用的工具函数的描述。模型会根据对话内容判断是否需要调用这些工具函数来获取信息。
  • tool_choice='auto' 表示让模型自动决定是否调用工具函数以及调用哪些函数。模型会根据对话内容和工具函数的描述,智能判断是否需要通过调用外部函数来更好地回答问题。
震惊!看似无所不能的 AI,竟偷偷向人类索要这份 “通关秘籍”!
# 打造一个函数调用的工具
tools = [
  {
    "type": "function",
    "function": {
      "name": "get_closing_price",
      "description": "获取指定股票的收盘价",
      "parameters": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "股票名称",
          },
        },
        "required": ["name"],
      }
    }
  }
]
tools ---"通关秘籍"

tools = [ ... ]这段代码创建了一个列表,用于定义可被大语言模型(LLM)调用的工具函数信息,是 FunctionCall 机制的关键组成部分。它就像是给模型的 “使用说明书”,让模型知道有哪些功能可供调用。下面为你详细拆解:

  1. 整体结构tools是一个列表,其中每个元素描述一个工具函数。当前列表只包含一个工具函数的描述,实际应用中可根据需求扩展多个。

  2. 工具类型定义

    "type": "function"
    

    明确告知模型,这个工具是一个函数类型。在 FunctionCall 机制中,除了函数类型,未来可能还会有其他类型(如 API 调用等),通过此字段进行区分。提醒:我们的演示数据都是固定的,后面主要是利用API调用去获取数据

  3. 函数详细信息

    • 函数名称

      "name": "get_closing_price"
      

      定义函数的名称,后续模型若判断需要调用该函数,会使用此名称指定操作。

  4. 函数描述

    "description": "获取指定股票的收盘价"
    

    用自然语言向模型解释函数的功能,帮助模型理解在什么场景下应该调用该函数。例如当用户询问 “贵州茅台今天收盘价是多少” 时,模型通过分析问题和该描述,判断是否调用get_closing_price函数。

  5. 参数定义

    "parameters": {
        "type": "object",
        "properties": {
            "name": {
                "type": "string",
                "description": "股票名称",
            },
        },
        "required": ["name"]
    }
    
    • type: "object" :表示函数的参数整体是一个对象(JSON 格式的数据结构)。
    • properties:定义对象中包含的属性。这里只有一个属性name,类型为字符串,描述为 “股票名称” ,即调用函数时需要传入股票名称。
    • required:指定必须传入的参数,这里表明name参数是调用函数时必不可少的。

四、两者区别

4.1 核心功能差异
第一段代码(无 FunctionCall)
  • 功能定位:简单的问答对话,AI 直接生成文本回答。
  • 交互模式:用户提问 → AI 基于知识库直接回答。
  • 应用场景:适用于一般性问答,如知识查询、闲聊等。
第二段代码(集成 FunctionCall)
  • 功能定位:智能工具调用,AI 可根据需求调用外部函数获取数据。
  • 交互模式:用户提问 → AI 判断是否需要调用工具 → 执行函数 → 返回结果。
  • 应用场景:适用于需要动态数据或外部服务的场景,如股票查询、天气获取等。
4.2 代码结构差异
核心组件
  • 第一段:直接通过completion = client.chat.completions.create()发送消息。
  • 第二段:封装为send_message()函数,并引入toolstool_choice参数。
FunctionCall 配置
  • 第一段:无 FunctionCall 相关代码,AI 仅依赖自身知识生成回答。

  • 第二段

    • 定义tools列表,包含函数描述(如get_closing_price)。
    • 设置tool_choice='auto'让 AI 自动决定是否调用函数。
函数实现
  • 第一段:无自定义函数,所有逻辑由 AI 完成。
  • 第二段:实现get_closing_price()函数,用于查询股票收盘价,AI 可调用此函数获取数据。

4.3. 对话流程差异

第一段代码的执行流程
  1. 用户提问:“C 罗是哪个国家的足球运动员?”
  2. AI 直接回答:“C 罗是葡萄牙足球运动员。”
第二段代码的执行流程
  1. 用户提问:“青岛啤酒的收盘价是多少?”
  2. AI 分析问题,判断需要调用get_closing_price函数。
  3. 执行函数,获取实际数据(如 “67.92”)。
  4. AI 结合函数结果生成最终回答。

4.4总结对比表

特性第一段代码(无 FunctionCall)第二段代码(FunctionCall)
核心功能文本对话生成智能工具调用
交互模式单轮问答多轮(问题→函数调用→结果整合)
代码结构简单直接,无函数定义复杂,需定义工具描述和函数实现
数据来源AI 知识库外部函数 / API
应用场景一般性问答、闲聊需要实时数据或特定工具的场景(如查询、计算)
扩展性弱(依赖模型更新)强(可自定义工具)

五、总结

FunctionCall 机制通过为 AI 配备标准化工具函数,构建起 "动态工具调用 - 数据验证 - 结果整合" 的闭环体系:不仅能实时获取股票行情、天气数据等动态信息,从源头规避 AI 因知识滞后产生的 "幻觉",更可通过多轮函数递归调用实现复杂逻辑处理。例如在订餐场景中,AI 可依次调用get_restaurant_listcheck_availabilityplace_order等工具,自动补全用户未明确的就餐时间、人数等信息,直至完成订单提交,真正实现从 "被动回答" 到 "主动执行" 的能力跃迁。这种工具赋能模式,既保持了 AI 自然语言交互的灵活性,又通过工程化手段确保任务执行的准确性,为构建可落地的智能应用提供了关键技术支撑。