0基础进大厂,第10天:LLM 入门篇——什么是FuntionCall?

240 阅读6分钟

前言

在AI开发的路上,我们经常会遇到这样的问题:如何让AI模型不仅仅是回答问题,还能够执行具体的操作?比如查询股票价格、获取天气信息、操作数据库等。这就是今天要讲的核心概念——Function Call(函数调用)

什么是Function Call?

Function Call是大语言模型(LLM)的一个重要功能,它允许AI模型在对话过程中主动调用外部函数或API来获取实时数据或执行特定操作。简单来说,就是让AI不仅能"说话",还能"做事"。

传统对话 vs Function Call

传统对话模式:

  • 用户:青岛啤酒的股价是多少?
  • AI:抱歉,我无法获取实时股价信息...

Function Call模式:

  • 用户:青岛啤酒的股价是多少?
  • AI:(调用股价查询函数)青岛啤酒当前收盘价为67.92元

凡事先看官方文档:Function Calling | DeepSeek API Docs

官方文档里有示例代码的模板,也有些代码解释。
接下来,我就用官网的模板进行演示

image.png

实战案例:股票价格查询系统

让我们通过一个完整的代码示例来理解Function Call的工作原理。

1. 环境准备

首先,如果你没有安装过,我们需要安装必要的依赖包:

pip3 install openai 

2. 核心代码解析

import json
from openai import OpenAI

# 初始化客户端
client = OpenAI(
    api_key=os.getenv('DEEPSEEK_API_KEY'),
    base_url="https://api.deepseek.com/v1",
)

3. 定义Function Call工具

这是Function Call的核心部分——工具定义:

tools = [
    {
        "type": "function",
        "function": {
            "name": "get_closing_price",
            "description": "获取指定股票的收盘价",
            "parameters": {
                "type": "object",
                "properties": {
                    "name": {
                        "type": "string",
                        "description": "股票名称",
                    },
                },
                "required": ["name"],
            }
        }
    }
]

关键字段解释:

  • type: 工具类型,这里是"function"
  • name: 函数名称,AI会根据这个名称调用对应函数
  • description: 函数描述,帮助AI理解何时使用这个函数
  • parameters: 参数定义,遵循JSON Schema格式
  • required: 必需参数列表

4. 实现具体函数

这里并没有真的去某某股票网站获取api,我只是写了一个简单的函数,帮助理解这个工具函数的作用,具体的api获取不是本篇文章的重点。

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

这个函数就是模拟了股票价格查询的逻辑。在实际应用中,你可以接入真实的股票API。

5. 发送消息并处理Function Call

def send_message(messages):
    response = client.chat.completions.create(
        model='deepseek-reasoner',
        messages=messages,
        tools=tools,
        tool_choice='auto'  # 自动选择是否使用工具
    )
    return response

Function Call的完整执行流程

让我们跟踪一次完整的Function Call过程:

第一步:用户提问

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

第二步:AI决定使用工具

AI分析用户问题,发现需要调用get_closing_price函数:

# AI的响应会包含tool_calls
print("AI回复:", response.choices[0].message.content)
print("工具调用:", response.choices[0].message.tool_calls)

第三步:执行函数调用

if response.choices[0].message.tool_calls != None:
    tool_call = response.choices[0].message.tool_calls[0]
    
    if tool_call.function.name == "get_closing_price":
        # 解析参数
        arguments_dict = json.loads(tool_call.function.arguments)
        # 调用实际函数
        price = get_closing_price(arguments_dict['name'])
        
        # 将结果添加到消息历史
        messages.append({
            "role": "tool",
            "content": price,
            "tool_call_id": tool_call.id
        })

第四步:生成最终回复

# 再次调用AI,让它基于函数结果生成回复
response = send_message(messages)
print("最终回复:", response.choices[0].message.content)

消息历史的演变

在整个过程中,消息历史会经历以下变化:

# 初始状态
[
    {'role': 'user', 'content': '青岛啤酒的收盘价是多少?'}
]

# AI决定调用工具后
[
    {'role': 'user', 'content': '青岛啤酒的收盘价是多少?'},
    {'role': 'assistant', 'content': '我需要调用函数来获取青岛啤酒的收盘价。', 'tool_calls': [...]}
]

# 函数执行结果添加后
[
    {'role': 'user', 'content': '青岛啤酒的收盘价是多少?'},
    {'role': 'assistant', 'content': '我需要调用函数来获取青岛啤酒的收盘价。', 'tool_calls': [...]},
    {'role': 'tool', 'content': '67.92', 'tool_call_id': 'call_xxx'}
]

完整代码

这三行代码是为了git代码时,保护我的密钥写的,你可以忽略不看,直接替换自己的密钥即可

import os
from dotenv import load_dotenv # 首先:pip3 install dotenv
load_dotenv('.env.local')
import json
from openai import OpenAI #首次:pip3 install openai
import os
from dotenv import load_dotenv # 首先:pip3 install 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)

  print("工具选择:")
  print(response.choices[0].message.tool_calls)

  # LLM 已经确定了它要用的函数
  if response.choices[0].message.tool_calls != None:
    tool_call = response.choices[0].message.tool_calls[0]

    if tool_call.function.name == "get_closing_price":
      arguments_dict = json.loads(tool_call.function.arguments)  # {"name": "青岛啤酒"}
      price = get_closing_price(arguments_dict['name'])

      messages.append({
        "role": "tool",
        "content": price,
        "tool_call_id": tool_call.id
      })

    print("messages:", messages)

    response = send_message(messages)

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

代码执行结果: 可以看到在messages里面看到完整的消息链

image.png

Function Call的应用场景

  1. 数据查询:股票价格、天气信息、新闻资讯
  2. 系统操作:文件操作、数据库查询、API调用
  3. 计算任务:复杂计算、数据分析、图表生成
  4. 外部集成:第三方服务调用、支付处理、消息发送

最佳实践

1. 函数设计原则

  • 函数功能单一,职责明确
  • 参数验证和错误处理
  • 返回格式统一

2. 工具描述优化

{
    "name": "get_stock_price",
    "description": "获取指定股票的实时价格信息,支持A股主要股票查询",
    "parameters": {
        "type": "object",
        "properties": {
            "stock_name": {
                "type": "string",
                "description": "股票名称,如'青岛啤酒'、'贵州茅台'"
            },
            "price_type": {
                "type": "string",
                "enum": ["current", "closing", "opening"],
                "description": "价格类型:current-当前价格,closing-收盘价,opening-开盘价"
            }
        },
        "required": ["stock_name"]
    }
}

3. 错误处理

def get_closing_price(name):
    try:
        # 实际的股票API调用
        price = fetch_stock_price(name)
        return f"股票{name}的收盘价为{price}元"
    except Exception as e:
        return f"获取{name}股价失败:{str(e)}"

进阶技巧

1. 多函数协作

tools = [
    {"type": "function", "function": {"name": "get_stock_price", ...}},
    {"type": "function", "function": {"name": "analyze_stock_trend", ...}},
    {"type": "function", "function": {"name": "get_market_news", ...}}
]

2. 条件性工具选择

# 根据用户意图选择不同的tool_choice策略
if "紧急" in user_message:
    tool_choice = {"type": "function", "function": {"name": "emergency_handler"}}
else:
    tool_choice = "auto"

总结

Function Call是LLM这颗大脑进化出“手和脚”的第一步,它让AI从"信息处理器"升级为"行动执行者"。这项技术已经进化多轮,演化为如今爆火的MCP,但是,对于,初学者而言,我们需要知道、理解、掌握来龙去脉,这对我们进一步了解AIGC的知识有很大帮助。

让我们一起在AI的学习道路上乘风破浪!
欢迎点赞👍收藏⭐关注🔔~