DeepSeek实战--Function Calling
1.背景
Function Calling由OpenAI提出,用于解决AI与外部系统交互的“桥梁”,通过将自然语言转化为结构化请求。允许模型根据用户输入的自然语言指令,自动识别需要调用的外部工具或API函数,并生成符合要求的结构化参数(如JSON格式)。这一技术让AI不仅能生成文本,还能与外部系统交互,完成更复杂的任务。
今天我们通过一个demo演示Function Calling 应用。
2.环境
- python 版本:3.11
- LLM: deepseek-chat
- SDK:openai 1.63.2
3.步骤
1)先注册deepseek账号,并充值,获取到APIkey
链接:https://platform.deepseek.com/api_keys
2)写一个获取最新股价的tools
def get_closing_price(name):if name == "青岛啤酒":return "67.92"elif name == "贵州茅台":return "1488.21"else:return "未搜到该股票"
3)定义一个工具列表,用于结构化说明tools,便于大模型理解
tools = [# 定义一个字典,表示一个特定的工具{# 工具的类型是函数"type": "function",# 函数的具体信息"function": {# 函数的名称是get_closing_price"name": "get_closing_price",# 函数的描述,说明了该函数的用途"description": "使用该工具获取指定股票的收盘价",# 函数的参数信息"parameters": {# 参数的类型是对象"type": "object",# 参数的属性"properties": {# 需要一个名称参数"name": {# 参数类型是字符串"type": "string",# 参数的描述,说明了需要提供股票名称"description": "股票名称",}},# 表示在参数中,'name'字段是必须提供的"required": ["name"]},}},
]
4)写一个程序调用大模型 + tools
import json
import os
# 导入OpenAI库,用于与OpenAI的API进行交互
from openai import OpenAIclient = OpenAI(api_key="sk-xxx【自己申请】",base_url="https://api.deepseek.com/v1")def send_messages(messages):response = client.chat.completions.create(model="deepseek-chat",messages=messages,tools=tools,tool_choice="auto")return response# 定义一个工具列表,用于存储不同类型的工具信息
tools = [# 定义一个字典,表示一个特定的工具{# 工具的类型是函数"type": "function",# 函数的具体信息"function": {# 函数的名称是get_closing_price"name": "get_closing_price",# 函数的描述,说明了该函数的用途"description": "使用该工具获取指定股票的收盘价",# 函数的参数信息"parameters": {# 参数的类型是对象"type": "object",# 参数的属性"properties": {# 需要一个名称参数"name": {# 参数类型是字符串"type": "string",# 参数的描述,说明了需要提供股票名称"description": "股票名称",}},# 表示在参数中,'name'字段是必须提供的"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_messages(messages)# 将API响应中的第一个选择的消息添加到消息列表中messages.append(response.choices[0].message)print("回复:")# 打印回复消息的内容print(response.choices[0].message.content)print("工具选择:")# 打印AI模型的响应中第一个选择的消息的工具调用信息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})# 打印消息列表print("messages: ",messages)# 发送消息列表并获取新的响应response = send_messages(messages)print("回复:")print(response.choices[0].message.content)
4.成果
回复:工具选择:
[ChatCompletionMessageToolCall(id='call_0_bcae63ee-55f4-49cd-9310-800f443a8ed8', function=Function(arguments='{"name":"青岛啤酒"}', name='get_closing_price'), type='function', index=0)]
messages: [{'role': 'user', 'content': '青岛啤酒的收盘价是多少?'}, ChatCompletionMessage(content='', refusal=None, role='assistant', annotations=None, audio=None, function_call=None, tool_calls=[ChatCompletionMessageToolCall(id='call_0_bcae63ee-55f4-49cd-9310-800f443a8ed8', function=Function(arguments='{"name":"青岛啤酒"}', name='get_closing_price'), type='function', index=0)]), {'role': 'tool', 'content': '67.92', 'tool_call_id': 'call_0_bcae63ee-55f4-49cd-9310-800f443a8ed8'}]
回复:
青岛啤酒的收盘价是67.92元。
5.总结
1)我一直用的java开发,写python脚本比较吃力,借助“通义灵码”轻松多了
2) 为什么需要2次调用大模型?
第一次,交互用于触发工具调用;
第二次,交互用于将工具调用的结果返回给模型,使其能够整合信息并生成用户可理解的最终回复。
这种设计符合“工具调用”的典型使用模式:先由模型判断是否需要调用工具,再实际调用工具并将结果反馈回模型以生成完整回答。
3)为什么要导入OpenAI sdk ?
OpenAI sdk 调用大模型的协议,各个大模型都做了兼容。 这样底层换了LLM也不需要更改,接口定义及程序调用。