阿里云API函数调用与DeepSeek API对比分析

引言

随着大语言模型(LLM)技术的快速发展,各大云服务商都推出了自己的AI API服务。阿里云的DashScope和DeepSeek作为国内主要的AI服务提供商,都提供了函数调用(Function Calling)功能。本文将通过实际代码示例,详细分析阿里云API函数调用的实现逻辑,并与DeepSeek API进行对比,帮助开发者理解两者的异同。

一、函数调用概述

函数调用是LLM的一项重要能力,它允许模型在生成回复时调用外部函数或API,从而获取实时信息或执行特定操作。这种能力极大地扩展了AI模型的应用场景,使其能够:

  • 查询实时天气、股票等信息
  • 访问数据库获取数据
  • 执行文件操作
  • 调用第三方API
  • 等等…

二、阿里云API函数调用实现

2.1 函数定义

在阿里云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:函数参数定义,包括参数类型和描述

2.2 实际函数实现

# 定义函数用于通过高德天气接口查询天气
def get_weather(city):
    amap_api_key = os.getenv("AMAP_API_KEY")  # 建议使用环境变量获取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):
    with open(f"D:/path/to/directory/{filename}", "w", encoding="utf-8") as file:
        file.write(content)
    return f"文件{filename}写入成功"

2.3 API请求构建

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,
            "tool_choice": "auto",
            "temperature": 0.7
        }
    }
    
    # API密钥
    api_key = os.getenv("DASHSCOPE_API_KEY")
    
    # 请求头
    headers = {
        "Content-Type": "application/json",
        "Authorization": f"Bearer {api_key}"
    }
    
    # 发送请求
    response = requests.post(url, headers=headers, json=payload)
    
    return response.json()

2.4 响应处理与函数执行

def invoke(content):
    # 构建消息
    messages = [
        {"role": "system", "content": system_prompt},
        {"role": "user", "content": content}
    ]
    
    # 发送请求
    message = send_messages(messages)
    
    # 检查是否有函数调用
    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)
        
        return message.content
    else:
        return message.content

三、DeepSeek API对比

3.1 函数定义格式

阿里云API和DeepSeek API在函数定义格式上基本相同,都采用OpenAI标准的嵌套结构:

# 阿里云API格式
tools = [
    {
        "type": "function",
        "function": {
            "name": "get_weather",
            "description": "查询某个城市的天气",
            "parameters": {
                "type": "object",
                "properties": {
                    "city": {
                        "type": "string",
                        "description": "中国的城市名称",
                    }
                },
                "required": ["city"]
            },
        }
    }
]

# DeepSeek API格式(与阿里云相同)
tools = [
    {
        "type": "function",
        "function": {
            "name": "get_weather",
            "description": "查询某个城市的天气",
            "parameters": {
                "type": "object",
                "properties": {
                    "city": {
                        "type": "string",
                        "description": "中国的城市名称",
                    }
                },
                "required": ["city"]
            }
        }
    }
]

说明:两者的函数定义格式完全相同,都遵循OpenAI的标准格式。

3.2 API端点差异

服务商 API端点
阿里云 https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation
DeepSeek https://api.deepseek.com/v1/chat/completions

3.3 请求参数结构

阿里云API请求结构

payload = {
    "model": "qwen-plus",
    "input": {
        "messages": messages
    },
    "parameters": {
        "tools": tools,
        "tool_choice": "auto",
        "temperature": 0.7
    }
}

DeepSeek API请求结构

payload = {
    "model": "deepseek-chat",
    "messages": messages,
    "tools": tools,
    "tool_choice": "auto",
    "temperature": 0.7
}

3.4 响应格式差异

阿里云API响应

{
    "output": {
        "choices": [
            {
                "message": {
                    "content": "北京明天晴朗",
                    "tool_calls": [...]
                }
            }
        ]
    }
}

DeepSeek API响应

{
    "choices": [
        {
            "message": {
                "content": "北京明天晴朗",
                "tool_calls": [...]
            }
        }
    ]
}

四、核心区别总结

4.1 参数格式对比

特性 阿里云API DeepSeek API
函数定义格式 {"type": "function", "function": {...}} {"type": "function", "function": {...}}
工具参数名 tools tools
工具选择 tool_choice tool_choice
请求体结构 input.messages嵌套 直接messages数组
响应结构 output.choices choices
API版本 v1 v1

4.2 主要差异点

  1. 请求体结构

    • 阿里云:使用input字段包装messages
    • DeepSeek:直接使用messages数组
  2. 响应解析

    • 阿里云:从output.choices获取响应
    • DeepSeek:从choices直接获取响应
  3. 错误处理

    • 阿里云:返回codemessage字段
    • DeepSeek:返回error对象

4.3 代码适配示例

阿里云API

# 请求构建
payload = {
    "model": "qwen-plus",
    "input": {"messages": messages},
    "parameters": {"tools": tools}
}

# 响应解析
if "output" in response_data and "choices" in response_data["output"]:
    choice = response_data["output"]["choices"][0]
    message = choice["message"]

DeepSeek API

# 请求构建
payload = {
    "model": "deepseek-chat",
    "messages": messages,
    "tools": tools
}

# 响应解析
if "choices" in response_data:
    choice = response_data["choices"][0]
    message = choice["message"]

五、实践建议

5.1 统一封装

为了支持多个API提供商,可以创建统一的抽象层:

class BaseLLMClient:
    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_request(self, messages, functions):
        raise NotImplementedError

class AlibabaClient(BaseLLMClient):
    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"]

class DeepSeekClient(BaseLLMClient):
    def format_functions(self, functions):
        return [{"type": "function", "function": f} for f in functions]
    
    def parse_response(self, response):
        return response["choices"][0]["message"]

5.2 错误处理最佳实践

try:
    response = requests.post(url, headers=headers, json=payload)
    response.raise_for_status()
    
    response_data = response.json()
    
    if "error" in response_data:
        raise APIError(response_data["error"])
    
    # 正常处理响应
    result = self.parse_response(response_data)
    
except requests.exceptions.RequestException as e:
    logger.error(f"API请求失败: {e}")
    raise APIConnectionError(str(e))

5.3 性能优化

  1. 连接池:使用requests.Session()复用连接
  2. 超时设置:为请求设置合理的超时时间
  3. 重试机制:实现指数退避重试策略
  4. 缓存:对相同查询结果进行缓存

六、完整调用流程

# 1. 定义系统提示词
system_prompt = """
你是一名AI助手,具备函数调用的能力,
但是如果提供的信息已经足够回答用户的问题,则不需要再进行函数调用。
同时,请严格按照函数调用的方式进行处理。
"""

# 2. 定义可用函数
tools = [
    {
        "type": "function",
        "function": {
            "name": "get_weather",
            "description": "查询某个城市的天气",
            "parameters": {...}
        }
    }
]

# 3. 实现函数
def get_weather(city):
    # 调用天气API
    return weather_data

# 4. 创建客户端并调用
def main():
    client = AlibabaClient(api_key, api_endpoint)
    
    user_input = "明天北京天气怎么样?"
    result = client.invoke(user_input)
    
    print(result)

if __name__ == '__main__':
    main()

七、总结

阿里云API和DeepSeek API在函数调用方面都有各自的特点:

  1. 阿里云API

    • 使用input字段包装消息
    • 响应结构包含output
    • 需要额外的tool_choice参数
  2. DeepSeek API

    • 更接近OpenAI的标准格式
    • 响应结构更简洁
    • 使用统一的messages参数

重要说明:两者的函数定义格式完全相同,都采用{"type": "function", "function": {...}}的嵌套结构,遵循OpenAI的标准规范。

无论使用哪个API,关键在于:

  • 正确理解函数定义的格式要求
  • 正确解析API响应
  • 合理处理函数调用流程
  • 做好错误处理和异常恢复

通过合理的抽象和封装,可以实现对多个API提供商的统一支持,提高代码的可维护性和扩展性。

Logo

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

更多推荐