【Agent学习笔记1:Python调用Function Calling,阿里云API函数调用与DeepSeek API对比分析】
本文对比分析了阿里云API和DeepSeek API的函数调用功能。两者在函数定义格式上完全一致,均采用OpenAI标准结构,包含函数名称、描述和参数定义。阿里云API通过tools参数传递函数定义,响应中包含tool_calls字段指示函数调用。实际使用时需手动执行函数并返回结果给模型。主要差异在于API端点地址不同:阿里云使用DashScope服务端点,而DeepSeek有其专用地址。整体实现
阿里云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 主要差异点
-
请求体结构:
- 阿里云:使用
input字段包装messages - DeepSeek:直接使用
messages数组
- 阿里云:使用
-
响应解析:
- 阿里云:从
output.choices获取响应 - DeepSeek:从
choices直接获取响应
- 阿里云:从
-
错误处理:
- 阿里云:返回
code和message字段 - 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 性能优化
- 连接池:使用
requests.Session()复用连接 - 超时设置:为请求设置合理的超时时间
- 重试机制:实现指数退避重试策略
- 缓存:对相同查询结果进行缓存
六、完整调用流程
# 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在函数调用方面都有各自的特点:
-
阿里云API:
- 使用
input字段包装消息 - 响应结构包含
output层 - 需要额外的
tool_choice参数
- 使用
-
DeepSeek API:
- 更接近OpenAI的标准格式
- 响应结构更简洁
- 使用统一的
messages参数
重要说明:两者的函数定义格式完全相同,都采用{"type": "function", "function": {...}}的嵌套结构,遵循OpenAI的标准规范。
无论使用哪个API,关键在于:
- 正确理解函数定义的格式要求
- 正确解析API响应
- 合理处理函数调用流程
- 做好错误处理和异常恢复
通过合理的抽象和封装,可以实现对多个API提供商的统一支持,提高代码的可维护性和扩展性。
更多推荐



所有评论(0)