程序员转行学习 AI 大模型: Function Calling | 附清晰业务流程示例

6 阅读7分钟
本文是程序员转行学习AI大模型的第13个核心知识点笔记,附清晰业务流程示例。
当前阶段:还在学习知识点,由点及面,从 0 到 1 搭建 AI 大模型知识体系中。
系列更新,关注我,后续会持续记录分享转行经历~

原理

Function Calling,可以让模型通过调用外部工具,来增强自身能力。

使用 Function Calling, 获取用户当前位置的天气信息示例:

from openai import OpenAI

def send_messages(messages):
    response = client.chat.completions.create(
        model="deepseek-chat",
        messages=messages,
        tools=tools
    )
    return response.choices[0].message

client = OpenAI(
    api_key="<your api key>",
    base_url="https://api.deepseek.com",
)

tools = [
    {
        "type": "function",
        "function": {
            "name": "get_weather",
            "description": "Get weather of a location, the user should supply a location first.",
            "parameters": {
                "type": "object",
                "properties": {
                    "location": {
                        "type": "string",
                        "description": "The city and state, e.g. San Francisco, CA",
                    }
                },
                "required": ["location"]
            },
        }
    },
]

messages = [{"role": "user", "content": "How's the weather in Hangzhou, Zhejiang?"}]
message = send_messages(messages)
print(f"User>\t {messages[0]['content']}")

tool = message.tool_calls[0]
messages.append(message)

messages.append({"role": "tool", "tool_call_id": tool.id, "content": "24℃"})
message = send_messages(messages)
print(f"Model>\t {message.content}")

上述代码执行流程:

  1. 用户:查询现在的天气;
  2. 模型:返回 function get_weather({location:'Hangzhou'})
  3. 用户:调用 function get_weather({location:'Hangzhou'}),并传给模型
  4. 模型:返回自然语言,“The current temperature in Hangzhou is 24°C.

注:上述代码中 get_weather 函数功能需由用户提供,模型本身不执行具体函数。

"""
Function Calling中的函数实现位置:

1. 函数定义(JSON Schema):传给LLM,告诉LLM有哪些函数
2. 函数实现(Python代码):在开发者代码中,由开发者手动调用
"""

import openai
import json
import requests

# ========================================
# 步骤1:定义函数(JSON Schema)
# ========================================
# 这个定义传给LLM,告诉LLM有哪些函数可用
functions = [
    {
        "name": "get_weather",
        "description": "获取指定城市的天气信息",
        "parameters": {
            "type": "object",
            "properties": {
                "city": {
                    "type": "string",
                    "description": "城市名称"
                }
            },
            "required": ["city"]
        }
    }
]

# ========================================
# 步骤2:实现具体函数(Python代码)
# ========================================
# 这个函数在开发者代码中实现,由开发者手动调用
def get_weather(city: str) -> dict:
    """
    具体函数实现
    
    注意:这个函数不在LLM中,而是在开发者代码中!
    """
    # 函数内部调用外部API
    api_url = f"https://api.weather.com/v1/current?city={city}"

    try:
        # 调用外部天气API
        response = requests.get(api_url)
        weather_data = response.json()

        return {
            "status": "success",
            "temperature": weather_data["temp"],
            "condition": weather_data["condition"]
        }
    except Exception as e:
        return {
            "status": "error",
            "message": str(e)
        }

# ========================================
# 步骤3:调用LLM
# ========================================
# 将函数定义传给LLM
response = openai.ChatCompletion.create(
    model="gpt-3.5-turbo",
    messages=[
        {"role": "user", "content": "北京今天天气怎么样?"}
    ],
    functions=functions,  # 传入函数定义(JSON Schema)
    function_call="auto"  # 让LLM自动决定是否调用函数
)

# ========================================
# 步骤4:检查LLM是否要调用函数
# ========================================
if response.choices[0].message.get("function_call"):
    # LLM决定调用函数
    function_call = response.choices[0].message.function_call
    function_name = function_call.name
    function_args = json.loads(function_call.arguments)

    print(f"LLM决定调用函数: {function_name}")
    print(f"LLM传递的参数: {function_args}")

    # ========================================
    # 步骤5:开发者手动调用函数
    # ========================================
    # 注意:这里不是LLM调用函数,而是开发者手动调用!
    result = get_weather(function_args["city"])

    print(f"函数执行结果: {result}")

    # ========================================
    # 步骤6:将结果返回给LLM
    # ========================================
    second_response = openai.ChatCompletion.create(
        model="gpt-3.5-turbo",
        messages=[
            {"role": "user", "content": "北京今天天气怎么样?"},
            {"role": "assistant", "content": None, "function_call": function_call},
            {"role": "function", "name": function_name, "content": str(result)}
        ]
    )

    print(f"LLM最终回答: {second_response.choices[0].message.content}")

"""
总结:
1. 函数定义(JSON Schema)→ 传给LLM,告诉LLM有哪些函数
2. 函数实现(Python代码)→ 在开发者代码中,由开发者手动调用
3. LLM的作用 → 分析是否需要调用函数,生成函数调用请求
4. 开发者的作用 → 手动调用函数,将结果返回给LLM
"""

LLM 的角色和职责

"""
LLM的角色:
1. 分析用户问题
2. 判断是否需要调用函数
3. 生成函数调用请求(JSON格式)
4. 接收函数执行结果
5. 基于结果生成最终回答

LLM不做的:
1. 不执行函数
2. 不调用外部API
3. 不处理函数逻辑
"""

# LLM做的事情:
# 1. 分析
user_input = "北京今天天气怎么样?"
llm_analysis = "用户想查询北京天气"

# 2. 判断
llm_decision = "需要调用get_weather函数"

# 3. 生成请求
llm_request = {
    "function_call": {
        "name": "get_weather",
        "arguments": '{"city": "北京"}'
    }
}

# 4. 接收结果
llm_input = {
    "function_result": {
        "status": "success",
        "temperature": 25,
        "condition": "晴"
    }
}

# 5. 生成回答
llm_output = "根据天气API,北京今天天气晴,温度25°C"

"""
LLM只负责分析和生成,不负责执行!
"""

开发者的角色和职责

"""
开发者的角色:
1. 定义函数(JSON Schema)
2. 实现具体函数(Python代码)
3. 调用LLM
4. 解析LLM响应
5. 手动调用函数
6. 将结果返回给LLM

开发者做的:
1. 实现函数逻辑
2. 调用外部API
3. 处理错误和重试
4. 管理数据流
"""

# 开发者做的事情:
# 1. 定义函数
functions = [
    {
        "name": "get_weather",
        "description": "获取指定城市的天气信息",
        "parameters": {...}
    }
]

# 2. 实现函数
def get_weather(city: str) -> dict:
    # 调用外部API
    response = requests.get(f"https://api.weather.com/v1/current?city={city}")
    return response.json()

# 3. 调用LLM
response = openai.ChatCompletion.create(
    model="gpt-3.5-turbo",
    messages=[...],
    functions=functions
)

# 4. 解析响应
if response.choices[0].message.get("function_call"):
    function_call = response.choices[0].message.function_call
    function_args = json.loads(function_call.arguments)
    
    # 5. 手动调用函数
    result = get_weather(function_args["city"])
    
    # 6. 返回结果给LLM
    second_response = openai.ChatCompletion.create(
        model="gpt-3.5-turbo",
        messages=[
            ...,
            {"role": "function", "name": function_name, "content": str(result)}
        ]
    )

"""
开发者负责实现和调用函数!
"""

完整天气查询示例

import openai
import json
import requests

# ========================================
# 1. 定义函数(JSON Schema)
# ========================================
# 这个定义传给LLM,告诉LLM有哪些函数可用
functions = [
    {
        "name": "get_weather",
        "description": "获取指定城市的天气信息",
        "parameters": {
            "type": "object",
            "properties": {
                "city": {
                    "type": "string",
                    "description": "城市名称"
                }
            },
            "required": ["city"]
        }
    }
]

# ========================================
# 2. 实现具体函数(Python代码)
# ========================================
# 这个函数在开发者代码中实现
def get_weather(city: str) -> dict:
    """
    获取天气信息
    
    注意:这个函数在开发者代码中实现!
    """
    # 调用外部天气API
    # 这里调用的是真实的天气API
    api_url = f"https://api.weather.com/v1/current?city={city}"

    try:
        # 调用外部API
        print(f"正在调用外部API: {api_url}")
        response = requests.get(api_url)
        weather_data = response.json()

        return {
            "status": "success",
            "temperature": weather_data["temp"],
            "condition": weather_data["condition"],
            "humidity": weather_data["humidity"]
        }
    except Exception as e:
        return {
            "status": "error",
            "message": f"API调用失败: {str(e)}"
        }

# ========================================
# 3. 调用LLM
# ========================================
print("=== 步骤1:调用LLM ===")
response = openai.ChatCompletion.create(
    model="gpt-3.5-turbo",
    messages=[
        {"role": "user", "content": "北京今天天气怎么样?"}
    ],
    functions=functions,  # 传入函数定义
    function_call="auto"  # 让LLM自动决定
)

print(f"LLM响应: {response.choices[0].message}")

# ========================================
# 4. 检查LLM是否要调用函数
# ========================================
if response.choices[0].message.get("function_call"):
    print("\n=== 步骤2:LLM决定调用函数 ===")
    function_call = response.choices[0].message.function_call
    function_name = function_call.name
    function_args = json.loads(function_call.arguments)

    print(f"函数名: {function_name}")
    print(f"函数参数: {function_args}")

    # ========================================
    # 5. 开发者手动调用函数
    # ========================================
    print("\n=== 步骤3:开发者手动调用函数 ===")
    result = get_weather(function_args["city"])

    print(f"函数执行结果: {result}")

    # ========================================
    # 6. 将结果返回给LLM
    # ========================================
    print("\n=== 步骤4:将结果返回给LLM ===")
    second_response = openai.ChatCompletion.create(
        model="gpt-3.5-turbo",
        messages=[
            {"role": "user", "content": "北京今天天气怎么样?"},
            {"role": "assistant", "content": None, "function_call": function_call},
            {"role": "function", "name": function_name, "content": str(result)}
        ]
    )

    print(f"LLM最终回答: {second_response.choices[0].message.content}")

"""
输出示例:
=== 步骤1:调用LLM ===
LLM响应: {
    "function_call": {
        "name": "get_weather",
        "arguments": '{"city": "北京"}'
    }
}

=== 步骤2:LLM决定调用函数 ===
函数名: get_weather
函数参数: {"city": "北京"}

=== 步骤3:开发者手动调用函数 ===
正在调用外部API: https://api.weather.com/v1/current?city=北京
函数执行结果: {
    "status": "success",
    "temperature": 25,
    "condition": "晴",
    "humidity": 45
}

=== 步骤4:将结果返回给LLM ===
LLM最终回答: 根据天气API,北京今天天气晴,温度25°C,湿度45%
"""

Function Calling 工作流程

开发者代码:
1. 定义函数(JSON Schema)→ 传给LLM
2. 实现函数(Python代码)→ 在开发者代码中
3. 调用LLM → 传入函数定义
4. 解析LLM响应 → 检查是否要调用函数
5. 手动调用函数 → 调用开发者实现的函数
6. 将结果返回给LLM → 生成最终回答

LLM:
1. 分析用户问题
2. 判断是否需要调用函数
3. 生成函数调用请求(JSON格式)
4. 接收函数执行结果
5. 基于结果生成最终回答

外部API:
1. 被开发者实现的函数调用
2. 返回数据给函数
3. 函数将数据返回给开发者

Function Calling = LLM 分析 + 开发者执行

  • LLM:分析问题,生成调用请求
  • 开发者:实现函数,手动调用
  • 外部 API:被函数调用,返回数据

学习资料:Function Calling | DeepSeek API Docs