深入理解Function Calling技术:从原理到实践

引言

在人工智能和大语言模型(LLM)快速发展的今天,Function Calling(函数调用)技术已经成为扩展AI能力边界的关键技术之一。传统的AI模型虽然具备强大的自然语言理解和生成能力,但其知识库受限于训练数据,无法获取实时信息或执行具体操作。Function Calling技术的出现,完美解决了这一痛点,使得AI模型能够调用外部函数、访问实时数据、执行特定任务。

本文将通过一个完整的实际项目案例,详细讲解Function Calling技术的工作原理、实现方式以及在实际开发中的应用。我们将以阿里云DashScope API为例,演示如何让AI模型具备查询天气、写入文件等真实世界的能力。

一、Function Calling技术概述

1.1 什么是Function Calling

Function Calling是一种让大语言模型与外部工具、API或函数进行交互的技术。在传统的对话场景中,AI模型只能基于其训练数据来回答问题。但现实世界瞬息万变,股票价格、天气情况、新闻事件等实时信息都不在模型的训练数据范围内。Function Calling技术通过以下机制解决了这个问题:

  1. 模型识别需求:当用户提出需要外部信息或执行特定操作的请求时,模型能够识别并判断需要调用外部函数
  2. 参数提取:模型从用户输入中提取函数所需的参数
  3. 函数执行:外部系统执行实际函数调用,获取结果
  4. 结果整合:将函数执行结果返回给模型,由模型生成最终回复

这种机制使得AI模型从"知识库"转变为"智能助手",能够实时获取信息、执行操作,大大扩展了其应用场景。

1.2 Function Calling的应用场景

Function Calling技术的应用场景非常广泛:

  • 信息查询:查询实时天气、股票价格、航班信息、新闻资讯等
  • 数据操作:读写数据库、执行文件操作、管理系统资源
  • 第三方集成:调用第三方API、执行支付操作、发送通知等
  • 任务执行:预订机票酒店、安排日程、生成报告等

通过Function Calling,AI助手不再局限于"聊天",而是真正成为了能够帮助用户完成实际任务的智能助手。

1.3 技术原理简述

Function Calling的工作流程可以分为以下几个步骤:

  1. 用户输入:用户向AI助手提出请求
  2. 意图识别:AI模型分析用户请求,判断是否需要调用外部函数
  3. 参数提取:如果需要函数调用,模型从用户输入中提取相关参数
  4. 函数调用:外部系统执行实际函数,获取结果
  5. 结果处理:将函数结果整合到对话中,生成最终回复

这个过程的关键在于模型能够准确理解用户意图,并正确提取函数参数。这需要精心设计的系统提示词和函数定义。

二、项目整体架构

2.1 项目结构

项目包含一个主Python文件,实现了完整的Function Calling功能。项目结构如下:

项目目录/
├── aliyun_function_calling.py    # 主程序文件(包含Function Calling核心逻辑)
├── .env                          # 环境变量配置文件(存储API密钥)
└── 文档目录/
    └── 阿里云API函数调用与DeepSeek_API对比分析.md  # 技术对比文档

2.2 核心功能

本项目实现了两个核心功能演示:

  1. 天气查询功能

    • 用户询问天气相关问题(如"明天去北京出差适合穿什么衣服?")
    • AI模型识别需要查询天气,自动调用天气API
    • 获取天气数据后,结合用户问题给出穿衣建议
  2. 文件写入功能

    • 用户要求写入文件(如"请在Test2.txt文件中写入内容")
    • AI模型识别需要写入文件,自动调用文件操作函数
    • 将指定内容写入到用户指定的文件中

2.3 技术栈

  • 编程语言:Python 3.x
  • HTTP请求库:requests
  • 环境变量管理:python-dotenv
  • AI服务提供商:阿里云DashScope(通义千问模型)
  • 第三方天气API:高德地图天气API

三、核心代码解析

3.1 系统提示词设计

系统提示词(System Prompt)是引导AI模型行为的关键。在我们的项目中,系统提示词定义了AI助手的基本行为准则:

# 系统级提示词
system_prompt = """
	你是一名AI助手,具备函数调用的能力,但是如果提供的信息已经足够回答用户的问题,则不需要再进行函数调用。
	同时,请严格按照函数调用的方式进行处理,如果用户未提供函数所需参数,则必须询问,而不能自作主张。
"""

设计要点

  1. 明确能力:告知模型具备函数调用能力
  2. 条件判断:如果现有信息足够,则不需要调用函数
  3. 参数完整性:如果参数不完整,必须询问用户而不是自行假设

这种设计确保了AI助手的行为是可预测和可控的,避免了因模型自行假设而导致的错误。

3.2 函数定义

函数定义是Function Calling的核心,它告诉AI模型有哪些函数可以调用、每个函数的用途以及参数要求。在阿里云API中,函数定义采用嵌套的JSON结构:

# 阿里云API需要的tools格式
tools = [
    {
        "type": "function",
        "function": {
            "name": "get_weather",
            "description": "查询某个城市的天气",
            "parameters": {
                "type": "object",
                "properties": {
                    "city": {
                        "type": "string",
                        "description": "中国的城市名称或区县的名称",
                    }
                },
                "required": ["city"]
            },
        }
    },
    {
        "type": "function",
        "function": {
            "name": "write_file",
            "description": "往某个文件中写入内容",
            "parameters": {
                "type": "object",
                "properties": {
                    "filename": {
                        "type": "string",
                        "description": "待写入的文件路径",
                    },
                    "content": {
                        "type": "string",
                        "description": "写入文件中的内容",
                    }
                },
                "required": ["filename", "content"]
            },
        }
    }
]

函数定义的关键字段

字段 说明 设计要点
type 工具类型 固定为 "function"
function.name 函数名称 使用清晰的英文命名,见名知意
function.description 函数描述 详细说明函数用途,帮助模型理解何时调用
function.parameters 参数定义 包含参数类型、属性、描述和是否必需

设计原则

  1. 描述要具体:函数描述应该让模型能够理解何时应该调用这个函数
  2. 参数要完整:每个参数都应有类型、描述,必要参数要标记在required
  3. 命名要规范:使用清晰的英文命名,避免歧义

3.3 实际函数实现

函数定义告诉AI模型"有什么函数可以用",而实际的函数实现则是真正执行操作的代码:

# 定义函数用于通过高德天气接口查询天气
def get_weather(city):
    # 从环境变量获取高德地图API密钥
    amap_api_key = os.getenv("AMAP_API_KEY")
    if not amap_api_key:
        return {"error": "未配置高德地图API密钥"}
    
    url = f"https://restapi.amap.com/v3/weather/weatherInfo?city={city}&key={amap_api_key}&extensions=all"
    response = requests.get(url)
    return response.json()["forecasts"]

# 定义函数用于写入文件
def write_file(filename, content):
    # 使用当前目录或指定目录
    import os
    base_dir = os.path.dirname(os.path.abspath(__file__))
    file_path = os.path.join(base_dir, filename)
    
    with open(file_path, "w", encoding="utf-8") as file:
        file.write(content)
    
    return f"文件{filename}写入成功"

函数实现要点

  1. 函数名称一致:函数名必须与tools定义中的name完全一致
  2. 参数匹配:函数的参数名和个数必须与函数定义中的参数一致
  3. 返回值清晰:函数应该返回清晰的结果,便于后续处理
  4. 错误处理:实际生产环境中应添加异常处理逻辑
  5. 路径处理:使用相对路径或动态获取路径,避免硬编码

3.4 API请求构建

send_messages函数负责构建和发送API请求到阿里云DashScope服务:

def send_messages(messages):
    # 阿里云大模型API地址
    url = "https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation"
    
    # 构建请求数据
    payload = {
        "model": "qwen-plus",  # 可以根据需要替换为其他阿里云模型
        "input": {
            "messages": messages
        },
        "parameters": {
            "tools": tools,  # 使用阿里云API需要的tools格式
            "tool_choice": "auto",  # 自动选择工具
            "temperature": 0.7
        }
    }
    
    # 阿里云API密钥
    api_key = os.getenv("DASHSCOPE_API_KEY")
    
    # 检查API密钥是否设置
    if not api_key:
        print("错误: 未设置 DASHSCOPE_API_KEY 环境变量")
        # 如果响应格式不符合预期,返回一个空消息
        class EmptyMessage:
            def __init__(self):
                self.content = ""
                self.tool_calls = None
        
        return EmptyMessage()
    
    # 发送请求
    headers = {
        "Content-Type": "application/json",
        "Authorization": f"Bearer {api_key}"
    }
    
    try:
        response = requests.post(url, headers=headers, json=payload)
        print(f"API请求状态码: {response.status_code}")
        
        # 检查响应状态码
        if response.status_code != 200:
            print(f"API请求失败,状态码: {response.status_code}")
            print(f"错误信息: {response.text[:1000]}")  # 限制输出长度,避免截断
            # 如果响应格式不符合预期,返回一个空消息
            class EmptyMessage:
                def __init__(self):
                    self.content = ""
                    self.tool_calls = None
            
            return EmptyMessage()
        
        response_data = response.json()
        
        # 检查响应数据中是否有错误
        if "error" in response_data:
            print(f"API返回错误: {response_data['error']}")
            # 如果响应格式不符合预期,返回一个空消息
            class EmptyMessage:
                def __init__(self):
                    self.content = ""
                    self.tool_calls = None
            
            return EmptyMessage()
        
        # 处理响应
        if "output" in response_data and "choices" in response_data["output"]:
            choice = response_data["output"]["choices"][0]
            # 构建与原代码兼容的返回格式
            class Message:
                def __init__(self, content, tool_calls=None):
                    self.content = content
                    self.tool_calls = tool_calls
            
            class ToolCall:
                def __init__(self, function):
                    self.function = function
            
            class Function:
                def __init__(self, name, arguments):
                    self.name = name
                    self.arguments = arguments
            
            if "message" in choice:
                message = choice["message"]
                content = message.get("content", "")
                tool_calls = []
                
                if "tool_calls" in message:
                    for tool_call in message["tool_calls"]:
                        if "function" in tool_call:
                            func = tool_call["function"]
                            function_obj = Function(func.get("name"), func.get("arguments"))
                            tool_call_obj = ToolCall(function_obj)
                            tool_calls.append(tool_call_obj)
                
                return Message(content, tool_calls if tool_calls else None)
    except Exception as e:
        print(f"请求过程中发生错误: {str(e)}")
    
    # 如果响应格式不符合预期,返回一个空消息
    class EmptyMessage:
        def __init__(self):
            self.content = ""
            self.tool_calls = None
    
    return EmptyMessage()

代码结构说明

  1. 请求构建:构建符合阿里云API规范的请求体
  2. 认证管理:从环境变量获取API密钥
  3. 错误处理:检查API密钥、响应状态码、错误信息
  4. 响应解析:从阿里云特定的响应结构中提取数据和函数调用信息
  5. 数据封装:将原始响应数据封装为自定义对象,便于后续处理

3.5 响应处理与函数执行

invoke函数是整个流程的调度中心,负责协调整个函数调用过程:

def invoke(content):
    messages = [{"role": "system", "content": system_prompt},
                {"role": "user", "content": content}]
    message = send_messages(messages)
    print(f"收到模型响应: {'有函数调用' if message.tool_calls else '无函数调用'}")

    # 如果响应中存在tool_calls不为空,则说明大模型返回了函数及参数,需要进行函数调用
    if message.tool_calls:
        # 提取函数调用信息:函数名称和函数的参数
        func_name = message.tool_calls[0].function.name
        func_args = eval(message.tool_calls[0].function.arguments)  # 将参数字符串解析为字典

        func = globals()[func_name]  # 将函数名称字符串转换为函数体
        func_response = func(**func_args)  # 利用**将字典对象解析为参数

        # 将查询到的天气信息再次与用户提问一同提交给大模型进行分析
        messages = [
            {"role": "user", "content": f"请基于该信息:{func_response}\n来回答以下问题,请直接回答问题,不需要再进行函数调用,直接返回结果\n{content}"}]
        message = send_messages(messages)
        print(message.content)  # 得到最终的穿衣建议
    else:
        # 如果没有函数调用,直接输出模型的回复
        print("无函数调用,模型回复内容为:", message.content)

执行流程详解

  1. 构建消息:将系统提示词和用户输入组合成消息列表
  2. 发送请求:调用send_messages函数发送请求到AI服务
  3. 检查结果:判断响应中是否包含函数调用(tool_calls
  4. 提取信息:如果需要函数调用,提取函数名称和参数
  5. 执行函数:通过字符串名称动态获取函数对象并执行
  6. 结果整合:将函数执行结果和原始问题一起发送给模型
  7. 生成回复:模型基于函数结果生成最终回复

技术要点

  • globals()[func_name]:通过字符串名称动态获取函数对象
  • eval(message.tool_calls[0].function.arguments):将参数字符串转换为字典
  • func(**func_args):将字典解包为函数参数

3.6 主程序入口

if __name__ == '__main__':
    content = "明天去北京出差适合穿什么衣服?"
    invoke(content)
    content = "请在Test2.txt文件中写入内容:你好,Function Calling!"
    invoke(content)

主程序演示了两个典型的使用场景:

  1. 天气查询和穿衣建议
  2. 文件写入操作

3.7 环境变量配置

项目的正常运行需要配置以下环境变量,建议使用.env文件进行管理:

# 阿里云DashScope API密钥
# 获取地址:https://dashscope.console.aliyun.com/
DASHSCOPE_API_KEY=your_dashscope_api_key

# 高德地图天气API密钥
# 获取地址:https://lbs.amap.com/api/weather-api/list
AMAP_API_KEY=your_amap_api_key

环境变量管理最佳实践

  1. 使用.env文件:将API密钥存储在.env文件中,避免硬编码
  2. 添加到.gitignore:确保.env文件不会被提交到版本控制系统
  3. 提供模板:创建.env.example文件作为配置模板

四、运行结果分析

4.1 天气查询场景

用户输入明天去北京出差适合穿什么衣服?

执行过程

  1. 模型识别需要查询天气信息
  2. 提取参数:city="北京"
  3. 调用get_weather("北京")
  4. 获取天气数据
  5. 模型基于天气数据生成穿衣建议

模型回复

根据天气信息,明天北京天气为晴,白天温度5℃,夜间温度-5℃,风向为西南风,风力1-3级。
建议穿着:
- 白天:保暖外套(如羽绒服或厚呢大衣)、毛衣、围巾、手套;
- 夜间:需加强保暖,可加穿保暖内衣、帽子等。
整体以防寒为主,注意温差较大,建议采用叠穿方式便于调节。

4.2 文件写入场景

用户输入请在Test2.txt文件中写入内容:你好,FunctionCalling!

执行过程

  1. 模型识别需要写入文件
  2. 提取参数:filename="Test2.txt", content="你好,FunctionCalling!"
  3. 调用write_file("Test2.txt", "你好,FunctionCalling!")
  4. 执行文件写入操作
  5. 返回操作结果

执行结果

  • 在项目目录下创建Test2.txt文件
  • 文件内容为"你好,FunctionCalling!"
  • 函数返回"文件Test2.txt写入成功"

4.3 完整运行日志

运行程序后,控制台输出类似以下内容:

API请求状态码: 200
收到模型响应: 有函数调用
API请求状态码: 200
根据天气信息,明天北京天气为晴,白天温度5℃,夜间温度-5℃,风向为西南风,风力1-3级。
建议穿着:
- 白天:保暖外套(如羽绒服或厚呢大衣)、毛衣、围巾、手套;
- 夜间:需加强保暖,可加穿保暖内衣、帽子等。
整体以防寒为主,注意温差较大,建议采用叠穿方式便于调节。

API请求状态码: 200
收到模型响应: 有函数调用
API请求状态码: 200

五、技术要点总结

5.1 函数定义的最佳实践

  1. 描述要详细:函数描述应该清晰说明函数的用途和适用场景
  2. 参数要完整:每个参数都应有类型定义和描述说明
  3. 必要参数明确:将必要的参数标记在required数组中
  4. 命名要规范:使用清晰的英文命名,便于模型理解

示例:良好的函数定义

{
    "type": "function",
    "function": {
        "name": "search_products",
        "description": "根据关键词搜索商品,支持按价格区间和评分筛选",
        "parameters": {
            "type": "object",
            "properties": {
                "keyword": {
                    "type": "string",
                    "description": "搜索关键词,如:手机、耳机等"
                },
                "min_price": {
                    "type": "number",
                    "description": "最低价格,可选"
                },
                "max_price": {
                    "type": "number",
                    "description": "最高价格,可选"
                },
                "min_rating": {
                    "type": "number",
                    "description": "最低评分(0-5),可选"
                }
            },
            "required": ["keyword"]
        }
    }
}

5.2 错误处理策略

  1. API密钥检查:在发送请求前检查API密钥是否设置
  2. 状态码验证:检查HTTP响应状态码
  3. 错误信息处理:解析API返回的错误信息
  4. 异常捕获:使用try-except捕获可能的异常
  5. 返回值规范:定义统一的错误返回格式
def send_messages(messages):
    # 检查API密钥
    api_key = os.getenv("DASHSCOPE_API_KEY")
    if not api_key:
        print("错误: 未设置 DASHSCOPE_API_KEY 环境变量")
        return create_empty_response("未配置API密钥")
    
    # 发送请求并处理异常
    try:
        response = requests.post(url, headers=headers, json=payload, timeout=30)
        response.raise_for_status()  # 检查HTTP错误
        
        response_data = response.json()
        
        # 检查API业务错误
        if "error" in response_data:
            print(f"API返回错误: {response_data['error']}")
            return create_empty_response(f"API错误: {response_data['error']}")
        
        # 正常处理响应
        return parse_response(response_data)
        
    except requests.exceptions.Timeout:
        print("请求超时")
        return create_empty_response("请求超时,请稍后重试")
    except requests.exceptions.RequestException as e:
        print(f"请求失败: {str(e)}")
        return create_empty_response(f"网络请求失败: {str(e)}")

def create_empty_response(error_msg=None):
    class EmptyMessage:
        def __init__(self):
            self.content = error_msg or ""
            self.tool_calls = None
    return EmptyMessage()

5.3 响应解析要点

  1. 理解API响应结构:不同AI服务提供商的响应结构可能不同
  2. 提取工具调用:从响应中提取tool_calls信息
  3. 封装响应对象:将原始数据封装为易用的对象
  4. 处理边界情况:如无函数调用、响应格式异常等

阿里云API响应结构示例

{
    "output": {
        "choices": [
            {
                "message": {
                    "content": "明天北京天气晴朗,适合穿轻薄外套。",
                    "tool_calls": [
                        {
                            "id": "call_123456",
                            "type": "function",
                            "function": {
                                "name": "get_weather",
                                "arguments": "{\"city\": \"北京\"}"
                            }
                        }
                    ]
                }
            }
        ]
    },
    "usage": {
        "total_tokens": 150,
        "output_tokens": 50,
        "input_tokens": 100
    }
}

5.4 安全注意事项

  1. API密钥管理:使用环境变量存储敏感信息,不要硬编码在代码中
  2. 输入验证:对用户输入进行必要的验证和清理
  3. 函数安全:确保调用的函数是安全的,避免执行危险操作
  4. 日志记录:记录关键操作日志,便于问题排查
  5. 访问控制:对敏感函数实施访问控制

安全最佳实践

import os
import re

def validate_filename(filename):
    """验证文件名安全性"""
    # 阻止路径遍历攻击
    if ".." in filename or filename.startswith("/"):
        raise ValueError("非法的文件名")
    
    # 限制文件类型
    allowed_extensions = ['.txt', '.md', '.json', '.csv']
    if not any(filename.endswith(ext) for ext in allowed_extensions):
        raise ValueError("不支持的文件类型")
    
    # 限制文件名长度
    if len(filename) > 255:
        raise ValueError("文件名过长")
    
    return filename

def safe_write_file(filename, content):
    """安全的文件写入函数"""
    # 验证文件名
    safe_filename = validate_filename(filename)
    
    # 获取安全的路径
    base_dir = os.path.dirname(os.path.abspath(__file__))
    safe_path = os.path.join(base_dir, "user_files", safe_filename)
    
    # 确保目标目录存在
    os.makedirs(os.path.dirname(safe_path), exist_ok=True)
    
    # 写入文件
    with open(safe_path, "w", encoding="utf-8") as f:
        f.write(content)
    
    return f"文件{safe_filename}写入成功"

六、扩展与应用

6.1 添加新函数

要添加新的函数,只需要:

  1. tools数组中添加新的函数定义
  2. 实现对应的Python函数
  3. 确保函数名与定义中的name一致

示例:添加股票查询功能

# 1. 添加函数定义
tools = [
    # ... 现有函数 ...
    {
        "type": "function",
        "function": {
            "name": "get_stock_price",
            "description": "查询股票价格和相关信息",
            "parameters": {
                "type": "object",
                "properties": {
                    "stock_code": {
                        "type": "string",
                        "description": "股票代码,如:sh600519(上海)或 sz000001(深圳)",
                    }
                },
                "required": ["stock_code"]
            },
        }
    }
]

# 2. 实现函数
def get_stock_price(stock_code):
    """查询股票价格"""
    api_key = os.getenv("STOCK_API_KEY")
    if not api_key:
        return {"error": "未配置股票API密钥"}
    
    url = f"https://api.example.com/stock/quote?code={stock_code}"
    headers = {"Authorization": f"Bearer {api_key}"}
    
    response = requests.get(url, headers=headers)
    if response.status_code == 200:
        return response.json()
    else:
        return {"error": f"查询失败: {response.status_code}"}

6.2 支持多个AI服务提供商

通过封装可以支持多个AI服务提供商:

class LLMClient:
    """LLM客户端基类"""
    
    def __init__(self, api_key, api_endpoint):
        self.api_key = api_key
        self.api_endpoint = api_endpoint
    
    def format_functions(self, functions):
        """格式化函数定义"""
        raise NotImplementedError
    
    def parse_response(self, response):
        """解析响应"""
        raise NotImplementedError
    
    def send_message(self, messages, functions=None):
        """发送消息"""
        raise NotImplementedError


class AlibabaClient(LLMClient):
    """阿里云DashScope客户端"""
    
    def format_functions(self, functions):
        """阿里云格式的函数定义"""
        return [{"type": "function", "function": f} for f in functions]
    
    def parse_response(self, response):
        """解析阿里云响应"""
        return response["output"]["choices"][0]["message"]
    
    def send_message(self, messages, functions=None):
        """发送消息到阿里云"""
        payload = {
            "model": "qwen-plus",
            "input": {"messages": messages},
            "parameters": {
                "tools": self.format_functions(functions) if functions else [],
                "tool_choice": "auto"
            }
        }
        
        headers = {
            "Content-Type": "application/json",
            "Authorization": f"Bearer {self.api_key}"
        }
        
        response = requests.post(self.api_endpoint, headers=headers, json=payload)
        return self.parse_response(response.json())


class DeepSeekClient(LLMClient):
    """DeepSeek客户端"""
    
    def format_functions(self, functions):
        """DeepSeek格式的函数定义"""
        return [{"type": "function", "function": f} for f in functions]
    
    def parse_response(self, response):
        """解析DeepSeek响应"""
        return response["choices"][0]["message"]
    
    def send_message(self, messages, functions=None):
        """发送消息到DeepSeek"""
        payload = {
            "model": "deepseek-chat",
            "messages": messages,
            "tools": self.format_functions(functions) if functions else [],
            "tool_choice": "auto"
        }
        
        headers = {
            "Content-Type": "application/json",
            "Authorization": f"Bearer {self.api_key}"
        }
        
        response = requests.post(self.api_endpoint, headers=headers, json=payload)
        return self.parse_response(response.json())


# 使用示例
def create_client(provider):
    """工厂函数:创建指定提供商的客户端"""
    providers = {
        "alibaba": lambda: AlibabaClient(
            api_key=os.getenv("DASHSCOPE_API_KEY"),
            api_endpoint="https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation"
        ),
        "deepseek": lambda: DeepSeekClient(
            api_key=os.getenv("DEEPSEEK_API_KEY"),
            api_endpoint="https://api.deepseek.com/v1/chat/completions"
        )
    }
    
    if provider in providers:
        return providers[provider]()
    else:
        raise ValueError(f"不支持的提供商: {provider}")

6.3 高级功能

6.3.1 并发调用

支持同时调用多个函数:

import concurrent.futures

def execute_functions(tool_calls):
    """并发执行多个函数调用"""
    results = {}
    
    with concurrent.futures.ThreadPoolExecutor() as executor:
        # 准备所有函数调用任务
        future_to_func = {
            executor.submit(globals()[call.function.name], **eval(call.function.arguments)): call
            for call in tool_calls
        }
        
        # 收集结果
        for future in concurrent.futures.as_completed(future_to_func):
            call = future_to_func[future]
            try:
                result = future.result()
                results[call.function.name] = result
            except Exception as e:
                results[call.function.name] = {"error": str(e)}
    
    return results
6.3.2 函数链

支持多个函数按顺序调用:

def execute_function_chain(tool_calls, intermediate_results=None):
    """执行函数链,支持依赖传递"""
    if intermediate_results is None:
        intermediate_results = {}
    
    results = []
    
    for i, call in enumerate(tool_calls):
        func_name = call.function.name
        func_args = eval(call.function.arguments)
        
        # 替换依赖的参数
        for key, value in func_args.items():
            if isinstance(value, str) and value.startswith("$"):
                # 从中间结果中获取值
                ref_key = value[1:]
                if ref_key in intermediate_results:
                    func_args[key] = intermediate_results[ref_key]
        
        # 执行函数
        func = globals()[func_name]
        result = func(**func_args)
        
        # 保存结果供后续使用
        results.append({
            "function": func_name,
            "result": result
        })
        intermediate_results[func_name] = result
    
    return results
6.3.3 缓存机制

对重复调用进行缓存,提高效率:

from functools import lru_cache
import hashlib
import json

def cache_key(*args, **kwargs):
    """生成缓存键"""
    key_dict = {"args": args, "kwargs": kwargs}
    key_str = json.dumps(key_dict, sort_keys=True)
    return hashlib.md5(key_str.encode()).hexdigest()

class CachedFunctionCaller:
    """带缓存的函数调用器"""
    
    def __init__(self):
        self.cache = {}
        self.cache_ttl = 300  # 缓存5分钟
    
    def call_with_cache(self, func_name, **kwargs):
        """带缓存的函数调用"""
        key = cache_key(func_name, **kwargs)
        current_time = __import__('time').time()
        
        # 检查缓存
        if key in self.cache:
            cached_data = self.cache[key]
            if current_time - cached_data["time"] < self.cache_ttl:
                print(f"使用缓存: {func_name}")
                return cached_data["result"]
        
        # 执行函数
        func = globals()[func_name]
        result = func(**kwargs)
        
        # 保存到缓存
        self.cache[key] = {
            "time": current_time,
            "result": result
        }
        
        return result

七、总结与展望

7.1 技术总结

通过本文的讲解和实际代码示例,我们了解了:

  1. 技术原理:Function Calling如何让AI模型与外部世界交互
  2. 实现方式:如何在阿里云DashScope API中实现函数调用
  3. 代码结构:如何组织Function Calling的代码结构
  4. 最佳实践:函数定义、错误处理、响应解析等方面的最佳实践
  5. 扩展应用:如何添加新函数、支持多个服务提供商

7.2 应用前景

Function Calling技术的应用远不止本文所述的天气查询和文件操作。在实际开发中,您可以将其应用于:

  • 智能客服系统:自动查询订单状态、产品信息
  • 自动化工作流:按顺序执行多个操作步骤
  • 数据分析助手:查询数据库、生成报表
  • 智能家居控制:控制设备、查询状态
  • 企业应用集成:连接CRM、ERP等企业系统

7.3 未来发展方向

随着AI技术的不断发展,Function Calling技术也将持续演进:

  1. 更智能的函数选择:模型能够更准确地选择合适的函数
  2. 更强的参数理解:能够处理更复杂的参数提取场景
  3. 更丰富的工具生态:更多预定义的工具和API集成
  4. 更好的安全性:更严格的访问控制和权限管理

7.4 学习建议

对于想要深入学习Function Calling技术的开发者,建议:

  1. 理解原理:先理解Function Calling的基本原理和工作流程
  2. 动手实践:跟随本文示例动手实现一个简单的Function Calling应用
  3. 阅读文档:深入阅读阿里云、OpenAI等平台的官方文档
  4. 参与社区:加入AI开发者社区,了解最新动态和最佳实践
  5. 探索创新:尝试将Function Calling应用到自己的项目中

Function Calling技术是现代AI应用开发中不可或缺的技术之一。通过这项技术,AI不再仅仅是"聊天机器人",而是真正能够与现实世界交互、帮助用户完成实际任务的智能助手。希望本文能够帮助您更好地理解和应用这项技术,开启AI应用开发的新篇章。

关键词标签:Function Calling、AI、大语言模型、阿里云、Python、API集成

技术分类:人工智能、API开发、Python编程

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐